window layer working

This commit is contained in:
jacob 2025-10-26 18:33:31 -05:00
parent c724b79c2c
commit 6beb910f98
9 changed files with 538 additions and 412 deletions

View File

@ -55,6 +55,7 @@ Struct(SharedArenaCtx)
#define PopStructNoCopy(a, type) PopBytesNoCopy((a), sizeof(type)) #define PopStructNoCopy(a, type) PopBytesNoCopy((a), sizeof(type))
#define PopStructsNoCopy(a, type, n) PopBytesNoCopy((a), sizeof(type) * (n)) #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 ArenaBase(arena) ((u8 *)(arena) + ArenaHeaderSize)
#define ArenaCount(arena, type) ((arena)->pos / sizeof(type)) #define ArenaCount(arena, type) ((arena)->pos / sizeof(type))

View File

@ -2071,8 +2071,8 @@ GPU_D12_Swapchain *GPU_D12_AcquireSwapchain(HWND hwnd, GPU_Format format, Vec2I3
{ {
DXGI_SWAP_CHAIN_DESC1 desc = ZI; DXGI_SWAP_CHAIN_DESC1 desc = ZI;
desc.Format = GPU_D12_DxgiFormatFromGpuFormat(format); desc.Format = GPU_D12_DxgiFormatFromGpuFormat(format);
desc.Width = size.x; desc.Width = MaxI32(size.x, 1);
desc.Height = size.y; desc.Height = MaxI32(size.y, 1);
desc.SampleDesc.Count = 1; desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0; desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT; 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 */ /* Present */
{ {
__profn("Present"); __profn("Present");
if (vsync)
{
/* FIXME: Only flush if windowed mode? */
DwmFlush();
}
HRESULT hr = IDXGISwapChain3_Present(swapchain->swapchain, vsync, present_flags); HRESULT hr = IDXGISwapChain3_Present(swapchain->swapchain, vsync, present_flags);
if (!SUCCEEDED(hr)) if (!SUCCEEDED(hr))
{ {

View File

@ -30,8 +30,13 @@ void StartupUser(void)
g->local_to_user_client_store = AcquireClientStore(); g->local_to_user_client_store = AcquireClientStore();
g->local_to_user_client = AcquireClient(g->local_to_user_client_store); g->local_to_user_client = AcquireClient(g->local_to_user_client_store);
g->world_to_ui_xf = XformIdentity; /* Default persistent state */
g->world_to_render_xf = XformIdentity; {
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 */ /* Init from swap */
if (IsSwappedIn()); if (IsSwappedIn());
@ -42,7 +47,7 @@ void StartupUser(void)
{ {
SwappedUserState *swap = (SwappedUserState *)swap_str.text; SwappedUserState *swap = (SwappedUserState *)swap_str.text;
SharedUserState *old = &swap->s; SharedUserState *old = &swap->s;
CopyStructRegion(g, old, PERSIST_START, PERSIST_END); CopyStructRegion(g, old, AUTO_PERSIST_START, AUTO_PERSIST_END);
} }
EndScratch(scratch); EndScratch(scratch);
} }
@ -53,7 +58,7 @@ void StartupUser(void)
/* Create job pools */ /* Create job pools */
JobPoolId user_pool = InitJobPool(1, Lit("User"), JobPoolPriority_Graphics); 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 */ /* Start jobs */
g->shutdown_jobs_count += RunJob(UpdateUserOrSleep, .pool = user_pool, .fence = &g->shutdown_jobs_fence); g->shutdown_jobs_count += RunJob(UpdateUserOrSleep, .pool = user_pool, .fence = &g->shutdown_jobs_fence);
@ -308,114 +313,111 @@ P_LogEventCallbackFuncDef(ConsoleLogCallback, log)
} }
//- Draw console //- Draw console
void DrawDebugConsole(i32 level, b32 minimized) void DrawDebugConsole(b32 minimized)
{ {
/* FIXME: Enable this */ /* TODO: Remove this whole thing */
#if 0
__prof; __prof;
SharedUserState *g = &shared_user_state; SharedUserState *g = &shared_user_state;
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
Vec2 desired_start_pos = VEC2(10, minimized ? 100 : 600); // i32 console_level = minimized ? P_LogLevel_Success : P_LogLevel_Debug;
i64 fade_time_ns = NsFromSeconds(10); i32 console_level = P_LogLevel_Debug;
f32 fade_curve = 0.5;
f32 spacing = 0;
f32 bg_margin = 5;
u32 colors[P_LogLevel_Count][2] = ZI; u32 colors[P_LogLevel_Count][2] = ZI;
SetBytes(colors, 0xFF, sizeof(colors)); 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_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_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_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_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); 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; i64 max_time_ns = I64Max;
f32 bounds_top = F32Infinity; i64 fade_time_ns = max_time_ns;
f32 bounds_bottom = -F32Infinity; if (minimized)
if (g->console_logs_height < desired_start_pos.y)
{ {
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(); i64 now_ns = TimeNs();
F_Font *font = F_LoadFontAsync(ResourceKeyFromStore(&GameResources, Lit("font/fixedsys.ttf")), 12.0f); UI_PushCheckpoint();
if (font)
{ {
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); 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) if (minimized)
{ {
f32 lin = 1.0 - ClampF64((f64)(now_ns - log->time_ns) / (f64)fade_time_ns, 0, 1); max = 5;
opacity *= PowF32(lin, fade_curve);
} }
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 */ if (log->level <= console_level)
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)
{ {
P_DateTime datetime = log->datetime; display_logs[display_count] = log;
text = StringF( ++display_count;
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));
} }
}
D_TextParams params = D_TEXTPARAMS(.font = font, .pos = draw_pos, .offset_y = DRAW_TEXT_OFFSET_Y_BOTTOM, .color = Alpha32F(Color_White, opacity), .str = text); else
Rect bounds = draw_text(g->render_sig, params); {
done = 1;
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 }
/* 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); Unlock(&lock);
} }
if (bounds_top < F32Infinity && bounds_bottom > -F32Infinity) UI_PopCheckpoint();
{
g->console_logs_height = bounds_bottom - bounds_top;
}
EndScratch(scratch); EndScratch(scratch);
#else
LAX level;
LAX minimized;
#endif
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -486,19 +488,25 @@ void UpdateUser(void)
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
//- Begin frame //- 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; u64 inputs_count = window_event.inputs_count;
Input *inputs = win_event.inputs; Input *inputs = window_event.inputs;
g->real_dt_ns = TimeNs() - g->real_time_ns; g->real_dt_ns = TimeNs() - g->real_time_ns;
g->real_time_ns += g->real_dt_ns; g->real_time_ns += g->real_dt_ns;
g->screen_size = SubVec2I32(g->window_settings.p1, g->window_settings.p0); //- Begin window
if (EqVec2I32(g->screen_size, VEC2I32(0, 0))) 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 //- Begin UI
UI_BeginBuild(); UI_BeginBuild();
@ -516,7 +524,6 @@ void UpdateUser(void)
} }
//- Pull latest local sim snapshot //- Pull latest local sim snapshot
{ {
__profn("Pull snapshot"); __profn("Pull snapshot");
Lock lock = LockE(&g->local_to_user_client_mutex); Lock lock = LockE(&g->local_to_user_client_mutex);
@ -534,7 +541,6 @@ void UpdateUser(void)
} }
//- Create user world from blended snapshots //- Create user world from blended snapshots
{ {
__profn("Blend snapshots"); __profn("Blend snapshots");
/* Determine how far along are we between sim ticks (0 = start of tick, 1 = end of tick) */ /* 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 //- Process inputs into user bind state
{ {
__profn("Process inputs"); __profn("Process inputs");
@ -719,13 +724,11 @@ void UpdateUser(void)
} }
//- Find local entities //- Find local entities
Entity *local_player = EntityFromId(g->ss_blended, g->ss_blended->local_player); 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_control = EntityFromId(g->ss_blended, local_player->player_control_ent);
Entity *local_camera = EntityFromId(g->ss_blended, local_player->player_camera_ent); Entity *local_camera = EntityFromId(g->ss_blended, local_player->player_camera_ent);
//- Find hovered entity //- Find hovered entity
Entity *hovered_ent = NilEntity(); Entity *hovered_ent = NilEntity();
{ {
Xform mouse_xf = XformFromPos(g->world_cursor); Xform mouse_xf = XformFromPos(g->world_cursor);
@ -754,12 +757,10 @@ void UpdateUser(void)
} }
//- Update user state from binds //- Update user state from binds
/* Test fullscreen */
{ {
if (g->bind_states[BindKind_Fullscreen].num_presses && g->bind_states[BindKind_FullscreenMod].is_held) 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) 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"); P_LogSuccessF("Toggle topmost");
} }
@ -822,7 +823,6 @@ void UpdateUser(void)
} }
//- Apply shake //- Apply shake
for (u64 ent_index = 0; ent_index < g->ss_blended->num_ents_reserved; ++ent_index) for (u64 ent_index = 0; ent_index < g->ss_blended->num_ents_reserved; ++ent_index)
{ {
Entity *ent = &g->ss_blended->ents[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 //- Update ui to screen xform from screen size
if (g->debug_camera) if (g->debug_camera)
{ {
g->ui_size = g->screen_size; 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); g->ui_cursor = MulXformV2(InvertXform(g->ui_to_screen_xf), g->screen_cursor);
//- Update world to ui xform from camera //- Update world to ui xform from camera
if (g->debug_camera) if (g->debug_camera)
{ {
g->world_to_ui_xf = XformWithWorldRotation(g->world_to_ui_xf, 0); g->world_to_ui_xf = XformWithWorldRotation(g->world_to_ui_xf, 0);
@ -998,7 +996,6 @@ void UpdateUser(void)
} }
//- Update render to ui xform //- Update render to ui xform
{ {
Xform world_to_ui_xf = g->world_to_ui_xf; Xform world_to_ui_xf = g->world_to_ui_xf;
Xform world_to_render_xf = g->world_to_render_xf; Xform world_to_render_xf = g->world_to_render_xf;
@ -1008,7 +1005,6 @@ void UpdateUser(void)
} }
//- Update listener from view //- Update listener from view
{ {
Vec2 up = VEC2(0, -1); Vec2 up = VEC2(0, -1);
Vec2 ui_center = MulVec2(VEC2(g->ui_size.x, g->ui_size.y), 0.5f); Vec2 ui_center = MulVec2(VEC2(g->ui_size.x, g->ui_size.y), 0.5f);
@ -1018,7 +1014,6 @@ void UpdateUser(void)
} }
//- Draw grid //- Draw grid
{ {
f32 thickness = 2; f32 thickness = 2;
@ -1155,7 +1150,6 @@ void UpdateUser(void)
#endif #endif
//- Sort drawable entities //- Sort drawable entities
Entity **sorted = PushDry(scratch.arena, Entity *); Entity **sorted = PushDry(scratch.arena, Entity *);
u64 sorted_count = 0; u64 sorted_count = 0;
{ {
@ -1180,7 +1174,6 @@ void UpdateUser(void)
} }
//- Draw entities //- Draw entities
{ {
__profn("Draw entities"); __profn("Draw entities");
for (u64 sorted_index = 0; sorted_index < sorted_count; ++sorted_index) for (u64 sorted_index = 0; sorted_index < sorted_count; ++sorted_index)
@ -2042,9 +2035,7 @@ void UpdateUser(void)
////////////////////////////// //////////////////////////////
//- Debug draw //- Debug draw
/* FIXME: Enable this */ /* Draw debug info */
#if 1
#if 1
if (g->debug_draw) if (g->debug_draw)
{ {
__profn("Draw debug info"); __profn("Draw debug info");
@ -2115,144 +2106,15 @@ void UpdateUser(void)
UI_BuildSpacer(UI_PixelSize(20, 0)); UI_BuildSpacer(UI_PixelSize(20, 0));
UI_BuildLabelF("Debug steps: %F", FmtUint(GetGstat(GSTAT_DEBUG_STEPS))); UI_BuildLabelF("Debug steps: %F", FmtUint(GetGstat(GSTAT_DEBUG_STEPS)));
//UI_BuildLabelF(\n")); //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 #endif
} }
UI_PopCheckpoint(); 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; b32 console_minimized = !g->debug_console;
i32 console_level = console_minimized ? P_LogLevel_Success : P_LogLevel_Debug; DrawDebugConsole(console_minimized);
DrawDebugConsole(console_level, console_minimized);
#else
if (g->debug_draw)
{
DrawDebugConsole(P_LogLevel_Info, 0);
}
#endif
} }
////////////////////////////// //////////////////////////////
@ -2261,7 +2123,7 @@ void UpdateUser(void)
Rect ui_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->ui_size.x, g->ui_size.y)); 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)); Rect render_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->render_size.x, g->render_size.y));
GPU_QueueKind gpu_render_queue = GPU_QueueKind_Direct; 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"); __profn("Render");
@ -2270,7 +2132,7 @@ void UpdateUser(void)
if (g->shade_target && !EqVec2I32(g->render_size, GPU_GetTextureSize2D(g->shade_target))) if (g->shade_target && !EqVec2I32(g->render_size, GPU_GetTextureSize2D(g->shade_target)))
{ {
__profn("Release render resources"); __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->albedo, GPU_ReleaseFlag_None);
GPU_ReleaseResource(g->emittance, GPU_ReleaseFlag_None); GPU_ReleaseResource(g->emittance, GPU_ReleaseFlag_None);
GPU_ReleaseResource(g->emittance_flood_read, 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); 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 */ /* Upload transient buffers */
GPU_Resource *material_instances_buffer = GPU_UploadTransientBufferFromArena(&g->material_instances_tbuff, g->material_instances_arena); 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); 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_read);
GPU_TransitionToReadable(cl, g->shade_target); 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 */ /* Reset render data */
GPU_ResetTransientBuffer(&g->material_instances_tbuff, g->gpu_render_fence_target); GPU_ResetTransientBuffer(&g->material_instances_tbuff, g->gpu_submit_fence_target);
GPU_ResetTransientBuffer(&g->grids_tbuff, g->gpu_render_fence_target); GPU_ResetTransientBuffer(&g->grids_tbuff, g->gpu_submit_fence_target);
ResetArena(g->material_instances_arena); ResetArena(g->material_instances_arena);
ResetArena(g->grids_arena); ResetArena(g->grids_arena);
} }
@ -2472,35 +2349,23 @@ void UpdateUser(void)
} }
/* Render UI */ /* 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 //- 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; WND_Cmd cmd = ZI;
cmd.settings = g->window_settings; cmd.desired_settings = g->desired_window;
cmd.texture = ui_render; cmd.texture = g->ui_target;
cmd.vsync = VSYNC;
{ {
Vec2 backbuffer_dst_f = MulXformV2(g->ui_to_screen_xf, VEC2(0, 0)); 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)); 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); EndScratch(scratch);
} }

View File

@ -115,7 +115,6 @@ Struct(ConsoleLog)
i32 color_index; i32 color_index;
P_DateTime datetime; P_DateTime datetime;
i64 time_ns; i64 time_ns;
Rect bounds;
ConsoleLog *prev; ConsoleLog *prev;
ConsoleLog *next; ConsoleLog *next;
}; };
@ -165,6 +164,9 @@ Struct(SharedUserState)
Client *user_blended_client; /* Contains single snapshot from result of blending local sim snapshots */ 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 */ Snapshot *ss_blended; /* Points to blended snapshot contained in blended client */
u64 user_tick;
u64 window_os_gen;
//- Usage stats //- Usage stats
i64 last_second_reset_ns; i64 last_second_reset_ns;
SecondsStat net_bytes_read; SecondsStat net_bytes_read;
@ -178,6 +180,9 @@ Struct(SharedUserState)
GPU_Resource *shade_read; GPU_Resource *shade_read;
GPU_Resource *shade_target; GPU_Resource *shade_target;
//- Renderer target
GPU_Resource *ui_target;
//- Renderer transient buffers //- Renderer transient buffers
GPU_TransientBuffer material_instances_tbuff; GPU_TransientBuffer material_instances_tbuff;
GPU_TransientBuffer grids_tbuff; GPU_TransientBuffer grids_tbuff;
@ -187,7 +192,7 @@ Struct(SharedUserState)
//- Renderer state //- Renderer state
RandState frame_rand; RandState frame_rand;
u64 frame_index; u64 frame_index;
i64 gpu_render_fence_target; i64 gpu_submit_fence_target;
//- Bind state //- Bind state
BindState bind_states[BindKind_Count]; BindState bind_states[BindKind_Count];
@ -198,7 +203,6 @@ Struct(SharedUserState)
ConsoleLog *first_console_log; ConsoleLog *first_console_log;
ConsoleLog *last_console_log; ConsoleLog *last_console_log;
i32 console_log_color_indices[P_LogLevel_Count]; i32 console_log_color_indices[P_LogLevel_Count];
f32 console_logs_height;
b32 debug_console; b32 debug_console;
//- Window -> user //- Window -> user
@ -238,11 +242,11 @@ Struct(SharedUserState)
////////////////////////////// //////////////////////////////
//- Persist start //- Persist start
StructRegion(PERSIST_START); StructRegion(AUTO_PERSIST_START);
//- Window //- Window
WND_Settings window_settings; WND_Settings desired_window;
//- Debug camera //- Debug camera
@ -270,7 +274,7 @@ Struct(SharedUserState)
Vec2 focus_send; Vec2 focus_send;
StructRegion(PERSIST_END); StructRegion(AUTO_PERSIST_END);
//- Persist end //- Persist end
////////////////////////////// //////////////////////////////
@ -306,7 +310,7 @@ String DebugStringFromEntity(Arena *arena, Entity *ent);
//~ Console draw operations //~ Console draw operations
P_LogEventCallbackFuncDef(ConsoleLogCallback, log); P_LogEventCallbackFuncDef(ConsoleLogCallback, log);
void DrawDebugConsole(i32 level, b32 minimized); void DrawDebugConsole(b32 minimized);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Gpu buffer helpers //~ Gpu buffer helpers

