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 PopStructsNoCopy(a, type, n) PopBytesNoCopy((a), sizeof(type) * (n))
/* TOOD: Replace ArenaBase with 'ArenaFirst(type)' for dynamic-array-style uses */
#define ArenaBase(arena) ((u8 *)(arena) + ArenaHeaderSize)
#define ArenaCount(arena, type) ((arena)->pos / sizeof(type))

View File

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

View File

@ -30,8 +30,13 @@ void StartupUser(void)
g->local_to_user_client_store = AcquireClientStore();
g->local_to_user_client = AcquireClient(g->local_to_user_client_store);
g->world_to_ui_xf = XformIdentity;
g->world_to_render_xf = XformIdentity;
/* Default persistent state */
{
g->world_to_ui_xf = XformIdentity;
g->world_to_render_xf = XformIdentity;
// g->desired_window.flags = WND_Flag_Fullscreen;
g->desired_window.restore_p1 = VEC2I32(1920, 1080);
}
/* Init from swap */
if (IsSwappedIn());
@ -42,7 +47,7 @@ void StartupUser(void)
{
SwappedUserState *swap = (SwappedUserState *)swap_str.text;
SharedUserState *old = &swap->s;
CopyStructRegion(g, old, PERSIST_START, PERSIST_END);
CopyStructRegion(g, old, AUTO_PERSIST_START, AUTO_PERSIST_END);
}
EndScratch(scratch);
}
@ -53,7 +58,7 @@ void StartupUser(void)
/* Create job pools */
JobPoolId user_pool = InitJobPool(1, Lit("User"), JobPoolPriority_Graphics);
JobPoolId sim_pool = InitJobPool(4, Lit("Simulation"), JobPoolPriority_Simulation);
JobPoolId sim_pool = InitJobPool(1, Lit("Simulation"), JobPoolPriority_Simulation);
/* Start jobs */
g->shutdown_jobs_count += RunJob(UpdateUserOrSleep, .pool = user_pool, .fence = &g->shutdown_jobs_fence);
@ -308,114 +313,111 @@ P_LogEventCallbackFuncDef(ConsoleLogCallback, log)
}
//- Draw console
void DrawDebugConsole(i32 level, b32 minimized)
void DrawDebugConsole(b32 minimized)
{
/* FIXME: Enable this */
#if 0
/* TODO: Remove this whole thing */
__prof;
SharedUserState *g = &shared_user_state;
TempArena scratch = BeginScratchNoConflict();
Vec2 desired_start_pos = VEC2(10, minimized ? 100 : 600);
i64 fade_time_ns = NsFromSeconds(10);
f32 fade_curve = 0.5;
f32 spacing = 0;
f32 bg_margin = 5;
// i32 console_level = minimized ? P_LogLevel_Success : P_LogLevel_Debug;
i32 console_level = P_LogLevel_Debug;
u32 colors[P_LogLevel_Count][2] = ZI;
SetBytes(colors, 0xFF, sizeof(colors));
#if 1
colors[P_LogLevel_Debug][0] = Rgb32F(0.4, 0.1, 0.4); colors[P_LogLevel_Debug][1] = Rgb32F(0.5, 0.2, 0.5);
colors[P_LogLevel_Info][0] = Rgb32F(0.4, 0.4, 0.4); colors[P_LogLevel_Info][1] = Rgb32F(0.5, 0.5, 0.5);
colors[P_LogLevel_Success][0] = Rgb32F(0.1, 0.3, 0.1); colors[P_LogLevel_Success][1] = Rgb32F(0.2, 0.4, 0.2);
colors[P_LogLevel_Warning][0] = Rgb32F(0.4, 0.4, 0.1); colors[P_LogLevel_Warning][1] = Rgb32F(0.5, 0.5, 0.2);
colors[P_LogLevel_Error][0] = Rgb32F(0.4, 0.1, 0.1); colors[P_LogLevel_Error][1] = Rgb32F(0.5, 0.2, 0.2);
#else
u32 info_colors[2] = { Rgb32F(0.4, 0.4, 0.4), Rgb32F(0.5, 0.5, 0.5) };
u32 success_colors[2] = { Rgb32F(0.1, 0.3, 0.1), Rgb32F(0.2, 0.4, 0.2) };
u32 warning_colors[2] = { Rgb32F(0.4, 0.4, 0.1), Rgb32F(0.5, 0.5, 0.2) };
u32 error_colors[2] = { Rgb32F(0.4, 0.1, 0.1), Rgb32F(0.5, 0.2, 0.2) };
#endif
Vec2 draw_pos = desired_start_pos;
f32 bounds_top = F32Infinity;
f32 bounds_bottom = -F32Infinity;
if (g->console_logs_height < desired_start_pos.y)
i64 max_time_ns = I64Max;
i64 fade_time_ns = max_time_ns;
if (minimized)
{
draw_pos.y = g->console_logs_height;
max_time_ns = NsFromSeconds(10);
fade_time_ns = max_time_ns;
}
g->console_logs_height = 0;
f32 fade_curve = 0.5;
f32 spacing = 0;
f32 bg_margin = 5;
i64 now_ns = TimeNs();
F_Font *font = F_LoadFontAsync(ResourceKeyFromStore(&GameResources, Lit("font/fixedsys.ttf")), 12.0f);
if (font)
UI_PushCheckpoint();
{
UI_Box *console_box = 0;
{
UI_SetNext(LayoutAxis, Axis_Y);
UI_SetNext(Tint, 0);
console_box = UI_BuildBox(0, UI_NilKey);
}
UI_Push(Parent, console_box);
UI_Push(Width, UI_TextSize(0));
UI_Push(Height, UI_TextSize(0));
UI_Push(BorderColor, Rgba32F(0.25, 0.25, 0.25, 1));
UI_Push(Border, 2);
UI_Push(Rounding, 0.5);
UI_Push(TextPadding, 6);
Lock lock = LockE(&g->console_logs_mutex);
{
for (ConsoleLog *log = g->last_console_log; log; log = log->prev)
/* Gather display logs */
u64 max = 20;
u64 display_count = 0;
ConsoleLog **display_logs = PushStructs(scratch.arena, ConsoleLog *, max);
{
f32 opacity = 0.75;
b32 done = 0;
if (minimized)
{
f32 lin = 1.0 - ClampF64((f64)(now_ns - log->time_ns) / (f64)fade_time_ns, 0, 1);
opacity *= PowF32(lin, fade_curve);
max = 5;
}
if (draw_pos.y > -desired_start_pos.y && opacity > 0)
for (ConsoleLog *log = g->last_console_log; log && display_count < max && !done; log = log->prev)
{
if (log->level <= level)
if (log->time_ns > (now_ns - max_time_ns))
{
/* Draw background */
u32 color = colors[log->level][log->color_index];
D_DrawQuad(g->render_sig, QuadFromRect(log->bounds), Alpha32F(color, opacity));
/* Draw text */
String text = log->msg;
if (!minimized)
if (log->level <= console_level)
{
P_DateTime datetime = log->datetime;
text = StringF(
scratch.arena,
"[%F:%F:%F.%F] %F",
FmtUintZ(datetime.hour, 2),
FmtUintZ(datetime.minute, 2),
FmtUintZ(datetime.second, 2),
FmtUintZ(datetime.milliseconds, 3),
FmtString(text));
display_logs[display_count] = log;
++display_count;
}
D_TextParams params = D_TEXTPARAMS(.font = font, .pos = draw_pos, .offset_y = DRAW_TEXT_OFFSET_Y_BOTTOM, .color = Alpha32F(Color_White, opacity), .str = text);
Rect bounds = draw_text(g->render_sig, params);
Rect draw_bounds = bounds;
draw_bounds.x -= bg_margin;
draw_bounds.y -= bg_margin;
draw_bounds.width += bg_margin * 2.f;
draw_bounds.height += bg_margin * 2.f;
draw_pos.y -= draw_bounds.height + spacing;
log->bounds = draw_bounds;
bounds_top = MinF32(bounds_top, draw_bounds.y);
bounds_bottom = MaxF32(bounds_bottom, draw_bounds.y + draw_bounds.height);
}
else
{
done = 1;
}
}
else
}
/* Display logs in reverse */
for (u64 i = display_count; i-- > 0;)
{
ConsoleLog *log = display_logs[i];
f32 opacity = 0.75;
f32 lin = 1.0 - ClampF64((f64)(now_ns - log->time_ns) / (f64)fade_time_ns, 0, 1);
opacity *= PowF32(lin, fade_curve);
String text = log->msg;
if (!minimized)
{
break;
P_DateTime datetime = log->datetime;
text = StringF(
scratch.arena,
"[%F:%F:%F.%F] %F",
FmtUintZ(datetime.hour, 2),
FmtUintZ(datetime.minute, 2),
FmtUintZ(datetime.second, 2),
FmtUintZ(datetime.milliseconds, 3),
FmtString(text));
}
u32 color = colors[log->level][log->color_index];
UI_SetNext(BackgroundColor, color);
UI_SetNext(Tint, Alpha32F(0xFFFFFFFF, opacity));
UI_Box *log_box = UI_BuildBox(UI_BoxFlag_DrawText, UI_NilKey);
UI_SetDisplayText(log_box, text);
}
}
Unlock(&lock);
}
if (bounds_top < F32Infinity && bounds_bottom > -F32Infinity)
{
g->console_logs_height = bounds_bottom - bounds_top;
}
UI_PopCheckpoint();
EndScratch(scratch);
#else
LAX level;
LAX minimized;
#endif
}
////////////////////////////////////////////////////////////
@ -486,19 +488,25 @@ void UpdateUser(void)
TempArena scratch = BeginScratchNoConflict();
//- Begin frame
WND_Event win_event = WND_BeginUpdate(scratch.arena);
WND_Event window_event = WND_BeginUpdate(scratch.arena);
u64 inputs_count = win_event.inputs_count;
Input *inputs = win_event.inputs;
u64 inputs_count = window_event.inputs_count;
Input *inputs = window_event.inputs;
g->real_dt_ns = TimeNs() - g->real_time_ns;
g->real_time_ns += g->real_dt_ns;
g->screen_size = SubVec2I32(g->window_settings.p1, g->window_settings.p0);
if (EqVec2I32(g->screen_size, VEC2I32(0, 0)))
//- Begin window
WND_Settings cur_window = window_event.settings;
if (window_event.os_gen > g->window_os_gen && window_event.cmd_gen > 0)
{
g->screen_size = VEC2I32(1920, 1080);
/* Window was modified outside of program. Reflect this in our own state. */
g->desired_window = cur_window;
}
g->window_os_gen = window_event.os_gen;
g->screen_size = SubVec2I32(window_event.draw_p1, window_event.draw_p0);
g->screen_size.x = MaxI32(g->screen_size.x, 1);
g->screen_size.y = MaxI32(g->screen_size.y, 1);
//- Begin UI
UI_BeginBuild();
@ -516,7 +524,6 @@ void UpdateUser(void)
}
//- Pull latest local sim snapshot
{
__profn("Pull snapshot");
Lock lock = LockE(&g->local_to_user_client_mutex);
@ -534,7 +541,6 @@ void UpdateUser(void)
}
//- Create user world from blended snapshots
{
__profn("Blend snapshots");
/* Determine how far along are we between sim ticks (0 = start of tick, 1 = end of tick) */
@ -640,7 +646,6 @@ void UpdateUser(void)
}
//- Process inputs into user bind state
{
__profn("Process inputs");
@ -719,13 +724,11 @@ void UpdateUser(void)
}
//- Find local entities
Entity *local_player = EntityFromId(g->ss_blended, g->ss_blended->local_player);
Entity *local_control = EntityFromId(g->ss_blended, local_player->player_control_ent);
Entity *local_camera = EntityFromId(g->ss_blended, local_player->player_camera_ent);
//- Find hovered entity
Entity *hovered_ent = NilEntity();
{
Xform mouse_xf = XformFromPos(g->world_cursor);
@ -754,12 +757,10 @@ void UpdateUser(void)
}
//- Update user state from binds
/* Test fullscreen */
{
if (g->bind_states[BindKind_Fullscreen].num_presses && g->bind_states[BindKind_FullscreenMod].is_held)
{
g->window_settings.flags ^= WND_Flag_Fullscreen;
g->desired_window.flags ^= WND_Flag_Fullscreen;
}
}
@ -770,7 +771,7 @@ void UpdateUser(void)
if (g->bind_states[BindKind_DebugToggleTopmost].num_presses > 0)
{
g->window_settings.flags ^= WND_Flag_ForcedTop;
g->desired_window.flags ^= WND_Flag_ForcedTop;
P_LogSuccessF("Toggle topmost");
}
@ -822,7 +823,6 @@ void UpdateUser(void)
}
//- Apply shake
for (u64 ent_index = 0; ent_index < g->ss_blended->num_ents_reserved; ++ent_index)
{
Entity *ent = &g->ss_blended->ents[ent_index];
@ -853,7 +853,6 @@ void UpdateUser(void)
}
//- Update ui to screen xform from screen size
if (g->debug_camera)
{
g->ui_size = g->screen_size;
@ -895,7 +894,6 @@ void UpdateUser(void)
g->ui_cursor = MulXformV2(InvertXform(g->ui_to_screen_xf), g->screen_cursor);
//- Update world to ui xform from camera
if (g->debug_camera)
{
g->world_to_ui_xf = XformWithWorldRotation(g->world_to_ui_xf, 0);
@ -998,7 +996,6 @@ void UpdateUser(void)
}
//- Update render to ui xform
{
Xform world_to_ui_xf = g->world_to_ui_xf;
Xform world_to_render_xf = g->world_to_render_xf;
@ -1008,7 +1005,6 @@ void UpdateUser(void)
}
//- Update listener from view
{
Vec2 up = VEC2(0, -1);
Vec2 ui_center = MulVec2(VEC2(g->ui_size.x, g->ui_size.y), 0.5f);
@ -1018,7 +1014,6 @@ void UpdateUser(void)
}
//- Draw grid
{
f32 thickness = 2;
@ -1155,7 +1150,6 @@ void UpdateUser(void)
#endif
//- Sort drawable entities
Entity **sorted = PushDry(scratch.arena, Entity *);
u64 sorted_count = 0;
{
@ -1180,7 +1174,6 @@ void UpdateUser(void)
}
//- Draw entities
{
__profn("Draw entities");
for (u64 sorted_index = 0; sorted_index < sorted_count; ++sorted_index)
@ -2042,9 +2035,7 @@ void UpdateUser(void)
//////////////////////////////
//- Debug draw
/* FIXME: Enable this */
#if 1
#if 1
/* Draw debug info */
if (g->debug_draw)
{
__profn("Draw debug info");
@ -2115,144 +2106,15 @@ void UpdateUser(void)
UI_BuildSpacer(UI_PixelSize(20, 0));
UI_BuildLabelF("Debug steps: %F", FmtUint(GetGstat(GSTAT_DEBUG_STEPS)));
//UI_BuildLabelF(\n"));
#endif
//draw_text(g->render_sig, font, pos, StringF(scratch.arena, "blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved)));
//draw_text(g->render_sig, font, pos, text);
#if 0
Vec2 pos = VEC2(10, g->ui_size.y);
D_TextOffsetY offset_y = DRAW_TEXT_OFFSET_Y_BOTTOM;
draw_text(g->render_sig, D_TEXTPARAMS(.font = font, .pos = pos, .str = text, .offset_y = offset_y, .color = Color_White));
#endif
}
UI_PopCheckpoint();
}
#else
if (g->debug_draw)
/* Draw console */
{
__profn("Draw debug info");
F_Font *font = F_LoadFontAsync(ResourceKeyFromStore(&GameResources, Lit("font/fixedsys.ttf")), 12.0f);
if (font)
{
TempArena temp = BeginTempArena(scratch.arena);
String text = ZI;
text.text = PushDry(temp.arena, u8);
#if BITBUFF_DEBUG
text.len += StringF(temp.arena, "(bitbuff debug enabled)").len;
text.len += StringF(temp.arena, "\n").len;
#endif
text.len += StringF(temp.arena, "blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved)).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "blended world tick: %F", FmtUint(g->ss_blended->tick)).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "blended world time: %F", FmtFloat(SecondsFromNs(g->ss_blended->sim_time_ns))).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "average local sim publish dt: %F", FmtFloat(SecondsFromNs(g->average_local_to_user_snapshot_publish_dt_ns))).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "local sim last known tick: %F", FmtUint(g->local_sim_last_known_tick)).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "local sim last known time: %F", FmtFloat(SecondsFromNs(g->local_sim_last_known_time_ns))).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "local sim predicted time: %F", FmtFloat(SecondsFromNs(g->local_sim_predicted_time_ns))).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "render time target: %F", FmtFloat(SecondsFromNs(g->render_time_target_ns))).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "render time: %F", FmtFloat(SecondsFromNs(g->render_time_ns))).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "local player: [%F]", FmtUid(local_player->id.uid)).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "\n").len;
Vec2 world_cursor = g->world_cursor;
text.len += StringF(temp.arena, "cursor world: %F, %F", FmtFloat(world_cursor.x), FmtFloat(world_cursor.y)).len;
text.len += StringF(temp.arena, "\n").len;
Vec2I32 world_tile_cursor = WorldTileIndexFromPos(world_cursor);
text.len += StringF(temp.arena, "cursor world tile: %F, %F", FmtSint(world_tile_cursor.x), FmtSint(world_tile_cursor.y)).len;
text.len += StringF(temp.arena, "\n").len;
Vec2I32 local_tile_cursor = LocalTileIndexFromWorldTileIndex(world_tile_cursor);
text.len += StringF(temp.arena, "cursor local tile: %F, %F", FmtSint(local_tile_cursor.x), FmtSint(local_tile_cursor.y)).len;
text.len += StringF(temp.arena, "\n").len;
Vec2I32 tile_chunk_cursor = TileChunkIndexFromWorldTileIndex(world_tile_cursor);
text.len += StringF(temp.arena, "cursor tile chunk: %F, %F", FmtSint(tile_chunk_cursor.x), FmtSint(tile_chunk_cursor.y)).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "Network read: %F mbit/s", FmtFloat((f64)g->net_bytes_read.last_second * 8 / 1000 / 1000)).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "Network write: %F mbit/s", FmtFloat((f64)g->net_bytes_sent.last_second * 8 / 1000 / 1000)).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "Ping (real): %F ms", FmtFloat(SecondsFromNs(local_player->player_last_rtt_ns) * 1000)).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "Ping (average): %F ms", FmtFloat(local_player->player_average_rtt_seconds * 1000)).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "Memory committed: %F MiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_COMMITTED) / 1024 / 1024)).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "Virtual memory reserved: %F TiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_RESERVED) / 1024 / 1024 / 1024 / 1024)).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "Arenas allocated: %F", FmtUint(GetGstat(GSTAT_NUM_ARENAS))).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "Video memory (GPU): %F MiB", FmtFloat((f64)vram.local_used / 1024 / 1024)).len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "Video memory (shared): %F MiB", FmtFloat((f64)vram.non_local_used / 1024 / 1024)).len;
//text.len += StringF(temp.arena, \n")).len;
//text.len += StringF(temp.arena, \n")).len;
#if RtcIsEnabled
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "\n").len;
text.len += StringF(temp.arena, "Debug steps: %F", FmtUint(GetGstat(GSTAT_DEBUG_STEPS))).len;
//text.len += StringF(temp.arena, \n")).len;
#endif
//draw_text(g->render_sig, font, pos, StringF(temp.arena, "blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved)));
//draw_text(g->render_sig, font, pos, text);
Vec2 pos = VEC2(10, g->ui_size.y);
D_TextOffsetY offset_y = DRAW_TEXT_OFFSET_Y_BOTTOM;
draw_text(g->render_sig, D_TEXTPARAMS(.font = font, .pos = pos, .str = text, .offset_y = offset_y, .color = Color_White));
EndTempArena(temp);
}
}
#endif
#endif
{
#if DeveloperIsEnabled
b32 console_minimized = !g->debug_console;
i32 console_level = console_minimized ? P_LogLevel_Success : P_LogLevel_Debug;
DrawDebugConsole(console_level, console_minimized);
#else
if (g->debug_draw)
{
DrawDebugConsole(P_LogLevel_Info, 0);
}
#endif
DrawDebugConsole(console_minimized);
}
//////////////////////////////
@ -2261,7 +2123,7 @@ void UpdateUser(void)
Rect ui_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->ui_size.x, g->ui_size.y));
Rect render_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->render_size.x, g->render_size.y));
GPU_QueueKind gpu_render_queue = GPU_QueueKind_Direct;
Fence *render_fence = GPU_FenceFromQueue(gpu_render_queue);
Fence *submit_fence = GPU_FenceFromQueue(gpu_render_queue);
{
__profn("Render");
@ -2270,7 +2132,7 @@ void UpdateUser(void)
if (g->shade_target && !EqVec2I32(g->render_size, GPU_GetTextureSize2D(g->shade_target)))
{
__profn("Release render resources");
YieldOnFence(render_fence, g->gpu_render_fence_target);
YieldOnFence(submit_fence, g->gpu_submit_fence_target);
GPU_ReleaseResource(g->albedo, GPU_ReleaseFlag_None);
GPU_ReleaseResource(g->emittance, GPU_ReleaseFlag_None);
GPU_ReleaseResource(g->emittance_flood_read, GPU_ReleaseFlag_None);
@ -2290,6 +2152,21 @@ void UpdateUser(void)
g->shade_target = AcquireGbuffer(GPU_Format_R16G16B16A16_Float, g->render_size);
}
/* Acquire ui target */
if (g->ui_target && !EqVec2I32(g->ui_size, GPU_GetTextureSize2D(g->ui_target)))
{
__profn("Release ui target");
YieldOnFence(submit_fence, g->gpu_submit_fence_target);
GPU_ReleaseResource(g->ui_target, GPU_ReleaseFlag_None);
g->ui_target = 0;
}
if (!g->ui_target)
{
__profn("Acquire ui target");
GPU_ResourceDesc desc = UI_GetRenderTargetDesc(g->ui_size);
g->ui_target = GPU_AcquireResource(desc);
}
/* Upload transient buffers */
GPU_Resource *material_instances_buffer = GPU_UploadTransientBufferFromArena(&g->material_instances_tbuff, g->material_instances_arena);
GPU_Resource *grids_buffer = GPU_UploadTransientBufferFromArena(&g->grids_tbuff, g->grids_arena);
@ -2452,11 +2329,11 @@ void UpdateUser(void)
GPU_TransitionToReadable(cl, g->shade_read);
GPU_TransitionToReadable(cl, g->shade_target);
}
g->gpu_render_fence_target = GPU_EndCommandList(cl);
g->gpu_submit_fence_target = GPU_EndCommandList(cl);
/* Reset render data */
GPU_ResetTransientBuffer(&g->material_instances_tbuff, g->gpu_render_fence_target);
GPU_ResetTransientBuffer(&g->grids_tbuff, g->gpu_render_fence_target);
GPU_ResetTransientBuffer(&g->material_instances_tbuff, g->gpu_submit_fence_target);
GPU_ResetTransientBuffer(&g->grids_tbuff, g->gpu_submit_fence_target);
ResetArena(g->material_instances_arena);
ResetArena(g->grids_arena);
}
@ -2472,35 +2349,23 @@ void UpdateUser(void)
}
/* Render UI */
GPU_Resource *ui_render = UI_EndBuild(ui_viewport);
g->gpu_submit_fence_target = UI_EndBuild(g->ui_target);
#if 0
//////////////////////////////
//- Present
Vec2 backbuffer_dst_f = MulXformV2(g->ui_to_screen_xf, VEC2(0, 0));
Vec2I32 backbuffer_dst = VEC2I32(RoundF32ToI32(backbuffer_dst_f.x), RoundF32ToI32(backbuffer_dst_f.y));
g->gpu_render_fence_target = GPU_PresentSwapchain(g->swapchain, ui_render, g->screen_size, backbuffer_dst, VSYNC);
// g->gpu_render_fence_target = GPU_PresentSwapchain(g->swapchain, g->ui_target, g->screen_size, backbuffer_dst, VSYNC);
#else
//////////////////////////////
//- End window update
g->window_settings.vsync = VSYNC;
g->window_settings.p0 = VEC2I32(0, 0);
g->window_settings.p1 = g->screen_size;
{
WND_Cmd cmd = ZI;
cmd.settings = g->window_settings;
cmd.texture = ui_render;
cmd.desired_settings = g->desired_window;
cmd.texture = g->ui_target;
cmd.vsync = VSYNC;
{
Vec2 backbuffer_dst_f = MulXformV2(g->ui_to_screen_xf, VEC2(0, 0));
cmd.backbuffer_dst = VEC2I32(RoundF32ToI32(backbuffer_dst_f.x), RoundF32ToI32(backbuffer_dst_f.y));
}
WND_EndUpdate(cmd);
g->gpu_submit_fence_target = WND_EndUpdateAndPresent(cmd);
}
#endif
++g->user_tick;
EndScratch(scratch);
}

