simplify window layer
This commit is contained in:
parent
6beb910f98
commit
9297e40b0c
@ -115,7 +115,9 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
|
||||
if (bytes_needed > max_len)
|
||||
{
|
||||
/* Writer overflowed fixed buffer */
|
||||
#if BITBUFF_DEBUG
|
||||
Assert(0);
|
||||
#endif
|
||||
result = 1;
|
||||
bw->cur_bit = max_len << 3;
|
||||
bw->overflowed = 1;
|
||||
@ -447,7 +449,9 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits)
|
||||
if (bits_needed > base_len_bits)
|
||||
{
|
||||
/* Tried to read past bitbuff memory */
|
||||
#if BITBUFF_DEBUG
|
||||
Assert(0);
|
||||
#endif
|
||||
result = 1;
|
||||
br->cur_bit = base_len_bits;
|
||||
br->overflowed = 1;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
@Layer gpu
|
||||
|
||||
//- Dependencies
|
||||
@Dep window
|
||||
@Dep platform
|
||||
|
||||
//- Api
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
Struct(GPU_Resource);
|
||||
Struct(GPU_CommandList);
|
||||
Struct(GPU_Swapchain);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Queue types
|
||||
@ -468,3 +469,19 @@ void GPU_CopyBytesToFootprint(void *dst, void *src, GPU_Resource *footprint_refe
|
||||
//~ @hookdecl Memory info operations
|
||||
|
||||
GPU_MemoryInfo GPU_QueryMemoryInfo(void);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Swapchain operations
|
||||
|
||||
GPU_Swapchain *GPU_AcquireSwapchain(WND_Handle window, GPU_Format format, Vec2I32 size);
|
||||
void GPU_ReleaseSwapchain(GPU_Swapchain *swapchain);
|
||||
|
||||
/* Waits until a new backbuffer is ready to be written to.
|
||||
* This should be called before rendering for minimum latency. */
|
||||
void GPU_YieldOnSwapchain(GPU_Swapchain *swapchain);
|
||||
|
||||
/* 1. Ensures the backbuffer size matches `backbuffer_size`
|
||||
* 2. Blits `texture` into position `dst` in the backbuffer
|
||||
* 3. Presents the backbuffer
|
||||
* 4. Returns the value that the Direct queue fence will reach once GPU completes blitting (`texture` shouldn't be released while blit is in flight) */
|
||||
i64 GPU_PresentSwapchain(GPU_Swapchain *swapchain, GPU_Resource *texture, Vec2I32 backbuffer_size, Vec2I32 dst, i32 vsync);
|
||||
|
||||
@ -2036,12 +2036,13 @@ i64 GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *dst, GPU_D12_Resource *text
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Swapchain operations
|
||||
//~ @hookdef Swapchain operations
|
||||
|
||||
GPU_D12_Swapchain *GPU_D12_AcquireSwapchain(HWND hwnd, GPU_Format format, Vec2I32 size)
|
||||
GPU_Swapchain *GPU_AcquireSwapchain(WND_Handle window, GPU_Format format, Vec2I32 size)
|
||||
{
|
||||
GPU_D12_SharedState *g = &GPU_D12_shared_state;
|
||||
HRESULT hr = 0;
|
||||
HWND hwnd = WND_W32_WindowFromHandle(window)->hwnd;
|
||||
GPU_D12_Queue *queue = GPU_D12_QueueFromKind(GPU_QueueKind_Direct);
|
||||
|
||||
GPU_D12_Swapchain *swapchain = 0;
|
||||
@ -2110,15 +2111,15 @@ GPU_D12_Swapchain *GPU_D12_AcquireSwapchain(HWND hwnd, GPU_Format format, Vec2I3
|
||||
|
||||
GPU_D12_InitSwapchainResources(swapchain);
|
||||
|
||||
return (GPU_D12_Swapchain *)swapchain;
|
||||
return (GPU_Swapchain *)swapchain;
|
||||
}
|
||||
|
||||
void GPU_D12_ReleaseSwapchain(GPU_D12_Swapchain *swapchain)
|
||||
void GPU_ReleaseSwapchain(GPU_Swapchain *gpu_swapchain)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
void GPU_D12_YieldOnSwapchain(GPU_D12_Swapchain *gpu_swapchain)
|
||||
void GPU_YieldOnSwapchain(GPU_Swapchain *gpu_swapchain)
|
||||
{
|
||||
/* TODO: Actually yield, don't block */
|
||||
GPU_D12_Swapchain *swapchain = (GPU_D12_Swapchain *)gpu_swapchain;
|
||||
@ -2128,7 +2129,7 @@ void GPU_D12_YieldOnSwapchain(GPU_D12_Swapchain *gpu_swapchain)
|
||||
}
|
||||
}
|
||||
|
||||
i64 GPU_D12_PresentSwapchain(GPU_D12_Swapchain *gpu_swapchain, GPU_Resource *gpu_texture, Vec2I32 backbuffer_size, Vec2I32 dst, i32 vsync)
|
||||
i64 GPU_PresentSwapchain(GPU_Swapchain *gpu_swapchain, GPU_Resource *gpu_texture, Vec2I32 backbuffer_size, Vec2I32 dst, i32 vsync)
|
||||
{
|
||||
GPU_D12_Swapchain *swapchain = (GPU_D12_Swapchain *)gpu_swapchain;
|
||||
GPU_D12_Resource *texture = (GPU_D12_Resource *)gpu_texture;
|
||||
@ -2156,6 +2157,12 @@ i64 GPU_D12_PresentSwapchain(GPU_D12_Swapchain *gpu_swapchain, GPU_Resource *gpu
|
||||
present_flags |= DXGI_PRESENT_ALLOW_TEARING;
|
||||
}
|
||||
|
||||
if (vsync != 0)
|
||||
{
|
||||
/* FIXME: Don't flush in fullscreen mode? */
|
||||
// DwmFlush();
|
||||
}
|
||||
|
||||
/* Present */
|
||||
{
|
||||
__profn("Present");
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
#define GPU_D12_TearingIsAllowed 1
|
||||
#define GPU_D12_FrameLatency 2
|
||||
#define GPU_D12_SwapchainBufferCount 3
|
||||
#define GPU_D12_SwapchainBufferCount 2
|
||||
#define GPU_D12_SwapchainFlags (((GPU_D12_TearingIsAllowed != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) \
|
||||
| ((GPU_D12_FrameLatency != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
|
||||
|
||||
@ -375,22 +375,6 @@ void GPU_D12_InitSwapchainResources(GPU_D12_Swapchain *swapchain);
|
||||
GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, Vec2I32 resolution);
|
||||
i64 GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *swapchain_buffer, GPU_D12_Resource *texture, Vec2I32 dst_pos);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Swapchain operations
|
||||
|
||||
GPU_D12_Swapchain *GPU_D12_AcquireSwapchain(HWND hwnd, GPU_Format format, Vec2I32 size);
|
||||
void GPU_D12_ReleaseSwapchain(GPU_D12_Swapchain *swapchain);
|
||||
|
||||
/* Waits until a new backbuffer is ready to be written to.
|
||||
* This should be called before rendering for minimum latency. */
|
||||
void GPU_D12_YieldOnSwapchain(GPU_D12_Swapchain *swapchain);
|
||||
|
||||
/* 1. Ensures the backbuffer size matches `backbuffer_size`
|
||||
* 2. Blits `texture` into position `dst` in the backbuffer
|
||||
* 3. Presents the backbuffer
|
||||
* 4. Returns the value that the Direct queue fence will reach once GPU completes blitting (`texture` shouldn't be released while blit is in flight) */
|
||||
i64 GPU_D12_PresentSwapchain(GPU_D12_Swapchain *swapchain, GPU_Resource *texture, Vec2I32 backbuffer_size, Vec2I32 dst, i32 vsync);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Sync job
|
||||
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
@Layer gpu_dx12
|
||||
|
||||
//- Dependencies
|
||||
@Dep window_win32
|
||||
|
||||
//- Api
|
||||
@IncludeC gpu_dx12.h
|
||||
|
||||
|
||||
97
src/pp/pp.c
97
src/pp/pp.c
@ -10,12 +10,12 @@ void StartupUser(void)
|
||||
|
||||
SetGstat(GSTAT_DEBUG_STEPS, U64Max);
|
||||
|
||||
g->arena = AcquireArena(Gibi(64));
|
||||
Arena *perm = PermArena();
|
||||
g->real_time_ns = TimeNs();
|
||||
|
||||
/* TODO: Remove this */
|
||||
String connect_address_str = Lit("");
|
||||
g->connect_address_str = PushString(g->arena, connect_address_str);
|
||||
g->connect_address_str = PushString(perm, connect_address_str);
|
||||
|
||||
/* Initialize average dt to a reasonable value */
|
||||
g->average_local_to_user_snapshot_publish_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
|
||||
@ -30,25 +30,26 @@ void StartupUser(void)
|
||||
g->local_to_user_client_store = AcquireClientStore();
|
||||
g->local_to_user_client = AcquireClient(g->local_to_user_client_store);
|
||||
|
||||
/* 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());
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
String swap_str = SwappedStateFromName(scratch.arena, Lit("pp_user"));
|
||||
String swap_encoded = SwappedStateFromName(scratch.arena, Lit("pp_user"));
|
||||
|
||||
BB_Buff bb = BB_BuffFromString(swap_encoded);
|
||||
BB_Reader br = BB_ReaderFromBuff(&bb);
|
||||
|
||||
String swap_str = BB_ReadString(scratch.arena, &br);
|
||||
g->window_restore = BB_ReadString(perm, &br);
|
||||
|
||||
if (swap_str.len == sizeof(SwappedUserState))
|
||||
{
|
||||
SwappedUserState *swap = (SwappedUserState *)swap_str.text;
|
||||
SwappedUserState *swap = PushStructNoZero(scratch.arena, SwappedUserState);
|
||||
CopyBytes(swap, swap_str.text, swap_str.len);
|
||||
SharedUserState *old = &swap->s;
|
||||
CopyStructRegion(g, old, AUTO_PERSIST_START, AUTO_PERSIST_END);
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
@ -80,10 +81,17 @@ ExitFuncDef(ShutdownUser)
|
||||
if (IsSwappingOut())
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
|
||||
u64 max_size = Mebi(16);
|
||||
u8 *bytes = PushStructsNoZero(scratch.arena, u8, max_size);
|
||||
BB_Buff bb = BB_BuffFromString(STRING(max_size, bytes));
|
||||
{
|
||||
BB_Writer bw = BB_WriterFromBuff(&bb);
|
||||
SwappedUserState *swap = PushStruct(scratch.arena, SwappedUserState);
|
||||
swap->s = *g;
|
||||
WriteSwappedState(Lit("pp_user"), StringFromStruct(swap));
|
||||
BB_WriteString(&bw, StringFromStruct(swap));
|
||||
BB_WriteString(&bw, g->window_restore);
|
||||
WriteSwappedState(Lit("pp_user"), STRING(BB_GetNumBytesWritten(&bw), BB_GetWrittenRaw(&bw)));
|
||||
}
|
||||
EndScratch(scratch);
|
||||
}
|
||||
}
|
||||
@ -487,24 +495,39 @@ void UpdateUser(void)
|
||||
SharedUserState *g = &shared_user_state;
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
|
||||
//- Begin frame
|
||||
WND_Event window_event = WND_BeginUpdate(scratch.arena);
|
||||
|
||||
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;
|
||||
|
||||
//- Begin window
|
||||
WND_Settings cur_window = window_event.settings;
|
||||
if (window_event.os_gen > g->window_os_gen && window_event.cmd_gen > 0)
|
||||
if (g->swapchain)
|
||||
{
|
||||
/* Window was modified outside of program. Reflect this in our own state. */
|
||||
g->desired_window = cur_window;
|
||||
GPU_YieldOnSwapchain(g->swapchain);
|
||||
}
|
||||
g->window_os_gen = window_event.os_gen;
|
||||
g->screen_size = SubVec2I32(window_event.draw_p1, window_event.draw_p0);
|
||||
|
||||
//- Begin window frame
|
||||
WND_Frame window_frame = WND_BeginFrame(scratch.arena);
|
||||
if (g->user_tick == 0)
|
||||
{
|
||||
String restore = g->window_restore;
|
||||
if (restore.len > 0)
|
||||
{
|
||||
WND_PushCmd(window_frame, .kind = WND_CmdKind_Restore, .restore = restore);
|
||||
}
|
||||
}
|
||||
{
|
||||
String src = window_frame.restore;
|
||||
if (src.len > g->window_restore.len)
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
g->window_restore = PushString(perm, src);
|
||||
}
|
||||
CopyBytes(g->window_restore.text, src.text, src.len);
|
||||
g->window_restore.len = src.len;
|
||||
}
|
||||
|
||||
u64 inputs_count = window_frame.inputs_count;
|
||||
Input *inputs = window_frame.inputs;
|
||||
|
||||
g->screen_size = window_frame.draw_size;
|
||||
g->screen_size.x = MaxI32(g->screen_size.x, 1);
|
||||
g->screen_size.y = MaxI32(g->screen_size.y, 1);
|
||||
|
||||
@ -760,7 +783,7 @@ void UpdateUser(void)
|
||||
{
|
||||
if (g->bind_states[BindKind_Fullscreen].num_presses && g->bind_states[BindKind_FullscreenMod].is_held)
|
||||
{
|
||||
g->desired_window.flags ^= WND_Flag_Fullscreen;
|
||||
WND_PushCmd(window_frame, .kind = WND_CmdKind_SetFullscreen, .v = !window_frame.fullscreen);
|
||||
}
|
||||
}
|
||||
|
||||
@ -771,7 +794,7 @@ void UpdateUser(void)
|
||||
|
||||
if (g->bind_states[BindKind_DebugToggleTopmost].num_presses > 0)
|
||||
{
|
||||
g->desired_window.flags ^= WND_Flag_ForcedTop;
|
||||
WND_PushCmd(window_frame, .kind = WND_CmdKind_SetForcedTop, .v = !window_frame.forced_top);
|
||||
P_LogSuccessF("Toggle topmost");
|
||||
}
|
||||
|
||||
@ -2352,18 +2375,18 @@ void UpdateUser(void)
|
||||
g->gpu_submit_fence_target = UI_EndBuild(g->ui_target);
|
||||
|
||||
//////////////////////////////
|
||||
//- End window update
|
||||
//- Present & end frame
|
||||
|
||||
{
|
||||
WND_Cmd cmd = ZI;
|
||||
cmd.desired_settings = g->desired_window;
|
||||
cmd.texture = g->ui_target;
|
||||
cmd.vsync = VSYNC;
|
||||
if (!g->swapchain)
|
||||
{
|
||||
g->swapchain = GPU_AcquireSwapchain(window_frame.window_handle, GPU_Format_R8G8B8A8_Unorm, g->screen_size);
|
||||
}
|
||||
Vec2 backbuffer_dst_f = MulXformV2(g->ui_to_screen_xf, VEC2(0, 0));
|
||||
cmd.backbuffer_dst = VEC2I32(RoundF32ToI32(backbuffer_dst_f.x), RoundF32ToI32(backbuffer_dst_f.y));
|
||||
}
|
||||
g->gpu_submit_fence_target = WND_EndUpdateAndPresent(cmd);
|
||||
Vec2I32 backbuffer_dst = VEC2I32(RoundF32ToI32(backbuffer_dst_f.x), RoundF32ToI32(backbuffer_dst_f.y));
|
||||
g->gpu_submit_fence_target = GPU_PresentSwapchain(g->swapchain, g->ui_target, g->screen_size, backbuffer_dst, VSYNC);
|
||||
}
|
||||
WND_EndFrame(window_frame);
|
||||
|
||||
++g->user_tick;
|
||||
EndScratch(scratch);
|
||||
|
||||
10
src/pp/pp.h
10
src/pp/pp.h
@ -240,14 +240,16 @@ Struct(SharedUserState)
|
||||
i64 real_dt_ns;
|
||||
i64 real_time_ns;
|
||||
|
||||
//- Window
|
||||
|
||||
WND_Handle window;
|
||||
GPU_Swapchain *swapchain;
|
||||
String window_restore;
|
||||
|
||||
//////////////////////////////
|
||||
//- Persist start
|
||||
StructRegion(AUTO_PERSIST_START);
|
||||
|
||||
//- Window
|
||||
|
||||
WND_Settings desired_window;
|
||||
|
||||
//- Debug camera
|
||||
|
||||
EntityId debug_following;
|
||||
|
||||
@ -1,55 +1,64 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Window types
|
||||
//~ Handle types
|
||||
|
||||
Enum(WND_Flag)
|
||||
Struct(WND_Handle)
|
||||
{
|
||||
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),
|
||||
u64 v;
|
||||
};
|
||||
|
||||
Struct(WND_Settings)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Cmd types
|
||||
|
||||
Enum(WND_CmdKind)
|
||||
{
|
||||
WND_Flag flags;
|
||||
Vec2I32 restore_p0;
|
||||
Vec2I32 restore_p1;
|
||||
};
|
||||
|
||||
Struct(WND_Event)
|
||||
{
|
||||
WND_Settings settings;
|
||||
u64 inputs_count;
|
||||
Input *inputs;
|
||||
|
||||
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) */
|
||||
WND_CmdKind_None,
|
||||
WND_CmdKind_SetMinimized,
|
||||
WND_CmdKind_SetMaximized,
|
||||
WND_CmdKind_SetFullscreen,
|
||||
WND_CmdKind_SetForcedTop,
|
||||
WND_CmdKind_Restore,
|
||||
};
|
||||
|
||||
Struct(WND_Cmd)
|
||||
{
|
||||
WND_Settings desired_settings;
|
||||
|
||||
GPU_Resource *texture;
|
||||
Vec2I32 backbuffer_dst;
|
||||
i32 vsync;
|
||||
WND_CmdKind kind;
|
||||
String restore;
|
||||
b32 v;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Startup hooks
|
||||
//~ Frame types
|
||||
|
||||
Struct(WND_Frame)
|
||||
{
|
||||
WND_Handle window_handle;
|
||||
|
||||
/* User input since last update */
|
||||
u64 inputs_count;
|
||||
Input *inputs;
|
||||
|
||||
/* Window info */
|
||||
Vec2I32 draw_size;
|
||||
String restore;
|
||||
b32 minimized;
|
||||
b32 maximized;
|
||||
b32 fullscreen;
|
||||
b32 forced_top;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Startup
|
||||
|
||||
void WND_Startup(void);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Window hooks
|
||||
//~ @hookdecl Command operations
|
||||
|
||||
WND_Event WND_BeginUpdate(Arena *arena);
|
||||
i64 WND_EndUpdateAndPresent(WND_Cmd cmd);
|
||||
#define WND_PushCmd(frame, ...) WND_PushCmd_((frame), (WND_Cmd) { __VA_ARGS__ })
|
||||
void WND_PushCmd_(WND_Frame frame, WND_Cmd desc);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Frame
|
||||
|
||||
WND_Frame WND_BeginFrame(Arena *arena);
|
||||
void WND_EndFrame(WND_Frame frame);
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
@Layer window
|
||||
|
||||
//- Dependencies
|
||||
@Dep gpu
|
||||
|
||||
//- Api
|
||||
@IncludeC window.h
|
||||
|
||||
|
||||
@ -90,6 +90,14 @@ void WND_Startup(void)
|
||||
RunJob(WND_W32_ProcessMessagesForever, .pool = message_job_pool);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Window helpers
|
||||
|
||||
WND_W32_Window *WND_W32_WindowFromHandle(WND_Handle handle)
|
||||
{
|
||||
return (WND_W32_Window *)handle.v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Initialization
|
||||
|
||||
@ -133,6 +141,7 @@ JobDef(WND_W32_ProcessMessagesForever, sig, id)
|
||||
DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&dark_mode, sizeof(dark_mode));
|
||||
|
||||
/* Set window as userdata */
|
||||
/* FIXME: Necessary? */
|
||||
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)window);
|
||||
}
|
||||
window->hwnd = hwnd;
|
||||
@ -370,6 +379,7 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
|
||||
EndScratch(scratch);
|
||||
} break;
|
||||
|
||||
#if 0
|
||||
//- Process command
|
||||
case WND_CmdMsgId:
|
||||
{
|
||||
@ -543,25 +553,7 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
|
||||
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;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -569,25 +561,44 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdef Update
|
||||
//~ @hookdef Cmds
|
||||
|
||||
WND_Event WND_BeginUpdate(Arena *arena)
|
||||
void WND_PushCmd_(WND_Frame frame, WND_Cmd desc)
|
||||
{
|
||||
WND_W32_Window *window = WND_W32_WindowFromHandle(frame.window_handle);
|
||||
WND_W32_CmdNode *n = PushStruct(window->cmds_arena, WND_W32_CmdNode);
|
||||
n->cmd = desc;
|
||||
QueuePush(window->first_cmd, window->last_cmd, n);
|
||||
if (desc.kind == WND_CmdKind_Restore)
|
||||
{
|
||||
n->cmd.restore = PushString(window->cmds_arena, desc.restore);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdef Frame
|
||||
|
||||
WND_Frame WND_BeginFrame(Arena *arena)
|
||||
{
|
||||
WND_W32_SharedState *g = &WND_W32_shared_state;
|
||||
WND_W32_Window *window = &g->window;
|
||||
WND_Event result = ZI;
|
||||
WND_Frame result = ZI;
|
||||
|
||||
while (!Atomic32Fetch(&window->is_ready))
|
||||
{
|
||||
_mm_pause();
|
||||
}
|
||||
HWND hwnd = window->hwnd;
|
||||
result.window_handle.v = (u64)window;
|
||||
|
||||
/* Wait on swapchain */
|
||||
if (window->swapchain)
|
||||
/* Reset cmds */
|
||||
if (!window->cmds_arena)
|
||||
{
|
||||
GPU_D12_YieldOnSwapchain(window->swapchain);
|
||||
window->cmds_arena = AcquireArena(Gibi(64));
|
||||
}
|
||||
ResetArena(window->cmds_arena);
|
||||
window->first_cmd = 0;
|
||||
window->last_cmd = 0;
|
||||
|
||||
/* Pop inputs */
|
||||
{
|
||||
@ -603,124 +614,199 @@ WND_Event WND_BeginUpdate(Arena *arena)
|
||||
}
|
||||
|
||||
/* Grab monitor info */
|
||||
RECT monitor_rect = ZI;
|
||||
{
|
||||
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;
|
||||
monitor_rect = monitor_info.rcMonitor;
|
||||
}
|
||||
|
||||
/* Grab window info */
|
||||
WND_Settings settings = ZI;
|
||||
{
|
||||
/* Draw size */
|
||||
{
|
||||
RECT screen_rect = ZI;
|
||||
GetClientRect(hwnd, (LPRECT)&screen_rect);
|
||||
/* Client rect */
|
||||
RECT client_rect = ZI;
|
||||
GetClientRect(hwnd, (LPRECT)&client_rect);
|
||||
|
||||
/* Screen rect */
|
||||
RECT screen_rect = client_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);
|
||||
}
|
||||
result.draw_size = VEC2I32(screen_rect.right - screen_rect.left, screen_rect.bottom - screen_rect.top);
|
||||
|
||||
/* 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 */
|
||||
/* Minimized / maximized / fullscreen */
|
||||
DWORD style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE);
|
||||
DWORD ex_style = (DWORD)GetWindowLongPtr(hwnd, GWL_EXSTYLE);
|
||||
WINDOWPLACEMENT placement = { .length = sizeof(placement) };
|
||||
GetWindowPlacement(hwnd, &placement);
|
||||
{
|
||||
if (placement.showCmd == SW_MAXIMIZE)
|
||||
{
|
||||
settings.flags |= WND_Flag_Maximized;
|
||||
result.maximized = 1;
|
||||
}
|
||||
if (placement.showCmd == SW_MINIMIZE)
|
||||
{
|
||||
settings.flags |= WND_Flag_Minimized;
|
||||
result.minimized = 1;
|
||||
}
|
||||
if (placement.flags & WPF_RESTORETOMAXIMIZED)
|
||||
if (screen_rect.left == monitor_rect.left &&
|
||||
screen_rect.top == monitor_rect.top &&
|
||||
screen_rect.right == monitor_rect.right &&
|
||||
screen_rect.bottom == monitor_rect.bottom)
|
||||
{
|
||||
settings.flags |= WND_Flag_RestoreToMaximized;
|
||||
result.fullscreen = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore size */
|
||||
result.forced_top = window->is_forced_top;
|
||||
result.fullscreen = window->is_fullscreen;
|
||||
|
||||
/* Generate restore data */
|
||||
{
|
||||
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))
|
||||
WND_W32_RestorableData restore = ZI;
|
||||
{
|
||||
settings.flags |= WND_Flag_Fullscreen;
|
||||
restore.magic = WND_W32_RestoreMagic;
|
||||
restore.placement = placement;
|
||||
restore.style = style;
|
||||
restore.ex_style = ex_style;
|
||||
restore.is_forced_top = window->is_forced_top;
|
||||
restore.is_fullscreen = window->is_fullscreen;
|
||||
restore.fullscreen_restore_rect = window->fullscreen_restore_rect;
|
||||
if (IsWindowArranged(hwnd))
|
||||
{
|
||||
restore.is_snapped = 1;
|
||||
restore.snapped_screen_rect = screen_rect;
|
||||
}
|
||||
}
|
||||
result.restore = PushString(window->cmds_arena, StringFromStruct(&restore));
|
||||
}
|
||||
|
||||
result.settings = settings;
|
||||
}
|
||||
|
||||
result.os_gen = Atomic64Fetch(&window->os_gen);
|
||||
result.cmd_gen = Atomic64Fetch(&window->cmd_gen);
|
||||
|
||||
window->update_begin_event = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
i64 WND_EndUpdateAndPresent(WND_Cmd cmd)
|
||||
void WND_EndFrame(WND_Frame frame)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
WND_W32_SharedState *g = &WND_W32_shared_state;
|
||||
WND_W32_Window *window = &g->window;
|
||||
WND_W32_Window *window = WND_W32_WindowFromHandle(frame.window_handle);
|
||||
HWND hwnd = window->hwnd;
|
||||
|
||||
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);
|
||||
|
||||
if (!window->swapchain)
|
||||
/* Process cmds */
|
||||
for (WND_W32_CmdNode *n = window->first_cmd; n; n = n->next)
|
||||
{
|
||||
window->swapchain = GPU_D12_AcquireSwapchain(window->hwnd, GPU_Format_R8G8B8A8_Unorm, draw_size);
|
||||
WND_Cmd cmd = n->cmd;
|
||||
switch(cmd.kind)
|
||||
{
|
||||
//- Minimize
|
||||
case WND_CmdKind_SetMinimized:
|
||||
{
|
||||
ShowWindow(hwnd, SW_MINIMIZE);
|
||||
} break;
|
||||
|
||||
//- Maximize
|
||||
case WND_CmdKind_SetMaximized:
|
||||
{
|
||||
ShowWindow(hwnd, SW_MAXIMIZE);
|
||||
} break;
|
||||
|
||||
//- Fullscreen
|
||||
case WND_CmdKind_SetFullscreen:
|
||||
{
|
||||
if (cmd.v != window->is_fullscreen)
|
||||
{
|
||||
DWORD old_style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE);
|
||||
RECT old_rect = ZI;
|
||||
{
|
||||
GetClientRect(hwnd, (LPRECT)&old_rect);
|
||||
ClientToScreen(hwnd, (LPPOINT)&old_rect.left);
|
||||
ClientToScreen(hwnd, (LPPOINT)&old_rect.right);
|
||||
AdjustWindowRect(&old_rect, old_style, 0);
|
||||
}
|
||||
RECT new_rect = ZI;
|
||||
HWND new_hwnd = 0;
|
||||
DWORD new_style = old_style;
|
||||
if (cmd.v)
|
||||
{
|
||||
/* Enter fullscreen */
|
||||
{
|
||||
MONITORINFO monitor_info = { .cbSize = sizeof(monitor_info) };
|
||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info);
|
||||
new_rect = monitor_info.rcMonitor;
|
||||
}
|
||||
new_style &= ~WS_OVERLAPPEDWINDOW;
|
||||
new_style |= WS_POPUP;
|
||||
window->fullscreen_restore_rect = old_rect;
|
||||
new_hwnd = HWND_TOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Exit fullscreen */
|
||||
new_rect = window->fullscreen_restore_rect;
|
||||
new_style &= ~WS_POPUP;
|
||||
new_style |= WS_OVERLAPPEDWINDOW;
|
||||
new_hwnd = window->is_forced_top ? HWND_TOPMOST : HWND_NOTOPMOST;
|
||||
}
|
||||
window->is_fullscreen = cmd.v;
|
||||
SetWindowLongPtr(hwnd, GWL_STYLE, new_style);
|
||||
SetWindowPos(hwnd, new_hwnd, new_rect.left, new_rect.top, new_rect.right - new_rect.left, new_rect.bottom - new_rect.top, 0);
|
||||
}
|
||||
} break;
|
||||
|
||||
//- Force top
|
||||
case WND_CmdKind_SetForcedTop:
|
||||
{
|
||||
window->is_forced_top = cmd.v;
|
||||
SetWindowPos(hwnd, window->is_forced_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||
} break;
|
||||
|
||||
//- Restore
|
||||
case WND_CmdKind_Restore:
|
||||
{
|
||||
/* FIXME: Cap bounds */
|
||||
String restore_str = cmd.restore;
|
||||
if (restore_str.len == sizeof(WND_W32_RestorableData))
|
||||
{
|
||||
WND_W32_RestorableData *restore = PushStructNoZero(scratch.arena, WND_W32_RestorableData);
|
||||
CopyBytes(restore, restore_str.text, restore_str.len);
|
||||
if (restore->magic == WND_W32_RestoreMagic)
|
||||
{
|
||||
WINDOWPLACEMENT placement = restore->placement;
|
||||
SetWindowPlacement(hwnd, &placement);
|
||||
SetWindowLongPtr(hwnd, GWL_STYLE, restore->style);
|
||||
SetWindowLongPtr(hwnd, GWL_EXSTYLE, restore->ex_style);
|
||||
|
||||
if (restore->is_fullscreen)
|
||||
{
|
||||
MONITORINFO monitor_info = { .cbSize = sizeof(monitor_info) };
|
||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info);
|
||||
RECT rect = monitor_info.rcMonitor;
|
||||
window->is_fullscreen = 1;
|
||||
window->fullscreen_restore_rect = restore->fullscreen_restore_rect;
|
||||
SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
|
||||
}
|
||||
|
||||
/* Present */
|
||||
i64 present_fence_target = 0;
|
||||
if (cmd.texture != 0)
|
||||
if (restore->is_forced_top)
|
||||
{
|
||||
Vec2I32 backbuffer_dst = cmd.backbuffer_dst;
|
||||
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);
|
||||
window->is_forced_top = 1;
|
||||
SetWindowPos(hwnd, window->is_forced_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||
}
|
||||
|
||||
/* Push cmd to window */
|
||||
b32 desires_change = !EqStruct(&cmd.desired_settings, &begin_event.settings);
|
||||
if (desires_change)
|
||||
if (restore->is_snapped)
|
||||
{
|
||||
LockTicketMutex(&window->u2w_tm);
|
||||
{
|
||||
window->u2w_update_end_cmd = cmd;
|
||||
window->u2w_update_end_event = begin_event;
|
||||
PostMessageW(window->hwnd, WND_CmdMsgId, 0, 0);
|
||||
RECT rect = restore->snapped_screen_rect;
|
||||
HWND pos_hwnd = window->is_forced_top ? HWND_TOPMOST : HWND_NOTOPMOST;
|
||||
SetWindowPos(hwnd, pos_hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
UnlockTicketMutex(&window->u2w_tm);
|
||||
}
|
||||
|
||||
return present_fence_target;
|
||||
/* Bring window to front on first show */
|
||||
if (!window->first_shown)
|
||||
{
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
SetForegroundWindow(hwnd);
|
||||
BringWindowToTop(hwnd);
|
||||
window->first_shown = 1;
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
@ -1,36 +1,58 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Window types
|
||||
|
||||
#define WND_CmdMsgId (WM_USER + 1)
|
||||
|
||||
Struct(WND_W32_Window)
|
||||
{
|
||||
HWND hwnd;
|
||||
GPU_D12_Swapchain *swapchain;
|
||||
Atomic32 is_ready;
|
||||
|
||||
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;
|
||||
Arena *cmds_arena;
|
||||
struct WND_W32_CmdNode *first_cmd;
|
||||
struct WND_W32_CmdNode *last_cmd;
|
||||
b32 first_shown;
|
||||
b32 is_forced_top;
|
||||
b32 is_fullscreen;
|
||||
RECT fullscreen_restore_rect;
|
||||
|
||||
/* Window -> User */
|
||||
/* Reads outside of window thread must lock */
|
||||
TicketMutex w2u_tm;
|
||||
Arena *w2u_inputs_arena;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Restore types
|
||||
|
||||
/* 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 */
|
||||
#define WND_W32_RestoreMagic 0xc4b4842a
|
||||
|
||||
Struct(WND_W32_RestorableData)
|
||||
{
|
||||
u32 magic;
|
||||
|
||||
WINDOWPLACEMENT placement;
|
||||
DWORD style;
|
||||
DWORD ex_style;
|
||||
|
||||
b32 is_forced_top;
|
||||
|
||||
b32 is_fullscreen;
|
||||
RECT fullscreen_restore_rect;
|
||||
|
||||
b32 is_snapped;
|
||||
RECT snapped_screen_rect;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Cmd types
|
||||
|
||||
Struct(WND_W32_CmdNode)
|
||||
{
|
||||
WND_W32_CmdNode *next;
|
||||
WND_Cmd cmd;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -42,9 +64,14 @@ Struct(WND_W32_SharedState)
|
||||
{
|
||||
Btn vk_to_btn[256];
|
||||
WNDCLASSEXW window_class;
|
||||
WND_W32_Window window; /* Only single-window for now */
|
||||
WND_W32_Window window; /* Single-window for now */
|
||||
} extern WND_W32_shared_state;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Window helpers
|
||||
|
||||
WND_W32_Window *WND_W32_WindowFromHandle(WND_Handle handle);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Initialization
|
||||
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
@Layer window_win32
|
||||
|
||||
//- Dependencies
|
||||
@Dep gpu_dx12
|
||||
|
||||
//- Api
|
||||
@IncludeC window_win32.h
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user