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.
This commit is contained in:
Henri Verbeet
2025-06-06 11:57:19 +02:00
parent cea7b4e920
commit 14477b1066
Notes: Henri Verbeet 2025-06-10 18:06:56 +02:00
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1556
4 changed files with 70 additions and 43 deletions

View File

@@ -70,6 +70,7 @@ static inline void demo_window_cleanup(struct demo_window *window)
struct demo_swapchain struct demo_swapchain
{ {
IDXGISwapChain3 *swapchain; IDXGISwapChain3 *swapchain;
unsigned int buffer_count;
}; };
static inline void demo_cleanup(struct demo *demo) 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)) if (FAILED(hr))
goto fail; goto fail;
swapchain->buffer_count = desc->buffer_count;
hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void **)&swapchain->swapchain); hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void **)&swapchain->swapchain);
IDXGISwapChain1_Release(swapchain1); IDXGISwapChain1_Release(swapchain1);
if (FAILED(hr)) if (FAILED(hr))
@@ -190,6 +192,11 @@ static inline ID3D12Resource *demo_swapchain_get_back_buffer(struct demo_swapcha
return buffer; 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) static inline void demo_swapchain_present(struct demo_swapchain *swapchain)
{ {
IDXGISwapChain3_Present(swapchain->swapchain, 1, 0); IDXGISwapChain3_Present(swapchain->swapchain, 1, 0);

View File

@@ -392,9 +392,13 @@ static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *c
if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device, vk_surface, &surface_caps) < 0) if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device, vk_surface, &surface_caps) < 0)
goto fail; goto fail;
if ((surface_caps.maxImageCount && desc->buffer_count > surface_caps.maxImageCount) image_count = desc->buffer_count;
|| desc->buffer_count < surface_caps.minImageCount if (image_count < surface_caps.minImageCount)
|| desc->width > surface_caps.maxImageExtent.width || desc->width < surface_caps.minImageExtent.width 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 || desc->height > surface_caps.maxImageExtent.height || desc->height < surface_caps.minImageExtent.height
|| !(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) || !(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR))
goto fail; goto fail;
@@ -432,7 +436,7 @@ static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *c
vk_swapchain_desc.pNext = NULL; vk_swapchain_desc.pNext = NULL;
vk_swapchain_desc.flags = 0; vk_swapchain_desc.flags = 0;
vk_swapchain_desc.surface = vk_surface; 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.imageFormat = format;
vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
vk_swapchain_desc.imageExtent.width = desc->width; vk_swapchain_desc.imageExtent.width = desc->width;
@@ -555,6 +559,11 @@ static inline ID3D12Resource *demo_swapchain_get_back_buffer(struct demo_swapcha
return resource; 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) static inline void demo_swapchain_present(struct demo_swapchain *swapchain)
{ {
VkPresentInfoKHR present_desc; VkPresentInfoKHR present_desc;

View File

@@ -120,14 +120,17 @@ struct cx_gears
ID3D12Device *device; ID3D12Device *device;
ID3D12CommandQueue *command_queue; ID3D12CommandQueue *command_queue;
struct demo_swapchain *swapchain; struct demo_swapchain *swapchain;
struct
{
ID3D12Resource *render_target;
ID3D12CommandAllocator *command_allocator;
ID3D12GraphicsCommandList *command_list;
} *swapchain_images;
ID3D12DescriptorHeap *rtv_heap, *dsv_heap; ID3D12DescriptorHeap *rtv_heap, *dsv_heap;
unsigned int rtv_descriptor_size; unsigned int rtv_descriptor_size;
ID3D12Resource *render_targets[3];
ID3D12CommandAllocator *command_allocator[3];
ID3D12RootSignature *root_signature; ID3D12RootSignature *root_signature;
ID3D12PipelineState *pipeline_state_smooth, *pipeline_state_flat; ID3D12PipelineState *pipeline_state_smooth, *pipeline_state_flat;
ID3D12GraphicsCommandList *command_list[3];
ID3D12Resource *ds, *cb, *vb[2], *ib; ID3D12Resource *ds, *cb, *vb[2], *ib;
D3D12_VERTEX_BUFFER_VIEW vbv[2]; D3D12_VERTEX_BUFFER_VIEW vbv[2];
D3D12_INDEX_BUFFER_VIEW ibv; 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) 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}; static const float clear_colour[] = {0.0f, 0.0f, 0.0f, 1.0f};
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle, dsv_handle; 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; HRESULT hr;
size_t i; size_t i;
hr = ID3D12CommandAllocator_Reset(cxg->command_allocator[rt_idx]); hr = ID3D12CommandAllocator_Reset(cxg->swapchain_images[rt_idx].command_allocator);
assert(SUCCEEDED(hr)); 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)); assert(SUCCEEDED(hr));
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, cxg->root_signature); 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.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 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.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; 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); demo_vec4_set(&cxg->instance_data[2].transform, cosf(a), sinf(a), -3.1f, 4.2f);
ID3D12CommandQueue_ExecuteCommandLists(cxg->command_queue, 1, 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); demo_swapchain_present(cxg->swapchain);
cxg_wait_for_previous_frame(cxg); cxg_wait_for_previous_frame(cxg);
} }
@@ -304,16 +308,14 @@ static void cxg_destroy_pipeline(struct cx_gears *cxg)
{ {
unsigned int i; 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->dsv_heap);
ID3D12DescriptorHeap_Release(cxg->rtv_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); demo_swapchain_destroy(cxg->swapchain);
ID3D12CommandQueue_Release(cxg->command_queue); ID3D12CommandQueue_Release(cxg->command_queue);
ID3D12Device_Release(cxg->device); ID3D12Device_Release(cxg->device);
@@ -325,7 +327,7 @@ static void cxg_load_pipeline(struct cx_gears *cxg)
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle; D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle;
D3D12_DESCRIPTOR_HEAP_DESC heap_desc; D3D12_DESCRIPTOR_HEAP_DESC heap_desc;
D3D12_COMMAND_QUEUE_DESC queue_desc; D3D12_COMMAND_QUEUE_DESC queue_desc;
unsigned int i; unsigned int i, rt_count;
HRESULT hr; HRESULT hr;
hr = D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)&cxg->device); 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); &IID_ID3D12CommandQueue, (void **)&cxg->command_queue);
assert(SUCCEEDED(hr)); 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.format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapchain_desc.width = cxg->width; swapchain_desc.width = cxg->width;
swapchain_desc.height = cxg->height; swapchain_desc.height = cxg->height;
cxg->swapchain = demo_swapchain_create(cxg->command_queue, cxg->window, &swapchain_desc); cxg->swapchain = demo_swapchain_create(cxg->command_queue, cxg->window, &swapchain_desc);
assert(cxg->swapchain); 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); cxg->rt_idx = demo_swapchain_get_current_back_buffer_index(cxg->swapchain);
memset(&heap_desc, 0, sizeof(heap_desc)); 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.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
hr = ID3D12Device_CreateDescriptorHeap(cxg->device, &heap_desc, 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, cxg->rtv_descriptor_size = ID3D12Device_GetDescriptorHandleIncrementSize(cxg->device,
D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
rtv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cxg->rtv_heap); 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); cxg->swapchain_images[i].render_target = demo_swapchain_get_back_buffer(cxg->swapchain, i);
ID3D12Device_CreateRenderTargetView(cxg->device, cxg->render_targets[i], NULL, rtv_handle); ID3D12Device_CreateRenderTargetView(cxg->device, cxg->swapchain_images[i].render_target, NULL, rtv_handle);
rtv_handle.ptr += cxg->rtv_descriptor_size; 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); &IID_ID3D12DescriptorHeap, (void **)&cxg->dsv_heap);
assert(SUCCEEDED(hr)); 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, 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)); assert(SUCCEEDED(hr));
} }
} }
@@ -397,8 +402,8 @@ static void cxg_destroy_assets(struct cx_gears *cxg)
ID3D12Resource_Unmap(cxg->cb, 0, NULL); ID3D12Resource_Unmap(cxg->cb, 0, NULL);
ID3D12Resource_Release(cxg->cb); ID3D12Resource_Release(cxg->cb);
ID3D12Resource_Release(cxg->ds); ID3D12Resource_Release(cxg->ds);
for (i = 0; i < ARRAY_SIZE(cxg->command_list); ++i) for (i = 0; i < demo_swapchain_get_back_buffer_count(cxg->swapchain); ++i)
ID3D12GraphicsCommandList_Release(cxg->command_list[i]); ID3D12GraphicsCommandList_Release(cxg->swapchain_images[i].command_list);
ID3D12PipelineState_Release(cxg->pipeline_state_smooth); ID3D12PipelineState_Release(cxg->pipeline_state_smooth);
ID3D12PipelineState_Release(cxg->pipeline_state_flat); ID3D12PipelineState_Release(cxg->pipeline_state_flat);
ID3D12RootSignature_Release(cxg->root_signature); 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_flat);
ID3D10Blob_Release(ps_smooth); 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, hr = ID3D12Device_CreateCommandList(cxg->device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
cxg->command_allocator[i], cxg->pipeline_state_flat, cxg->swapchain_images[i].command_allocator, cxg->pipeline_state_flat,
&IID_ID3D12GraphicsCommandList, (void **)&cxg->command_list[i]); &IID_ID3D12GraphicsCommandList, (void **)&cxg->swapchain_images[i].command_list);
assert(SUCCEEDED(hr)); assert(SUCCEEDED(hr));
hr = ID3D12GraphicsCommandList_Close(cxg->command_list[i]); hr = ID3D12GraphicsCommandList_Close(cxg->swapchain_images[i].command_list);
assert(SUCCEEDED(hr)); assert(SUCCEEDED(hr));
} }
@@ -850,6 +855,7 @@ static int cxg_main(void)
unsigned int width = 300, height = 300; unsigned int width = 300, height = 300;
struct cx_gears cxg; struct cx_gears cxg;
double dpi_x, dpi_y; double dpi_x, dpi_y;
size_t i;
memset(&cxg, 0, sizeof(cxg)); memset(&cxg, 0, sizeof(cxg));
if (!demo_init(&cxg.demo, &cxg)) if (!demo_init(&cxg.demo, &cxg))
@@ -880,9 +886,10 @@ static int cxg_main(void)
cxg_load_pipeline(&cxg); cxg_load_pipeline(&cxg);
cxg_load_assets(&cxg); cxg_load_assets(&cxg);
cxg_populate_command_list(&cxg, 0); for (i = 0; i < demo_swapchain_get_back_buffer_count(cxg.swapchain); ++i)
cxg_populate_command_list(&cxg, 1); {
cxg_populate_command_list(&cxg, 2); cxg_populate_command_list(&cxg, i);
}
demo_process_events(&cxg.demo); demo_process_events(&cxg.demo);