View File

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

View File

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

View File

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

View File

@ -3,35 +3,44 @@
Enum(WND_Flag)
{
WND_Flag_None = (0),
WND_Flag_Fullscreen = (1 << 0),
WND_Flag_ForcedTop = (1 << 1),
WND_Flag_None = (0),
WND_Flag_ForcedTop = (1 << 0),
WND_Flag_RestoreToMaximized = (1 << 1),
WND_Flag_Fullscreen = (1 << 2),
WND_Flag_Maximized = (1 << 3),
WND_Flag_Minimized = (1 << 4),
};
Struct(WND_Settings)
{
WND_Flag flags;
Vec2I32 p0;
Vec2I32 p1;
i32 vsync;
};
Struct(WND_Cmd)
{
WND_Settings settings;
GPU_Resource *texture;
Vec2I32 backbuffer_dst;
Vec2I32 restore_p0;
Vec2I32 restore_p1;
};
Struct(WND_Event)
{
WND_Settings settings;
u64 inputs_count;
Input *inputs;
WND_Settings settings;
/* The backbuffer src texture is no longer in use once the direct queue fence reaches this target */
i64 backbuffer_fence_target;
Vec2I32 monitor_p0;
Vec2I32 monitor_p1;
Vec2I32 draw_p0;
Vec2I32 draw_p1;
u64 cmd_gen; /* How many times has a window cmd changed the window state */
u64 os_gen; /* How many times has the OS changed window state (e.g. mouse drags OS window border) */
};
Struct(WND_Cmd)
{
WND_Settings desired_settings;
GPU_Resource *texture;
Vec2I32 backbuffer_dst;
i32 vsync;
};
////////////////////////////////////////////////////////////
@ -43,4 +52,4 @@ void WND_Startup(void);
//~ @hookdecl Window hooks
WND_Event WND_BeginUpdate(Arena *arena);
void WND_EndUpdate(WND_Cmd cmd);
i64 WND_EndUpdateAndPresent(WND_Cmd cmd);

