From 2fdf891d4933eea60b4b4556a97d44af167f3b8c Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 15 Oct 2025 12:02:38 -0500 Subject: [PATCH] ui layer testing --- src/base/base_string.c | 2 +- src/config.h | 4 +- src/draw/draw.h | 2 +- src/gpu/gpu_dx12/gpu_dx12.c | 5 ++ src/pp/pp.c | 117 ++++++++++++++++++++++-- src/pp/pp.lay | 1 + src/ui/ui.c | 88 ++++++++++++++++++ src/ui/ui.h | 174 ++++++++++++++++++++++++++++++++++++ src/ui/ui.lay | 15 ++++ src/ui/ui_widgets.c | 32 +++++++ src/ui/ui_widgets.h | 11 +++ 11 files changed, 441 insertions(+), 10 deletions(-) create mode 100644 src/ui/ui.c create mode 100644 src/ui/ui.h create mode 100644 src/ui/ui.lay create mode 100644 src/ui/ui_widgets.c create mode 100644 src/ui/ui_widgets.h diff --git a/src/base/base_string.c b/src/base/base_string.c index 320edd2e..5cf9d7d6 100644 --- a/src/base/base_string.c +++ b/src/base/base_string.c @@ -518,7 +518,7 @@ String TrimWhitespace(String s) * Example: * FormatString(arena, Lit("Hello there %F"), FmtString(Lit("George"))) * - * NOTE: FmtEnd must be passed as the last arg in the va_list (This is + * NOTE: FmtEnd must be passed as the last arg in the va_list (this is * done automatically by the `FormatString` macro). * * Format arguments: diff --git a/src/config.h b/src/config.h index 53532d05..b663b6cb 100644 --- a/src/config.h +++ b/src/config.h @@ -69,7 +69,7 @@ #define FLOOD_DEBUG 0 -#define GPU_DEBUG 0 +#define GPU_DEBUG 1 /* If virtual fibers are enabled, each fiber will get its own OS thread, * and fiber suspend/resume will be emulated using OS thread primitives. @@ -94,6 +94,6 @@ /* TODO: Move these to user-configurable settings */ -#define VSYNC 0 +#define VSYNC 1 #define AUDIO_ENABLED 0 #define FPS_LIMIT 300 diff --git a/src/draw/draw.h b/src/draw/draw.h index 34573680..6dd377b3 100644 --- a/src/draw/draw.h +++ b/src/draw/draw.h @@ -36,7 +36,7 @@ Struct(D_UiRectParams) //~ Text types /* How is text aligned within its area */ -Enum( D_TextAlignment) +Enum(D_TextAlignment) { DRAW_TEXT_ALIGNMENT_LEFT, /* Default */ DRAW_TEXT_ALIGNMENT_CENTER, diff --git a/src/gpu/gpu_dx12/gpu_dx12.c b/src/gpu/gpu_dx12/gpu_dx12.c index ba526ea2..1f17a6c4 100644 --- a/src/gpu/gpu_dx12/gpu_dx12.c +++ b/src/gpu/gpu_dx12/gpu_dx12.c @@ -2153,6 +2153,11 @@ i64 GPU_PresentSwapchain(GPU_Swapchain *gpu_swapchain, GPU_Resource *gpu_texture /* 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 a3cd55b0..96e05d65 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -2023,9 +2023,116 @@ void UpdateUser(P_Window *window) GPU_MemoryInfo vram = GPU_QueryMemoryInfo(); - //- Draw global debug info + //~ Draw global debug info /* FIXME: Enable this */ +#if 1 +#if 1 + if (g->debug_draw) + { + __profn("Draw debug info"); + + UI_Box *dbg_box = UI_BuildBox(0, UI_NilKey); + UI_PushParent(dbg_box); + { + UI_BuildLabelF("blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved)); + UI_BuildSeparator(); + + UI_BuildLabelF("blended world tick: %F", FmtUint(g->ss_blended->tick)); + UI_BuildSeparator(); + + UI_BuildLabelF("blended world time: %F", FmtFloat(SecondsFromNs(g->ss_blended->sim_time_ns))); + UI_BuildSeparator(); + UI_BuildSeparator(); + + UI_BuildLabelF("average local sim publish dt: %F", FmtFloat(SecondsFromNs(g->average_local_to_user_snapshot_publish_dt_ns))); + UI_BuildSeparator(); + + UI_BuildLabelF("local sim last known tick: %F", FmtUint(g->local_sim_last_known_tick)); + UI_BuildSeparator(); + + UI_BuildLabelF("local sim last known time: %F", FmtFloat(SecondsFromNs(g->local_sim_last_known_time_ns))); + UI_BuildSeparator(); + + UI_BuildLabelF("local sim predicted time: %F", FmtFloat(SecondsFromNs(g->local_sim_predicted_time_ns))); + UI_BuildSeparator(); + + UI_BuildLabelF("render time target: %F", FmtFloat(SecondsFromNs(g->render_time_target_ns))); + UI_BuildSeparator(); + + UI_BuildLabelF("render time: %F", FmtFloat(SecondsFromNs(g->render_time_ns))); + UI_BuildSeparator(); + UI_BuildSeparator(); + + UI_BuildLabelF("local player: [%F]", FmtUid(local_player->id.uid)); + UI_BuildSeparator(); + UI_BuildSeparator(); + + Vec2 world_cursor = g->world_cursor; + UI_BuildLabelF("cursor world: %F, %F", FmtFloat(world_cursor.x), FmtFloat(world_cursor.y)); + UI_BuildSeparator(); + + Vec2I32 world_tile_cursor = WorldTileIndexFromPos(world_cursor); + UI_BuildLabelF("cursor world tile: %F, %F", FmtSint(world_tile_cursor.x), FmtSint(world_tile_cursor.y)); + UI_BuildSeparator(); + + Vec2I32 local_tile_cursor = LocalTileIndexFromWorldTileIndex(world_tile_cursor); + UI_BuildLabelF("cursor local tile: %F, %F", FmtSint(local_tile_cursor.x), FmtSint(local_tile_cursor.y)); + UI_BuildSeparator(); + + Vec2I32 tile_chunk_cursor = TileChunkIndexFromWorldTileIndex(world_tile_cursor); + UI_BuildLabelF("cursor tile chunk: %F, %F", FmtSint(tile_chunk_cursor.x), FmtSint(tile_chunk_cursor.y)); + UI_BuildSeparator(); + UI_BuildSeparator(); + + UI_BuildLabelF("Network read: %F mbit/s", FmtFloat((f64)g->net_bytes_read.last_second * 8 / 1000 / 1000)); + UI_BuildSeparator(); + + UI_BuildLabelF("Network write: %F mbit/s", FmtFloat((f64)g->net_bytes_sent.last_second * 8 / 1000 / 1000)); + UI_BuildSeparator(); + + UI_BuildLabelF("Ping (real): %F ms", FmtFloat(SecondsFromNs(local_player->player_last_rtt_ns) * 1000)); + UI_BuildSeparator(); + + UI_BuildLabelF("Ping (average): %F ms", FmtFloat(local_player->player_average_rtt_seconds * 1000)); + UI_BuildSeparator(); + UI_BuildSeparator(); + + UI_BuildLabelF("Memory committed: %F MiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_COMMITTED) / 1024 / 1024)); + UI_BuildSeparator(); + + UI_BuildLabelF("Virtual memory reserved: %F TiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_RESERVED) / 1024 / 1024 / 1024 / 1024)); + UI_BuildSeparator(); + + UI_BuildLabelF("Arenas allocated: %F", FmtUint(GetGstat(GSTAT_NUM_ARENAS))); + UI_BuildSeparator(); + UI_BuildSeparator(); + + UI_BuildLabelF("Video memory (GPU): %F MiB", FmtFloat((f64)vram.local_used / 1024 / 1024)); + UI_BuildSeparator(); + UI_BuildLabelF("Video memory (shared): %F MiB", FmtFloat((f64)vram.non_local_used / 1024 / 1024)); + //UI_BuildLabelF(\n")); + //UI_BuildLabelF(\n")); + +#if RtcIsEnabled + UI_BuildSeparator(); + UI_BuildSeparator(); + 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 = ColorWhite)); +#endif + } + UI_PopParent(); + } +#else if (g->debug_draw) { __profn("Draw debug info"); @@ -2130,14 +2237,14 @@ void UpdateUser(P_Window *window) //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); -#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 = ColorWhite)); -#endif EndTempArena(temp); } } +#endif +#endif { #if DeveloperIsEnabled @@ -2152,8 +2259,7 @@ void UpdateUser(P_Window *window) #endif } - //- Render - + //~ Render { __profn("Render"); GPU_QueueKind gpu_render_queue = GPU_QueueKind_Direct; @@ -3136,7 +3242,6 @@ JobDef(UpdateSim, UNUSED sig, UNUSED id) mispredicted_tick = master_ss->tick; } - u64 step_base_tick = local_client->last_tick; u64 step_end_tick = step_base_tick + 1; if (mispredicted_tick > 0) diff --git a/src/pp/pp.lay b/src/pp/pp.lay index 80824325..8c7af611 100644 --- a/src/pp/pp.lay +++ b/src/pp/pp.lay @@ -9,6 +9,7 @@ @Dep mixer @Dep rendertest @Dep playback +@Dep ui //- Api @IncludeC pp_sim.h diff --git a/src/ui/ui.c b/src/ui/ui.c new file mode 100644 index 00000000..7ae4504c --- /dev/null +++ b/src/ui/ui.c @@ -0,0 +1,88 @@ +UI_SharedState UI_shared_state = ZI; + +//////////////////////////////// +//~ State helpers + +UI_FiberState *UI_GetFiberState(void) +{ + UI_FiberState *f = UI_shared_state.fiber_states[FiberId()]; + if (!f) + { + { + Arena *perm = PermArena(); + PushAlign(perm, CachelineSize); + f = PushStruct(perm, UI_FiberState); + UI_shared_state.fiber_states[FiberId()] = f; + PushAlign(perm, CachelineSize); + } + f->build_arena = AcquireArena(Gibi(64)); + } + return f; +} + +//////////////////////////////// +//~ Key helpers + +UI_Key UI_KeyFromString(String str) +{ + UI_Key key = ZI; + key.hash = HashFnv64(Fnv64Basis, str); + return key; +} + +//////////////////////////////// +//~ Stack helpers + +void UI_PushParent(UI_Box *box) +{ + UI_FiberState *f = UI_GetFiberState(); +} + +UI_Box *UI_PopParent(void) +{ + UI_FiberState *f = UI_GetFiberState(); + UI_Box *box = 0; + return box; +} + +//////////////////////////////// +//~ Box helpers + +UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key) +{ + UI_Box *box = 0; + return box; +} + +//////////////////////////////// +//~ Text + +String UI_DisplayTextFromString(String str) +{ + /* Cap string at non-display pattern (e.g. "Hello##hiddentext" becomes "Hello") */ + u64 new_len = str.len; + if (str.len > 0) + { + b32 escaped = 0; + for (u64 i = 0; i < str.len - 1 && new_len == str.len; ++i) + { + u8 c = str.text[i]; + if (c == '\\') + { + escaped = !escaped; + } + else if (!escaped && c == '#' && str.text[i + 1] == '#') + { + new_len = i; + } + } + } + return STRING(new_len, str.text); +} + +void UI_SetDisplayText(UI_Box *box, String str) +{ + UI_FiberState *f = UI_GetFiberState(); + String text = PushString(f->build_arena, UI_DisplayTextFromString(str)); + box->display_text = text; +} diff --git a/src/ui/ui.h b/src/ui/ui.h new file mode 100644 index 00000000..0a74bfc1 --- /dev/null +++ b/src/ui/ui.h @@ -0,0 +1,174 @@ +//////////////////////////////// +//~ Key types + +#define UI_NilKey ((UI_Key) { 0 }) + +Struct(UI_Key) +{ + u64 hash; +}; + +//////////////////////////////// +//~ Box types + +Enum(UI_Flag) +{ + UI_Flag_None = 0, + UI_Flag_DrawText = (1 << 0), +}; + +Struct(UI_Box) +{ + UI_Flag flags; + String display_text; +}; + +//////////////////////////////// +//~ State types + +Struct(UI_FiberState) +{ + Arena *build_arena; +}; + +Struct(UI_SharedState) +{ + UI_FiberState *fiber_states[MaxFibers]; +} extern UI_shared_state; + +//////////////////////////////// +//~ State helpers + +UI_FiberState *UI_GetFiberState(void); + +//////////////////////////////// +//~ Key helpers + +UI_Key UI_KeyFromString(String text); + +//////////////////////////////// +//~ Stack helpers + +void UI_PushParent(UI_Box *box); +UI_Box *UI_PopParent(void); + +//////////////////////////////// +//~ Box + +UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key); + +//////////////////////////////// +//~ Text + +String UI_DisplayTextFromString(String str); +void UI_SetDisplayText(UI_Box *box, String str); + + + + + + + + + + + + + + + +/* TODO: Remove this */ + +#if 0 + +//////////////////////////////// +//~ Rect + +Struct(UI_RectParams) +{ + Xform xf; + GPU_Resource *texture; + ClipRect clip; + u32 tint; +}; +#define UI_RECTPARAMS(...) ((UI_RectParams) { \ + .tint = ColorWhite, \ + .clip = AllClipped, \ + __VA_ARGS__ \ +}) + +//////////////////////////////// +//~ Text types + +/* How is text aligned within its area */ +Enum(UI_TextAlignment) +{ + UI_TextAlignment_Left, /* Default */ + UI_TextAlignment_Center, + UI_TextAlignment_Right +}; + +/* How does the specified text position relate to the text area. + * E.g. Bottom & Right means the bottom-right of the text area will snap to + * the specified position. */ +Enum(UI_TextOffsetX) +{ + UI_TextOffsetX_Left, /* Default */ + UI_TextOffsetX_Center, + UI_TextOffsetX_Right +}; + +Enum(UI_TextOffsetY) +{ + UI_TextOffsetY_Top, /* Default */ + UI_TextOffsetY_Center, + UI_TextOffsetY_Bottom +}; + +Struct(UI_TextGlyph) +{ + f32 off_x; + f32 off_y; + f32 width; + f32 height; + f32 advance; + ClipRect clip; +}; + +Struct(UI_TextLine) +{ + f32 line_width; + u32 num_glyphs; + UI_TextGlyph *glyphs; + UI_TextLine *next; +}; + +Struct(UI_TextParams) +{ + F_Font *font; + Vec2 pos; + f32 scale; + u32 color; + UI_TextAlignment alignment; + UI_TextOffsetX offset_x; + UI_TextOffsetY offset_y; + String str; +}; +#define UI_TEXTPARAMS(...) ((UI_TextParams) { \ + .scale = 1.0, \ + .alignment = UI_TextAlignment_Left, \ + .offset_x = UI_TextOffsetX_Left, \ + .offset_y = UI_TextOffsetY_Top, \ + .color = ColorWhite, \ + __VA_ARGS__ \ +})s + +//////////////////////////////// +//~ State types + +Struct(UI_SharedState) +{ + i32 _; +} extern UI_shared_state; + +#endif diff --git a/src/ui/ui.lay b/src/ui/ui.lay new file mode 100644 index 00000000..5743761a --- /dev/null +++ b/src/ui/ui.lay @@ -0,0 +1,15 @@ +@Layer ui + +//- Dependencies +@Dep gpu + +//- Api +@IncludeC ui.h +@IncludeC ui_widgets.h + +//- Impl +@IncludeC ui.c +@IncludeC ui_widgets.c + +//- Startup +@startup UI_Startup diff --git a/src/ui/ui_widgets.c b/src/ui/ui_widgets.c new file mode 100644 index 00000000..b4cbfa99 --- /dev/null +++ b/src/ui/ui_widgets.c @@ -0,0 +1,32 @@ +//////////////////////////////// +//~ Label widget + +UI_Box *UI_BuildLabel(String text) +{ + UI_Key key = UI_KeyFromString(text); + UI_Box *box = UI_BuildBox(UI_Flag_DrawText, key); + UI_SetDisplayText(box, text); + return box; +} + +UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...) +{ + UI_FiberState *f = UI_GetFiberState(); + TempArena scratch = BeginScratchNoConflict(); + va_list args; + va_start(args, fmt_cstr); + String text = FormatStringV(scratch.arena, StringFromCstrNoLimit(fmt_cstr), args); + UI_Box *box = UI_BuildLabel(text); + va_end(args); + EndScratch(scratch); + return box; +} + +//////////////////////////////// +//~ Separator widget + +UI_Box *UI_BuildSeparator(void) +{ + UI_Box *box = UI_BuildBox(0, UI_NilKey); + return box; +} diff --git a/src/ui/ui_widgets.h b/src/ui/ui_widgets.h new file mode 100644 index 00000000..2c38155b --- /dev/null +++ b/src/ui/ui_widgets.h @@ -0,0 +1,11 @@ +//////////////////////////////// +//~ Label widget + +UI_Box *UI_BuildLabel(String text); +UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...); +#define UI_BuildLabelF(fmt_cstr, ...) UI_BuildLabelF_(fmt_cstr, __VA_ARGS__, FmtEnd) + +//////////////////////////////// +//~ Separator widget + +UI_Box *UI_BuildSeparator(void);