diff --git a/src/gpu/gpu.h b/src/gpu/gpu.h index f231c13b..88de629d 100644 --- a/src/gpu/gpu.h +++ b/src/gpu/gpu.h @@ -295,7 +295,7 @@ Vec2I32 GPU_GetTextureSize(GPU_Resource *resource); //~ @hookdecl Command list operations GPU_CommandList *GPU_BeginCommandList(GPU_QueueKind queue_kind); -u64 GPU_EndCommandList(GPU_CommandList *cl); /* Returns the value that the queue's fence will be set to once the command is completed */ +i64 GPU_EndCommandList(GPU_CommandList *cl); /* Returns the value that the queue's fence will be set to once the command is completed */ //////////////////////////////// //~ @hookdecl Profiling helpers @@ -350,9 +350,9 @@ void GPU_CopyResource(GPU_CommandList *cl, GPU_Resource *dst, GPU_Resource *src) //~ @hookdecl Map operations GPU_Mapped GPU_Map(GPU_Resource *r); -void GPU_Unmap(GPU_Mapped *mapped); +void GPU_Unmap(GPU_Mapped mapped); -void GPU_CopyToMapped(GPU_Mapped *mapped, String data); +void GPU_CopyToMapped(GPU_Mapped mapped, String data); //////////////////////////////// //~ @hookdecl Memory info operations @@ -369,7 +369,8 @@ void GPU_ReleaseSwapchain(GPU_Swapchain *swapchain); * This should be called before rendering for minimum latency. */ void GPU_YieldOnSwapchain(GPU_Swapchain *swapchain); -/* 1. Clears the backbuffer and ensures it's at size `backbuffer_resolution` - * 2. Blits `texture` to the backbuffer using `texture_xf` - * 3. Presents the backbuffer */ -void GPU_PresentSwapchain(GPU_Swapchain *swapchain, Vec2I32 backbuffer_resolution, GPU_Resource *texture, Xform texture_xf, i32 vsync); +/* 1. Ensures the backbuffer matches the size of `texture` + * 2. Blits `texture` to 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, i32 vsync); diff --git a/src/gpu/gpu_dx12/gpu_dx12.c b/src/gpu/gpu_dx12/gpu_dx12.c index a80ca6de..9054cc76 100644 --- a/src/gpu/gpu_dx12/gpu_dx12.c +++ b/src/gpu/gpu_dx12/gpu_dx12.c @@ -540,11 +540,85 @@ GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, V return &swapchain->buffers[backbuffer_index]; } -void GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *dst, GPU_D12_Resource *texture_resource, Xform texture_xf) +i64 GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *dst, GPU_D12_Resource *texture) { #if 1 GPU_D12_SharedState *g = &GPU_D12_shared_state; + 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 COPY_DEST */ + { + D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++]; + D3D12_RESOURCE_TRANSITION_BARRIER rtb = ZI; + rtb.pResource = dst->d3d_resource; + rtb.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + rtb.StateBefore = D3D12_RESOURCE_STATE_PRESENT; + rtb.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; + rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + rb->Transition = rtb; + } + /* Transition texture to COPY_SRC */ + if (texture->state != D3D12_RESOURCE_STATE_COPY_SOURCE) + { + D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++]; + D3D12_RESOURCE_TRANSITION_BARRIER rtb = ZI; + rtb.pResource = texture->d3d_resource; + rtb.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + rtb.StateBefore = texture->state; + rtb.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; + rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + rb->Transition = rtb; + texture->state = rtb.StateAfter; + } + ID3D12GraphicsCommandList_ResourceBarrier(rcl, barriers_count, rbs); + } + + // Copy (entire resource or a region) + ID3D12GraphicsCommandList_CopyResource(rcl, dst->d3d_resource, texture->d3d_resource); + + { + u32 barriers_count = 0; + D3D12_RESOURCE_BARRIER rbs[2] = ZI; + /* Transition backbuffer to PRESENT */ + { + D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++]; + D3D12_RESOURCE_TRANSITION_BARRIER rtb = ZI; + rtb.pResource = dst->d3d_resource; + rtb.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + rtb.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + rtb.StateAfter = D3D12_RESOURCE_STATE_PRESENT; + rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + rb->Transition = rtb; + } + /* Transition texture to original state */ + if (texture->state != old_texture_state) + { + D3D12_RESOURCE_BARRIER *rb = &rbs[barriers_count++]; + D3D12_RESOURCE_TRANSITION_BARRIER rtb = ZI; + rtb.pResource = texture->d3d_resource; + rtb.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + rtb.StateBefore = texture->state; + rtb.StateAfter = old_texture_state; + rb->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + rb->Transition = rtb; + texture->state = rtb.StateAfter; + } + ID3D12GraphicsCommandList_ResourceBarrier(rcl, barriers_count, rbs); + } + + i64 fence_target = GPU_D12_EndRawCommandList(dx12_cl); + return fence_target; + + + + + #else GPU_D12_SharedState *g = &GPU_D12_shared_state; @@ -805,8 +879,8 @@ GPU_Resource *GPU_AcquireResource(GPU_ResourceDesc desc) d3d_desc.SampleDesc.Quality = 0; d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS * !!(desc.flags & GPU_ResourceFlag_AllowUav); d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET * !!(desc.flags & GPU_ResourceFlag_AllowRtv); - D3D12_RESOURCE_STATES initial_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, initial_state, 0, &IID_ID3D12Resource, (void **)&r->d3d_resource); + 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); if (FAILED(hr)) { /* TODO: Don't panic */ @@ -841,10 +915,10 @@ GPU_Resource *GPU_AcquireResource(GPU_ResourceDesc desc) d3d_desc.SampleDesc.Quality = 0; d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS * !!(desc.flags & GPU_ResourceFlag_AllowUav); d3d_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET * !!(desc.flags & GPU_ResourceFlag_AllowRtv); - D3D12_RESOURCE_STATES initial_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_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, initial_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)) { /* TODO: Don't panic */ @@ -919,8 +993,9 @@ GPU_CommandList *GPU_BeginCommandList(GPU_QueueKind queue_kind) return (GPU_CommandList *)cl; } -u64 GPU_EndCommandList(GPU_CommandList *gpu_cl) +i64 GPU_EndCommandList(GPU_CommandList *gpu_cl) { + GPU_D12_SharedState *g = &GPU_D12_shared_state; GPU_D12_FiberState *f = GPU_D12_FiberStateFromId(FiberId()); GPU_D12_CommandList *cl = (GPU_D12_CommandList *)gpu_cl; GPU_QueueKind queue_kind = cl->queue_kind; @@ -954,6 +1029,33 @@ u64 GPU_EndCommandList(GPU_CommandList *gpu_cl) /* TODO */ } break; + //- Copy resource + case GPU_D12_CommandKind_Copy: + { + GPU_D12_Resource *dst = cmd->copy.dst; + GPU_D12_Resource *src = cmd->copy.src; + // ID3D12GraphicsCommandList_CopyResource(rcl, dst->d3d_resource, src->d3d_resource); + + D3D12_RESOURCE_DESC dst_desc = ZI; + ID3D12Resource_GetDesc(dst->d3d_resource, &dst_desc); + + D3D12_PLACED_SUBRESOURCE_FOOTPRINT dst_placed_footprint = ZI; + ID3D12Device_GetCopyableFootprints(g->device, &dst_desc, 0, 1, 0, &dst_placed_footprint, 0, 0, 0); + + 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 = src->d3d_resource; + src_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + src_loc.PlacedFootprint = dst_placed_footprint; + + ID3D12GraphicsCommandList_CopyTextureRegion(rcl, &dst_loc, 0, 0, 0, &src_loc, 0); + + } break; + //- Dispatch Vs/Ps shader case GPU_D12_CommandKind_Rasterize: { @@ -1217,7 +1319,7 @@ void GPU_CopyResource(GPU_CommandList *gpu_cl, GPU_Resource *gpu_dst, GPU_Resour GPU_D12_Command *cmd = GPU_D12_PushCmd(cl); cmd->kind = GPU_D12_CommandKind_Copy; cmd->copy.dst = dst; - cmd->copy.src_resource = src; + cmd->copy.src = src; } //////////////////////////////// @@ -1238,16 +1340,16 @@ GPU_Mapped GPU_Map(GPU_Resource *gpu_r) return result; } -void GPU_Unmap(GPU_Mapped *m) +void GPU_Unmap(GPU_Mapped m) { - GPU_D12_Resource *r = (GPU_D12_Resource *)m->resource; + GPU_D12_Resource *r = (GPU_D12_Resource *)m.resource; ID3D12Resource_Unmap(r->d3d_resource, 0, 0); } -void GPU_CopyToMapped(GPU_Mapped *mapped, String data) +void GPU_CopyToMapped(GPU_Mapped mapped, String data) { GPU_D12_SharedState *g = &GPU_D12_shared_state; - GPU_D12_Resource *r = (GPU_D12_Resource *)mapped->resource; + GPU_D12_Resource *r = (GPU_D12_Resource *)mapped.resource; D3D12_RESOURCE_DESC desc = ZI; ID3D12Resource_GetDesc(r->d3d_resource, &desc); @@ -1261,7 +1363,7 @@ void GPU_CopyToMapped(GPU_Mapped *mapped, String data) { D3D12_RANGE read_range = ZI; - u8 *dst_base = (u8 *)mapped->mem + placed_footprint.Offset; + u8 *dst_base = (u8 *)mapped.mem + placed_footprint.Offset; u8 *src_base = data.text; u32 z_size = upload_row_size * upload_num_rows; @@ -1385,28 +1487,48 @@ void GPU_YieldOnSwapchain(GPU_Swapchain *swapchain) /* TODO */ } -void GPU_PresentSwapchain(GPU_Swapchain *gpu_swapchain, Vec2I32 backbuffer_resolution, GPU_Resource *texture, Xform texture_xf, i32 vsync) +i64 GPU_PresentSwapchain(GPU_Swapchain *gpu_swapchain, GPU_Resource *gpu_texture, i32 vsync) { GPU_D12_Swapchain *swapchain = (GPU_D12_Swapchain *)gpu_swapchain; - GPU_D12_SwapchainBuffer *swapchain_buffer = GPU_D12_UpdateSwapchain(swapchain, backbuffer_resolution); - GPU_D12_Resource *texture_resource = (GPU_D12_Resource *)texture; + GPU_D12_Resource *texture = (GPU_D12_Resource *)gpu_texture; + GPU_D12_SwapchainBuffer *swapchain_buffer = GPU_D12_UpdateSwapchain(swapchain, VEC2I32(texture->desc.texture.size.x, texture->desc.texture.size.y)); - /* Blit */ - GPU_D12_BlitToSwapchain(swapchain_buffer, texture_resource, texture_xf); + D3D12_RESOURCE_DESC src_desc = ZI; + D3D12_RESOURCE_DESC dst_desc = ZI; + ID3D12Resource_GetDesc(texture->d3d_resource, &src_desc); + ID3D12Resource_GetDesc(swapchain_buffer->d3d_resource, &dst_desc); - u32 present_flags = 0; - if (GPU_D12_TearingIsAllowed && vsync == 0) + b32 is_blitable = src_desc.Dimension == dst_desc.Dimension + && src_desc.Format == dst_desc.Format + && src_desc.SampleDesc.Count == dst_desc.SampleDesc.Count + && src_desc.SampleDesc.Quality == dst_desc.SampleDesc.Quality + && src_desc.Width == dst_desc.Width + && src_desc.Height == dst_desc.Height + && src_desc.DepthOrArraySize == dst_desc.DepthOrArraySize; + Assert(is_blitable == 1); /* Texture resource must be similar enough to backbuffer resource to blit */ + + i64 fence_target = 0; + if (is_blitable) { - present_flags |= DXGI_PRESENT_ALLOW_TEARING; - } + /* Blit */ + fence_target = GPU_D12_BlitToSwapchain(swapchain_buffer, texture); - /* Present */ - { - __profn("Present"); - HRESULT hr = IDXGISwapChain3_Present(swapchain->swapchain, vsync, present_flags); - if (!SUCCEEDED(hr)) + u32 present_flags = 0; + if (GPU_D12_TearingIsAllowed && vsync == 0) { - Assert(0); + present_flags |= DXGI_PRESENT_ALLOW_TEARING; + } + + /* Present */ + { + __profn("Present"); + HRESULT hr = IDXGISwapChain3_Present(swapchain->swapchain, vsync, present_flags); + if (!SUCCEEDED(hr)) + { + Assert(0); + } } } + + return fence_target; } diff --git a/src/gpu/gpu_dx12/gpu_dx12.h b/src/gpu/gpu_dx12/gpu_dx12.h index 9298fb7c..dd20d834 100644 --- a/src/gpu/gpu_dx12/gpu_dx12.h +++ b/src/gpu/gpu_dx12/gpu_dx12.h @@ -48,6 +48,7 @@ Struct(GPU_D12_Resource) GPU_ResourceDesc desc; ID3D12Resource *d3d_resource; + D3D12_RESOURCE_STATES state; u64 reuse_hash; D3D12_GPU_VIRTUAL_ADDRESS buffer_gpu_address; @@ -159,7 +160,7 @@ Struct(GPU_D12_Command) struct { GPU_D12_Resource *dst; - GPU_D12_Resource *src_resource; + GPU_D12_Resource *src; String src_string; } copy; struct @@ -312,7 +313,7 @@ u64 GPU_D12_EndRawCommandList(GPU_D12_RawCommandList *cl); void GPU_D12_InitSwapchainResources(GPU_D12_Swapchain *swapchain); GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, Vec2I32 resolution); -void GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *swapchain_buffer, GPU_D12_Resource *texture_resource, Xform texture_xf); +i64 GPU_D12_BlitToSwapchain(GPU_D12_SwapchainBuffer *swapchain_buffer, GPU_D12_Resource *texture); //////////////////////////////// //~ Sync job diff --git a/src/pp/pp.c b/src/pp/pp.c index a151947d..dbf36e67 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -417,8 +417,8 @@ GPU_Resource *AcquireUploadBuffer_(void *src, u32 element_size, u32 element_coun { __profn("Copy to transfer buffer"); GPU_Mapped m = GPU_Map(r); - GPU_CopyToMapped(&m, STRING(element_size * element_count, src)); - GPU_Unmap(&m); + GPU_CopyToMapped(m, STRING(element_size * element_count, src)); + GPU_Unmap(m); } return r; } @@ -2469,7 +2469,14 @@ void UpdateUser(P_Window *window) g->grids_count = 0; } - GPU_PresentSwapchain(g->swapchain, g->ui_size, g->ui_target, g->ui_to_screen_xf, 1); + /* FIXME: Enable this */ +#if 0 + g->gpu_render_fence_target = GPU_PresentSwapchain(g->swapchain, g->ui_target, 1); +#else + Resource test_sprite = ResourceFromStore(&GameResources, Lit("sprite/tim.ase")); + S_Texture *test = S_TextureFromResource(test_sprite); + g->gpu_render_fence_target = GPU_PresentSwapchain(g->swapchain, test->gpu_texture, 1); +#endif } EndScratch(scratch); diff --git a/src/sprite/sprite.c b/src/sprite/sprite.c index b723fdb3..63740f14 100644 --- a/src/sprite/sprite.c +++ b/src/sprite/sprite.c @@ -25,15 +25,46 @@ JobDef(S_LoadTexture, sig, _) GPU_ResourceDesc desc = ZI; desc.kind = GPU_ResourceKind_Texture2D; desc.flags = GPU_ResourceFlag_None; - desc.texture.format = GPU_Format_R8G8B8A8_Unorm_Srgb; + + /* FIXME: Use srgb format */ + desc.texture.format = GPU_Format_R8G8B8A8_Unorm; + // desc.texture.format = GPU_Format_R8G8B8A8_Unorm_Srgb; + desc.texture.size = VEC3I32(decoded.width, decoded.height, 1); desc.texture.mip_levels = 1; - texture->gpu_resource = GPU_AcquireResource(desc); + texture->gpu_texture = GPU_AcquireResource(desc); texture->width = decoded.width; texture->height = decoded.height; - /* FIXME: Upload to resource here */ - } + /* Fill upload buffer */ + u32 upload_size = desc.texture.size.x * desc.texture.size.y * sizeof(*decoded.pixels); + GPU_ResourceDesc upload_desc = ZI; + upload_desc.kind = GPU_ResourceKind_Buffer; + upload_desc.buffer.heap_kind = GPU_HeapKind_Upload; + upload_desc.buffer.size = upload_size; + GPU_Resource *upload = GPU_AcquireResource(upload_desc); + { + GPU_Mapped mapped = GPU_Map(upload); + GPU_CopyToMapped(mapped, STRING(upload_size, (u8 *)decoded.pixels)); + GPU_Unmap(mapped); + } + + /* Upload to GPU resource */ + GPU_QueueKind queue = GPU_QueueKind_BackgroundCopy; + Fence *queue_fence = GPU_FenceFromQueue(queue); + i64 queue_fence_target = 0; + { + GPU_CommandList *cl = GPU_BeginCommandList(queue); + { + GPU_CopyResource(cl, texture->gpu_texture, upload); + } + queue_fence_target = GPU_EndCommandList(cl); + } + + /* Release upload buffer after copy finishes */ + YieldOnFence(queue_fence, queue_fence_target); + GPU_ReleaseResource(upload, GPU_ReleaseFlag_None); + } texture->loaded = 1; SetFence(&entry->texture_ready_fence, 1); diff --git a/src/sprite/sprite.h b/src/sprite/sprite.h index 2dffb9a4..7e690e86 100644 --- a/src/sprite/sprite.h +++ b/src/sprite/sprite.h @@ -5,7 +5,7 @@ Struct(S_Texture) { b32 valid; b32 loaded; - GPU_Resource *gpu_resource; + GPU_Resource *gpu_texture; u32 width; u32 height; };