View File

@ -86,22 +86,10 @@ void WND_Startup(void)
}
//- Start message processing job
JobPoolId message_job_pool = InitJobPool(1, Lit("Win32 message loop"), JobPoolPriority_Background);
JobPoolId message_job_pool = InitJobPool(1, Lit("Win32 message loop"), JobPoolPriority_Graphics);
RunJob(WND_W32_ProcessMessagesForever, .pool = message_job_pool);
}
////////////////////////////////////////////////////////////
//~ Input helpers
void WND_W32_PushInput(WND_W32_Window *window, Input input)
{
LockTicketMutex(&window->inputs_tm);
{
*PushStructNoZero(window->inputs_arena, Input) = input;
}
UnlockTicketMutex(&window->inputs_tm);
}
////////////////////////////////////////////////////////////
//~ Initialization
@ -110,7 +98,7 @@ JobDef(WND_W32_ProcessMessagesForever, sig, id)
{
WND_W32_SharedState *g = &WND_W32_shared_state;
WND_W32_Window *window = &g->window;
window->inputs_arena = AcquireArena(Gibi(64));
window->w2u_inputs_arena = AcquireArena(Gibi(64));
//- Init hwnd
HWND hwnd = 0;
@ -170,18 +158,21 @@ JobDef(WND_W32_ProcessMessagesForever, sig, id)
////////////////////////////////////////////////////////////
//~ Message processing
void WND_W32_PushInput(WND_W32_Window *window, Input input)
{
LockTicketMutex(&window->w2u_tm);
{
*PushStructNoZero(window->w2u_inputs_arena, Input) = input;
}
UnlockTicketMutex(&window->w2u_tm);
}
LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
WND_W32_SharedState *g = &WND_W32_shared_state;
WND_W32_Window *window = &g->window;
++window->proc_depth;
LRESULT result = 0;
Lock lock = ZI;
if (window->proc_depth == 1)
{
lock = LockE(&window->update_mutex);
}
{
switch(msg)
{
@ -199,18 +190,6 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
WND_W32_PushInput(window, (Input) { .kind = InputKind_Quit });
} break;
//- Resizing
case WM_ENTERSIZEMOVE:
case WM_MOVE:
case WM_MOVING:
case WM_SIZE:
case WM_SIZING:
{
/* TODO */
// P_W32_UpdateWindowFromSystem(window);
result = DefWindowProcW(hwnd, msg, wparam, lparam);
} break;
//- Keyboard button
case WM_SYSKEYUP:
case WM_SYSKEYDOWN:;
@ -390,14 +369,202 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
}
EndScratch(scratch);
} break;
//- Process command
case WND_CmdMsgId:
{
P_LogWarningF("RAAAAH");
WND_Event user_event = ZI;
WND_Cmd user_cmd = ZI;
{
LockTicketMutex(&window->u2w_tm);
{
user_event = window->u2w_update_end_event;
user_cmd = window->u2w_update_end_cmd;
}
UnlockTicketMutex(&window->u2w_tm);
}
/* Determine old settings */
Vec2I32 old_draw_p0 = ZI;
Vec2I32 old_draw_p1 = ZI;
Vec2I32 old_restore_p0 = ZI;
Vec2I32 old_restore_p1 = ZI;
b32 old_is_visible = 0;
b32 old_has_border = 0;
{
{
RECT screen_rect = ZI;
GetClientRect(hwnd, (LPRECT)&screen_rect);
ClientToScreen(hwnd, (LPPOINT)&screen_rect.left);
ClientToScreen(hwnd, (LPPOINT)&screen_rect.right);
old_draw_p0 = VEC2I32(screen_rect.left, screen_rect.top);
old_draw_p1 = VEC2I32(screen_rect.right, screen_rect.bottom);
}
{
WINDOWPLACEMENT placement = { .length = sizeof(placement) };
GetWindowPlacement(hwnd, &placement);
RECT placement_rect = placement.rcNormalPosition;
old_restore_p0 = VEC2I32(placement_rect.left, placement_rect.top);
old_restore_p1 = VEC2I32(placement_rect.right, placement_rect.bottom);
}
{
DWORD style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE);
old_is_visible = !!(style & WS_VISIBLE);
old_has_border = !(style & WS_POPUP);
}
}
/* Determine new settings */
Vec2I32 new_draw_p0 = old_draw_p0;
Vec2I32 new_draw_p1 = old_draw_p1;
Vec2I32 new_restore_p0 = old_restore_p0;
Vec2I32 new_restore_p1 = old_restore_p1;
b32 new_is_visible = old_is_visible;
b32 new_has_border = old_has_border;
{
WND_Settings desired_settings = user_cmd.desired_settings;
if (desired_settings.flags & WND_Flag_Fullscreen)
{
new_has_border = 0;
new_draw_p0 = user_event.monitor_p0;
new_draw_p1 = user_event.monitor_p1;
}
else if (desired_settings.flags & WND_Flag_Maximized)
{
// show_cmd = SW_MAXIMIZE;
}
else if (desired_settings.flags & WND_Flag_Minimized)
{
// show_cmd = SW_MINIMIZE;
}
else
{
new_has_border = 1;
new_restore_p0 = desired_settings.restore_p0;
new_restore_p1 = desired_settings.restore_p1;
}
new_is_visible = 1;
}
/* Determine new style & placement */
b32 has_user_seen_os_settings = user_event.os_gen == (u64)Atomic64Fetch(&window->os_gen);
if (has_user_seen_os_settings)
{
/* Calculate style */
b32 dirty_style = 0;
DWORD new_style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE);
{
if (new_is_visible != old_is_visible)
{
dirty_style = 1;
if (new_is_visible)
{
new_style |= WS_VISIBLE;
}
else
{
new_style &= ~WS_VISIBLE;
}
}
if (new_has_border != old_has_border)
{
dirty_style = 1;
if (new_has_border)
{
new_style &= ~WS_POPUP;
new_style |= WS_OVERLAPPEDWINDOW;
}
else
{
new_style &= ~WS_OVERLAPPEDWINDOW;
new_style |= WS_POPUP;
}
}
}
/* Calculate placement */
b32 dirty_placement = 0;
WINDOWPLACEMENT new_placement = { .length = sizeof(new_placement) };
GetWindowPlacement(hwnd, &new_placement);
{
if (!EqVec2I32(new_restore_p0, old_restore_p0) || !EqVec2I32(new_restore_p1, old_restore_p1))
{
dirty_placement = 1;
new_placement.rcNormalPosition.left = new_restore_p0.x;
new_placement.rcNormalPosition.top = new_restore_p0.y;
new_placement.rcNormalPosition.right = new_restore_p1.x;
new_placement.rcNormalPosition.bottom = new_restore_p1.y;
}
}
/* Calculate draw position */
b32 dirty_draw_rect = 0;
RECT new_draw_rect = ZI;
if (!EqVec2I32(new_draw_p0, old_draw_p0) || !EqVec2I32(new_draw_p1, old_draw_p1))
{
dirty_draw_rect = 1;
new_draw_rect.left = new_draw_p0.x;
new_draw_rect.top = new_draw_p0.y;
new_draw_rect.right = new_draw_p1.x;
new_draw_rect.bottom = new_draw_p1.y;
AdjustWindowRect(&new_draw_rect, new_style, 0);
}
/* Apply changes */
if (dirty_style || dirty_placement || dirty_draw_rect)
{
if (dirty_style)
{
++window->cmd_depth;
SetWindowLongPtrW(hwnd, GWL_STYLE, new_style);
}
if (dirty_placement)
{
++window->cmd_depth;
SetWindowPlacement(hwnd, &new_placement);
}
if (dirty_draw_rect)
{
u32 pflags = 0;
Vec2I32 size = VEC2I32(new_draw_rect.right - new_draw_rect.left, new_draw_rect.bottom - new_draw_rect.top);
++window->cmd_depth;
SetWindowPos(hwnd, 0, new_draw_rect.left, new_draw_rect.top, size.x, size.y, pflags);
}
}
}
/* Bring window to front on first show */
if (!window->first_shown)
{
SetForegroundWindow(hwnd);
BringWindowToTop(hwnd);
window->first_shown = 1;
}
} break;
//- Detect changes
case WM_WINDOWPOSCHANGED:
{
if (window->cmd_depth == 0)
{
/* This change occurred outside of a user window command, so it must come from the OS */
Atomic64FetchAdd(&window->os_gen, 1);
P_LogInfoF("OS change");
}
else
{
/* FIXME: In order for this to truly be the result of a user cmd we should clear the message queue after cmd submission */
P_LogDebugF("Cmd change");
Atomic64FetchAdd(&window->cmd_gen, 1);
--window->cmd_depth;
}
result = DefWindowProcW(hwnd, msg, wparam, lparam);
} break;
}
}
if (window->proc_depth == 1)
{
Unlock(&lock);
}
--window->proc_depth;
return result;
}
@ -410,72 +577,150 @@ WND_Event WND_BeginUpdate(Arena *arena)
WND_W32_Window *window = &g->window;
WND_Event result = ZI;
/* TODO: Yield on swapchain instead */
while (!Atomic32Fetch(&window->is_ready))
{
_mm_pause();
}
HWND hwnd = window->hwnd;
/* FIXME: Don't use TM */
Lock *lock = &window->user_update_lock;
*lock = LockE(&window->update_mutex);
/* Wait on swapchain */
if (window->swapchain)
{
GPU_D12_YieldOnSwapchain(window->swapchain);
}
/* Pop inputs */
LockTicketMutex(&window->inputs_tm);
{
Input *src = (Input *)ArenaBase(window->inputs_arena);
result.inputs_count = ArenaCount(window->inputs_arena, Input);
result.inputs = PushStructsNoZero(arena, Input, result.inputs_count);
CopyStructs(result.inputs, src, result.inputs_count);
ResetArena(window->inputs_arena);
LockTicketMutex(&window->w2u_tm);
{
Input *src = (Input *)ArenaBase(window->w2u_inputs_arena);
result.inputs_count = ArenaCount(window->w2u_inputs_arena, Input);
result.inputs = PushStructsNoZero(arena, Input, result.inputs_count);
CopyStructs(result.inputs, src, result.inputs_count);
ResetArena(window->w2u_inputs_arena);
}
UnlockTicketMutex(&window->w2u_tm);
}
UnlockTicketMutex(&window->inputs_tm);
/* FIXME: Remove this */
result.settings.p0 = window->previous_cmd.settings.p0;
result.settings.p1 = window->previous_cmd.settings.p1;
/* Grab monitor info */
{
MONITORINFO monitor_info = { .cbSize = sizeof(monitor_info) };
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info);
RECT monitor_rect = monitor_info.rcMonitor;
result.monitor_p0.x = monitor_rect.left;
result.monitor_p0.y = monitor_rect.top;
result.monitor_p1.x = monitor_rect.right;
result.monitor_p1.y = monitor_rect.bottom;
}
/* Grab window info */
WND_Settings settings = ZI;
{
/* Draw size */
{
RECT screen_rect = ZI;
GetClientRect(hwnd, (LPRECT)&screen_rect);
ClientToScreen(hwnd, (LPPOINT)&screen_rect.left);
ClientToScreen(hwnd, (LPPOINT)&screen_rect.right);
result.draw_p0 = VEC2I32(screen_rect.left, screen_rect.top);
result.draw_p1 = VEC2I32(screen_rect.right, screen_rect.bottom);
}
/* Clamp */
// {
// RECT virt_rect = ZI;
// virt_rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
// virt_rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
// virt_rect.right = virt_rect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
// virt_rect.bottom = virt_rect.top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
// result.draw_p0.x = MaxI32(result.draw_p0.x, virt_rect.left);
// result.draw_p0.y = MaxI32(result.draw_p0.y, virt_rect.top);
// result.draw_p1.x = MinI32(result.draw_p1.x, virt_rect.right);
// result.draw_p1.y = MinI32(result.draw_p1.y, virt_rect.bottom);
// }
// result.draw_p1.x = MaxI32(result.draw_p1.x, result.draw_p0.x + 320);
// result.draw_p1.y = MaxI32(result.draw_p1.y, result.draw_p0.y + 180);
/* Minimized / maximized */
WINDOWPLACEMENT placement = { .length = sizeof(placement) };
GetWindowPlacement(hwnd, &placement);
if (placement.showCmd == SW_MAXIMIZE)
{
settings.flags |= WND_Flag_Maximized;
}
if (placement.showCmd == SW_MINIMIZE)
{
settings.flags |= WND_Flag_Minimized;
}
if (placement.flags & WPF_RESTORETOMAXIMIZED)
{
settings.flags |= WND_Flag_RestoreToMaximized;
}
/* Restore size */
{
RECT placement_rect = placement.rcNormalPosition;
settings.restore_p0 = VEC2I32(placement_rect.left, placement_rect.top);
settings.restore_p1 = VEC2I32(placement_rect.right, placement_rect.bottom);
}
/* Fullscreen */
/* TODO: Verify WS_POPUP as well */
if (EqVec2I32(result.draw_p0, result.monitor_p0) && EqVec2I32(result.draw_p1, result.monitor_p1))
{
settings.flags |= WND_Flag_Fullscreen;
}
result.settings = settings;
}
result.os_gen = Atomic64Fetch(&window->os_gen);
result.cmd_gen = Atomic64Fetch(&window->cmd_gen);
window->update_begin_event = result;
return result;
}
void WND_EndUpdate(WND_Cmd cmd)
i64 WND_EndUpdateAndPresent(WND_Cmd cmd)
{
WND_W32_SharedState *g = &WND_W32_shared_state;
WND_W32_Window *window = &g->window;
HWND hwnd = window->hwnd;
Unlock(&window->user_update_lock);
WND_Event begin_event = window->update_begin_event;
WND_Settings draw_settings = begin_event.settings;
Vec2I32 draw_size = SubVec2I32(begin_event.draw_p1, begin_event.draw_p0);
WND_Settings old = window->previous_cmd.settings;
WND_Settings new = cmd.settings;
Vec2I32 new_size = SubVec2I32(new.p1, new.p0);
/* Acquire swapchain */
if (!window->swapchain)
{
window->swapchain = GPU_D12_AcquireSwapchain(window->hwnd, GPU_Format_R8G8B8A8_Unorm, new_size);
window->swapchain = GPU_D12_AcquireSwapchain(window->hwnd, GPU_Format_R8G8B8A8_Unorm, draw_size);
}
/* Present */
/* TODO: Get fence */
i64 present_fence_target = 0;
if (cmd.texture != 0)
{
Vec2I32 backbuffer_dst = cmd.backbuffer_dst;
i32 vsync = new.vsync;
GPU_D12_PresentSwapchain(window->swapchain, cmd.texture, new_size, backbuffer_dst, vsync);
if (cmd.vsync != 0)
{
/* FIXME: Don't flush in fullscreen mode? */
DwmFlush();
}
present_fence_target = GPU_D12_PresentSwapchain(window->swapchain, cmd.texture, draw_size, backbuffer_dst, cmd.vsync);
}
/* Show window */
if (!window->first_shown)
/* Push cmd to window */
b32 desires_change = !EqStruct(&cmd.desired_settings, &begin_event.settings);
if (desires_change)
{
i32 show_cmd = SW_SHOWMAXIMIZED;
ShowWindow(window->hwnd, show_cmd);
SetForegroundWindow(window->hwnd);
BringWindowToTop(window->hwnd);
window->first_shown = 1;
LockTicketMutex(&window->u2w_tm);
{
window->u2w_update_end_cmd = cmd;
window->u2w_update_end_event = begin_event;
PostMessageW(window->hwnd, WND_CmdMsgId, 0, 0);
}
UnlockTicketMutex(&window->u2w_tm);
}
window->previous_cmd = cmd;
return present_fence_target;
}

