begin window layer

This commit is contained in:
jacob 2025-10-25 10:27:47 -05:00
parent a6f31e4fae
commit 5f7de288ac
16 changed files with 1136 additions and 369 deletions

View File

@ -22,6 +22,7 @@
# include "base_entry.h" # include "base_entry.h"
# include "base_bitbuff.h" # include "base_bitbuff.h"
# include "base_resource.h" # include "base_resource.h"
# include "base_input.h"
#elif LanguageIsGpu #elif LanguageIsGpu
# include "base_math_gpu.h" # include "base_math_gpu.h"
#endif #endif

149
src/base/base_input.h Normal file
View File

@ -0,0 +1,149 @@
////////////////////////////////////////////////////////////
//~ Button types
Enum(Btn)
{
Btn_None,
//- Mouse buttons
Btn_M1,
Btn_M2,
Btn_M3,
Btn_M4,
Btn_M5,
//- Mouse wheel
Btn_MWheelUp,
Btn_MWheelDown,
//- Keyboard buttons
Btn_Esc,
Btn_F1,
Btn_F2,
Btn_F3,
Btn_F4,
Btn_F5,
Btn_F6,
Btn_F7,
Btn_F8,
Btn_F9,
Btn_F10,
Btn_F11,
Btn_F12,
Btn_F13,
Btn_F14,
Btn_F15,
Btn_F16,
Btn_F17,
Btn_F18,
Btn_F19,
Btn_F20,
Btn_F21,
Btn_F22,
Btn_F23,
Btn_F24,
Btn_GraveAccent,
Btn_0,
Btn_1,
Btn_2,
Btn_3,
Btn_4,
Btn_5,
Btn_6,
Btn_7,
Btn_8,
Btn_9,
Btn_Minus,
Btn_Equal,
Btn_Backspace,
Btn_Delete,
Btn_Tab,
Btn_A,
Btn_B,
Btn_C,
Btn_D,
Btn_E,
Btn_F,
Btn_G,
Btn_H,
Btn_I,
Btn_J,
Btn_K,
Btn_L,
Btn_M,
Btn_N,
Btn_O,
Btn_P,
Btn_Q,
Btn_R,
Btn_S,
Btn_T,
Btn_U,
Btn_V,
Btn_W,
Btn_X,
Btn_Y,
Btn_Z,
Btn_Space,
Btn_Enter,
Btn_Ctrl,
Btn_Shift,
Btn_Alt,
Btn_Up,
Btn_Left,
Btn_Down,
Btn_Right,
Btn_PageUp,
Btn_PageDown,
Btn_Home,
Btn_End,
Btn_ForwardSlash,
Btn_Period,
Btn_Comma,
Btn_Quote,
Btn_LeftBracket,
Btn_RightBracket,
Btn_Insert,
Btn_Semicolon,
Btn_Count
};
////////////////////////////////////////////////////////////
//~ Input types
Enum(InputKind)
{
InputKind_None,
InputKind_ButtonDown,
InputKind_ButtonUp,
InputKind_CursorMove,
InputKind_MouseMove,
InputKind_Text,
InputKind_Quit,
InputKind_Count
};
Struct(Input)
{
InputKind kind;
/* InputKind_ButtonDown */
/* InputKind_ButtonUp */
Btn button;
b32 is_repeat;
/* InputKind_Text */
u32 text_codepoint;
/* InputKind_CursorMove */
Vec2I32 cursor_pos;
/* InputKind_MouseMove */
Vec2I32 mouse_delta;
};

View File

@ -18,8 +18,10 @@ void SetMemoryReadWrite(void *address, u64 size);
//- Wrappers //- Wrappers
#define ZeroStruct(ptr) ZeroBytes((ptr), sizeof(*(ptr))) #define ZeroStruct(ptr) ZeroBytes((ptr), sizeof(*(ptr)))
#define ZeroStructs(ptr, n) ZeroBytes((ptr), sizeof(*(ptr)) * (n))
#define ZeroArray(a) Assert(IsArray(a)); ZeroBytes((a), sizeof((a))) #define ZeroArray(a) Assert(IsArray(a)); ZeroBytes((a), sizeof((a)))
#define CopyStruct(ptr_dst, ptr_src) CopyBytes((ptr_dst), (ptr_src), sizeof(*(ptr_dst))) #define CopyStruct(ptr_dst, ptr_src) CopyBytes((ptr_dst), (ptr_src), sizeof(*(ptr_dst)))
#define CopyStructs(ptr_dst, ptr_src, n) CopyBytes((ptr_dst), (ptr_src), sizeof(*(ptr_dst)) * (n))
#define EqStruct(p1, p2) EqBytes((p1), (p2), sizeof(*p1)) #define EqStruct(p1, p2) EqBytes((p1), (p2), sizeof(*p1))
#define ZeroBytes(ptr, count) SetBytes((ptr), 0, (count)) #define ZeroBytes(ptr, count) SetBytes((ptr), 0, (count))
#define EqBytes(p1, p2, n) (CmpBytes((p1), (p2), (n)) == 0) #define EqBytes(p1, p2, n) (CmpBytes((p1), (p2), (n)) == 0)

View File