View File

@ -60,6 +60,7 @@ void UI_PushCheckpoint(void)
{ {
cp = PushStruct(g->build_arena, UI_Checkpoint); cp = PushStruct(g->build_arena, UI_Checkpoint);
} }
cp->next = g->top_checkpoint;
cp->v = g->top_checkpoint->v + 1; cp->v = g->top_checkpoint->v + 1;
g->top_checkpoint = cp; g->top_checkpoint = cp;
} }
@ -69,6 +70,10 @@ void UI_PopCheckpoint(void)
UI_SharedState *g = &UI_shared_state; UI_SharedState *g = &UI_shared_state;
UI_Checkpoint *cp = g->top_checkpoint; UI_Checkpoint *cp = g->top_checkpoint;
u64 v = cp->v; u64 v = cp->v;
if (v == 0)
{
DEBUGBREAKABLE;
}
for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind) for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind)
{ {
UI_StyleNode *n = g->style_tops[kind]; UI_StyleNode *n = g->style_tops[kind];
@ -81,6 +86,7 @@ void UI_PopCheckpoint(void)
n = next; n = next;
} }
} }
g->top_checkpoint = cp->next;
cp->next = g->first_free_checkpoint; cp->next = g->first_free_checkpoint;
g->first_free_checkpoint = cp; g->first_free_checkpoint = cp;
} }
@ -256,6 +262,7 @@ void UI_BeginBuild(void)
ResetArena(g->build_arena); ResetArena(g->build_arena);
g->boxes_count = 0; g->boxes_count = 0;
g->first_free_style_node = 0; g->first_free_style_node = 0;
g->first_free_checkpoint = 0;
/* Init bins */ /* Init bins */
g->box_bins = PushStructs(g->build_arena, UI_BoxBin, UI_NumBoxLookupBins); g->box_bins = PushStructs(g->build_arena, UI_BoxBin, UI_NumBoxLookupBins);
@ -299,11 +306,26 @@ void UI_BeginBuild(void)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ End build //~ 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(); TempArena scratch = BeginScratchNoConflict();
UI_SharedState *g = &UI_shared_state; 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 */ /* TODO: Ensure root is parent */
////////////////////////////// //////////////////////////////
@ -311,9 +333,9 @@ GPU_Resource *UI_EndBuild(Rect render_viewport)
/* Init root size */ /* Init root size */
g->root_box->pref_size[Axis_X].kind = UI_SizeKind_Pixel; 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].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 */ /* Build pre-order & post-order box arrays */
u64 boxes_count = g->boxes_count; u64 boxes_count = g->boxes_count;
@ -554,23 +576,6 @@ GPU_Resource *UI_EndBuild(Rect render_viewport)
////////////////////////////// //////////////////////////////
//- Render //- 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 */ /* Upload transient buffers */
GPU_Resource *draw_rects_buffer = GPU_UploadTransientBufferFromArena(&g->draw_rects_tbuff, g->draw_rects_arena); GPU_Resource *draw_rects_buffer = GPU_UploadTransientBufferFromArena(&g->draw_rects_tbuff, g->draw_rects_arena);
u32 draw_rects_count = GPU_GetBufferCount(draw_rects_buffer); u32 draw_rects_count = GPU_GetBufferCount(draw_rects_buffer);
@ -582,8 +587,8 @@ GPU_Resource *UI_EndBuild(Rect render_viewport)
{ {
__profn("Clear target"); __profn("Clear target");
GPU_ProfN(cl, Lit("Clear target")); GPU_ProfN(cl, Lit("Clear target"));
GPU_TransitionToRenderable(cl, g->render_target, 0); GPU_TransitionToRenderable(cl, render_target, 0);
GPU_ClearRenderable(cl, g->render_target); GPU_ClearRenderable(cl, render_target);
} }
//- Rect pass //- Rect pass
@ -612,7 +617,7 @@ GPU_Resource *UI_EndBuild(Rect render_viewport)
//- Prep post pass //- Prep post pass
{ {
GPU_TransitionToWritable(cl, g->render_target); GPU_TransitionToWritable(cl, render_target);
} }
//- Post pass //- Post pass
@ -622,17 +627,17 @@ GPU_Resource *UI_EndBuild(Rect render_viewport)
Vec2I32 viewport_size = RoundVec2ToVec2I32(render_viewport.size); Vec2I32 viewport_size = RoundVec2ToVec2I32(render_viewport.size);
UI_PostSig sig = ZI; UI_PostSig sig = ZI;
sig.tex_size = viewport_size; sig.tex_size = viewport_size;
sig.tex = GPU_RWTexture2DRidFromResource(g->render_target); sig.tex = GPU_RWTexture2DRidFromResource(render_target);
sig.gamma = 2.2f; sig.gamma = 2.2f;
GPU_Compute(cl, &sig, UI_PostCS, (viewport_size.x + 7) / 8, (viewport_size.y + 7) / 8, 1); 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 */ /* 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); ResetArena(g->draw_rects_arena);
EndScratch(scratch); EndScratch(scratch);
return g->render_target; return submit_fence_target;
} }

View File

@ -180,9 +180,7 @@ Struct(UI_SharedState)
UI_StyleNode *first_free_style_node; UI_StyleNode *first_free_style_node;
//- Render state //- Render state
GPU_Resource *render_target; i64 gpu_submit_fence_target;
i64 render_fence_target;
GPU_TransientBuffer draw_rects_tbuff; GPU_TransientBuffer draw_rects_tbuff;
Arena *draw_rects_arena; Arena *draw_rects_arena;
@ -249,4 +247,5 @@ void UI_BeginBuild(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ End build //~ End build
GPU_Resource *UI_EndBuild(Rect render_viewport); GPU_ResourceDesc UI_GetRenderTargetDesc(Vec2I32 size);
i64 UI_EndBuild(GPU_Resource *render_target);

View File

@ -3,35 +3,44 @@
Enum(WND_Flag) Enum(WND_Flag)
{ {
WND_Flag_None = (0), WND_Flag_None = (0),
WND_Flag_Fullscreen = (1 << 0), WND_Flag_ForcedTop = (1 << 0),
WND_Flag_ForcedTop = (1 << 1), WND_Flag_RestoreToMaximized = (1 << 1),
WND_Flag_Fullscreen = (1 << 2),
WND_Flag_Maximized = (1 << 3),
WND_Flag_Minimized = (1 << 4),
}; };
Struct(WND_Settings) Struct(WND_Settings)
{ {
WND_Flag flags; WND_Flag flags;
Vec2I32 p0; Vec2I32 restore_p0;
Vec2I32 p1; Vec2I32 restore_p1;
i32 vsync;
};
Struct(WND_Cmd)
{
WND_Settings settings;
GPU_Resource *texture;
Vec2I32 backbuffer_dst;
}; };
Struct(WND_Event) Struct(WND_Event)
{ {
WND_Settings settings;
u64 inputs_count; u64 inputs_count;
Input *inputs; Input *inputs;
WND_Settings settings;
/* The backbuffer src texture is no longer in use once the direct queue fence reaches this target */ Vec2I32 monitor_p0;
i64 backbuffer_fence_target; 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 //~ @hookdecl Window hooks
WND_Event WND_BeginUpdate(Arena *arena); WND_Event WND_BeginUpdate(Arena *arena);
void WND_EndUpdate(WND_Cmd cmd); i64 WND_EndUpdateAndPresent(WND_Cmd cmd);

