diff --git a/src/base/base_arena.h b/src/base/base_arena.h index 036e87f2..1eecf465 100644 --- a/src/base/base_arena.h +++ b/src/base/base_arena.h @@ -55,6 +55,7 @@ Struct(SharedArenaCtx) #define PopStructNoCopy(a, type) PopBytesNoCopy((a), sizeof(type)) #define PopStructsNoCopy(a, type, n) PopBytesNoCopy((a), sizeof(type) * (n)) +/* TOOD: Replace ArenaBase with 'ArenaFirst(type)' for dynamic-array-style uses */ #define ArenaBase(arena) ((u8 *)(arena) + ArenaHeaderSize) #define ArenaCount(arena, type) ((arena)->pos / sizeof(type)) diff --git a/src/gpu/gpu_dx12/gpu_dx12.c b/src/gpu/gpu_dx12/gpu_dx12.c index 0c84706e..f20cde27 100644 --- a/src/gpu/gpu_dx12/gpu_dx12.c +++ b/src/gpu/gpu_dx12/gpu_dx12.c @@ -2071,8 +2071,8 @@ GPU_D12_Swapchain *GPU_D12_AcquireSwapchain(HWND hwnd, GPU_Format format, Vec2I3 { DXGI_SWAP_CHAIN_DESC1 desc = ZI; desc.Format = GPU_D12_DxgiFormatFromGpuFormat(format); - desc.Width = size.x; - desc.Height = size.y; + desc.Width = MaxI32(size.x, 1); + desc.Height = MaxI32(size.y, 1); desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.BufferUsage = DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT; @@ -2159,11 +2159,6 @@ i64 GPU_D12_PresentSwapchain(GPU_D12_Swapchain *gpu_swapchain, GPU_Resource *gpu /* Present */ { __profn("Present"); - if (vsync) - { - /* FIXME: Only flush if windowed mode? */ - DwmFlush(); - } HRESULT hr = IDXGISwapChain3_Present(swapchain->swapchain, vsync, present_flags); if (!SUCCEEDED(hr)) { diff --git a/src/pp/pp.c b/src/pp/pp.c index ba37c365..8e7d91a9 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -30,8 +30,13 @@ void StartupUser(void) g->local_to_user_client_store = AcquireClientStore(); g->local_to_user_client = AcquireClient(g->local_to_user_client_store); - g->world_to_ui_xf = XformIdentity; - g->world_to_render_xf = XformIdentity; + /* Default persistent state */ + { + g->world_to_ui_xf = XformIdentity; + g->world_to_render_xf = XformIdentity; + // g->desired_window.flags = WND_Flag_Fullscreen; + g->desired_window.restore_p1 = VEC2I32(1920, 1080); + } /* Init from swap */ if (IsSwappedIn()); @@ -42,7 +47,7 @@ void StartupUser(void) { SwappedUserState *swap = (SwappedUserState *)swap_str.text; SharedUserState *old = &swap->s; - CopyStructRegion(g, old, PERSIST_START, PERSIST_END); + CopyStructRegion(g, old, AUTO_PERSIST_START, AUTO_PERSIST_END); } EndScratch(scratch); } @@ -53,7 +58,7 @@ void StartupUser(void) /* Create job pools */ JobPoolId user_pool = InitJobPool(1, Lit("User"), JobPoolPriority_Graphics); - JobPoolId sim_pool = InitJobPool(4, Lit("Simulation"), JobPoolPriority_Simulation); + JobPoolId sim_pool = InitJobPool(1, Lit("Simulation"), JobPoolPriority_Simulation); /* Start jobs */ g->shutdown_jobs_count += RunJob(UpdateUserOrSleep, .pool = user_pool, .fence = &g->shutdown_jobs_fence); @@ -308,114 +313,111 @@ P_LogEventCallbackFuncDef(ConsoleLogCallback, log) } //- Draw console -void DrawDebugConsole(i32 level, b32 minimized) +void DrawDebugConsole(b32 minimized) { - /* FIXME: Enable this */ -#if 0 + /* TODO: Remove this whole thing */ __prof; SharedUserState *g = &shared_user_state; TempArena scratch = BeginScratchNoConflict(); - Vec2 desired_start_pos = VEC2(10, minimized ? 100 : 600); - i64 fade_time_ns = NsFromSeconds(10); - f32 fade_curve = 0.5; - f32 spacing = 0; - f32 bg_margin = 5; + // i32 console_level = minimized ? P_LogLevel_Success : P_LogLevel_Debug; + i32 console_level = P_LogLevel_Debug; u32 colors[P_LogLevel_Count][2] = ZI; SetBytes(colors, 0xFF, sizeof(colors)); -#if 1 colors[P_LogLevel_Debug][0] = Rgb32F(0.4, 0.1, 0.4); colors[P_LogLevel_Debug][1] = Rgb32F(0.5, 0.2, 0.5); colors[P_LogLevel_Info][0] = Rgb32F(0.4, 0.4, 0.4); colors[P_LogLevel_Info][1] = Rgb32F(0.5, 0.5, 0.5); colors[P_LogLevel_Success][0] = Rgb32F(0.1, 0.3, 0.1); colors[P_LogLevel_Success][1] = Rgb32F(0.2, 0.4, 0.2); colors[P_LogLevel_Warning][0] = Rgb32F(0.4, 0.4, 0.1); colors[P_LogLevel_Warning][1] = Rgb32F(0.5, 0.5, 0.2); colors[P_LogLevel_Error][0] = Rgb32F(0.4, 0.1, 0.1); colors[P_LogLevel_Error][1] = Rgb32F(0.5, 0.2, 0.2); -#else - u32 info_colors[2] = { Rgb32F(0.4, 0.4, 0.4), Rgb32F(0.5, 0.5, 0.5) }; - u32 success_colors[2] = { Rgb32F(0.1, 0.3, 0.1), Rgb32F(0.2, 0.4, 0.2) }; - u32 warning_colors[2] = { Rgb32F(0.4, 0.4, 0.1), Rgb32F(0.5, 0.5, 0.2) }; - u32 error_colors[2] = { Rgb32F(0.4, 0.1, 0.1), Rgb32F(0.5, 0.2, 0.2) }; -#endif - Vec2 draw_pos = desired_start_pos; - f32 bounds_top = F32Infinity; - f32 bounds_bottom = -F32Infinity; - - if (g->console_logs_height < desired_start_pos.y) + i64 max_time_ns = I64Max; + i64 fade_time_ns = max_time_ns; + if (minimized) { - draw_pos.y = g->console_logs_height; + max_time_ns = NsFromSeconds(10); + fade_time_ns = max_time_ns; } - g->console_logs_height = 0; + f32 fade_curve = 0.5; + f32 spacing = 0; + f32 bg_margin = 5; i64 now_ns = TimeNs(); - F_Font *font = F_LoadFontAsync(ResourceKeyFromStore(&GameResources, Lit("font/fixedsys.ttf")), 12.0f); - if (font) + UI_PushCheckpoint(); { + UI_Box *console_box = 0; + { + UI_SetNext(LayoutAxis, Axis_Y); + UI_SetNext(Tint, 0); + console_box = UI_BuildBox(0, UI_NilKey); + } + UI_Push(Parent, console_box); + UI_Push(Width, UI_TextSize(0)); + UI_Push(Height, UI_TextSize(0)); + UI_Push(BorderColor, Rgba32F(0.25, 0.25, 0.25, 1)); + UI_Push(Border, 2); + UI_Push(Rounding, 0.5); + UI_Push(TextPadding, 6); Lock lock = LockE(&g->console_logs_mutex); { - for (ConsoleLog *log = g->last_console_log; log; log = log->prev) + /* Gather display logs */ + u64 max = 20; + u64 display_count = 0; + ConsoleLog **display_logs = PushStructs(scratch.arena, ConsoleLog *, max); { - f32 opacity = 0.75; + b32 done = 0; if (minimized) { - f32 lin = 1.0 - ClampF64((f64)(now_ns - log->time_ns) / (f64)fade_time_ns, 0, 1); - opacity *= PowF32(lin, fade_curve); + max = 5; } - if (draw_pos.y > -desired_start_pos.y && opacity > 0) + for (ConsoleLog *log = g->last_console_log; log && display_count < max && !done; log = log->prev) { - if (log->level <= level) + if (log->time_ns > (now_ns - max_time_ns)) { - /* Draw background */ - u32 color = colors[log->level][log->color_index]; - D_DrawQuad(g->render_sig, QuadFromRect(log->bounds), Alpha32F(color, opacity)); - - /* Draw text */ - String text = log->msg; - if (!minimized) + if (log->level <= console_level) { - P_DateTime datetime = log->datetime; - text = StringF( - scratch.arena, - "[%F:%F:%F.%F] %F", - FmtUintZ(datetime.hour, 2), - FmtUintZ(datetime.minute, 2), - FmtUintZ(datetime.second, 2), - FmtUintZ(datetime.milliseconds, 3), - FmtString(text)); + display_logs[display_count] = log; + ++display_count; } - - D_TextParams params = D_TEXTPARAMS(.font = font, .pos = draw_pos, .offset_y = DRAW_TEXT_OFFSET_Y_BOTTOM, .color = Alpha32F(Color_White, opacity), .str = text); - Rect bounds = draw_text(g->render_sig, params); - - Rect draw_bounds = bounds; - draw_bounds.x -= bg_margin; - draw_bounds.y -= bg_margin; - draw_bounds.width += bg_margin * 2.f; - draw_bounds.height += bg_margin * 2.f; - draw_pos.y -= draw_bounds.height + spacing; - log->bounds = draw_bounds; - - bounds_top = MinF32(bounds_top, draw_bounds.y); - bounds_bottom = MaxF32(bounds_bottom, draw_bounds.y + draw_bounds.height); + } + else + { + done = 1; } } - else + } + + /* Display logs in reverse */ + for (u64 i = display_count; i-- > 0;) + { + ConsoleLog *log = display_logs[i]; + f32 opacity = 0.75; + f32 lin = 1.0 - ClampF64((f64)(now_ns - log->time_ns) / (f64)fade_time_ns, 0, 1); + opacity *= PowF32(lin, fade_curve); + String text = log->msg; + if (!minimized) { - break; + P_DateTime datetime = log->datetime; + text = StringF( + scratch.arena, + "[%F:%F:%F.%F] %F", + FmtUintZ(datetime.hour, 2), + FmtUintZ(datetime.minute, 2), + FmtUintZ(datetime.second, 2), + FmtUintZ(datetime.milliseconds, 3), + FmtString(text)); } + u32 color = colors[log->level][log->color_index]; + UI_SetNext(BackgroundColor, color); + UI_SetNext(Tint, Alpha32F(0xFFFFFFFF, opacity)); + UI_Box *log_box = UI_BuildBox(UI_BoxFlag_DrawText, UI_NilKey); + UI_SetDisplayText(log_box, text); } } Unlock(&lock); } - if (bounds_top < F32Infinity && bounds_bottom > -F32Infinity) - { - g->console_logs_height = bounds_bottom - bounds_top; - } + UI_PopCheckpoint(); EndScratch(scratch); -#else - LAX level; - LAX minimized; -#endif } //////////////////////////////////////////////////////////// @@ -486,19 +488,25 @@ void UpdateUser(void) TempArena scratch = BeginScratchNoConflict(); //- Begin frame - WND_Event win_event = WND_BeginUpdate(scratch.arena); + WND_Event window_event = WND_BeginUpdate(scratch.arena); - u64 inputs_count = win_event.inputs_count; - Input *inputs = win_event.inputs; + u64 inputs_count = window_event.inputs_count; + Input *inputs = window_event.inputs; g->real_dt_ns = TimeNs() - g->real_time_ns; g->real_time_ns += g->real_dt_ns; - g->screen_size = SubVec2I32(g->window_settings.p1, g->window_settings.p0); - if (EqVec2I32(g->screen_size, VEC2I32(0, 0))) + //- Begin window + WND_Settings cur_window = window_event.settings; + if (window_event.os_gen > g->window_os_gen && window_event.cmd_gen > 0) { - g->screen_size = VEC2I32(1920, 1080); + /* Window was modified outside of program. Reflect this in our own state. */ + g->desired_window = cur_window; } + g->window_os_gen = window_event.os_gen; + g->screen_size = SubVec2I32(window_event.draw_p1, window_event.draw_p0); + g->screen_size.x = MaxI32(g->screen_size.x, 1); + g->screen_size.y = MaxI32(g->screen_size.y, 1); //- Begin UI UI_BeginBuild(); @@ -516,7 +524,6 @@ void UpdateUser(void) } //- Pull latest local sim snapshot - { __profn("Pull snapshot"); Lock lock = LockE(&g->local_to_user_client_mutex); @@ -534,7 +541,6 @@ void UpdateUser(void) } //- Create user world from blended snapshots - { __profn("Blend snapshots"); /* Determine how far along are we between sim ticks (0 = start of tick, 1 = end of tick) */ @@ -640,7 +646,6 @@ void UpdateUser(void) } //- Process inputs into user bind state - { __profn("Process inputs"); @@ -719,13 +724,11 @@ void UpdateUser(void) } //- Find local entities - Entity *local_player = EntityFromId(g->ss_blended, g->ss_blended->local_player); Entity *local_control = EntityFromId(g->ss_blended, local_player->player_control_ent); Entity *local_camera = EntityFromId(g->ss_blended, local_player->player_camera_ent); //- Find hovered entity - Entity *hovered_ent = NilEntity(); { Xform mouse_xf = XformFromPos(g->world_cursor); @@ -754,12 +757,10 @@ void UpdateUser(void) } //- Update user state from binds - - /* Test fullscreen */ { if (g->bind_states[BindKind_Fullscreen].num_presses && g->bind_states[BindKind_FullscreenMod].is_held) { - g->window_settings.flags ^= WND_Flag_Fullscreen; + g->desired_window.flags ^= WND_Flag_Fullscreen; } } @@ -770,7 +771,7 @@ void UpdateUser(void) if (g->bind_states[BindKind_DebugToggleTopmost].num_presses > 0) { - g->window_settings.flags ^= WND_Flag_ForcedTop; + g->desired_window.flags ^= WND_Flag_ForcedTop; P_LogSuccessF("Toggle topmost"); } @@ -822,7 +823,6 @@ void UpdateUser(void) } //- Apply shake - for (u64 ent_index = 0; ent_index < g->ss_blended->num_ents_reserved; ++ent_index) { Entity *ent = &g->ss_blended->ents[ent_index]; @@ -853,7 +853,6 @@ void UpdateUser(void) } //- Update ui to screen xform from screen size - if (g->debug_camera) { g->ui_size = g->screen_size; @@ -895,7 +894,6 @@ void UpdateUser(void) g->ui_cursor = MulXformV2(InvertXform(g->ui_to_screen_xf), g->screen_cursor); //- Update world to ui xform from camera - if (g->debug_camera) { g->world_to_ui_xf = XformWithWorldRotation(g->world_to_ui_xf, 0); @@ -998,7 +996,6 @@ void UpdateUser(void) } //- Update render to ui xform - { Xform world_to_ui_xf = g->world_to_ui_xf; Xform world_to_render_xf = g->world_to_render_xf; @@ -1008,7 +1005,6 @@ void UpdateUser(void) } //- Update listener from view - { Vec2 up = VEC2(0, -1); Vec2 ui_center = MulVec2(VEC2(g->ui_size.x, g->ui_size.y), 0.5f); @@ -1018,7 +1014,6 @@ void UpdateUser(void) } //- Draw grid - { f32 thickness = 2; @@ -1155,7 +1150,6 @@ void UpdateUser(void) #endif //- Sort drawable entities - Entity **sorted = PushDry(scratch.arena, Entity *); u64 sorted_count = 0; { @@ -1180,7 +1174,6 @@ void UpdateUser(void) } //- Draw entities - { __profn("Draw entities"); for (u64 sorted_index = 0; sorted_index < sorted_count; ++sorted_index) @@ -2042,9 +2035,7 @@ void UpdateUser(void) ////////////////////////////// //- Debug draw - /* FIXME: Enable this */ -#if 1 -#if 1 + /* Draw debug info */ if (g->debug_draw) { __profn("Draw debug info"); @@ -2115,144 +2106,15 @@ void UpdateUser(void) UI_BuildSpacer(UI_PixelSize(20, 0)); UI_BuildLabelF("Debug steps: %F", FmtUint(GetGstat(GSTAT_DEBUG_STEPS))); //UI_BuildLabelF(\n")); - -#endif - //draw_text(g->render_sig, font, pos, StringF(scratch.arena, "blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved))); - //draw_text(g->render_sig, font, pos, text); - -#if 0 - Vec2 pos = VEC2(10, g->ui_size.y); - D_TextOffsetY offset_y = DRAW_TEXT_OFFSET_Y_BOTTOM; - draw_text(g->render_sig, D_TEXTPARAMS(.font = font, .pos = pos, .str = text, .offset_y = offset_y, .color = Color_White)); #endif } UI_PopCheckpoint(); } -#else - if (g->debug_draw) + + /* Draw console */ { - __profn("Draw debug info"); - F_Font *font = F_LoadFontAsync(ResourceKeyFromStore(&GameResources, Lit("font/fixedsys.ttf")), 12.0f); - if (font) - { - TempArena temp = BeginTempArena(scratch.arena); - String text = ZI; - text.text = PushDry(temp.arena, u8); - -#if BITBUFF_DEBUG - text.len += StringF(temp.arena, "(bitbuff debug enabled)").len; - text.len += StringF(temp.arena, "\n").len; -#endif - - text.len += StringF(temp.arena, "blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved)).len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "blended world tick: %F", FmtUint(g->ss_blended->tick)).len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "blended world time: %F", FmtFloat(SecondsFromNs(g->ss_blended->sim_time_ns))).len; - text.len += StringF(temp.arena, "\n").len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "average local sim publish dt: %F", FmtFloat(SecondsFromNs(g->average_local_to_user_snapshot_publish_dt_ns))).len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "local sim last known tick: %F", FmtUint(g->local_sim_last_known_tick)).len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "local sim last known time: %F", FmtFloat(SecondsFromNs(g->local_sim_last_known_time_ns))).len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "local sim predicted time: %F", FmtFloat(SecondsFromNs(g->local_sim_predicted_time_ns))).len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "render time target: %F", FmtFloat(SecondsFromNs(g->render_time_target_ns))).len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "render time: %F", FmtFloat(SecondsFromNs(g->render_time_ns))).len; - text.len += StringF(temp.arena, "\n").len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "local player: [%F]", FmtUid(local_player->id.uid)).len; - text.len += StringF(temp.arena, "\n").len; - text.len += StringF(temp.arena, "\n").len; - - Vec2 world_cursor = g->world_cursor; - text.len += StringF(temp.arena, "cursor world: %F, %F", FmtFloat(world_cursor.x), FmtFloat(world_cursor.y)).len; - text.len += StringF(temp.arena, "\n").len; - - Vec2I32 world_tile_cursor = WorldTileIndexFromPos(world_cursor); - text.len += StringF(temp.arena, "cursor world tile: %F, %F", FmtSint(world_tile_cursor.x), FmtSint(world_tile_cursor.y)).len; - text.len += StringF(temp.arena, "\n").len; - - Vec2I32 local_tile_cursor = LocalTileIndexFromWorldTileIndex(world_tile_cursor); - text.len += StringF(temp.arena, "cursor local tile: %F, %F", FmtSint(local_tile_cursor.x), FmtSint(local_tile_cursor.y)).len; - text.len += StringF(temp.arena, "\n").len; - - Vec2I32 tile_chunk_cursor = TileChunkIndexFromWorldTileIndex(world_tile_cursor); - text.len += StringF(temp.arena, "cursor tile chunk: %F, %F", FmtSint(tile_chunk_cursor.x), FmtSint(tile_chunk_cursor.y)).len; - text.len += StringF(temp.arena, "\n").len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "Network read: %F mbit/s", FmtFloat((f64)g->net_bytes_read.last_second * 8 / 1000 / 1000)).len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "Network write: %F mbit/s", FmtFloat((f64)g->net_bytes_sent.last_second * 8 / 1000 / 1000)).len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "Ping (real): %F ms", FmtFloat(SecondsFromNs(local_player->player_last_rtt_ns) * 1000)).len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "Ping (average): %F ms", FmtFloat(local_player->player_average_rtt_seconds * 1000)).len; - text.len += StringF(temp.arena, "\n").len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "Memory committed: %F MiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_COMMITTED) / 1024 / 1024)).len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "Virtual memory reserved: %F TiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_RESERVED) / 1024 / 1024 / 1024 / 1024)).len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "Arenas allocated: %F", FmtUint(GetGstat(GSTAT_NUM_ARENAS))).len; - text.len += StringF(temp.arena, "\n").len; - text.len += StringF(temp.arena, "\n").len; - - text.len += StringF(temp.arena, "Video memory (GPU): %F MiB", FmtFloat((f64)vram.local_used / 1024 / 1024)).len; - text.len += StringF(temp.arena, "\n").len; - text.len += StringF(temp.arena, "Video memory (shared): %F MiB", FmtFloat((f64)vram.non_local_used / 1024 / 1024)).len; - //text.len += StringF(temp.arena, \n")).len; - //text.len += StringF(temp.arena, \n")).len; - -#if RtcIsEnabled - text.len += StringF(temp.arena, "\n").len; - text.len += StringF(temp.arena, "\n").len; - text.len += StringF(temp.arena, "Debug steps: %F", FmtUint(GetGstat(GSTAT_DEBUG_STEPS))).len; - //text.len += StringF(temp.arena, \n")).len; - -#endif - //draw_text(g->render_sig, font, pos, StringF(temp.arena, "blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved))); - //draw_text(g->render_sig, font, pos, text); - - Vec2 pos = VEC2(10, g->ui_size.y); - D_TextOffsetY offset_y = DRAW_TEXT_OFFSET_Y_BOTTOM; - draw_text(g->render_sig, D_TEXTPARAMS(.font = font, .pos = pos, .str = text, .offset_y = offset_y, .color = Color_White)); - EndTempArena(temp); - } - } -#endif -#endif - - { -#if DeveloperIsEnabled b32 console_minimized = !g->debug_console; - i32 console_level = console_minimized ? P_LogLevel_Success : P_LogLevel_Debug; - DrawDebugConsole(console_level, console_minimized); -#else - if (g->debug_draw) - { - DrawDebugConsole(P_LogLevel_Info, 0); - } -#endif + DrawDebugConsole(console_minimized); } ////////////////////////////// @@ -2261,7 +2123,7 @@ void UpdateUser(void) Rect ui_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->ui_size.x, g->ui_size.y)); Rect render_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->render_size.x, g->render_size.y)); GPU_QueueKind gpu_render_queue = GPU_QueueKind_Direct; - Fence *render_fence = GPU_FenceFromQueue(gpu_render_queue); + Fence *submit_fence = GPU_FenceFromQueue(gpu_render_queue); { __profn("Render"); @@ -2270,7 +2132,7 @@ void UpdateUser(void) if (g->shade_target && !EqVec2I32(g->render_size, GPU_GetTextureSize2D(g->shade_target))) { __profn("Release render resources"); - YieldOnFence(render_fence, g->gpu_render_fence_target); + YieldOnFence(submit_fence, g->gpu_submit_fence_target); GPU_ReleaseResource(g->albedo, GPU_ReleaseFlag_None); GPU_ReleaseResource(g->emittance, GPU_ReleaseFlag_None); GPU_ReleaseResource(g->emittance_flood_read, GPU_ReleaseFlag_None); @@ -2290,6 +2152,21 @@ void UpdateUser(void) g->shade_target = AcquireGbuffer(GPU_Format_R16G16B16A16_Float, g->render_size); } + /* Acquire ui target */ + if (g->ui_target && !EqVec2I32(g->ui_size, GPU_GetTextureSize2D(g->ui_target))) + { + __profn("Release ui target"); + YieldOnFence(submit_fence, g->gpu_submit_fence_target); + GPU_ReleaseResource(g->ui_target, GPU_ReleaseFlag_None); + g->ui_target = 0; + } + if (!g->ui_target) + { + __profn("Acquire ui target"); + GPU_ResourceDesc desc = UI_GetRenderTargetDesc(g->ui_size); + g->ui_target = GPU_AcquireResource(desc); + } + /* Upload transient buffers */ GPU_Resource *material_instances_buffer = GPU_UploadTransientBufferFromArena(&g->material_instances_tbuff, g->material_instances_arena); GPU_Resource *grids_buffer = GPU_UploadTransientBufferFromArena(&g->grids_tbuff, g->grids_arena); @@ -2452,11 +2329,11 @@ void UpdateUser(void) GPU_TransitionToReadable(cl, g->shade_read); GPU_TransitionToReadable(cl, g->shade_target); } - g->gpu_render_fence_target = GPU_EndCommandList(cl); + g->gpu_submit_fence_target = GPU_EndCommandList(cl); /* Reset render data */ - GPU_ResetTransientBuffer(&g->material_instances_tbuff, g->gpu_render_fence_target); - GPU_ResetTransientBuffer(&g->grids_tbuff, g->gpu_render_fence_target); + GPU_ResetTransientBuffer(&g->material_instances_tbuff, g->gpu_submit_fence_target); + GPU_ResetTransientBuffer(&g->grids_tbuff, g->gpu_submit_fence_target); ResetArena(g->material_instances_arena); ResetArena(g->grids_arena); } @@ -2472,35 +2349,23 @@ void UpdateUser(void) } /* Render UI */ - GPU_Resource *ui_render = UI_EndBuild(ui_viewport); + g->gpu_submit_fence_target = UI_EndBuild(g->ui_target); -#if 0 - ////////////////////////////// - //- Present - - Vec2 backbuffer_dst_f = MulXformV2(g->ui_to_screen_xf, VEC2(0, 0)); - Vec2I32 backbuffer_dst = VEC2I32(RoundF32ToI32(backbuffer_dst_f.x), RoundF32ToI32(backbuffer_dst_f.y)); - g->gpu_render_fence_target = GPU_PresentSwapchain(g->swapchain, ui_render, g->screen_size, backbuffer_dst, VSYNC); - // g->gpu_render_fence_target = GPU_PresentSwapchain(g->swapchain, g->ui_target, g->screen_size, backbuffer_dst, VSYNC); -#else ////////////////////////////// //- End window update - - g->window_settings.vsync = VSYNC; - g->window_settings.p0 = VEC2I32(0, 0); - g->window_settings.p1 = g->screen_size; { WND_Cmd cmd = ZI; - cmd.settings = g->window_settings; - cmd.texture = ui_render; + cmd.desired_settings = g->desired_window; + cmd.texture = g->ui_target; + cmd.vsync = VSYNC; { Vec2 backbuffer_dst_f = MulXformV2(g->ui_to_screen_xf, VEC2(0, 0)); cmd.backbuffer_dst = VEC2I32(RoundF32ToI32(backbuffer_dst_f.x), RoundF32ToI32(backbuffer_dst_f.y)); } - WND_EndUpdate(cmd); + g->gpu_submit_fence_target = WND_EndUpdateAndPresent(cmd); } -#endif + ++g->user_tick; EndScratch(scratch); } diff --git a/src/pp/pp.h b/src/pp/pp.h index 55e20e0b..d78b02fe 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -115,7 +115,6 @@ Struct(ConsoleLog) i32 color_index; P_DateTime datetime; i64 time_ns; - Rect bounds; ConsoleLog *prev; ConsoleLog *next; }; @@ -165,6 +164,9 @@ Struct(SharedUserState) Client *user_blended_client; /* Contains single snapshot from result of blending local sim snapshots */ Snapshot *ss_blended; /* Points to blended snapshot contained in blended client */ + u64 user_tick; + u64 window_os_gen; + //- Usage stats i64 last_second_reset_ns; SecondsStat net_bytes_read; @@ -178,6 +180,9 @@ Struct(SharedUserState) GPU_Resource *shade_read; GPU_Resource *shade_target; + //- Renderer target + GPU_Resource *ui_target; + //- Renderer transient buffers GPU_TransientBuffer material_instances_tbuff; GPU_TransientBuffer grids_tbuff; @@ -187,7 +192,7 @@ Struct(SharedUserState) //- Renderer state RandState frame_rand; u64 frame_index; - i64 gpu_render_fence_target; + i64 gpu_submit_fence_target; //- Bind state BindState bind_states[BindKind_Count]; @@ -198,7 +203,6 @@ Struct(SharedUserState) ConsoleLog *first_console_log; ConsoleLog *last_console_log; i32 console_log_color_indices[P_LogLevel_Count]; - f32 console_logs_height; b32 debug_console; //- Window -> user @@ -238,11 +242,11 @@ Struct(SharedUserState) ////////////////////////////// //- Persist start - StructRegion(PERSIST_START); + StructRegion(AUTO_PERSIST_START); //- Window - WND_Settings window_settings; + WND_Settings desired_window; //- Debug camera @@ -270,7 +274,7 @@ Struct(SharedUserState) Vec2 focus_send; - StructRegion(PERSIST_END); + StructRegion(AUTO_PERSIST_END); //- Persist end ////////////////////////////// @@ -306,7 +310,7 @@ String DebugStringFromEntity(Arena *arena, Entity *ent); //~ Console draw operations P_LogEventCallbackFuncDef(ConsoleLogCallback, log); -void DrawDebugConsole(i32 level, b32 minimized); +void DrawDebugConsole(b32 minimized); //////////////////////////////////////////////////////////// //~ Gpu buffer helpers diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 314fa314..c5f81734 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -60,6 +60,7 @@ void UI_PushCheckpoint(void) { cp = PushStruct(g->build_arena, UI_Checkpoint); } + cp->next = g->top_checkpoint; cp->v = g->top_checkpoint->v + 1; g->top_checkpoint = cp; } @@ -69,6 +70,10 @@ void UI_PopCheckpoint(void) UI_SharedState *g = &UI_shared_state; UI_Checkpoint *cp = g->top_checkpoint; u64 v = cp->v; + if (v == 0) + { + DEBUGBREAKABLE; + } for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind) { UI_StyleNode *n = g->style_tops[kind]; @@ -81,6 +86,7 @@ void UI_PopCheckpoint(void) n = next; } } + g->top_checkpoint = cp->next; cp->next = g->first_free_checkpoint; g->first_free_checkpoint = cp; } @@ -256,6 +262,7 @@ void UI_BeginBuild(void) ResetArena(g->build_arena); g->boxes_count = 0; g->first_free_style_node = 0; + g->first_free_checkpoint = 0; /* Init bins */ g->box_bins = PushStructs(g->build_arena, UI_BoxBin, UI_NumBoxLookupBins); @@ -299,11 +306,26 @@ void UI_BeginBuild(void) //////////////////////////////////////////////////////////// //~ End build -GPU_Resource *UI_EndBuild(Rect render_viewport) +GPU_ResourceDesc UI_GetRenderTargetDesc(Vec2I32 size) +{ + GPU_ResourceDesc desc = ZI; + desc.kind = GPU_ResourceKind_Texture2D; + desc.flags = GPU_ResourceFlag_Renderable | GPU_ResourceFlag_Writable; + desc.texture.format = GPU_Format_R8G8B8A8_Unorm; + desc.texture.size = VEC3I32(size.x, size.y, 1); + return desc; +} + +i64 UI_EndBuild(GPU_Resource *render_target) { TempArena scratch = BeginScratchNoConflict(); UI_SharedState *g = &UI_shared_state; + Vec2I32 render_target_size = GPU_GetTextureSize2D(render_target); + Rect render_viewport = ZI; + render_viewport.pos = VEC2(0, 0); + render_viewport.size = VEC2(render_target_size.x, render_target_size.y); + /* TODO: Ensure root is parent */ ////////////////////////////// @@ -311,9 +333,9 @@ GPU_Resource *UI_EndBuild(Rect render_viewport) /* Init root size */ g->root_box->pref_size[Axis_X].kind = UI_SizeKind_Pixel; - g->root_box->pref_size[Axis_X].v = render_viewport.size.x; + g->root_box->pref_size[Axis_X].v = render_viewport.size.x; g->root_box->pref_size[Axis_Y].kind = UI_SizeKind_Pixel; - g->root_box->pref_size[Axis_Y].v = render_viewport.size.y; + g->root_box->pref_size[Axis_Y].v = render_viewport.size.y; /* Build pre-order & post-order box arrays */ u64 boxes_count = g->boxes_count; @@ -554,23 +576,6 @@ GPU_Resource *UI_EndBuild(Rect render_viewport) ////////////////////////////// //- Render - /* Init render target */ - if (g->render_target && !EqVec2I32(VEC2I32(render_viewport.size.x, render_viewport.size.y), GPU_GetTextureSize2D(g->render_target))) - { - YieldOnFence(render_fence, g->render_fence_target); - GPU_ReleaseResource(g->render_target, GPU_ReleaseFlag_None); - g->render_target = 0; - } - if (!g->render_target) - { - GPU_ResourceDesc desc = ZI; - desc.kind = GPU_ResourceKind_Texture2D; - desc.flags = GPU_ResourceFlag_Renderable | GPU_ResourceFlag_Writable; - desc.texture.format = GPU_Format_R8G8B8A8_Unorm; - desc.texture.size = VEC3I32(render_viewport.size.x, render_viewport.size.y, 1); - g->render_target = GPU_AcquireResource(desc); - } - /* Upload transient buffers */ GPU_Resource *draw_rects_buffer = GPU_UploadTransientBufferFromArena(&g->draw_rects_tbuff, g->draw_rects_arena); u32 draw_rects_count = GPU_GetBufferCount(draw_rects_buffer); @@ -582,8 +587,8 @@ GPU_Resource *UI_EndBuild(Rect render_viewport) { __profn("Clear target"); GPU_ProfN(cl, Lit("Clear target")); - GPU_TransitionToRenderable(cl, g->render_target, 0); - GPU_ClearRenderable(cl, g->render_target); + GPU_TransitionToRenderable(cl, render_target, 0); + GPU_ClearRenderable(cl, render_target); } //- Rect pass @@ -612,7 +617,7 @@ GPU_Resource *UI_EndBuild(Rect render_viewport) //- Prep post pass { - GPU_TransitionToWritable(cl, g->render_target); + GPU_TransitionToWritable(cl, render_target); } //- Post pass @@ -622,17 +627,17 @@ GPU_Resource *UI_EndBuild(Rect render_viewport) Vec2I32 viewport_size = RoundVec2ToVec2I32(render_viewport.size); UI_PostSig sig = ZI; sig.tex_size = viewport_size; - sig.tex = GPU_RWTexture2DRidFromResource(g->render_target); + sig.tex = GPU_RWTexture2DRidFromResource(render_target); sig.gamma = 2.2f; GPU_Compute(cl, &sig, UI_PostCS, (viewport_size.x + 7) / 8, (viewport_size.y + 7) / 8, 1); } } - g->render_fence_target = GPU_EndCommandList(cl); + i64 submit_fence_target = GPU_EndCommandList(cl); /* Reset render data */ - GPU_ResetTransientBuffer(&g->draw_rects_tbuff, g->render_fence_target); + GPU_ResetTransientBuffer(&g->draw_rects_tbuff, submit_fence_target); ResetArena(g->draw_rects_arena); EndScratch(scratch); - return g->render_target; + return submit_fence_target; } diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index 1de3c85c..7cb8501e 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -180,9 +180,7 @@ Struct(UI_SharedState) UI_StyleNode *first_free_style_node; //- Render state - GPU_Resource *render_target; - i64 render_fence_target; - + i64 gpu_submit_fence_target; GPU_TransientBuffer draw_rects_tbuff; Arena *draw_rects_arena; @@ -249,4 +247,5 @@ void UI_BeginBuild(void); //////////////////////////////////////////////////////////// //~ End build -GPU_Resource *UI_EndBuild(Rect render_viewport); +GPU_ResourceDesc UI_GetRenderTargetDesc(Vec2I32 size); +i64 UI_EndBuild(GPU_Resource *render_target); diff --git a/src/window/window.h b/src/window/window.h index 1a8f2d53..010bdec7 100644 --- a/src/window/window.h +++ b/src/window/window.h @@ -3,35 +3,44 @@ Enum(WND_Flag) { - WND_Flag_None = (0), - WND_Flag_Fullscreen = (1 << 0), - WND_Flag_ForcedTop = (1 << 1), + WND_Flag_None = (0), + WND_Flag_ForcedTop = (1 << 0), + WND_Flag_RestoreToMaximized = (1 << 1), + WND_Flag_Fullscreen = (1 << 2), + WND_Flag_Maximized = (1 << 3), + WND_Flag_Minimized = (1 << 4), }; Struct(WND_Settings) { WND_Flag flags; - Vec2I32 p0; - Vec2I32 p1; - i32 vsync; -}; - -Struct(WND_Cmd) -{ - WND_Settings settings; - - GPU_Resource *texture; - Vec2I32 backbuffer_dst; + Vec2I32 restore_p0; + Vec2I32 restore_p1; }; Struct(WND_Event) { + WND_Settings settings; u64 inputs_count; Input *inputs; - WND_Settings settings; - /* The backbuffer src texture is no longer in use once the direct queue fence reaches this target */ - i64 backbuffer_fence_target; + Vec2I32 monitor_p0; + Vec2I32 monitor_p1; + + Vec2I32 draw_p0; + Vec2I32 draw_p1; + + u64 cmd_gen; /* How many times has a window cmd changed the window state */ + u64 os_gen; /* How many times has the OS changed window state (e.g. mouse drags OS window border) */ +}; + +Struct(WND_Cmd) +{ + WND_Settings desired_settings; + + GPU_Resource *texture; + Vec2I32 backbuffer_dst; + i32 vsync; }; //////////////////////////////////////////////////////////// @@ -43,4 +52,4 @@ void WND_Startup(void); //~ @hookdecl Window hooks WND_Event WND_BeginUpdate(Arena *arena); -void WND_EndUpdate(WND_Cmd cmd); +i64 WND_EndUpdateAndPresent(WND_Cmd cmd); diff --git a/src/window/window_win32/window_win32.c b/src/window/window_win32/window_win32.c index de1ac4c7..d4a171df 100644 --- a/src/window/window_win32/window_win32.c +++ b/src/window/window_win32/window_win32.c @@ -86,22 +86,10 @@ void WND_Startup(void) } //- Start message processing job - JobPoolId message_job_pool = InitJobPool(1, Lit("Win32 message loop"), JobPoolPriority_Background); + JobPoolId message_job_pool = InitJobPool(1, Lit("Win32 message loop"), JobPoolPriority_Graphics); RunJob(WND_W32_ProcessMessagesForever, .pool = message_job_pool); } -//////////////////////////////////////////////////////////// -//~ Input helpers - -void WND_W32_PushInput(WND_W32_Window *window, Input input) -{ - LockTicketMutex(&window->inputs_tm); - { - *PushStructNoZero(window->inputs_arena, Input) = input; - } - UnlockTicketMutex(&window->inputs_tm); -} - //////////////////////////////////////////////////////////// //~ Initialization @@ -110,7 +98,7 @@ JobDef(WND_W32_ProcessMessagesForever, sig, id) { WND_W32_SharedState *g = &WND_W32_shared_state; WND_W32_Window *window = &g->window; - window->inputs_arena = AcquireArena(Gibi(64)); + window->w2u_inputs_arena = AcquireArena(Gibi(64)); //- Init hwnd HWND hwnd = 0; @@ -170,18 +158,21 @@ JobDef(WND_W32_ProcessMessagesForever, sig, id) //////////////////////////////////////////////////////////// //~ Message processing +void WND_W32_PushInput(WND_W32_Window *window, Input input) +{ + LockTicketMutex(&window->w2u_tm); + { + *PushStructNoZero(window->w2u_inputs_arena, Input) = input; + } + UnlockTicketMutex(&window->w2u_tm); +} + LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { WND_W32_SharedState *g = &WND_W32_shared_state; WND_W32_Window *window = &g->window; - ++window->proc_depth; LRESULT result = 0; - Lock lock = ZI; - if (window->proc_depth == 1) - { - lock = LockE(&window->update_mutex); - } { switch(msg) { @@ -199,18 +190,6 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l WND_W32_PushInput(window, (Input) { .kind = InputKind_Quit }); } break; - //- Resizing - case WM_ENTERSIZEMOVE: - case WM_MOVE: - case WM_MOVING: - case WM_SIZE: - case WM_SIZING: - { - /* TODO */ - // P_W32_UpdateWindowFromSystem(window); - result = DefWindowProcW(hwnd, msg, wparam, lparam); - } break; - //- Keyboard button case WM_SYSKEYUP: case WM_SYSKEYDOWN:; @@ -390,14 +369,202 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l } EndScratch(scratch); } break; + + //- Process command + case WND_CmdMsgId: + { + P_LogWarningF("RAAAAH"); + + WND_Event user_event = ZI; + WND_Cmd user_cmd = ZI; + { + LockTicketMutex(&window->u2w_tm); + { + user_event = window->u2w_update_end_event; + user_cmd = window->u2w_update_end_cmd; + } + UnlockTicketMutex(&window->u2w_tm); + } + + /* Determine old settings */ + Vec2I32 old_draw_p0 = ZI; + Vec2I32 old_draw_p1 = ZI; + Vec2I32 old_restore_p0 = ZI; + Vec2I32 old_restore_p1 = ZI; + b32 old_is_visible = 0; + b32 old_has_border = 0; + { + { + RECT screen_rect = ZI; + GetClientRect(hwnd, (LPRECT)&screen_rect); + ClientToScreen(hwnd, (LPPOINT)&screen_rect.left); + ClientToScreen(hwnd, (LPPOINT)&screen_rect.right); + old_draw_p0 = VEC2I32(screen_rect.left, screen_rect.top); + old_draw_p1 = VEC2I32(screen_rect.right, screen_rect.bottom); + } + { + WINDOWPLACEMENT placement = { .length = sizeof(placement) }; + GetWindowPlacement(hwnd, &placement); + RECT placement_rect = placement.rcNormalPosition; + old_restore_p0 = VEC2I32(placement_rect.left, placement_rect.top); + old_restore_p1 = VEC2I32(placement_rect.right, placement_rect.bottom); + } + { + DWORD style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE); + old_is_visible = !!(style & WS_VISIBLE); + old_has_border = !(style & WS_POPUP); + } + } + + /* Determine new settings */ + Vec2I32 new_draw_p0 = old_draw_p0; + Vec2I32 new_draw_p1 = old_draw_p1; + Vec2I32 new_restore_p0 = old_restore_p0; + Vec2I32 new_restore_p1 = old_restore_p1; + b32 new_is_visible = old_is_visible; + b32 new_has_border = old_has_border; + { + WND_Settings desired_settings = user_cmd.desired_settings; + if (desired_settings.flags & WND_Flag_Fullscreen) + { + new_has_border = 0; + new_draw_p0 = user_event.monitor_p0; + new_draw_p1 = user_event.monitor_p1; + } + else if (desired_settings.flags & WND_Flag_Maximized) + { + // show_cmd = SW_MAXIMIZE; + } + else if (desired_settings.flags & WND_Flag_Minimized) + { + // show_cmd = SW_MINIMIZE; + } + else + { + new_has_border = 1; + new_restore_p0 = desired_settings.restore_p0; + new_restore_p1 = desired_settings.restore_p1; + } + new_is_visible = 1; + } + + /* Determine new style & placement */ + b32 has_user_seen_os_settings = user_event.os_gen == (u64)Atomic64Fetch(&window->os_gen); + if (has_user_seen_os_settings) + { + /* Calculate style */ + b32 dirty_style = 0; + DWORD new_style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE); + { + if (new_is_visible != old_is_visible) + { + dirty_style = 1; + if (new_is_visible) + { + new_style |= WS_VISIBLE; + } + else + { + new_style &= ~WS_VISIBLE; + } + } + if (new_has_border != old_has_border) + { + dirty_style = 1; + if (new_has_border) + { + new_style &= ~WS_POPUP; + new_style |= WS_OVERLAPPEDWINDOW; + } + else + { + new_style &= ~WS_OVERLAPPEDWINDOW; + new_style |= WS_POPUP; + } + } + } + + /* Calculate placement */ + b32 dirty_placement = 0; + WINDOWPLACEMENT new_placement = { .length = sizeof(new_placement) }; + GetWindowPlacement(hwnd, &new_placement); + { + if (!EqVec2I32(new_restore_p0, old_restore_p0) || !EqVec2I32(new_restore_p1, old_restore_p1)) + { + dirty_placement = 1; + new_placement.rcNormalPosition.left = new_restore_p0.x; + new_placement.rcNormalPosition.top = new_restore_p0.y; + new_placement.rcNormalPosition.right = new_restore_p1.x; + new_placement.rcNormalPosition.bottom = new_restore_p1.y; + } + } + + /* Calculate draw position */ + b32 dirty_draw_rect = 0; + RECT new_draw_rect = ZI; + if (!EqVec2I32(new_draw_p0, old_draw_p0) || !EqVec2I32(new_draw_p1, old_draw_p1)) + { + dirty_draw_rect = 1; + new_draw_rect.left = new_draw_p0.x; + new_draw_rect.top = new_draw_p0.y; + new_draw_rect.right = new_draw_p1.x; + new_draw_rect.bottom = new_draw_p1.y; + AdjustWindowRect(&new_draw_rect, new_style, 0); + } + + /* Apply changes */ + if (dirty_style || dirty_placement || dirty_draw_rect) + { + if (dirty_style) + { + ++window->cmd_depth; + SetWindowLongPtrW(hwnd, GWL_STYLE, new_style); + } + if (dirty_placement) + { + ++window->cmd_depth; + SetWindowPlacement(hwnd, &new_placement); + } + if (dirty_draw_rect) + { + u32 pflags = 0; + Vec2I32 size = VEC2I32(new_draw_rect.right - new_draw_rect.left, new_draw_rect.bottom - new_draw_rect.top); + ++window->cmd_depth; + SetWindowPos(hwnd, 0, new_draw_rect.left, new_draw_rect.top, size.x, size.y, pflags); + } + } + } + + /* Bring window to front on first show */ + if (!window->first_shown) + { + SetForegroundWindow(hwnd); + BringWindowToTop(hwnd); + window->first_shown = 1; + } + } break; + + //- Detect changes + case WM_WINDOWPOSCHANGED: + { + if (window->cmd_depth == 0) + { + /* This change occurred outside of a user window command, so it must come from the OS */ + Atomic64FetchAdd(&window->os_gen, 1); + P_LogInfoF("OS change"); + } + else + { + /* FIXME: In order for this to truly be the result of a user cmd we should clear the message queue after cmd submission */ + P_LogDebugF("Cmd change"); + Atomic64FetchAdd(&window->cmd_gen, 1); + --window->cmd_depth; + } + result = DefWindowProcW(hwnd, msg, wparam, lparam); + } break; } } - if (window->proc_depth == 1) - { - Unlock(&lock); - } - --window->proc_depth; return result; } @@ -410,72 +577,150 @@ WND_Event WND_BeginUpdate(Arena *arena) WND_W32_Window *window = &g->window; WND_Event result = ZI; - /* TODO: Yield on swapchain instead */ while (!Atomic32Fetch(&window->is_ready)) { _mm_pause(); } + HWND hwnd = window->hwnd; - /* FIXME: Don't use TM */ - Lock *lock = &window->user_update_lock; - *lock = LockE(&window->update_mutex); + /* Wait on swapchain */ + if (window->swapchain) + { + GPU_D12_YieldOnSwapchain(window->swapchain); + } /* Pop inputs */ - LockTicketMutex(&window->inputs_tm); { - Input *src = (Input *)ArenaBase(window->inputs_arena); - result.inputs_count = ArenaCount(window->inputs_arena, Input); - result.inputs = PushStructsNoZero(arena, Input, result.inputs_count); - CopyStructs(result.inputs, src, result.inputs_count); - ResetArena(window->inputs_arena); + LockTicketMutex(&window->w2u_tm); + { + Input *src = (Input *)ArenaBase(window->w2u_inputs_arena); + result.inputs_count = ArenaCount(window->w2u_inputs_arena, Input); + result.inputs = PushStructsNoZero(arena, Input, result.inputs_count); + CopyStructs(result.inputs, src, result.inputs_count); + ResetArena(window->w2u_inputs_arena); + } + UnlockTicketMutex(&window->w2u_tm); } - UnlockTicketMutex(&window->inputs_tm); - /* FIXME: Remove this */ - result.settings.p0 = window->previous_cmd.settings.p0; - result.settings.p1 = window->previous_cmd.settings.p1; + /* Grab monitor info */ + { + MONITORINFO monitor_info = { .cbSize = sizeof(monitor_info) }; + GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info); + RECT monitor_rect = monitor_info.rcMonitor; + result.monitor_p0.x = monitor_rect.left; + result.monitor_p0.y = monitor_rect.top; + result.monitor_p1.x = monitor_rect.right; + result.monitor_p1.y = monitor_rect.bottom; + } + /* Grab window info */ + WND_Settings settings = ZI; + { + /* Draw size */ + { + RECT screen_rect = ZI; + GetClientRect(hwnd, (LPRECT)&screen_rect); + ClientToScreen(hwnd, (LPPOINT)&screen_rect.left); + ClientToScreen(hwnd, (LPPOINT)&screen_rect.right); + result.draw_p0 = VEC2I32(screen_rect.left, screen_rect.top); + result.draw_p1 = VEC2I32(screen_rect.right, screen_rect.bottom); + } + + /* Clamp */ + // { + // RECT virt_rect = ZI; + // virt_rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN); + // virt_rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN); + // virt_rect.right = virt_rect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN); + // virt_rect.bottom = virt_rect.top + GetSystemMetrics(SM_CYVIRTUALSCREEN); + // result.draw_p0.x = MaxI32(result.draw_p0.x, virt_rect.left); + // result.draw_p0.y = MaxI32(result.draw_p0.y, virt_rect.top); + // result.draw_p1.x = MinI32(result.draw_p1.x, virt_rect.right); + // result.draw_p1.y = MinI32(result.draw_p1.y, virt_rect.bottom); + // } + // result.draw_p1.x = MaxI32(result.draw_p1.x, result.draw_p0.x + 320); + // result.draw_p1.y = MaxI32(result.draw_p1.y, result.draw_p0.y + 180); + + /* Minimized / maximized */ + WINDOWPLACEMENT placement = { .length = sizeof(placement) }; + GetWindowPlacement(hwnd, &placement); + if (placement.showCmd == SW_MAXIMIZE) + { + settings.flags |= WND_Flag_Maximized; + } + if (placement.showCmd == SW_MINIMIZE) + { + settings.flags |= WND_Flag_Minimized; + } + if (placement.flags & WPF_RESTORETOMAXIMIZED) + { + settings.flags |= WND_Flag_RestoreToMaximized; + } + + /* Restore size */ + { + RECT placement_rect = placement.rcNormalPosition; + settings.restore_p0 = VEC2I32(placement_rect.left, placement_rect.top); + settings.restore_p1 = VEC2I32(placement_rect.right, placement_rect.bottom); + } + + /* Fullscreen */ + /* TODO: Verify WS_POPUP as well */ + if (EqVec2I32(result.draw_p0, result.monitor_p0) && EqVec2I32(result.draw_p1, result.monitor_p1)) + { + settings.flags |= WND_Flag_Fullscreen; + } + + result.settings = settings; + } + + result.os_gen = Atomic64Fetch(&window->os_gen); + result.cmd_gen = Atomic64Fetch(&window->cmd_gen); + + window->update_begin_event = result; return result; } -void WND_EndUpdate(WND_Cmd cmd) +i64 WND_EndUpdateAndPresent(WND_Cmd cmd) { WND_W32_SharedState *g = &WND_W32_shared_state; WND_W32_Window *window = &g->window; + HWND hwnd = window->hwnd; - Unlock(&window->user_update_lock); + WND_Event begin_event = window->update_begin_event; + WND_Settings draw_settings = begin_event.settings; + Vec2I32 draw_size = SubVec2I32(begin_event.draw_p1, begin_event.draw_p0); - - - WND_Settings old = window->previous_cmd.settings; - WND_Settings new = cmd.settings; - - Vec2I32 new_size = SubVec2I32(new.p1, new.p0); - - /* Acquire swapchain */ if (!window->swapchain) { - window->swapchain = GPU_D12_AcquireSwapchain(window->hwnd, GPU_Format_R8G8B8A8_Unorm, new_size); + window->swapchain = GPU_D12_AcquireSwapchain(window->hwnd, GPU_Format_R8G8B8A8_Unorm, draw_size); } /* Present */ - /* TODO: Get fence */ + i64 present_fence_target = 0; if (cmd.texture != 0) { Vec2I32 backbuffer_dst = cmd.backbuffer_dst; - i32 vsync = new.vsync; - GPU_D12_PresentSwapchain(window->swapchain, cmd.texture, new_size, backbuffer_dst, vsync); + if (cmd.vsync != 0) + { + /* FIXME: Don't flush in fullscreen mode? */ + DwmFlush(); + } + present_fence_target = GPU_D12_PresentSwapchain(window->swapchain, cmd.texture, draw_size, backbuffer_dst, cmd.vsync); } - /* Show window */ - if (!window->first_shown) + /* Push cmd to window */ + b32 desires_change = !EqStruct(&cmd.desired_settings, &begin_event.settings); + if (desires_change) { - i32 show_cmd = SW_SHOWMAXIMIZED; - ShowWindow(window->hwnd, show_cmd); - SetForegroundWindow(window->hwnd); - BringWindowToTop(window->hwnd); - window->first_shown = 1; + LockTicketMutex(&window->u2w_tm); + { + window->u2w_update_end_cmd = cmd; + window->u2w_update_end_event = begin_event; + PostMessageW(window->hwnd, WND_CmdMsgId, 0, 0); + } + UnlockTicketMutex(&window->u2w_tm); } - window->previous_cmd = cmd; + return present_fence_target; } diff --git a/src/window/window_win32/window_win32.h b/src/window/window_win32/window_win32.h index 2512cac7..9ba9c3a0 100644 --- a/src/window/window_win32/window_win32.h +++ b/src/window/window_win32/window_win32.h @@ -1,29 +1,36 @@ //////////////////////////////////////////////////////////// //~ Window types +#define WND_CmdMsgId (WM_USER + 1) + Struct(WND_W32_Window) { - Atomic32 is_ready; HWND hwnd; GPU_D12_Swapchain *swapchain; + Atomic32 is_ready; - TicketMutex inputs_tm; - Arena *inputs_arena; - - - /* TODO: Remove this */ - // TicketMutex update_tm; - Mutex update_mutex; - Lock user_update_lock; - i32 proc_depth; - - - /* TODO: Remove this */ - b32 first_shown; - - WND_Cmd previous_cmd; + Atomic64 cmd_gen; + Atomic64 os_gen; + /* Window state */ u16 previous_utf16_high_surrogate; + b32 first_shown; + i64 cmd_depth; + + /* User state */ + WND_Event update_begin_event; + + /* Window -> User */ + /* Reads outside of window thread must lock */ + TicketMutex w2u_tm; + Arena *w2u_inputs_arena; + + + /* User -> Window */ + /* Reads outside of user thread must lock */ + TicketMutex u2w_tm; + WND_Event u2w_update_end_event; /* The user's processed event at end of update */ + WND_Cmd u2w_update_end_cmd; /* The user's cmd at the end of update */ }; //////////////////////////////////////////////////////////// @@ -38,11 +45,6 @@ Struct(WND_W32_SharedState) WND_W32_Window window; /* Only single-window for now */ } extern WND_W32_shared_state; -//////////////////////////////////////////////////////////// -//~ Input helpers - -void WND_W32_PushInput(WND_W32_Window *window, Input input); - //////////////////////////////////////////////////////////// //~ Initialization @@ -51,4 +53,5 @@ JobDecl(WND_W32_ProcessMessagesForever, EmptySig); //////////////////////////////////////////////////////////// //~ Message processing +void WND_W32_PushInput(WND_W32_Window *window, Input input); LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);