View File

@ -1,29 +1,36 @@
////////////////////////////////////////////////////////////
//~ Window types
#define WND_CmdMsgId (WM_USER + 1)
Struct(WND_W32_Window)
{
Atomic32 is_ready;
HWND hwnd;
GPU_D12_Swapchain *swapchain;
Atomic32 is_ready;
TicketMutex inputs_tm;
Arena *inputs_arena;
/* TODO: Remove this */
// TicketMutex update_tm;
Mutex update_mutex;
Lock user_update_lock;
i32 proc_depth;
/* TODO: Remove this */
b32 first_shown;
WND_Cmd previous_cmd;
Atomic64 cmd_gen;
Atomic64 os_gen;
/* Window state */
u16 previous_utf16_high_surrogate;
b32 first_shown;
i64 cmd_depth;
/* User state */
WND_Event update_begin_event;
/* Window -> User */
/* Reads outside of window thread must lock */
TicketMutex w2u_tm;
Arena *w2u_inputs_arena;
/* User -> Window */
/* Reads outside of user thread must lock */
TicketMutex u2w_tm;
WND_Event u2w_update_end_event; /* The user's processed event at end of update */
WND_Cmd u2w_update_end_cmd; /* The user's cmd at the end of update */
};
////////////////////////////////////////////////////////////
@ -38,11 +45,6 @@ Struct(WND_W32_SharedState)
WND_W32_Window window; /* Only single-window for now */
} extern WND_W32_shared_state;
////////////////////////////////////////////////////////////
//~ Input helpers
void WND_W32_PushInput(WND_W32_Window *window, Input input);
////////////////////////////////////////////////////////////
//~ Initialization
@ -51,4 +53,5 @@ JobDecl(WND_W32_ProcessMessagesForever, EmptySig);
////////////////////////////////////////////////////////////
//~ Message processing
void WND_W32_PushInput(WND_W32_Window *window, Input input);
LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);