View File

@ -86,22 +86,10 @@ void WND_Startup(void)
} }
//- Start message processing job //- 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); 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 //~ Initialization
@ -110,7 +98,7 @@ JobDef(WND_W32_ProcessMessagesForever, sig, id)
{ {
WND_W32_SharedState *g = &WND_W32_shared_state; WND_W32_SharedState *g = &WND_W32_shared_state;
WND_W32_Window *window = &g->window; WND_W32_Window *window = &g->window;
window->inputs_arena = AcquireArena(Gibi(64)); window->w2u_inputs_arena = AcquireArena(Gibi(64));
//- Init hwnd //- Init hwnd
HWND hwnd = 0; HWND hwnd = 0;
@ -170,18 +158,21 @@ JobDef(WND_W32_ProcessMessagesForever, sig, id)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Message processing //~ 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) LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{ {
WND_W32_SharedState *g = &WND_W32_shared_state; WND_W32_SharedState *g = &WND_W32_shared_state;
WND_W32_Window *window = &g->window; WND_W32_Window *window = &g->window;
++window->proc_depth;
LRESULT result = 0; LRESULT result = 0;
Lock lock = ZI;
if (window->proc_depth == 1)
{
lock = LockE(&window->update_mutex);
}
{ {
switch(msg) 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 }); WND_W32_PushInput(window, (Input) { .kind = InputKind_Quit });
} break; } 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 //- Keyboard button
case WM_SYSKEYUP: case WM_SYSKEYUP:
case WM_SYSKEYDOWN:; case WM_SYSKEYDOWN:;
@ -390,14 +369,202 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
} }
EndScratch(scratch); EndScratch(scratch);
} break; } 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; return result;
} }
@ -410,72 +577,150 @@ WND_Event WND_BeginUpdate(Arena *arena)
WND_W32_Window *window = &g->window; WND_W32_Window *window = &g->window;
WND_Event result = ZI; WND_Event result = ZI;
/* TODO: Yield on swapchain instead */
while (!Atomic32Fetch(&window->is_ready)) while (!Atomic32Fetch(&window->is_ready))
{ {
_mm_pause(); _mm_pause();
} }
HWND hwnd = window->hwnd;
/* FIXME: Don't use TM */ /* Wait on swapchain */
Lock *lock = &window->user_update_lock; if (window->swapchain)
*lock = LockE(&window->update_mutex); {
GPU_D12_YieldOnSwapchain(window->swapchain);
}
/* Pop inputs */ /* Pop inputs */
LockTicketMutex(&window->inputs_tm);
{ {
Input *src = (Input *)ArenaBase(window->inputs_arena); LockTicketMutex(&window->w2u_tm);
result.inputs_count = ArenaCount(window->inputs_arena, Input); {
result.inputs = PushStructsNoZero(arena, Input, result.inputs_count); Input *src = (Input *)ArenaBase(window->w2u_inputs_arena);
CopyStructs(result.inputs, src, result.inputs_count); result.inputs_count = ArenaCount(window->w2u_inputs_arena, Input);
ResetArena(window->inputs_arena); 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 */ /* Grab monitor info */
result.settings.p0 = window->previous_cmd.settings.p0; {
result.settings.p1 = window->previous_cmd.settings.p1; 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; return result;
} }
void WND_EndUpdate(WND_Cmd cmd) i64 WND_EndUpdateAndPresent(WND_Cmd cmd)
{ {
WND_W32_SharedState *g = &WND_W32_shared_state; WND_W32_SharedState *g = &WND_W32_shared_state;
WND_W32_Window *window = &g->window; 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) 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 */ /* Present */
/* TODO: Get fence */ i64 present_fence_target = 0;
if (cmd.texture != 0) if (cmd.texture != 0)
{ {
Vec2I32 backbuffer_dst = cmd.backbuffer_dst; Vec2I32 backbuffer_dst = cmd.backbuffer_dst;
i32 vsync = new.vsync; if (cmd.vsync != 0)
GPU_D12_PresentSwapchain(window->swapchain, cmd.texture, new_size, backbuffer_dst, vsync); {
/* 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 */ /* Push cmd to window */
if (!window->first_shown) b32 desires_change = !EqStruct(&cmd.desired_settings, &begin_event.settings);
if (desires_change)
{ {
i32 show_cmd = SW_SHOWMAXIMIZED; LockTicketMutex(&window->u2w_tm);
ShowWindow(window->hwnd, show_cmd); {
SetForegroundWindow(window->hwnd); window->u2w_update_end_cmd = cmd;
BringWindowToTop(window->hwnd); window->u2w_update_end_event = begin_event;
window->first_shown = 1; PostMessageW(window->hwnd, WND_CmdMsgId, 0, 0);
}
UnlockTicketMutex(&window->u2w_tm);
} }
window->previous_cmd = cmd; return present_fence_target;
} }

View File

@ -1,29 +1,36 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Window types //~ Window types
#define WND_CmdMsgId (WM_USER + 1)
Struct(WND_W32_Window) Struct(WND_W32_Window)
{ {
Atomic32 is_ready;
HWND hwnd; HWND hwnd;
GPU_D12_Swapchain *swapchain; GPU_D12_Swapchain *swapchain;
Atomic32 is_ready;
TicketMutex inputs_tm; Atomic64 cmd_gen;
Arena *inputs_arena; Atomic64 os_gen;
/* 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;
/* Window state */
u16 previous_utf16_high_surrogate; 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 */ WND_W32_Window window; /* Only single-window for now */
} extern WND_W32_shared_state; } extern WND_W32_shared_state;
////////////////////////////////////////////////////////////
//~ Input helpers
void WND_W32_PushInput(WND_W32_Window *window, Input input);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Initialization //~ Initialization
@ -51,4 +53,5 @@ JobDecl(WND_W32_ProcessMessagesForever, EmptySig);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Message processing //~ 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); LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);