@ -565,8 +565,7 @@ void ResumeFibers(i16 fiber_ids_count, i16 *fiber_ids)
Atomic8Set(&fiber->status, W32_FiberStatus_None); Atomic8Set(&fiber->status, W32_FiberStatus_None);
W32_Task *task = fiber->task; W32_Task *task = fiber->task;
// if (task->job->flags & JobFlag_Dedicated) if (task->job->flags & JobFlag_Dedicated)
if (0)
{ {
/* TODO: Wake dedicated fiber right now */ /* TODO: Wake dedicated fiber right now */
WakeByAddressSingle(&fiber->status); WakeByAddressSingle(&fiber->status);

View File

@ -3,7 +3,6 @@
Struct(GPU_Resource); Struct(GPU_Resource);
Struct(GPU_CommandList); Struct(GPU_CommandList);
Struct(GPU_Swapchain);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Queue types //~ Queue types
@ -469,19 +468,3 @@ void GPU_CopyBytesToFootprint(void *dst, void *src, GPU_Resource *footprint_refe
//~ @hookdecl Memory info operations //~ @hookdecl Memory info operations
GPU_MemoryInfo GPU_QueryMemoryInfo(void); GPU_MemoryInfo GPU_QueryMemoryInfo(void);
////////////////////////////////////////////////////////////
//~ @hookdecl Swapchain operations
GPU_Swapchain *GPU_AcquireSwapchain(P_Window *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);

View File

@ -696,225 +696,6 @@ u64 GPU_D12_EndRawCommandList(GPU_D12_RawCommandList *cl)
return target; return target;
} }
////////////////////////////////////////////////////////////
//~ Swapchain helpers
void GPU_D12_InitSwapchainResources(GPU_D12_Swapchain *swapchain)
{
GPU_D12_SharedState *g = &GPU_D12_shared_state;
for (u32 i = 0; i < countof(swapchain->buffers); ++i)
{
ID3D12Resource *resource = 0;
HRESULT hr = IDXGISwapChain3_GetBuffer(swapchain->swapchain, i, &IID_ID3D12Resource, (void **)&resource);
if (FAILED(hr))
{
/* TODO: Don't panic */
Panic(Lit("Failed to get swapchain buffer"));
}
GPU_D12_SwapchainBuffer *sb = &swapchain->buffers[i];
ZeroStruct(sb);
sb->swapchain = swapchain;
sb->d3d_resource = resource;
sb->rtv_descriptor = GPU_D12_AcquireDescriptor(g->rtv_heap);
sb->state = D3D12_RESOURCE_STATE_COMMON;
ID3D12Device_CreateRenderTargetView(g->device, sb->d3d_resource, 0, sb->rtv_descriptor->handle);
}
}
GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, Vec2I32 resolution)
{
__prof;
GPU_D12_SharedState *g = &GPU_D12_shared_state;
resolution.x = MaxI32(resolution.x, 1);
resolution.y = MaxI32(resolution.y, 1);
b32 should_rebuild = !EqVec2I32(swapchain->resolution, resolution);
if (should_rebuild)
{
HRESULT hr = 0;
GPU_D12_Queue *queue = GPU_D12_QueueFromKind(GPU_QueueKind_Direct);
/* Lock direct queue submissions (in case any write to backbuffer) */
/* TODO: Less overkill approach - Only flush GPU_D12_BlitToSwapchain since we know it's the only operation targeting backbuffer */
Lock lock = LockE(&queue->submit_mutex);
//DEBUGBREAKABLE;
//Lock lock = LockE(&g->global_command_list_record_mutex);
{
/* Flush direct queue */
//ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, ++cq->submit_fence_target);
{
HANDLE event = CreateEvent(0, 0, 0, 0);
ID3D12Fence_SetEventOnCompletion(queue->submit_fence, queue->submit_fence_target, event);
WaitForSingleObject(event, INFINITE);
CloseHandle(event);
}
/* Release buffers */
for (u32 i = 0; i < countof(swapchain->buffers); ++i)
{
GPU_D12_SwapchainBuffer *sb = &swapchain->buffers[i];
GPU_D12_ReleaseDescriptor(sb->rtv_descriptor);
ID3D12Resource_Release(sb->d3d_resource);
}
/* Resize buffers */
hr = IDXGISwapChain_ResizeBuffers(swapchain->swapchain, 0, resolution.x, resolution.y, DXGI_FORMAT_UNKNOWN, GPU_D12_SwapchainFlags);
if (FAILED(hr))
{
/* TODO: Don't panic */
Panic(Lit("Failed to resize swapchain"));
}
}
Unlock(&lock);
GPU_D12_InitSwapchainResources(swapchain);
swapchain->resolution = resolution;
}
u32 backbuffer_index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain->swapchain);
return &swapchain->buffers[backbuffer_index];
}
i64 GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *dst, GPU_D12_Resource *texture, Vec2I32 dst_pos)
{
GPU_D12_SharedState *g = &GPU_D12_shared_state;
GPU_D12_Swapchain *swapchain = dst->swapchain;
GPU_D12_RawCommandList *dx12_cl = GPU_D12_BeginRawCommandList(GPU_QueueKind_Direct);
ID3D12GraphicsCommandList *rcl = dx12_cl->cl;
D3D12_RESOURCE_STATES old_texture_state = texture->state;
{
u32 barriers_count = 0;
D3D12_RESOURCE_BARRIER rbs[2] = ZI;
/* Transition backbuffer to RENDER_TARGET */
{
D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++];
rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
rb->Transition.pResource = dst->d3d_resource;
rb->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
rb->Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
rb->Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
}
ID3D12GraphicsCommandList_ResourceBarrier(rcl, barriers_count, rbs);
}
/* Clear */
{
f32 clear_color[4] = ZI;
ID3D12GraphicsCommandList_ClearRenderTargetView(rcl, dst->rtv_descriptor->handle, clear_color, 0, 0);
}
{
u32 barriers_count = 0;
D3D12_RESOURCE_BARRIER rbs[2] = ZI;
/* Transition backbuffer to COPY_DEST */
{
D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++];
rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
rb->Transition.pResource = dst->d3d_resource;
rb->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
rb->Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
rb->Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
}
/* Transition texture to COPY_SRC */
if (texture->state != D3D12_RESOURCE_STATE_COPY_SOURCE)
{
D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++];
rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
rb->Transition.pResource = texture->d3d_resource;
rb->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
rb->Transition.StateBefore = texture->state;
rb->Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
texture->state = rb->Transition.StateAfter;
}
ID3D12GraphicsCommandList_ResourceBarrier(rcl, barriers_count, rbs);
}
/* Copy */
{
D3D12_TEXTURE_COPY_LOCATION dst_loc = ZI;
dst_loc.pResource = dst->d3d_resource;
dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst_loc.SubresourceIndex = 0;
D3D12_TEXTURE_COPY_LOCATION src_loc = ZI;
src_loc.pResource = texture->d3d_resource;
src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
src_loc.SubresourceIndex = 0;
Vec2I32 dst_size = swapchain->resolution;
Vec2I32 src_size = VEC2I32(texture->desc.texture.size.x, texture->desc.texture.size.y);
i32 dst_left = dst_pos.x;
i32 dst_top = dst_pos.y;
i32 src_left = 0;
i32 src_top = 0;
i32 src_right = src_size.x;
i32 src_bottom = src_size.y;
/* Clamp copy src & dst */
if (dst_left < 0)
{
src_left -= dst_left;
dst_left = 0;
}
if (dst_top < 0)
{
src_top -= dst_top;
dst_top = 0;
}
if (dst_left + (src_left + src_right) > dst_size.x)
{
src_right -= (dst_left + (src_left + src_right)) - dst_size.x;
}
if (dst_top + (src_top + src_bottom) > dst_size.y)
{
src_bottom -= (dst_top + (src_top + src_bottom)) - dst_size.y;
}
if (src_left < src_right && src_bottom > src_top)
{
D3D12_BOX src_box = ZI;
src_box.left = src_left;
src_box.top = src_top;
src_box.right = src_right;
src_box.bottom = src_bottom;
src_box.back = 1;
ID3D12GraphicsCommandList_CopyTextureRegion(rcl, &dst_loc, dst_left, dst_top, 0, &src_loc, &src_box);
}
}
{
u32 barriers_count = 0;
D3D12_RESOURCE_BARRIER rbs[2] = ZI;
/* Transition backbuffer to PRESENT */
{
D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++];
rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
rb->Transition.pResource = dst->d3d_resource;
rb->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
rb->Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
rb->Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
}
/* Transition texture to original state */
if (texture->state != old_texture_state)
{
D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++];
rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
rb->Transition.pResource = texture->d3d_resource;
rb->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
rb->Transition.StateBefore = texture->state;
rb->Transition.StateAfter = old_texture_state;
texture->state = rb->Transition.StateAfter;
}
ID3D12GraphicsCommandList_ResourceBarrier(rcl, barriers_count, rbs);
}
i64 fence_target = GPU_D12_EndRawCommandList(dx12_cl);
return fence_target;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Queue sync job //~ Queue sync job
@ -1091,17 +872,17 @@ GPU_Resource *GPU_AcquireResource(GPU_ResourceDesc desc)
}; };
Assert(!(desc.flags & GPU_ResourceFlag_Renderable)); Assert(!(desc.flags & GPU_ResourceFlag_Renderable));
D3D12_RESOURCE_DESC d3d_desc = ZI; D3D12_RESOURCE_DESC d3d_desc = ZI;
d3d_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; d3d_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
d3d_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; d3d_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
d3d_desc.Format = DXGI_FORMAT_UNKNOWN; d3d_desc.Format = DXGI_FORMAT_UNKNOWN;
d3d_desc.Alignment = 0; d3d_desc.Alignment = 0;
d3d_desc.Width = buffer_size; d3d_desc.Width = buffer_size;
d3d_desc.Height = 1; d3d_desc.Height = 1;
d3d_desc.DepthOrArraySize = 1; d3d_desc.DepthOrArraySize = 1;
d3d_desc.MipLevels = 1; d3d_desc.MipLevels = 1;
d3d_desc.SampleDesc.Count = 1; d3d_desc.SampleDesc.Count = 1;
d3d_desc.SampleDesc.Quality = 0; d3d_desc.SampleDesc.Quality = 0;
d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS * !!(desc.flags & GPU_ResourceFlag_Writable); d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS * !!(desc.flags & GPU_ResourceFlag_Writable);
r->state = desc.buffer.heap_kind == GPU_HeapKind_Upload ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST; r->state = desc.buffer.heap_kind == GPU_HeapKind_Upload ? D3D12_RESOURCE_STATE_GENERIC_READ : D3D12_RESOURCE_STATE_COPY_DEST;
HRESULT hr = ID3D12Device_CreateCommittedResource(g->device, &heap_props, heap_flags, &d3d_desc, r->state, 0, &IID_ID3D12Resource, (void **)&r->d3d_resource); HRESULT hr = ID3D12Device_CreateCommittedResource(g->device, &heap_props, heap_flags, &d3d_desc, r->state, 0, &IID_ID3D12Resource, (void **)&r->d3d_resource);
if (FAILED(hr)) if (FAILED(hr))
@ -1119,27 +900,27 @@ GPU_Resource *GPU_AcquireResource(GPU_ResourceDesc desc)
{ {
D3D12_HEAP_FLAGS heap_flags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED; D3D12_HEAP_FLAGS heap_flags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
D3D12_HEAP_PROPERTIES heap_props = { .Type = D3D12_HEAP_TYPE_DEFAULT }; D3D12_HEAP_PROPERTIES heap_props = { .Type = D3D12_HEAP_TYPE_DEFAULT };
D3D12_RESOURCE_DESC d3d_desc = ZI; D3D12_RESOURCE_DESC d3d_desc = ZI;
d3d_desc.Dimension = desc.kind == GPU_ResourceKind_Texture1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D d3d_desc.Dimension = desc.kind == GPU_ResourceKind_Texture1D ? D3D12_RESOURCE_DIMENSION_TEXTURE1D
: desc.kind == GPU_ResourceKind_Texture2D ? D3D12_RESOURCE_DIMENSION_TEXTURE2D : desc.kind == GPU_ResourceKind_Texture2D ? D3D12_RESOURCE_DIMENSION_TEXTURE2D
: D3D12_RESOURCE_DIMENSION_TEXTURE3D; : D3D12_RESOURCE_DIMENSION_TEXTURE3D;
d3d_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; d3d_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
d3d_desc.Format = GPU_D12_DxgiFormatFromGpuFormat(desc.texture.format); d3d_desc.Format = GPU_D12_DxgiFormatFromGpuFormat(desc.texture.format);
d3d_desc.Alignment = 0; d3d_desc.Alignment = 0;
d3d_desc.Width = desc.texture.size.x; d3d_desc.Width = MaxI32(desc.texture.size.x, 1);
d3d_desc.Height = desc.texture.size.y; d3d_desc.Height = MaxI32(desc.texture.size.y, 1);
d3d_desc.DepthOrArraySize = desc.texture.size.z; d3d_desc.DepthOrArraySize = MaxI32(desc.texture.size.z, 1);
d3d_desc.MipLevels = (desc.flags & GPU_ResourceFlag_MaxMipLevels) ? 0 : MaxI32(desc.texture.mip_levels, 1); d3d_desc.MipLevels = (desc.flags & GPU_ResourceFlag_MaxMipLevels) ? 0 : MaxI32(desc.texture.mip_levels, 1);
d3d_desc.SampleDesc.Count = 1; d3d_desc.SampleDesc.Count = 1;
d3d_desc.SampleDesc.Quality = 0; d3d_desc.SampleDesc.Quality = 0;
d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS * !!(desc.flags & GPU_ResourceFlag_Writable); d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS * !!(desc.flags & GPU_ResourceFlag_Writable);
d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET * !!(desc.flags & GPU_ResourceFlag_Renderable); d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET * !!(desc.flags & GPU_ResourceFlag_Renderable);
r->state = D3D12_RESOURCE_STATE_COPY_DEST; r->state = D3D12_RESOURCE_STATE_COPY_DEST;
D3D12_CLEAR_VALUE clear_value = { .Format = d3d_desc.Format, .Color = { 0 } }; D3D12_CLEAR_VALUE clear_value = { .Format = d3d_desc.Format, .Color = { 0 } };
clear_value.Color[0] = desc.clear_color.x; clear_value.Color[0] = desc.clear_color.x;
clear_value.Color[1] = desc.clear_color.y; clear_value.Color[1] = desc.clear_color.y;
clear_value.Color[2] = desc.clear_color.z; clear_value.Color[2] = desc.clear_color.z;
clear_value.Color[3] = desc.clear_color.w; clear_value.Color[3] = desc.clear_color.w;
D3D12_CLEAR_VALUE *clear_value_ptr = d3d_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET ? &clear_value : 0; D3D12_CLEAR_VALUE *clear_value_ptr = d3d_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET ? &clear_value : 0;
HRESULT hr = ID3D12Device_CreateCommittedResource(g->device, &heap_props, heap_flags, &d3d_desc, r->state, clear_value_ptr, &IID_ID3D12Resource, (void **)&r->d3d_resource); HRESULT hr = ID3D12Device_CreateCommittedResource(g->device, &heap_props, heap_flags, &d3d_desc, r->state, clear_value_ptr, &IID_ID3D12Resource, (void **)&r->d3d_resource);
if (FAILED(hr)) if (FAILED(hr))
@ -2035,13 +1816,231 @@ GPU_MemoryInfo GPU_QueryMemoryInfo(void)
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdef Swapchain hooks //~ Swapchain helpers
GPU_Swapchain *GPU_AcquireSwapchain(P_Window *window, GPU_Format format, Vec2I32 size) void GPU_D12_InitSwapchainResources(GPU_D12_Swapchain *swapchain)
{
GPU_D12_SharedState *g = &GPU_D12_shared_state;
for (u32 i = 0; i < countof(swapchain->buffers); ++i)
{
ID3D12Resource *resource = 0;
HRESULT hr = IDXGISwapChain3_GetBuffer(swapchain->swapchain, i, &IID_ID3D12Resource, (void **)&resource);
if (FAILED(hr))
{
/* TODO: Don't panic */
Panic(Lit("Failed to get swapchain buffer"));
}
GPU_D12_SwapchainBuffer *sb = &swapchain->buffers[i];
ZeroStruct(sb);
sb->swapchain = swapchain;
sb->d3d_resource = resource;
sb->rtv_descriptor = GPU_D12_AcquireDescriptor(g->rtv_heap);
sb->state = D3D12_RESOURCE_STATE_COMMON;
ID3D12Device_CreateRenderTargetView(g->device, sb->d3d_resource, 0, sb->rtv_descriptor->handle);
}
}
GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, Vec2I32 resolution)
{
__prof;
GPU_D12_SharedState *g = &GPU_D12_shared_state;
resolution.x = MaxI32(resolution.x, 1);
resolution.y = MaxI32(resolution.y, 1);
b32 should_rebuild = !EqVec2I32(swapchain->resolution, resolution);
if (should_rebuild)
{
HRESULT hr = 0;
GPU_D12_Queue *queue = GPU_D12_QueueFromKind(GPU_QueueKind_Direct);
/* Lock direct queue submissions (in case any write to backbuffer) */
/* TODO: Less overkill approach - Only flush GPU_D12_BlitToSwapchain since we know it's the only operation targeting backbuffer */
Lock lock = LockE(&queue->submit_mutex);
//DEBUGBREAKABLE;
//Lock lock = LockE(&g->global_command_list_record_mutex);
{
/* Flush direct queue */
//ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, ++cq->submit_fence_target);
{
HANDLE event = CreateEvent(0, 0, 0, 0);
ID3D12Fence_SetEventOnCompletion(queue->submit_fence, queue->submit_fence_target, event);
WaitForSingleObject(event, INFINITE);
CloseHandle(event);
}
/* Release buffers */
for (u32 i = 0; i < countof(swapchain->buffers); ++i)
{
GPU_D12_SwapchainBuffer *sb = &swapchain->buffers[i];
GPU_D12_ReleaseDescriptor(sb->rtv_descriptor);
ID3D12Resource_Release(sb->d3d_resource);
}
/* Resize buffers */
hr = IDXGISwapChain_ResizeBuffers(swapchain->swapchain, 0, resolution.x, resolution.y, DXGI_FORMAT_UNKNOWN, GPU_D12_SwapchainFlags);
if (FAILED(hr))
{
/* TODO: Don't panic */
Panic(Lit("Failed to resize swapchain"));
}
}
Unlock(&lock);
GPU_D12_InitSwapchainResources(swapchain);
swapchain->resolution = resolution;
}
u32 backbuffer_index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain->swapchain);
return &swapchain->buffers[backbuffer_index];
}
i64 GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *dst, GPU_D12_Resource *texture, Vec2I32 dst_pos)
{
GPU_D12_SharedState *g = &GPU_D12_shared_state;
GPU_D12_Swapchain *swapchain = dst->swapchain;
GPU_D12_RawCommandList *dx12_cl = GPU_D12_BeginRawCommandList(GPU_QueueKind_Direct);
ID3D12GraphicsCommandList *rcl = dx12_cl->cl;
D3D12_RESOURCE_STATES old_texture_state = texture->state;
{
u32 barriers_count = 0;
D3D12_RESOURCE_BARRIER rbs[2] = ZI;
/* Transition backbuffer to RENDER_TARGET */
{
D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++];
rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
rb->Transition.pResource = dst->d3d_resource;
rb->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
rb->Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
rb->Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
}
ID3D12GraphicsCommandList_ResourceBarrier(rcl, barriers_count, rbs);
}
/* Clear */
{
f32 clear_color[4] = ZI;
ID3D12GraphicsCommandList_ClearRenderTargetView(rcl, dst->rtv_descriptor->handle, clear_color, 0, 0);
}
{
u32 barriers_count = 0;
D3D12_RESOURCE_BARRIER rbs[2] = ZI;
/* Transition backbuffer to COPY_DEST */
{
D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++];
rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
rb->Transition.pResource = dst->d3d_resource;
rb->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
rb->Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
rb->Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
}
/* Transition texture to COPY_SRC */
if (texture->state != D3D12_RESOURCE_STATE_COPY_SOURCE)
{
D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++];
rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
rb->Transition.pResource = texture->d3d_resource;
rb->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
rb->Transition.StateBefore = texture->state;
rb->Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
texture->state = rb->Transition.StateAfter;
}
ID3D12GraphicsCommandList_ResourceBarrier(rcl, barriers_count, rbs);
}
/* Copy */
{
D3D12_TEXTURE_COPY_LOCATION dst_loc = ZI;
dst_loc.pResource = dst->d3d_resource;
dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst_loc.SubresourceIndex = 0;
D3D12_TEXTURE_COPY_LOCATION src_loc = ZI;
src_loc.pResource = texture->d3d_resource;
src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
src_loc.SubresourceIndex = 0;
Vec2I32 dst_size = swapchain->resolution;
Vec2I32 src_size = VEC2I32(texture->desc.texture.size.x, texture->desc.texture.size.y);
i32 dst_left = dst_pos.x;
i32 dst_top = dst_pos.y;
i32 src_left = 0;
i32 src_top = 0;
i32 src_right = src_size.x;
i32 src_bottom = src_size.y;
/* Clamp copy src & dst */
if (dst_left < 0)
{
src_left -= dst_left;
dst_left = 0;
}
if (dst_top < 0)
{
src_top -= dst_top;
dst_top = 0;
}
if (dst_left + (src_left + src_right) > dst_size.x)
{
src_right -= (dst_left + (src_left + src_right)) - dst_size.x;
}
if (dst_top + (src_top + src_bottom) > dst_size.y)
{
src_bottom -= (dst_top + (src_top + src_bottom)) - dst_size.y;
}
if (src_left < src_right && src_bottom > src_top)
{
D3D12_BOX src_box = ZI;
src_box.left = src_left;
src_box.top = src_top;
src_box.right = src_right;
src_box.bottom = src_bottom;
src_box.back = 1;
ID3D12GraphicsCommandList_CopyTextureRegion(rcl, &dst_loc, dst_left, dst_top, 0, &src_loc, &src_box);
}
}
{
u32 barriers_count = 0;
D3D12_RESOURCE_BARRIER rbs[2] = ZI;
/* Transition backbuffer to PRESENT */
{
D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++];
rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
rb->Transition.pResource = dst->d3d_resource;
rb->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
rb->Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
rb->Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
}
/* Transition texture to original state */
if (texture->state != old_texture_state)
{
D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++];
rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
rb->Transition.pResource = texture->d3d_resource;
rb->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
rb->Transition.StateBefore = texture->state;
rb->Transition.StateAfter = old_texture_state;
texture->state = rb->Transition.StateAfter;
}
ID3D12GraphicsCommandList_ResourceBarrier(rcl, barriers_count, rbs);
}
i64 fence_target = GPU_D12_EndRawCommandList(dx12_cl);
return fence_target;
}
////////////////////////////////////////////////////////////
//~ Swapchain operations
GPU_D12_Swapchain *GPU_D12_AcquireSwapchain(HWND hwnd, GPU_Format format, Vec2I32 size)
{ {
GPU_D12_SharedState *g = &GPU_D12_shared_state; GPU_D12_SharedState *g = &GPU_D12_shared_state;
HRESULT hr = 0; HRESULT hr = 0;
HWND hwnd = (HWND)P_GetInternalWindowHandle(window);
GPU_D12_Queue *queue = GPU_D12_QueueFromKind(GPU_QueueKind_Direct); GPU_D12_Queue *queue = GPU_D12_QueueFromKind(GPU_QueueKind_Direct);
GPU_D12_Swapchain *swapchain = 0; GPU_D12_Swapchain *swapchain = 0;
@ -2070,17 +2069,17 @@ GPU_Swapchain *GPU_AcquireSwapchain(P_Window *window, GPU_Format format, Vec2I32
IDXGISwapChain1 *swapchain1 = 0; IDXGISwapChain1 *swapchain1 = 0;
{ {
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 = size.x;
desc.Height = size.y; desc.Height = size.y;
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;
desc.BufferCount = GPU_D12_SwapchainBufferCount; desc.BufferCount = GPU_D12_SwapchainBufferCount;
desc.Scaling = DXGI_SCALING_NONE; desc.Scaling = DXGI_SCALING_NONE;
desc.Flags = GPU_D12_SwapchainFlags; desc.Flags = GPU_D12_SwapchainFlags;
desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
hr = IDXGIFactory2_CreateSwapChainForHwnd(g->factory, (IUnknown *)queue->d3d_queue, hwnd, &desc, 0, 0, &swapchain1); hr = IDXGIFactory2_CreateSwapChainForHwnd(g->factory, (IUnknown *)queue->d3d_queue, hwnd, &desc, 0, 0, &swapchain1);
if (FAILED(hr)) if (FAILED(hr))
{ {
@ -2110,15 +2109,15 @@ GPU_Swapchain *GPU_AcquireSwapchain(P_Window *window, GPU_Format format, Vec2I32
GPU_D12_InitSwapchainResources(swapchain); GPU_D12_InitSwapchainResources(swapchain);
return (GPU_Swapchain *)swapchain; return (GPU_D12_Swapchain *)swapchain;
} }
void GPU_ReleaseSwapchain(GPU_Swapchain *swapchain) void GPU_D12_ReleaseSwapchain(GPU_D12_Swapchain *swapchain)
{ {
/* TODO */ /* TODO */
} }
void GPU_YieldOnSwapchain(GPU_Swapchain *gpu_swapchain) void GPU_D12_YieldOnSwapchain(GPU_D12_Swapchain *gpu_swapchain)
{ {
/* TODO: Actually yield, don't block */ /* TODO: Actually yield, don't block */
GPU_D12_Swapchain *swapchain = (GPU_D12_Swapchain *)gpu_swapchain; GPU_D12_Swapchain *swapchain = (GPU_D12_Swapchain *)gpu_swapchain;
@ -2128,7 +2127,7 @@ void GPU_YieldOnSwapchain(GPU_Swapchain *gpu_swapchain)
} }
} }
i64 GPU_PresentSwapchain(GPU_Swapchain *gpu_swapchain, GPU_Resource *gpu_texture, Vec2I32 backbuffer_size, Vec2I32 dst, i32 vsync) i64 GPU_D12_PresentSwapchain(GPU_D12_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_Swapchain *swapchain = (GPU_D12_Swapchain *)gpu_swapchain;
GPU_D12_Resource *texture = (GPU_D12_Resource *)gpu_texture; GPU_D12_Resource *texture = (GPU_D12_Resource *)gpu_texture;

View File

@ -375,6 +375,22 @@ void GPU_D12_InitSwapchainResources(GPU_D12_Swapchain *swapchain);
GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, Vec2I32 resolution); 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); 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 //~ Sync job

View File

@ -1055,9 +1055,9 @@ JobDef(Build, _, __)
String exe_file = Lit("pp.exe"); String exe_file = Lit("pp.exe");
{ {
/* Wait for exe to become writable (once program closes) */ /* Wait for exe to become writable (wait for program to close) */
i64 timeout_ns = NsFromSeconds(0.5); f32 timeout = 1.0;
OS_File file = OS_OpenFile(exe_file, OS_FileFlag_Write, timeout_ns); OS_File file = OS_OpenFile(exe_file, OS_FileFlag_Write, NsFromSeconds(timeout));
OS_CloseFile(file); OS_CloseFile(file);
} }

View File

@ -50,9 +50,6 @@ void StartupUser(void)
g->console_logs_arena = AcquireArena(Gibi(64)); g->console_logs_arena = AcquireArena(Gibi(64));
//P_RegisterLogCallback(ConsoleLogCallback, P_LogLevel_Success); //P_RegisterLogCallback(ConsoleLogCallback, P_LogLevel_Success);
P_RegisterLogCallback(ConsoleLogCallback, P_LogLevel_Debug); P_RegisterLogCallback(ConsoleLogCallback, P_LogLevel_Debug);
g->window = P_AcquireWindow();
g->swapchain = GPU_AcquireSwapchain(g->window, GPU_Format_R8G8B8A8_Unorm, VEC2I32(100, 100));
P_ShowWindow(g->window);
/* Start jobs */ /* Start jobs */
g->shutdown_jobs_count += RunJob(UpdateUserOrSleep, .pool = JobPool_User, .fence = &g->shutdown_jobs_fence); g->shutdown_jobs_count += RunJob(UpdateUserOrSleep, .pool = JobPool_User, .fence = &g->shutdown_jobs_fence);
@ -80,8 +77,6 @@ ExitFuncDef(ShutdownUser)
WriteSwappedState(Lit("pp_user"), StringFromStruct(swap)); WriteSwappedState(Lit("pp_user"), StringFromStruct(swap));
EndScratch(scratch); EndScratch(scratch);
} }
P_ReleaseWindow(g->window);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -480,16 +475,26 @@ MergesortCompareFuncDef(EntitySortCmp, arg_a, arg_b, _)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ User update //~ User update
void UpdateUser(P_Window *window) void UpdateUser(void)
{ {
__prof; __prof;
SharedUserState *g = &shared_user_state; SharedUserState *g = &shared_user_state;
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
//- Begin frame //- Begin frame
WND_Event win_event = WND_BeginUpdate(scratch.arena);
u64 inputs_count = win_event.inputs_count;
Input *inputs = win_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 = P_GetWindowSize(window);
g->screen_size = SubVec2I32(g->window_settings.p1, g->window_settings.p0);
if (EqVec2I32(g->screen_size, VEC2I32(0, 0)))
{
g->screen_size = VEC2I32(1920, 1080);
}
//- Begin UI //- Begin UI
UI_BeginBuild(); UI_BeginBuild();
@ -630,12 +635,10 @@ void UpdateUser(P_Window *window)
} }
} }
//- Process sys events into user bind state //- Process inputs into user bind state
{ {
__profn("Process sys events"); __profn("Process inputs");
P_WindowEventArray events = P_PopWindowEvents(scratch.arena, window);
/* Reset bind pressed / released states */ /* Reset bind pressed / released states */
for (u32 i = 0; i < countof(g->bind_states); ++i) for (u32 i = 0; i < countof(g->bind_states); ++i)
@ -645,40 +648,40 @@ void UpdateUser(P_Window *window)
}; };
} }
for (u64 ent_index = 0; ent_index < events.count; ++ent_index) for (u64 idx = 0; idx < inputs_count; ++idx)
{ {
P_WindowEvent *event = &events.events[ent_index]; Input *input = &inputs[idx];
if (event->kind == P_WindowEventKind_Quit) if (input->kind == InputKind_Quit)
{ {
SignalExit(0); SignalExit(0);
} }
if (event->kind == P_WindowEventKind_ButtonUp) if (input->kind == InputKind_ButtonUp)
{ {
/* Escape quit */ /* Escape quit */
if (event->button == P_Btn_ESC) if (input->button == Btn_Esc)
{ {
SignalExit(0); SignalExit(0);
} }
} }
/* Update mouse pos */ /* Update mouse pos */
if (event->kind == P_WindowEventKind_CursorMove) if (input->kind == InputKind_CursorMove)
{ {
g->screen_cursor = event->cursor_position; g->screen_cursor = Vec2FromFields(input->cursor_pos);
} }
/* Update bind states */ /* Update bind states */
if ((event->kind == P_WindowEventKind_ButtonDown || event->kind == P_WindowEventKind_ButtonUp)) if ((input->kind == InputKind_ButtonDown || input->kind == InputKind_ButtonUp))
{ {
P_Btn button = event->button; Btn button = input->button;
button = button >= P_Btn_Count ? P_Btn_None : button; button = button >= Btn_Count ? Btn_None : button;
BindKind bind = g_binds[button]; BindKind bind = g_binds[button];
if (bind) if (bind)
{ {
b32 pressed = event->kind == P_WindowEventKind_ButtonDown; b32 pressed = input->kind == InputKind_ButtonDown;
#if 0 #if 0
b32 out_of_bounds = button >= P_Btn_M1 && button <= P_Btn_M5 && b32 out_of_bounds = button >= Btn_M1 && button <= Btn_M5 &&
(g->ui_cursor.x < 0 || (g->ui_cursor.x < 0 ||
g->ui_cursor.y < 0 || g->ui_cursor.y < 0 ||
g->ui_cursor.x > g->ui_size.x || g->ui_cursor.x > g->ui_size.x ||
@ -692,7 +695,7 @@ void UpdateUser(P_Window *window)
if (!out_of_bounds) if (!out_of_bounds)
{ {
++g->bind_states[bind].num_presses_and_repeats; ++g->bind_states[bind].num_presses_and_repeats;
if (event->is_repeat) if (input->is_repeat)
{ {
++g->bind_states[bind].num_repeats; ++g->bind_states[bind].num_repeats;
} }
@ -748,13 +751,11 @@ void UpdateUser(P_Window *window)
//- Update user state from binds //- Update user state from binds
/* Test fullscreen */ /* 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)
{ {
P_WindowSettings settings = P_GetWindowSettings(window); g->window_settings.flags ^= WND_Flag_Fullscreen;
settings.flags ^= P_WindowSettingsFlag_Fullscreen;
P_UpdateWindowSettings(window, &settings);
} }
} }
@ -765,7 +766,7 @@ void UpdateUser(P_Window *window)
if (g->bind_states[BindKind_DebugToggleTopmost].num_presses > 0) if (g->bind_states[BindKind_DebugToggleTopmost].num_presses > 0)
{ {
P_ToggleWindowTopmost(window); g->window_settings.flags ^= WND_Flag_ForcedTop;
P_LogSuccessF("Toggle topmost"); P_LogSuccessF("Toggle topmost");
} }
@ -2469,6 +2470,7 @@ void UpdateUser(P_Window *window)
/* Render UI */ /* Render UI */
GPU_Resource *ui_render = UI_EndBuild(ui_viewport); GPU_Resource *ui_render = UI_EndBuild(ui_viewport);
#if 0
////////////////////////////// //////////////////////////////
//- Present //- Present
@ -2476,6 +2478,24 @@ void UpdateUser(P_Window *window)
Vec2I32 backbuffer_dst = VEC2I32(RoundF32ToI32(backbuffer_dst_f.x), RoundF32ToI32(backbuffer_dst_f.y)); 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, 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); // 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;
{
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);
}
#endif
EndScratch(scratch); EndScratch(scratch);
} }
@ -2489,22 +2509,14 @@ JobDef(UpdateUserOrSleep, UNUSED sig, UNUSED id)
i64 time_ns = TimeNs(); i64 time_ns = TimeNs();
while (!Atomic32Fetch(&g->shutdown)) while (!Atomic32Fetch(&g->shutdown))
{ {
P_Window *window = g->window;
{
__profn("User sleep");
#if FPS_LIMIT > 0 #if FPS_LIMIT > 0
{ {
__profn("Frame limiter wait"); __profn("User frame limit");
P_SleepFrame(time_ns, 1000000000 / FPS_LIMIT); P_SleepFrame(time_ns, 1000000000 / FPS_LIMIT);
time_ns = TimeNs(); time_ns = TimeNs();
}
#endif
{
__profn("Swapchain wait");
GPU_YieldOnSwapchain(g->swapchain);
}
} }
UpdateUser(window); #endif
UpdateUser();
} }
} }

View File

@ -52,46 +52,46 @@ Enum(BindKind)
//- Test bindings //- Test bindings
/* TODO: Remove this */ /* TODO: Remove this */
Global Readonly BindKind g_binds[P_Btn_Count] = { Global Readonly BindKind g_binds[Btn_Count] = {
[P_Btn_W] = BindKind_MoveUp, [Btn_W] = BindKind_MoveUp,
[P_Btn_S] = BindKind_MoveDown, [Btn_S] = BindKind_MoveDown,
[P_Btn_A] = BindKind_MoveLeft, [Btn_A] = BindKind_MoveLeft,
[P_Btn_D] = BindKind_MoveRight, [Btn_D] = BindKind_MoveRight,
[P_Btn_M1] = BindKind_Fire, [Btn_M1] = BindKind_Fire,
[P_Btn_M2] = BindKind_AltFire, [Btn_M2] = BindKind_AltFire,
#if 0 #if 0
[P_Btn_Alt] = BindKind_Walk, [Btn_Alt] = BindKind_Walk,
#endif #endif
/* Testing */ /* Testing */
[P_Btn_Z] = BindKind_TestTile, [Btn_Z] = BindKind_TestTile,
[P_Btn_M5] = BindKind_DebugDrag, [Btn_M5] = BindKind_DebugDrag,
[P_Btn_M4] = BindKind_DebugDelete, [Btn_M4] = BindKind_DebugDelete,
[P_Btn_F] = BindKind_DebugExplode, [Btn_F] = BindKind_DebugExplode,
[P_Btn_T] = BindKind_DebugTeleport, [Btn_T] = BindKind_DebugTeleport,
[P_Btn_C] = BindKind_DebugClear, [Btn_C] = BindKind_DebugClear,
[P_Btn_1] = BindKind_DebugSpawn1, [Btn_1] = BindKind_DebugSpawn1,
[P_Btn_2] = BindKind_DebugSpawn2, [Btn_2] = BindKind_DebugSpawn2,
[P_Btn_3] = BindKind_DebugSpawn3, [Btn_3] = BindKind_DebugSpawn3,
[P_Btn_4] = BindKind_DebugSpawn4, [Btn_4] = BindKind_DebugSpawn4,
[P_Btn_G] = BindKind_DebugWalls, [Btn_G] = BindKind_DebugWalls,
[P_Btn_N] = BindKind_DebugStep, [Btn_N] = BindKind_DebugStep,
[P_Btn_Q] = BindKind_DebugFollow, [Btn_Q] = BindKind_DebugFollow,
[P_Btn_F1] = BindKind_DebugPause, [Btn_F1] = BindKind_DebugPause,
[P_Btn_F2] = BindKind_DebugCamera, [Btn_F2] = BindKind_DebugCamera,
[P_Btn_F3] = BindKind_DebugDraw, [Btn_F3] = BindKind_DebugDraw,
[P_Btn_F4] = BindKind_DebugToggleTopmost, [Btn_F4] = BindKind_DebugToggleTopmost,
[P_Btn_GraveAccent] = BindKind_DebugConsole, [Btn_GraveAccent] = BindKind_DebugConsole,
[P_Btn_Alt] = BindKind_FullscreenMod, [Btn_Alt] = BindKind_FullscreenMod,
[P_Btn_Enter] = BindKind_Fullscreen, [Btn_Enter] = BindKind_Fullscreen,
[P_Btn_MWheelUp] = BindKind_ZoomIn, [Btn_MWheelUp] = BindKind_ZoomIn,
[P_Btn_MWheelDown] = BindKind_ZoomOut, [Btn_MWheelDown] = BindKind_ZoomOut,
[P_Btn_M3] = BindKind_Pan, [Btn_M3] = BindKind_Pan,
#if RtcIsEnabled #if RtcIsEnabled
[P_Btn_ForwardSlash] = BindKind_ResetDebugSteps, [Btn_ForwardSlash] = BindKind_ResetDebugSteps,
[P_Btn_Comma] = BindKind_DecrementDebugSteps, [Btn_Comma] = BindKind_DecrementDebugSteps,
[P_Btn_Period] = BindKind_IncrementDebugSteps [Btn_Period] = BindKind_IncrementDebugSteps
#endif #endif
}; };
@ -153,8 +153,6 @@ Struct(BindState)
Struct(SharedUserState) Struct(SharedUserState)
{ {
Atomic32 shutdown; Atomic32 shutdown;
P_Window *window;
GPU_Swapchain *swapchain;
Fence shutdown_jobs_fence; Fence shutdown_jobs_fence;
u64 shutdown_jobs_count; u64 shutdown_jobs_count;
@ -242,6 +240,10 @@ Struct(SharedUserState)
//- Persist start //- Persist start
StructRegion(PERSIST_START); StructRegion(PERSIST_START);
//- Window
WND_Settings window_settings;
//- Debug camera //- Debug camera
EntityId debug_following; EntityId debug_following;
@ -319,7 +321,7 @@ MergesortCompareFuncDef(EntitySortCmp, arg_a, arg_b, _);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ User update //~ User update
void UpdateUser(P_Window *window); void UpdateUser(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ User update job //~ User update job

View File

@ -9,6 +9,8 @@
@Dep mixer @Dep mixer
@Dep rendertest @Dep rendertest
@Dep playback @Dep playback
@Dep platform
@Dep window
@Dep ui @Dep ui
//- Api //- Api

46
src/window/window.h Normal file
View File

@ -0,0 +1,46 @@
////////////////////////////////////////////////////////////
//~ Window types
Enum(WND_Flag)
{
WND_Flag_None = (0),
WND_Flag_Fullscreen = (1 << 0),
WND_Flag_ForcedTop = (1 << 1),
};
Struct(WND_Settings)
{
WND_Flag flags;
Vec2I32 p0;
Vec2I32 p1;
i32 vsync;
};
Struct(WND_Cmd)
{
WND_Settings settings;
GPU_Resource *texture;
Vec2I32 backbuffer_dst;
};
Struct(WND_Event)
{
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;
};
////////////////////////////////////////////////////////////
//~ @hookdecl Startup hooks
void WND_Startup(void);
////////////////////////////////////////////////////////////
//~ @hookdecl Window hooks
WND_Event WND_BeginUpdate(Arena *arena);
void WND_EndUpdate(WND_Cmd cmd);

12
src/window/window.lay Normal file
View File

@ -0,0 +1,12 @@
@Layer window
//- Dependencies
@Dep gpu
//- Api
@IncludeC window.h
//- Win32 impl
@DefaultWindowsImpl window_win32
@Startup WND_Startup

View File

@ -0,0 +1,480 @@
WND_W32_SharedState WND_W32_shared_state = ZI;
////////////////////////////////////////////////////////////
//~ @hookdef Startup
void WND_Startup(void)
{
WND_W32_SharedState *g = &WND_W32_shared_state;
//- Initialize btn table
{
ZeroArray(g->vk_to_btn);
for (u32 i = 'A', j = Btn_A; i <= 'Z'; ++i, ++j)
{
g->vk_to_btn[i] = (Btn)j;
}
for (u32 i = '0', j = Btn_0; i <= '9'; ++i, ++j)
{
g->vk_to_btn[i] = (Btn)j;
}
for (u32 i = VK_F1, j = Btn_F1; i <= VK_F24; ++i, ++j)
{
g->vk_to_btn[i] = (Btn)j;
}
g->vk_to_btn[VK_ESCAPE] = Btn_Esc;
g->vk_to_btn[VK_OEM_3] = Btn_GraveAccent;
g->vk_to_btn[VK_OEM_MINUS] = Btn_Minus;
g->vk_to_btn[VK_OEM_PLUS] = Btn_Equal;
g->vk_to_btn[VK_BACK] = Btn_Backspace;
g->vk_to_btn[VK_TAB] = Btn_Tab;
g->vk_to_btn[VK_SPACE] = Btn_Space;
g->vk_to_btn[VK_RETURN] = Btn_Enter;
g->vk_to_btn[VK_CONTROL] = Btn_Ctrl;
g->vk_to_btn[VK_SHIFT] = Btn_Shift;
g->vk_to_btn[VK_MENU] = Btn_Alt;
g->vk_to_btn[VK_UP] = Btn_Up;
g->vk_to_btn[VK_LEFT] = Btn_Left;
g->vk_to_btn[VK_DOWN] = Btn_Down;
g->vk_to_btn[VK_RIGHT] = Btn_Right;
g->vk_to_btn[VK_DELETE] = Btn_Delete;
g->vk_to_btn[VK_PRIOR] = Btn_PageUp;
g->vk_to_btn[VK_NEXT] = Btn_PageDown;
g->vk_to_btn[VK_HOME] = Btn_Home;
g->vk_to_btn[VK_END] = Btn_End;
g->vk_to_btn[VK_OEM_2] = Btn_ForwardSlash;
g->vk_to_btn[VK_OEM_PERIOD] = Btn_Period;
g->vk_to_btn[VK_OEM_COMMA] = Btn_Comma;
g->vk_to_btn[VK_OEM_7] = Btn_Quote;
g->vk_to_btn[VK_OEM_4] = Btn_LeftBracket;
g->vk_to_btn[VK_OEM_6] = Btn_RightBracket;
g->vk_to_btn[VK_INSERT] = Btn_Insert;
g->vk_to_btn[VK_OEM_1] = Btn_Semicolon;
}
//- Create window class
{
HMODULE instance = GetModuleHandle(0);
/* Register the window class */
WNDCLASSEXW *wc = &g->window_class;
wc->cbSize = sizeof(WNDCLASSEX);
wc->lpszClassName = WND_W32_WindowClassName;
wc->hCursor = LoadCursor(0, IDC_ARROW);
wc->style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
// wc->hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc->lpfnWndProc = WND_W32_WindowProc;
wc->hInstance = instance;
/* Use first icon resource as window icon (same as explorer) */
wchar_t path[4096] = ZI;
GetModuleFileNameW(instance, path, countof(path));
ExtractIconExW(path, 0, &wc->hIcon, &wc->hIconSm, 1);
if (!RegisterClassExW(wc))
{
Panic(Lit("Failed to register window class"));
}
}
//- Register raw mouse input
{
RAWINPUTDEVICE rid = ZI;
rid.usUsagePage = 0x01; /* HID_USAGE_PAGE_GENERIC */
rid.usUsage = 0x02; /* HID_USAGE_GENERIC_MOUSE */
RegisterRawInputDevices(&rid, 1, sizeof(rid));
}
//- Start message processing job
RunJob(WND_W32_ProcessMessagesForever, .pool = JobPool_Hyper, .flags = JobFlag_Dedicated);
}
////////////////////////////////////////////////////////////
//~ 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
/* Win32 limitation: Window must be initialized on same thread that processes events */
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));
//- Init hwnd
HWND hwnd = 0;
{
/*
* From martins (https://gist.github.com/mmozeiko/5e727f845db182d468a34d524508ad5f#file-win32_d3d11-c-L66-L70):
* WS_EX_NOREDIRECTIONBITMAP flag here is needed to fix ugly bug with Windows 10
* when window is resized and DXGI swap chain uses FLIP presentation model
* DO NOT use it if you choose to use non-FLIP presentation model
* read about the bug here: https://stackoverflow.com/q/63096226 and here: https://stackoverflow.com/q/53000291
*/
DWORD exstyle = WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP;
/* TODO: Check for hwnd success */
hwnd = CreateWindowExW(
exstyle,
g->window_class.lpszClassName,
L"",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
g->window_class.hInstance,
0
);
/* Dark mode */
BOOL dark_mode = 1;
DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&dark_mode, sizeof(dark_mode));
/* Set window as userdata */
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)window);
}
window->hwnd = hwnd;
//- Begin processing messages
Atomic32Set(&window->is_ready, 1);
for (;;)
{
// SetFocus(window->hwnd);
MSG msg = ZI;
GetMessageW(&msg, 0, 0, 0);
{
__profn("Process window message");
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
/* Destroy window */
DestroyWindow(window->hwnd);
}
////////////////////////////////////////////////////////////
//~ Message processing
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)
{
//- Default
default:
{
result = DefWindowProcW(hwnd, msg, wparam, lparam);
} break;
//- Quit
case WM_QUIT:
case WM_CLOSE:
case WM_DESTROY:
{
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:;
case WM_KEYUP:
case WM_KEYDOWN:
{
WORD vk_code = LOWORD(wparam);
Input input = ZI;
if (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN)
{
input.kind = InputKind_ButtonDown;
input.is_repeat = (lparam & 0x40000000) != 0;
}
else if (msg == WM_KEYUP || msg == WM_SYSKEYUP)
{
input.kind = InputKind_ButtonUp;
}
if (vk_code < countof(g->vk_to_btn))
{
input.button = g->vk_to_btn[vk_code];
}
WND_W32_PushInput(window, input);
if (msg == WM_SYSKEYUP || msg == WM_SYSKEYDOWN)
{
result = DefWindowProcW(hwnd, msg, wparam, lparam);
}
} break;
//- Text
case WM_SYSCHAR:
case WM_CHAR:
{
u32 codepoint = 0;
{
u16 utf16_char = (u32)wparam;
if (IsUtf16HighSurrogate(utf16_char))
{
window->previous_utf16_high_surrogate = utf16_char;
}
else if (IsUtf16LowSurrogate(utf16_char))
{
u16 high = window->previous_utf16_high_surrogate;
u16 low = utf16_char;
if (high)
{
u16 utf16_pair_bytes[2] = { high, low };
Utf16DecodeResult decoded = DecodeUtf16((String16) { .len = countof(utf16_pair_bytes), .text = utf16_pair_bytes });
if (decoded.advance16 == 2 && decoded.codepoint < U32Max)
{
codepoint = decoded.codepoint;
}
}
window->previous_utf16_high_surrogate = 0;
}
else
{
window->previous_utf16_high_surrogate = 0;
codepoint = utf16_char;
}
if (codepoint != 0)
{
if (codepoint == '\r')
{
codepoint = '\n'; /* Just treat all \r as newline */
}
}
}
if ((codepoint >= 32 && codepoint != 127) || codepoint == '\t' || codepoint == '\n')
{
Input input = ZI;
input.kind = InputKind_Text;
input.text_codepoint = codepoint;
WND_W32_PushInput(window, input);
}
} break;
//- Mouse buttons
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
case WM_XBUTTONUP:
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_XBUTTONDOWN:
{
Input input = ZI;
b32 is_down = msg == WM_LBUTTONDOWN ||
msg == WM_MBUTTONDOWN ||
msg == WM_RBUTTONDOWN ||
msg == WM_XBUTTONDOWN;
if (is_down)
{
input.kind = InputKind_ButtonDown;
SetCapture(hwnd);
}
else
{
input.kind = InputKind_ButtonUp;
ReleaseCapture();
}
switch (msg)
{
case WM_LBUTTONUP: case WM_LBUTTONDOWN: input.button = Btn_M1; break;
case WM_RBUTTONUP: case WM_RBUTTONDOWN: input.button = Btn_M2; break;
case WM_MBUTTONUP: case WM_MBUTTONDOWN: input.button = Btn_M3; break;
case WM_XBUTTONUP: case WM_XBUTTONDOWN:
{
u32 wparam_xbutton = GET_XBUTTON_WPARAM(wparam);
if (wparam_xbutton == XBUTTON1)
{
input.button = Btn_M4;
}
else if (wparam_xbutton == XBUTTON2)
{
input.button = Btn_M5;
}
} break;
}
if (input.button)
{
WND_W32_PushInput(window, input);
}
} break;
//- Mouse wheel
case WM_MOUSEWHEEL:
{
int delta = GET_WHEEL_DELTA_WPARAM(wparam);
i32 dir = delta >= 0 ? 1 : -1;
Btn btn = dir >= 0 ? Btn_MWheelUp : Btn_MWheelDown;
for (i32 i = 0; i < (dir * delta); i += WHEEL_DELTA)
{
/* Send a button down & button up event simultaneously */
WND_W32_PushInput(window, (Input) { .kind = InputKind_ButtonDown, .button = btn });
WND_W32_PushInput(window, (Input) { .kind = InputKind_ButtonUp, .button = btn });
}
} break;
//- Cursor move
case WM_MOUSEMOVE:
{
i32 x = GET_X_LPARAM(lparam);
i32 y = GET_Y_LPARAM(lparam);
Input input = ZI;
input.kind = InputKind_CursorMove;
input.cursor_pos = VEC2I32(x, y);
WND_W32_PushInput(window, input);
} break;
//- Raw mouse move
case WM_INPUT:
{
TempArena scratch = BeginScratchNoConflict();
{
/* Read raw input buffer */
UINT buff_size;
GetRawInputData((HRAWINPUT)lparam, RID_INPUT, 0, &buff_size, sizeof(RAWINPUTHEADER));
u8 *buff = PushStructs(scratch.arena, u8, buff_size);
if (GetRawInputData((HRAWINPUT)lparam, RID_INPUT, buff, &buff_size, sizeof(RAWINPUTHEADER)) != buff_size)
{
P_LogErrorF("GetRawInputData did not return correct size");
break;
}
RAWINPUT raw = ZI;
CopyBytes(&raw, buff, sizeof(RAWINPUT));
if (raw.header.dwType == RIM_TYPEMOUSE)
{
i32 x = raw.data.mouse.lLastX;
i32 y = raw.data.mouse.lLastY;
Input input = ZI;
input.kind = InputKind_MouseMove;
input.mouse_delta = VEC2I32(x, y);
WND_W32_PushInput(window, input);
}
}
EndScratch(scratch);
} break;
}
}
if (window->proc_depth == 1)
{
Unlock(&lock);
}
--window->proc_depth;
return result;
}
////////////////////////////////////////////////////////////
//~ @hookdef Update
WND_Event WND_BeginUpdate(Arena *arena)
{
WND_W32_SharedState *g = &WND_W32_shared_state;
WND_W32_Window *window = &g->window;
WND_Event result = ZI;
/* TODO: Yield on swapchain instead */
while (!Atomic32Fetch(&window->is_ready))
{
_mm_pause();
}
/* FIXME: Don't use TM */
Lock *lock = &window->user_update_lock;
*lock = LockE(&window->update_mutex);
/* 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);
}
UnlockTicketMutex(&window->inputs_tm);
/* FIXME: Remove this */
result.settings.p0 = window->previous_cmd.settings.p0;
result.settings.p1 = window->previous_cmd.settings.p1;
return result;
}
void WND_EndUpdate(WND_Cmd cmd)
{
WND_W32_SharedState *g = &WND_W32_shared_state;
WND_W32_Window *window = &g->window;
Unlock(&window->user_update_lock);
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);
}
/* Present */
/* TODO: Get fence */
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);
}
/* Show window */
if (!window->first_shown)
{
i32 show_cmd = SW_SHOWMAXIMIZED;
ShowWindow(window->hwnd, show_cmd);
SetForegroundWindow(window->hwnd);
BringWindowToTop(window->hwnd);
window->first_shown = 1;
}
window->previous_cmd = cmd;
}

View File

@ -0,0 +1,54 @@
////////////////////////////////////////////////////////////
//~ Window types
Struct(WND_W32_Window)
{
Atomic32 is_ready;
HWND hwnd;
GPU_D12_Swapchain *swapchain;
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;
u16 previous_utf16_high_surrogate;
};
////////////////////////////////////////////////////////////
//~ State types
#define WND_W32_WindowClassName L"pp_window_class"
Struct(WND_W32_SharedState)
{
Btn vk_to_btn[256];
WNDCLASSEXW window_class;
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
JobDecl(WND_W32_ProcessMessagesForever, EmptySig);
////////////////////////////////////////////////////////////
//~ Message processing
LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);

View File

@ -0,0 +1,10 @@
@Layer window_win32
//- Dependencies
@Dep gpu_dx12
//- Api
@IncludeC window_win32.h
//- Impl
@IncludeC window_win32.c