From 638b459b08118642c3cdb800c3a4481b38a5d5af Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 4 Nov 2025 02:59:28 -0600 Subject: [PATCH] move window & presentation control into ui layer --- src/pp/pp.c | 82 ++++++------------ src/pp/pp.h | 5 -- src/ui/ui.lay | 1 + src/ui/ui_core.c | 110 ++++++++++++++++++------- src/ui/ui_core.h | 39 +++++---- src/window/window.h | 2 +- src/window/window_win32/window_win32.c | 18 ++-- src/window/window_win32/window_win32.h | 2 +- 8 files changed, 142 insertions(+), 117 deletions(-) diff --git a/src/pp/pp.c b/src/pp/pp.c index e741e480..0d6db3e7 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -357,16 +357,20 @@ void PP_UpdateUser(void) PP_SharedUserState *g = &PP_shared_user_state; TempArena scratch = BeginScratchNoConflict(); + //- Begin UI frame + UI_FrameFlag ui_frame_flags = 0; + if (g->ui_debug) + { + ui_frame_flags |= UI_FrameFlag_Debug; + } + UI_Frame ui_frame = UI_BeginFrame(ui_frame_flags); + WND_Frame window_frame = ui_frame.window_frame; + ControllerEventsArray controller_events = window_frame.controller_events; + g->real_dt_ns = TimeNs() - g->real_time_ns; g->real_time_ns += g->real_dt_ns; - if (g->swapchain) - { - GPU_YieldOnSwapchain(g->swapchain); - } - - //- Begin window frame - WND_Frame window_frame = WND_BeginFrame(scratch.arena); + //- Restore window if (g->user_tick == 0) { String restore = g->window_restore; @@ -387,30 +391,11 @@ void PP_UpdateUser(void) g->window_restore.len = src.len; } - ControllerEventsArray controller_events = window_frame.controller_events; g->screen_size = window_frame.draw_size; g->screen_size.x = MaxI32(g->screen_size.x, 1); g->screen_size.y = MaxI32(g->screen_size.y, 1); - //- Begin UI - UI_BuildFlag ui_build_flags = 0; - if (g->ui_debug) - { - ui_build_flags |= UI_BuildFlag_Debug; - } - - UI_BeginBuild(controller_events, ui_build_flags); - UI_Push(LayoutAxis, Axis_Y); - if (window_frame.forced_top) - { - UI_SetNext(Border, 10); - UI_SetNext(BorderColor, Rgba32F(1, 0, 0, 0.5)); - } - UI_Box *pp_root_box = UI_BuildBox(Lit("pp root")); - PP_PushGameUiStyle(); - UI_Push(Parent, pp_root_box); - //- Init render data buffers if (!g->material_instances_arena) { @@ -800,6 +785,20 @@ void PP_UpdateUser(void) g->ui_cursor = MulXformV2(InvertXform(g->ui_to_screen_xf), g->screen_cursor); + //- Init pp root box + UI_Push(LayoutAxis, Axis_Y); + if (window_frame.forced_top) + { + UI_SetNext(Border, 10); + UI_SetNext(BorderColor, Rgba32F(1, 0, 0, 0.5)); + } + UI_SetNext(Width, UI_PIX(g->ui_size.x, 1)); + UI_SetNext(Height, UI_PIX(g->ui_size.y, 1)); + UI_SetNext(Padding, UI_PADALL(UI_FILL(1, 0))); + UI_Box *pp_root_box = UI_BuildBox(Lit("pp root")); + PP_PushGameUiStyle(); + UI_Push(Parent, pp_root_box); + //- Update world to ui xform from camera if (g->debug_camera) { @@ -2144,21 +2143,6 @@ void PP_UpdateUser(void) g->shade_target = PP_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); @@ -2340,22 +2324,10 @@ void PP_UpdateUser(void) UI_SetBackgroundTexture(pp_root_box, g->shade_read, uv0, uv1); } - /* Render UI */ - g->gpu_submit_fence_target = UI_EndBuild(g->ui_target, g->ui_to_screen_xf); - ////////////////////////////// - //- Present & end frame + //- End frame - { - if (!g->swapchain) - { - g->swapchain = GPU_AcquireSwapchain(window_frame.window_handle, GPU_Format_R8G8B8A8_Unorm, g->screen_size); - } - 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_submit_fence_target = GPU_PresentSwapchain(g->swapchain, g->ui_target, window_frame.monitor_size, backbuffer_dst, VSYNC); - } - WND_EndFrame(window_frame); + g->gpu_submit_fence_target = UI_EndFrame(ui_frame); ++g->user_tick; EndScratch(scratch); diff --git a/src/pp/pp.h b/src/pp/pp.h index f21488ad..09cb3049 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -183,9 +183,6 @@ Struct(PP_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; @@ -237,8 +234,6 @@ Struct(PP_SharedUserState) //- Window - WND_Handle window; - GPU_Swapchain *swapchain; String window_restore; ////////////////////////////// diff --git a/src/ui/ui.lay b/src/ui/ui.lay index d3a92add..ff08a403 100644 --- a/src/ui/ui.lay +++ b/src/ui/ui.lay @@ -3,6 +3,7 @@ //- Dependencies @Dep gpu @Dep font +@Dep window //- Api @IncludeC ui_core.h diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 61380b4c..d0cb81e1 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -545,19 +545,33 @@ UI_Report UI_ReportFromKey(UI_Key key) } //////////////////////////////////////////////////////////// -//~ Begin build +//~ Begin frame -void UI_BeginBuild(ControllerEventsArray controller_events, UI_BuildFlag build_flags) +UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) { UI_SharedState *g = &UI_shared_state; + UI_Frame frame = ZI; + + ////////////////////////////// + //- Wait on swapchain + + if (g->swapchain) + { + GPU_YieldOnSwapchain(g->swapchain); + } + + ////////////////////////////// + //- Begin window frame + + frame.window_frame = WND_BeginFrame(); ////////////////////////////// //- Process controller events + ControllerEventsArray controller_events = frame.window_frame.controller_events; + if (g->build_arena != 0 && g->back_build_arena != 0) { - Xform screen_to_ui_xf = InvertXform(g->ui_to_screen_xf); - /* Locate boxes */ UI_Box *hovered_box = 0; UI_Box *active_box = 0; @@ -585,7 +599,7 @@ void UI_BeginBuild(ControllerEventsArray controller_events, UI_BuildFlag build_f case ControllerEventKind_CursorMove: { - g->cursor_pos = MulXformV2(screen_to_ui_xf, Vec2FromFields(cev.cursor_pos)); + g->cursor_pos = Vec2FromFields(cev.cursor_pos); if (hovered_box) { hovered_box->report.flags &= ~UI_ReportFlag_Hovered; @@ -650,7 +664,7 @@ void UI_BeginBuild(ControllerEventsArray controller_events, UI_BuildFlag build_f g->back_boxes_count = g->boxes_count; g->back_boxes_pre = g->boxes_pre; g->back_boxes_post = g->boxes_post; - g->back_build_flags = g->build_flags; + g->back_frame_flags = g->frame_flags; } ////////////////////////////// @@ -667,7 +681,7 @@ void UI_BeginBuild(ControllerEventsArray controller_events, UI_BuildFlag build_f g->first_free_checkpoint = 0; g->first_free_stack = 0; - g->build_flags = build_flags; + g->frame_flags = frame_flags; /* Init bins */ g->box_bins = PushStructs(g->build_arena, UI_BoxBin, UI_NumBoxLookupBins); @@ -682,7 +696,7 @@ void UI_BeginBuild(ControllerEventsArray controller_events, UI_BuildFlag build_f if (!g->back_build_arena) { /* Back buffer not initialized, swap again */ - UI_BeginBuild(controller_events, build_flags); + UI_BeginFrame(frame_flags); } } @@ -690,28 +704,42 @@ void UI_BeginBuild(ControllerEventsArray controller_events, UI_BuildFlag build_f //- Init style stack UI_PushStack(); + + return frame; } //////////////////////////////////////////////////////////// -//~ End build +//~ End frame -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, Xform ui_to_screen_xf) +i64 UI_EndFrame(UI_Frame frame) { TempArena scratch = BeginScratchNoConflict(); UI_SharedState *g = &UI_shared_state; - g->ui_to_screen_xf = ui_to_screen_xf; + Vec2I32 draw_size = frame.window_frame.draw_size; - Vec2I32 render_target_size = GPU_GetTextureSize2D(render_target); + GPU_QueueKind gpu_render_queue = GPU_QueueKind_Direct; + Fence *submit_fence = GPU_FenceFromQueue(gpu_render_queue); + + /* Acquire render target */ + if (g->render_target && !EqVec2I32(draw_size, GPU_GetTextureSize2D(g->render_target))) + { + __profn("Release ui render target"); + YieldOnFence(submit_fence, g->gpu_submit_fence_target); + GPU_ReleaseResource(g->render_target, GPU_ReleaseFlag_None); + g->render_target = 0; + } + if (!g->render_target) + { + __profn("Acquire ui 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(draw_size.x, draw_size.y, 1); + g->render_target = GPU_AcquireResource(desc); + } + + Vec2I32 render_target_size = GPU_GetTextureSize2D(g->render_target); Rect render_viewport = ZI; render_viewport.pos = VEC2(0, 0); render_viewport.size = VEC2(render_target_size.x, render_target_size.y); @@ -989,6 +1017,8 @@ i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf) /* Submit position */ box->p0 = final_pos; box->p1 = AddVec2(final_pos, dims); + box->report.screen_p0 = box->p0; + box->report.screen_p1 = box->p1; } /* Rounding */ @@ -1061,7 +1091,7 @@ i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf) is_visible = is_visible && ((box->tint & 0xFF000000) != 0); is_visible = is_visible && (box->p1.x > box->p0.x); is_visible = is_visible && (box->p1.y > box->p0.y); - if (is_visible || AnyBit(g->build_flags, UI_BuildFlag_Debug)) + if (is_visible || AnyBit(g->frame_flags, UI_FrameFlag_Debug)) { /* Box rect */ { @@ -1240,8 +1270,8 @@ i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf) { __profn("Clear target"); GPU_ProfN(cl, Lit("Clear target")); - GPU_TransitionToRenderable(cl, render_target, 0); - GPU_ClearRenderable(cl, render_target); + GPU_TransitionToRenderable(cl, g->render_target, 0); + GPU_ClearRenderable(cl, g->render_target); } //- Rect pass @@ -1271,7 +1301,7 @@ i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf) } /* Render rect wireframes */ - if (AnyBit(g->build_flags, UI_BuildFlag_Debug)) + if (AnyBit(g->frame_flags, UI_FrameFlag_Debug)) { UI_RectSig sig = ZI; sig.viewport_size = RoundVec2ToVec2I32(render_viewport.size); @@ -1292,7 +1322,7 @@ i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf) //- Prep post pass { - GPU_TransitionToWritable(cl, render_target); + GPU_TransitionToWritable(cl, g->render_target); } //- Post pass @@ -1302,17 +1332,35 @@ i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf) Vec2I32 viewport_size = RoundVec2ToVec2I32(render_viewport.size); UI_PostSig sig = ZI; sig.tex_size = viewport_size; - sig.tex = GPU_RWTexture2DRidFromResource(render_target); + sig.tex = GPU_RWTexture2DRidFromResource(g->render_target); sig.gamma = 2.2f; GPU_Compute(cl, &sig, UI_PostCS, (viewport_size.x + 7) / 8, (viewport_size.y + 7) / 8, 1); } } - i64 submit_fence_target = GPU_EndCommandList(cl); + g->gpu_submit_fence_target = GPU_EndCommandList(cl); /* Reset render data */ - GPU_ResetTransientBuffer(&g->draw_rects_tbuff, submit_fence_target); + GPU_ResetTransientBuffer(&g->draw_rects_tbuff, g->gpu_submit_fence_target); ResetArena(g->draw_rects_arena); + ////////////////////////////// + //- Present & end frame + + { + /* FIXME: Real xform */ + Xform ui_to_screen_xf = XformIdentity; + + Vec2I32 backbuffer_size = frame.window_frame.monitor_size; + if (!g->swapchain) + { + g->swapchain = GPU_AcquireSwapchain(frame.window_frame.window_handle, GPU_Format_R8G8B8A8_Unorm, backbuffer_size); + } + Vec2 backbuffer_dst_f = MulXformV2(ui_to_screen_xf, VEC2(0, 0)); + Vec2I32 backbuffer_dst = VEC2I32(RoundF32ToI32(backbuffer_dst_f.x), RoundF32ToI32(backbuffer_dst_f.y)); + g->gpu_submit_fence_target = GPU_PresentSwapchain(g->swapchain, g->render_target, backbuffer_size, backbuffer_dst, VSYNC); + } + WND_EndFrame(frame.window_frame); + EndScratch(scratch); - return submit_fence_target; + return g->gpu_submit_fence_target; } diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index 659e08ac..89057c18 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -9,15 +9,6 @@ Struct(UI_Key) u64 hash; }; -//////////////////////////////////////////////////////////// -//~ Build flags - -Enum(UI_BuildFlag) -{ - UI_BuildFlag_None = 0, - UI_BuildFlag_Debug = (1 << 0), -}; - //////////////////////////////////////////////////////////// //~ Size types @@ -182,6 +173,9 @@ Struct(UI_Report) { UI_ReportFlag flags; Vec2 activation_offset; + + Vec2 screen_p0; + Vec2 screen_p1; }; //////////////////////////////////////////////////////////// @@ -251,6 +245,20 @@ Struct(UI_BoxBin) UI_Box *last; }; +//////////////////////////////////////////////////////////// +//~ Frame types + +Enum(UI_FrameFlag) +{ + UI_FrameFlag_None = 0, + UI_FrameFlag_Debug = (1 << 0), +}; + +Struct(UI_Frame) +{ + WND_Frame window_frame; +}; + //////////////////////////////////////////////////////////// //~ State types @@ -260,14 +268,13 @@ Struct(UI_SharedState) { //- Control state Vec2 cursor_pos; - Xform ui_to_screen_xf; //- Build state Arena *build_arena; Arena *back_build_arena; - UI_BuildFlag build_flags; - UI_BuildFlag back_build_flags; + UI_FrameFlag frame_flags; + UI_FrameFlag back_frame_flags; UI_BoxBin *box_bins; UI_BoxBin *back_box_bins; @@ -290,6 +297,8 @@ Struct(UI_SharedState) UI_Box **back_boxes_post; //- Render state + GPU_Resource *render_target; + GPU_Swapchain *swapchain; i64 gpu_submit_fence_target; GPU_TransientBuffer draw_rects_tbuff; Arena *draw_rects_arena; @@ -385,12 +394,12 @@ b32 UI_IsPointInBox(UI_Box *box, Vec2 point); UI_Report UI_ReportFromKey(UI_Key key); //////////////////////////////////////////////////////////// -//~ Begin build +//~ Begin frame -void UI_BeginBuild(ControllerEventsArray controller_events, UI_BuildFlag flags); +UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags); //////////////////////////////////////////////////////////// //~ End build GPU_ResourceDesc UI_GetRenderTargetDesc(Vec2I32 size); -i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf); +i64 UI_EndFrame(UI_Frame frame); diff --git a/src/window/window.h b/src/window/window.h index ac397df9..30304650 100644 --- a/src/window/window.h +++ b/src/window/window.h @@ -61,5 +61,5 @@ void WND_PushCmd_(WND_Frame frame, WND_Cmd desc); //////////////////////////////////////////////////////////// //~ @hookdecl Frame -WND_Frame WND_BeginFrame(Arena *arena); +WND_Frame WND_BeginFrame(void); void WND_EndFrame(WND_Frame frame); diff --git a/src/window/window_win32/window_win32.c b/src/window/window_win32/window_win32.c index 03673226..32265a3f 100644 --- a/src/window/window_win32/window_win32.c +++ b/src/window/window_win32/window_win32.c @@ -390,19 +390,19 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l void WND_PushCmd_(WND_Frame frame, WND_Cmd desc) { WND_W32_Window *window = WND_W32_WindowFromHandle(frame.window_handle); - WND_W32_CmdNode *n = PushStruct(window->cmds_arena, WND_W32_CmdNode); + WND_W32_CmdNode *n = PushStruct(window->frame_arena, WND_W32_CmdNode); n->cmd = desc; QueuePush(window->first_cmd, window->last_cmd, n); if (desc.kind == WND_CmdKind_Restore) { - n->cmd.restore = PushString(window->cmds_arena, desc.restore); + n->cmd.restore = PushString(window->frame_arena, desc.restore); } } //////////////////////////////////////////////////////////// //~ @hookdef Frame -WND_Frame WND_BeginFrame(Arena *arena) +WND_Frame WND_BeginFrame(void) { WND_W32_SharedState *g = &WND_W32_shared_state; WND_W32_Window *window = &g->window; @@ -415,12 +415,12 @@ WND_Frame WND_BeginFrame(Arena *arena) HWND hwnd = window->hwnd; result.window_handle.v = (u64)window; - /* Reset cmds */ - if (!window->cmds_arena) + /* Reset per-frame data */ + if (!window->frame_arena) { - window->cmds_arena = AcquireArena(Gibi(64)); + window->frame_arena = AcquireArena(Gibi(64)); } - ResetArena(window->cmds_arena); + ResetArena(window->frame_arena); window->first_cmd = 0; window->last_cmd = 0; @@ -430,7 +430,7 @@ WND_Frame WND_BeginFrame(Arena *arena) { ControllerEvent *src = (ControllerEvent *)ArenaBase(window->w2u_events_arena); result.controller_events.count = ArenaCount(window->w2u_events_arena, ControllerEvent); - result.controller_events.events = PushStructsNoZero(arena, ControllerEvent, result.controller_events.count); + result.controller_events.events = PushStructsNoZero(window->frame_arena, ControllerEvent, result.controller_events.count); CopyStructs(result.controller_events.events, src, result.controller_events.count); ResetArena(window->w2u_events_arena); } @@ -501,7 +501,7 @@ WND_Frame WND_BeginFrame(Arena *arena) restore.snapped_screen_rect = screen_rect; } } - result.restore = PushString(window->cmds_arena, StringFromStruct(&restore)); + result.restore = PushString(window->frame_arena, StringFromStruct(&restore)); } return result; diff --git a/src/window/window_win32/window_win32.h b/src/window/window_win32/window_win32.h index 4e1bf0a9..0ec2ef90 100644 --- a/src/window/window_win32/window_win32.h +++ b/src/window/window_win32/window_win32.h @@ -10,7 +10,7 @@ Struct(WND_W32_Window) u16 previous_utf16_high_surrogate; /* User state */ - Arena *cmds_arena; + Arena *frame_arena; struct WND_W32_CmdNode *first_cmd; struct WND_W32_CmdNode *last_cmd; u64 frame_gen;