From 14477b1066cfd4d12ce044f98fea09507f320251 Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Fri, 6 Jun 2025 11:57:19 +0200 Subject: [PATCH] demos: Allow Vulkan to determine the swapchain image count. We currently always use 3. That's not a bad choice, but doesn't take the minImageCount/maxImageCount of the Vulkan implementation into account. --- demos/demo_d3d12.h | 7 +++++ demos/demo_vkd3d.h | 17 ++++++++--- demos/gears.c | 73 +++++++++++++++++++++++++--------------------- demos/triangle.c | 16 ++++++---- 4 files changed, 70 insertions(+), 43 deletions(-) diff --git a/demos/demo_d3d12.h b/demos/demo_d3d12.h index 792b2b05d..0b86ed2e2 100644 --- a/demos/demo_d3d12.h +++ b/demos/demo_d3d12.h @@ -70,6 +70,7 @@ static inline void demo_window_cleanup(struct demo_window *window) struct demo_swapchain { IDXGISwapChain3 *swapchain; + unsigned int buffer_count; }; static inline void demo_cleanup(struct demo *demo) @@ -162,6 +163,7 @@ static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *c if (FAILED(hr)) goto fail; + swapchain->buffer_count = desc->buffer_count; hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void **)&swapchain->swapchain); IDXGISwapChain1_Release(swapchain1); if (FAILED(hr)) @@ -190,6 +192,11 @@ static inline ID3D12Resource *demo_swapchain_get_back_buffer(struct demo_swapcha return buffer; } +static inline unsigned int demo_swapchain_get_back_buffer_count(struct demo_swapchain *swapchain) +{ + return swapchain->buffer_count; +} + static inline void demo_swapchain_present(struct demo_swapchain *swapchain) { IDXGISwapChain3_Present(swapchain->swapchain, 1, 0); diff --git a/demos/demo_vkd3d.h b/demos/demo_vkd3d.h index 7f4aa541d..d25275f16 100644 --- a/demos/demo_vkd3d.h +++ b/demos/demo_vkd3d.h @@ -392,9 +392,13 @@ static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *c if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device, vk_surface, &surface_caps) < 0) goto fail; - if ((surface_caps.maxImageCount && desc->buffer_count > surface_caps.maxImageCount) - || desc->buffer_count < surface_caps.minImageCount - || desc->width > surface_caps.maxImageExtent.width || desc->width < surface_caps.minImageExtent.width + image_count = desc->buffer_count; + if (image_count < surface_caps.minImageCount) + image_count = surface_caps.minImageCount; + else if (surface_caps.maxImageCount && image_count > surface_caps.maxImageCount) + image_count = surface_caps.maxImageCount; + + if (desc->width > surface_caps.maxImageExtent.width || desc->width < surface_caps.minImageExtent.width || desc->height > surface_caps.maxImageExtent.height || desc->height < surface_caps.minImageExtent.height || !(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) goto fail; @@ -432,7 +436,7 @@ static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *c vk_swapchain_desc.pNext = NULL; vk_swapchain_desc.flags = 0; vk_swapchain_desc.surface = vk_surface; - vk_swapchain_desc.minImageCount = desc->buffer_count; + vk_swapchain_desc.minImageCount = image_count; vk_swapchain_desc.imageFormat = format; vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; vk_swapchain_desc.imageExtent.width = desc->width; @@ -555,6 +559,11 @@ static inline ID3D12Resource *demo_swapchain_get_back_buffer(struct demo_swapcha return resource; } +static inline unsigned int demo_swapchain_get_back_buffer_count(struct demo_swapchain *swapchain) +{ + return swapchain->buffer_count; +} + static inline void demo_swapchain_present(struct demo_swapchain *swapchain) { VkPresentInfoKHR present_desc; diff --git a/demos/gears.c b/demos/gears.c index 310958db1..1ffe6fbbc 100644 --- a/demos/gears.c +++ b/demos/gears.c @@ -120,14 +120,17 @@ struct cx_gears ID3D12Device *device; ID3D12CommandQueue *command_queue; struct demo_swapchain *swapchain; + struct + { + ID3D12Resource *render_target; + ID3D12CommandAllocator *command_allocator; + ID3D12GraphicsCommandList *command_list; + } *swapchain_images; ID3D12DescriptorHeap *rtv_heap, *dsv_heap; unsigned int rtv_descriptor_size; - ID3D12Resource *render_targets[3]; - ID3D12CommandAllocator *command_allocator[3]; ID3D12RootSignature *root_signature; ID3D12PipelineState *pipeline_state_smooth, *pipeline_state_flat; - ID3D12GraphicsCommandList *command_list[3]; ID3D12Resource *ds, *cb, *vb[2], *ib; D3D12_VERTEX_BUFFER_VIEW vbv[2]; D3D12_INDEX_BUFFER_VIEW ibv; @@ -142,7 +145,7 @@ struct cx_gears static void cxg_populate_command_list(struct cx_gears *cxg, unsigned int rt_idx) { - ID3D12GraphicsCommandList *command_list = cxg->command_list[rt_idx]; + ID3D12GraphicsCommandList *command_list = cxg->swapchain_images[rt_idx].command_list; static const float clear_colour[] = {0.0f, 0.0f, 0.0f, 1.0f}; D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle, dsv_handle; @@ -150,10 +153,11 @@ static void cxg_populate_command_list(struct cx_gears *cxg, unsigned int rt_idx) HRESULT hr; size_t i; - hr = ID3D12CommandAllocator_Reset(cxg->command_allocator[rt_idx]); + hr = ID3D12CommandAllocator_Reset(cxg->swapchain_images[rt_idx].command_allocator); assert(SUCCEEDED(hr)); - hr = ID3D12GraphicsCommandList_Reset(command_list, cxg->command_allocator[rt_idx], cxg->pipeline_state_flat); + hr = ID3D12GraphicsCommandList_Reset(command_list, + cxg->swapchain_images[rt_idx].command_allocator, cxg->pipeline_state_flat); assert(SUCCEEDED(hr)); ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, cxg->root_signature); @@ -165,7 +169,7 @@ static void cxg_populate_command_list(struct cx_gears *cxg, unsigned int rt_idx) barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier.Transition.pResource = cxg->render_targets[rt_idx]; + barrier.Transition.pResource = cxg->swapchain_images[rt_idx].render_target; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; @@ -295,7 +299,7 @@ static void cxg_render_frame(struct cx_gears *cxg) demo_vec4_set(&cxg->instance_data[2].transform, cosf(a), sinf(a), -3.1f, 4.2f); ID3D12CommandQueue_ExecuteCommandLists(cxg->command_queue, 1, - (ID3D12CommandList **)&cxg->command_list[cxg->rt_idx]); + (ID3D12CommandList **)&cxg->swapchain_images[cxg->rt_idx].command_list); demo_swapchain_present(cxg->swapchain); cxg_wait_for_previous_frame(cxg); } @@ -304,16 +308,14 @@ static void cxg_destroy_pipeline(struct cx_gears *cxg) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(cxg->command_allocator); ++i) - { - ID3D12CommandAllocator_Release(cxg->command_allocator[i]); - } - for (i = 0; i < ARRAY_SIZE(cxg->render_targets); ++i) - { - ID3D12Resource_Release(cxg->render_targets[i]); - } ID3D12DescriptorHeap_Release(cxg->dsv_heap); ID3D12DescriptorHeap_Release(cxg->rtv_heap); + for (i = 0; i < demo_swapchain_get_back_buffer_count(cxg->swapchain); ++i) + { + ID3D12CommandAllocator_Release(cxg->swapchain_images[i].command_allocator); + ID3D12Resource_Release(cxg->swapchain_images[i].render_target); + } + free(cxg->swapchain_images); demo_swapchain_destroy(cxg->swapchain); ID3D12CommandQueue_Release(cxg->command_queue); ID3D12Device_Release(cxg->device); @@ -325,7 +327,7 @@ static void cxg_load_pipeline(struct cx_gears *cxg) D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle; D3D12_DESCRIPTOR_HEAP_DESC heap_desc; D3D12_COMMAND_QUEUE_DESC queue_desc; - unsigned int i; + unsigned int i, rt_count; HRESULT hr; hr = D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)&cxg->device); @@ -338,16 +340,19 @@ static void cxg_load_pipeline(struct cx_gears *cxg) &IID_ID3D12CommandQueue, (void **)&cxg->command_queue); assert(SUCCEEDED(hr)); - swapchain_desc.buffer_count = ARRAY_SIZE(cxg->render_targets); + swapchain_desc.buffer_count = 3; swapchain_desc.format = DXGI_FORMAT_B8G8R8A8_UNORM; swapchain_desc.width = cxg->width; swapchain_desc.height = cxg->height; cxg->swapchain = demo_swapchain_create(cxg->command_queue, cxg->window, &swapchain_desc); assert(cxg->swapchain); + rt_count = demo_swapchain_get_back_buffer_count(cxg->swapchain); + cxg->swapchain_images = calloc(rt_count, sizeof(*cxg->swapchain_images)); + assert(cxg->swapchain_images); cxg->rt_idx = demo_swapchain_get_current_back_buffer_index(cxg->swapchain); memset(&heap_desc, 0, sizeof(heap_desc)); - heap_desc.NumDescriptors = ARRAY_SIZE(cxg->render_targets); + heap_desc.NumDescriptors = rt_count; heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; hr = ID3D12Device_CreateDescriptorHeap(cxg->device, &heap_desc, @@ -357,10 +362,10 @@ static void cxg_load_pipeline(struct cx_gears *cxg) cxg->rtv_descriptor_size = ID3D12Device_GetDescriptorHandleIncrementSize(cxg->device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV); rtv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cxg->rtv_heap); - for (i = 0; i < ARRAY_SIZE(cxg->render_targets); ++i) + for (i = 0; i < rt_count; ++i) { - cxg->render_targets[i] = demo_swapchain_get_back_buffer(cxg->swapchain, i); - ID3D12Device_CreateRenderTargetView(cxg->device, cxg->render_targets[i], NULL, rtv_handle); + cxg->swapchain_images[i].render_target = demo_swapchain_get_back_buffer(cxg->swapchain, i); + ID3D12Device_CreateRenderTargetView(cxg->device, cxg->swapchain_images[i].render_target, NULL, rtv_handle); rtv_handle.ptr += cxg->rtv_descriptor_size; } @@ -371,10 +376,10 @@ static void cxg_load_pipeline(struct cx_gears *cxg) &IID_ID3D12DescriptorHeap, (void **)&cxg->dsv_heap); assert(SUCCEEDED(hr)); - for (i = 0; i < ARRAY_SIZE(cxg->command_allocator); ++i) + for (i = 0; i < rt_count; ++i) { hr = ID3D12Device_CreateCommandAllocator(cxg->device, D3D12_COMMAND_LIST_TYPE_DIRECT, - &IID_ID3D12CommandAllocator, (void **)&cxg->command_allocator[i]); + &IID_ID3D12CommandAllocator, (void **)&cxg->swapchain_images[i].command_allocator); assert(SUCCEEDED(hr)); } } @@ -397,8 +402,8 @@ static void cxg_destroy_assets(struct cx_gears *cxg) ID3D12Resource_Unmap(cxg->cb, 0, NULL); ID3D12Resource_Release(cxg->cb); ID3D12Resource_Release(cxg->ds); - for (i = 0; i < ARRAY_SIZE(cxg->command_list); ++i) - ID3D12GraphicsCommandList_Release(cxg->command_list[i]); + for (i = 0; i < demo_swapchain_get_back_buffer_count(cxg->swapchain); ++i) + ID3D12GraphicsCommandList_Release(cxg->swapchain_images[i].command_list); ID3D12PipelineState_Release(cxg->pipeline_state_smooth); ID3D12PipelineState_Release(cxg->pipeline_state_flat); ID3D12RootSignature_Release(cxg->root_signature); @@ -727,13 +732,13 @@ static void cxg_load_assets(struct cx_gears *cxg) ID3D10Blob_Release(ps_flat); ID3D10Blob_Release(ps_smooth); - for (i = 0; i < ARRAY_SIZE(cxg->command_list); ++i) + for (i = 0; i < demo_swapchain_get_back_buffer_count(cxg->swapchain); ++i) { hr = ID3D12Device_CreateCommandList(cxg->device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, - cxg->command_allocator[i], cxg->pipeline_state_flat, - &IID_ID3D12GraphicsCommandList, (void **)&cxg->command_list[i]); + cxg->swapchain_images[i].command_allocator, cxg->pipeline_state_flat, + &IID_ID3D12GraphicsCommandList, (void **)&cxg->swapchain_images[i].command_list); assert(SUCCEEDED(hr)); - hr = ID3D12GraphicsCommandList_Close(cxg->command_list[i]); + hr = ID3D12GraphicsCommandList_Close(cxg->swapchain_images[i].command_list); assert(SUCCEEDED(hr)); } @@ -850,6 +855,7 @@ static int cxg_main(void) unsigned int width = 300, height = 300; struct cx_gears cxg; double dpi_x, dpi_y; + size_t i; memset(&cxg, 0, sizeof(cxg)); if (!demo_init(&cxg.demo, &cxg)) @@ -880,9 +886,10 @@ static int cxg_main(void) cxg_load_pipeline(&cxg); cxg_load_assets(&cxg); - cxg_populate_command_list(&cxg, 0); - cxg_populate_command_list(&cxg, 1); - cxg_populate_command_list(&cxg, 2); + for (i = 0; i < demo_swapchain_get_back_buffer_count(cxg.swapchain); ++i) + { + cxg_populate_command_list(&cxg, i); + } demo_process_events(&cxg.demo); diff --git a/demos/triangle.c b/demos/triangle.c index bd106af5d..35ebc145c 100644 --- a/demos/triangle.c +++ b/demos/triangle.c @@ -72,7 +72,7 @@ struct cx_triangle struct demo_swapchain *swapchain; ID3D12DescriptorHeap *rtv_heap; unsigned int rtv_descriptor_size; - ID3D12Resource *render_targets[3]; + ID3D12Resource **render_targets; ID3D12CommandAllocator *command_allocator; ID3D12RootSignature *root_signature; @@ -164,10 +164,11 @@ static void cxt_destroy_pipeline(struct cx_triangle *cxt) unsigned int i; ID3D12CommandAllocator_Release(cxt->command_allocator); - for (i = 0; i < ARRAY_SIZE(cxt->render_targets); ++i) + for (i = 0; i < demo_swapchain_get_back_buffer_count(cxt->swapchain); ++i) { ID3D12Resource_Release(cxt->render_targets[i]); } + free(cxt->render_targets); ID3D12DescriptorHeap_Release(cxt->rtv_heap); demo_swapchain_destroy(cxt->swapchain); ID3D12CommandQueue_Release(cxt->command_queue); @@ -180,7 +181,7 @@ static void cxt_load_pipeline(struct cx_triangle *cxt) D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc; D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle; D3D12_COMMAND_QUEUE_DESC queue_desc; - unsigned int i; + unsigned int i, rt_count; HRESULT hr; hr = D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)&cxt->device); @@ -193,16 +194,19 @@ static void cxt_load_pipeline(struct cx_triangle *cxt) &IID_ID3D12CommandQueue, (void **)&cxt->command_queue); assert(SUCCEEDED(hr)); - swapchain_desc.buffer_count = ARRAY_SIZE(cxt->render_targets); + swapchain_desc.buffer_count = 3; swapchain_desc.format = DXGI_FORMAT_B8G8R8A8_UNORM; swapchain_desc.width = cxt->width; swapchain_desc.height = cxt->height; cxt->swapchain = demo_swapchain_create(cxt->command_queue, cxt->window, &swapchain_desc); assert(cxt->swapchain); + rt_count = demo_swapchain_get_back_buffer_count(cxt->swapchain); + cxt->render_targets = calloc(rt_count, sizeof(*cxt->render_targets)); + assert(cxt->render_targets); cxt->frame_idx = demo_swapchain_get_current_back_buffer_index(cxt->swapchain); memset(&rtv_heap_desc, 0, sizeof(rtv_heap_desc)); - rtv_heap_desc.NumDescriptors = ARRAY_SIZE(cxt->render_targets); + rtv_heap_desc.NumDescriptors = rt_count; rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; hr = ID3D12Device_CreateDescriptorHeap(cxt->device, &rtv_heap_desc, @@ -212,7 +216,7 @@ static void cxt_load_pipeline(struct cx_triangle *cxt) cxt->rtv_descriptor_size = ID3D12Device_GetDescriptorHandleIncrementSize(cxt->device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV); rtv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cxt->rtv_heap); - for (i = 0; i < ARRAY_SIZE(cxt->render_targets); ++i) + for (i = 0; i < rt_count; ++i) { cxt->render_targets[i] = demo_swapchain_get_back_buffer(cxt->swapchain, i); ID3D12Device_CreateRenderTargetView(cxt->device, cxt->render_targets[i], NULL, rtv_handle);