View File

@@ -72,7 +72,7 @@ struct cx_triangle
struct demo_swapchain *swapchain; struct demo_swapchain *swapchain;
ID3D12DescriptorHeap *rtv_heap; ID3D12DescriptorHeap *rtv_heap;
unsigned int rtv_descriptor_size; unsigned int rtv_descriptor_size;
ID3D12Resource *render_targets[3]; ID3D12Resource **render_targets;
ID3D12CommandAllocator *command_allocator; ID3D12CommandAllocator *command_allocator;
ID3D12RootSignature *root_signature; ID3D12RootSignature *root_signature;
@@ -164,10 +164,11 @@ static void cxt_destroy_pipeline(struct cx_triangle *cxt)
unsigned int i; unsigned int i;
ID3D12CommandAllocator_Release(cxt->command_allocator); 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]); ID3D12Resource_Release(cxt->render_targets[i]);
} }
free(cxt->render_targets);
ID3D12DescriptorHeap_Release(cxt->rtv_heap); ID3D12DescriptorHeap_Release(cxt->rtv_heap);
demo_swapchain_destroy(cxt->swapchain); demo_swapchain_destroy(cxt->swapchain);
ID3D12CommandQueue_Release(cxt->command_queue); 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_DESCRIPTOR_HEAP_DESC rtv_heap_desc;
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle; D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle;
D3D12_COMMAND_QUEUE_DESC queue_desc; D3D12_COMMAND_QUEUE_DESC queue_desc;
unsigned int i; unsigned int i, rt_count;
HRESULT hr; HRESULT hr;
hr = D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)&cxt->device); 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); &IID_ID3D12CommandQueue, (void **)&cxt->command_queue);
assert(SUCCEEDED(hr)); 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.format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapchain_desc.width = cxt->width; swapchain_desc.width = cxt->width;
swapchain_desc.height = cxt->height; swapchain_desc.height = cxt->height;
cxt->swapchain = demo_swapchain_create(cxt->command_queue, cxt->window, &swapchain_desc); cxt->swapchain = demo_swapchain_create(cxt->command_queue, cxt->window, &swapchain_desc);
assert(cxt->swapchain); 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); cxt->frame_idx = demo_swapchain_get_current_back_buffer_index(cxt->swapchain);
memset(&rtv_heap_desc, 0, sizeof(rtv_heap_desc)); 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.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
hr = ID3D12Device_CreateDescriptorHeap(cxt->device, &rtv_heap_desc, 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, cxt->rtv_descriptor_size = ID3D12Device_GetDescriptorHandleIncrementSize(cxt->device,
D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
rtv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cxt->rtv_heap); 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); cxt->render_targets[i] = demo_swapchain_get_back_buffer(cxt->swapchain, i);
ID3D12Device_CreateRenderTargetView(cxt->device, cxt->render_targets[i], NULL, rtv_handle); ID3D12Device_CreateRenderTargetView(cxt->device, cxt->render_targets[i], NULL, rtv_handle);