move window & presentation control into ui layer

This commit is contained in:
jacob 2025-11-04 02:59:28 -06:00
parent 2014f2474b
commit 638b459b08
8 changed files with 142 additions and 117 deletions

View File

@ -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);

View File

@ -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;
//////////////////////////////

View File

@ -3,6 +3,7 @@
//- Dependencies
@Dep gpu
@Dep font
@Dep window
//- Api
@IncludeC ui_core.h

View File

@ -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)
i64 UI_EndFrame(UI_Frame frame)
{
TempArena scratch = BeginScratchNoConflict();
UI_SharedState *g = &UI_shared_state;
Vec2I32 draw_size = frame.window_frame.draw_size;
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(size.x, size.y, 1);
return desc;
desc.texture.size = VEC3I32(draw_size.x, draw_size.y, 1);
g->render_target = GPU_AcquireResource(desc);
}
i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf)
{
TempArena scratch = BeginScratchNoConflict();
UI_SharedState *g = &UI_shared_state;
g->ui_to_screen_xf = ui_to_screen_xf;
Vec2I32 render_target_size = GPU_GetTextureSize2D(render_target);
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);
EndScratch(scratch);
return submit_fence_target;
//////////////////////////////
//- 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 g->gpu_submit_fence_target;
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;