begin window layer
This commit is contained in:
parent
a6f31e4fae
commit
5f7de288ac
@ -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
149
src/base/base_input.h
Normal 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;
|
||||||
|
};
|
||||||
@ -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)
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
@ -1126,9 +907,9 @@ GPU_Resource *GPU_AcquireResource(GPU_ResourceDesc desc)
|
|||||||
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;
|
||||||
@ -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;
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
88
src/pp/pp.c
88
src/pp/pp.c
@ -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;
|
||||||
}
|
}
|
||||||
@ -752,9 +755,7 @@ void UpdateUser(P_Window *window)
|
|||||||
{
|
{
|
||||||
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
|
#endif
|
||||||
{
|
UpdateUser();
|
||||||
__profn("Swapchain wait");
|
|
||||||
GPU_YieldOnSwapchain(g->swapchain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UpdateUser(window);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
76
src/pp/pp.h
76
src/pp/pp.h
@ -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
|
||||||
|
|||||||
@ -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
46
src/window/window.h
Normal 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
12
src/window/window.lay
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
@Layer window
|
||||||
|
|
||||||
|
//- Dependencies
|
||||||
|
@Dep gpu
|
||||||
|
|
||||||
|
//- Api
|
||||||
|
@IncludeC window.h
|
||||||
|
|
||||||
|
//- Win32 impl
|
||||||
|
@DefaultWindowsImpl window_win32
|
||||||
|
|
||||||
|
@Startup WND_Startup
|
||||||
480
src/window/window_win32/window_win32.c
Normal file
480
src/window/window_win32/window_win32.c
Normal 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;
|
||||||
|
}
|
||||||
54
src/window/window_win32/window_win32.h
Normal file
54
src/window/window_win32/window_win32.h
Normal 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);
|
||||||
10
src/window/window_win32/window_win32.lay
Normal file
10
src/window/window_win32/window_win32.lay
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
@Layer window_win32
|
||||||
|
|
||||||
|
//- Dependencies
|
||||||
|
@Dep gpu_dx12
|
||||||
|
|
||||||
|
//- Api
|
||||||
|
@IncludeC window_win32.h
|
||||||
|
|
||||||
|
//- Impl
|
||||||
|
@IncludeC window_win32.c
|
||||||
Loading…
Reference in New Issue
Block a user