new gpu resource blit testing

This commit is contained in:
jacob 2025-09-18 12:38:01 -05:00
parent 77affdd9b0
commit dfee727f56
6 changed files with 206 additions and 44 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -5,7 +5,7 @@ Struct(S_Texture)
{
b32 valid;
b32 loaded;
GPU_Resource *gpu_resource;
GPU_Resource *gpu_texture;
u32 width;
u32 height;
};