dxgi: Make Vulkan swapchain image count independent of DXGI buffer count.

Vulkan can create more swapchain images than requested.

Signed-off-by: Józef Kucia <jkucia@codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Józef Kucia 2019-05-06 11:46:01 +02:00 committed by Alexandre Julliard
parent 2002585000
commit 3084ea8269
1 changed files with 60 additions and 51 deletions

View File

@ -952,6 +952,7 @@ struct dxgi_vk_funcs
PFN_vkDestroyImage p_vkDestroyImage;
PFN_vkDestroySemaphore p_vkDestroySemaphore;
PFN_vkDestroySurfaceKHR p_vkDestroySurfaceKHR;
PFN_vkResetCommandBuffer p_vkResetCommandBuffer;
PFN_vkDestroySwapchainKHR p_vkDestroySwapchainKHR;
PFN_vkEndCommandBuffer p_vkEndCommandBuffer;
PFN_vkFreeMemory p_vkFreeMemory;
@ -1003,6 +1004,7 @@ struct d3d12_swapchain
VkDeviceMemory vk_memory;
VkCommandPool vk_cmd_pool;
VkImage vk_images[DXGI_MAX_SWAP_CHAIN_BUFFERS];
VkImage vk_swapchain_images[DXGI_MAX_SWAP_CHAIN_BUFFERS];
VkCommandBuffer vk_cmd_buffers[DXGI_MAX_SWAP_CHAIN_BUFFERS];
VkSemaphore vk_semaphores[DXGI_MAX_SWAP_CHAIN_BUFFERS];
ID3D12Resource *buffers[DXGI_MAX_SWAP_CHAIN_BUFFERS];
@ -1011,7 +1013,8 @@ struct d3d12_swapchain
unsigned int vk_swapchain_height;
VkPresentModeKHR present_mode;
uint32_t current_buffer_index;
uint32_t vk_image_index;
unsigned int current_buffer_index;
struct dxgi_vk_funcs vk_funcs;
ID3D12CommandQueue *command_queue;
@ -1226,7 +1229,7 @@ static HRESULT d3d12_swapchain_create_user_buffers(struct d3d12_swapchain *swapc
image_info.pQueueFamilyIndices = NULL;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
for (i = 0; i < swapchain->buffer_count; ++i)
for (i = 0; i < swapchain->desc.BufferCount; ++i)
{
if ((vr = vk_funcs->p_vkCreateImage(vk_device, &image_info, NULL, &swapchain->vk_images[i])) < 0)
{
@ -1238,7 +1241,7 @@ static HRESULT d3d12_swapchain_create_user_buffers(struct d3d12_swapchain *swapc
memory_size = 0;
memory_type_mask = ~0u;
for (i = 0; i < swapchain->buffer_count; ++i)
for (i = 0; i < swapchain->desc.BufferCount; ++i)
{
vk_funcs->p_vkGetImageMemoryRequirements(vk_device, swapchain->vk_images[i], &requirements);
@ -1269,7 +1272,7 @@ static HRESULT d3d12_swapchain_create_user_buffers(struct d3d12_swapchain *swapc
return hresult_from_vk_result(vr);
}
for (i = 0; i < swapchain->buffer_count; ++i)
for (i = 0; i < swapchain->desc.BufferCount; ++i)
{
if ((vr = vk_funcs->p_vkBindImageMemory(vk_device, swapchain->vk_images[i],
swapchain->vk_memory, image_offset[i])) < 0)
@ -1374,7 +1377,7 @@ static VkResult d3d12_swapchain_record_swapchain_blit(struct d3d12_swapchain *sw
}
static HRESULT d3d12_swapchain_prepare_command_buffers(struct d3d12_swapchain *swapchain,
uint32_t queue_family_index, VkImage vk_swapchain_images[DXGI_MAX_SWAP_CHAIN_BUFFERS])
uint32_t queue_family_index)
{
const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
VkDevice vk_device = swapchain->vk_device;
@ -1386,7 +1389,7 @@ static HRESULT d3d12_swapchain_prepare_command_buffers(struct d3d12_swapchain *s
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_info.pNext = NULL;
pool_info.flags = 0;
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
pool_info.queueFamilyIndex = queue_family_index;
if ((vr = vk_funcs->p_vkCreateCommandPool(vk_device, &pool_info,
@ -1410,15 +1413,6 @@ static HRESULT d3d12_swapchain_prepare_command_buffers(struct d3d12_swapchain *s
return hresult_from_vk_result(vr);
}
for (i = 0; i < swapchain->buffer_count; ++i)
{
VkCommandBuffer vk_cmd_buffer = swapchain->vk_cmd_buffers[i];
if ((vr = d3d12_swapchain_record_swapchain_blit(swapchain, vk_cmd_buffer,
vk_swapchain_images[i], swapchain->vk_images[i])) < 0)
return hresult_from_vk_result(vr);
}
for (i = 0; i < swapchain->buffer_count; ++i)
{
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
@ -1441,7 +1435,6 @@ static HRESULT d3d12_swapchain_create_buffers(struct d3d12_swapchain *swapchain,
VkFormat vk_swapchain_format, VkFormat vk_format)
{
const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
VkImage vk_swapchain_images[DXGI_MAX_SWAP_CHAIN_BUFFERS];
struct vkd3d_image_resource_create_info resource_info;
VkSwapchainKHR vk_swapchain = swapchain->vk_swapchain;
ID3D12CommandQueue *queue = swapchain->command_queue;
@ -1458,13 +1451,14 @@ static HRESULT d3d12_swapchain_create_buffers(struct d3d12_swapchain *swapchain,
WARN("Failed to get Vulkan swapchain images, vr %d.\n", vr);
return hresult_from_vk_result(vr);
}
if (image_count != swapchain->desc.BufferCount)
FIXME("Got %u swapchain images, expected %u.\n", image_count, swapchain->desc.BufferCount);
if (image_count > ARRAY_SIZE(vk_swapchain_images))
if (image_count > ARRAY_SIZE(swapchain->vk_swapchain_images))
{
FIXME("Unsupported Vulkan swapchain image count %u.\n", image_count);
return E_FAIL;
}
swapchain->buffer_count = image_count;
if ((vr = vk_funcs->p_vkGetSwapchainImagesKHR(vk_device, vk_swapchain,
&image_count, vk_swapchain_images)) < 0)
&image_count, swapchain->vk_swapchain_images)) < 0)
{
WARN("Failed to get Vulkan swapchain images, vr %d.\n", vr);
return hresult_from_vk_result(vr);
@ -1492,6 +1486,11 @@ static HRESULT d3d12_swapchain_create_buffers(struct d3d12_swapchain *swapchain,
FIXME("Swapchain blit not implemented for command queue type %#x.\n", queue_desc.Type);
if (vk_swapchain_format != vk_format)
return E_NOTIMPL;
if (image_count != swapchain->desc.BufferCount)
{
FIXME("Got %u swapchain images, expected %u.\n", image_count, swapchain->desc.BufferCount);
return E_NOTIMPL;
}
}
queue_family_index = vkd3d_get_vk_queue_family_index(queue);
@ -1502,15 +1501,14 @@ static HRESULT d3d12_swapchain_create_buffers(struct d3d12_swapchain *swapchain,
if (FAILED(hr = d3d12_swapchain_create_user_buffers(swapchain, vk_format)))
return hr;
if (FAILED(hr = d3d12_swapchain_prepare_command_buffers(swapchain,
queue_family_index, vk_swapchain_images)))
if (FAILED(hr = d3d12_swapchain_prepare_command_buffers(swapchain, queue_family_index)))
return hr;
}
if (swapchain->buffers[0])
return S_OK;
for (i = 0; i < swapchain->buffer_count; ++i)
for (i = 0; i < swapchain->desc.BufferCount; ++i)
{
if (swapchain->vk_images[i])
{
@ -1519,7 +1517,7 @@ static HRESULT d3d12_swapchain_create_buffers(struct d3d12_swapchain *swapchain,
}
else
{
resource_info.vk_image = vk_swapchain_images[i];
resource_info.vk_image = swapchain->vk_swapchain_images[i];
resource_info.present_state = D3D12_RESOURCE_STATE_PRESENT;
}
@ -1544,12 +1542,15 @@ static VkResult d3d12_swapchain_acquire_next_image(struct d3d12_swapchain *swapc
VkResult vr;
if ((vr = vk_funcs->p_vkAcquireNextImageKHR(vk_device, swapchain->vk_swapchain, UINT64_MAX,
VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer_index)) < 0)
VK_NULL_HANDLE, vk_fence, &swapchain->vk_image_index)) < 0)
{
WARN("Failed to acquire next Vulkan image, vr %d.\n", vr);
return vr;
}
if (!d3d12_swapchain_has_user_images(swapchain))
swapchain->current_buffer_index = swapchain->vk_image_index;
if ((vr = vk_funcs->p_vkWaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX)) != VK_SUCCESS)
{
ERR("Failed to wait for fence, vr %d.\n", vr);
@ -1581,28 +1582,27 @@ static void d3d12_swapchain_destroy_buffers(struct d3d12_swapchain *swapchain, B
}
}
for (i = 0; i < swapchain->buffer_count; ++i)
for (i = 0; i < swapchain->desc.BufferCount; ++i)
{
if (swapchain->buffers[i] && (destroy_user_buffers || !d3d12_swapchain_has_user_images(swapchain)))
{
vkd3d_resource_decref(swapchain->buffers[i]);
swapchain->buffers[i] = NULL;
}
if (swapchain->vk_device)
if (swapchain->vk_device && destroy_user_buffers)
{
if (destroy_user_buffers)
{
vk_funcs->p_vkDestroyImage(swapchain->vk_device, swapchain->vk_images[i], NULL);
swapchain->vk_images[i] = VK_NULL_HANDLE;
}
vk_funcs->p_vkDestroySemaphore(swapchain->vk_device, swapchain->vk_semaphores[i], NULL);
swapchain->vk_semaphores[i] = VK_NULL_HANDLE;
vk_funcs->p_vkDestroyImage(swapchain->vk_device, swapchain->vk_images[i], NULL);
swapchain->vk_images[i] = VK_NULL_HANDLE;
}
}
if (swapchain->vk_device)
{
for (i = 0; i < swapchain->buffer_count; ++i)
{
vk_funcs->p_vkDestroySemaphore(swapchain->vk_device, swapchain->vk_semaphores[i], NULL);
swapchain->vk_semaphores[i] = VK_NULL_HANDLE;
}
if (destroy_user_buffers)
{
vk_funcs->p_vkFreeMemory(swapchain->vk_device, swapchain->vk_memory, NULL);
@ -1893,16 +1893,6 @@ static HRESULT d3d12_swapchain_set_sync_interval(struct d3d12_swapchain *swapcha
if (swapchain->present_mode == present_mode)
return S_OK;
/*
* We recreate the swapchain only when the current buffer index is 0, in order to preserve the
* expected back buffer index sequence.
*/
if (swapchain->current_buffer_index)
{
WARN("Skipping sync interval change, current buffer index %u.\n", swapchain->current_buffer_index);
return S_OK;
}
if (!d3d12_swapchain_has_user_images(swapchain))
{
FIXME("Cannot recreate swapchain without user images.\n");
@ -1933,21 +1923,35 @@ static VkResult d3d12_swapchain_queue_present(struct d3d12_swapchain *swapchain,
present_info.pWaitSemaphores = NULL;
present_info.swapchainCount = 1;
present_info.pSwapchains = &swapchain->vk_swapchain;
present_info.pImageIndices = &swapchain->current_buffer_index;
present_info.pImageIndices = &swapchain->vk_image_index;
present_info.pResults = NULL;
if (d3d12_swapchain_has_user_images(swapchain))
{
/* blit */
VkCommandBuffer vk_cmd_buffer = swapchain->vk_cmd_buffers[swapchain->vk_image_index];
VkImage vk_dst_image = swapchain->vk_swapchain_images[swapchain->vk_image_index];
VkImage vk_src_image = swapchain->vk_images[swapchain->current_buffer_index];
if ((vr = vk_funcs->p_vkResetCommandBuffer(vk_cmd_buffer, 0)) < 0)
{
ERR("Failed to reset command buffer, vr %d.\n", vr);
return vr;
}
if ((vr = d3d12_swapchain_record_swapchain_blit(swapchain,
vk_cmd_buffer, vk_dst_image, vk_src_image)) < 0 )
return vr;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = NULL;
submit_info.waitSemaphoreCount = 0;
submit_info.pWaitSemaphores = NULL;
submit_info.pWaitDstStageMask = NULL;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &swapchain->vk_cmd_buffers[swapchain->current_buffer_index];
submit_info.pCommandBuffers = &vk_cmd_buffer;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &swapchain->vk_semaphores[swapchain->current_buffer_index];
submit_info.pSignalSemaphores = &swapchain->vk_semaphores[swapchain->vk_image_index];
if ((vr = vk_funcs->p_vkQueueSubmit(vk_queue, 1, &submit_info, VK_NULL_HANDLE)) < 0)
{
@ -1956,7 +1960,7 @@ static VkResult d3d12_swapchain_queue_present(struct d3d12_swapchain *swapchain,
}
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = &swapchain->vk_semaphores[swapchain->current_buffer_index];
present_info.pWaitSemaphores = &swapchain->vk_semaphores[swapchain->vk_image_index];
}
return vk_funcs->p_vkQueuePresentKHR(vk_queue, &present_info);
@ -2027,6 +2031,8 @@ static HRESULT d3d12_swapchain_present(struct d3d12_swapchain *swapchain,
return hresult_from_vk_result(vr);
}
swapchain->current_buffer_index = (swapchain->current_buffer_index + 1) % swapchain->desc.BufferCount;
vr = d3d12_swapchain_acquire_next_image(swapchain);
if (vr == VK_ERROR_OUT_OF_DATE_KHR)
{
@ -2063,7 +2069,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetBuffer(IDXGISwapChain3 *ifac
TRACE("iface %p, buffer_idx %u, iid %s, surface %p.\n",
iface, buffer_idx, debugstr_guid(iid), surface);
if (buffer_idx >= swapchain->buffer_count)
if (buffer_idx >= swapchain->desc.BufferCount)
{
WARN("Invalid buffer index %u.\n", buffer_idx);
return DXGI_ERROR_INVALID_CALL;
@ -2133,7 +2139,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_ResizeBuffers(IDXGISwapChain3 *
if (flags)
FIXME("Ignoring flags %#x.\n", flags);
for (i = 0; i < swapchain->buffer_count; ++i)
for (i = 0; i < swapchain->desc.BufferCount; ++i)
{
ID3D12Resource_AddRef(swapchain->buffers[i]);
if ((refcount = ID3D12Resource_Release(swapchain->buffers[i])))
@ -2416,6 +2422,7 @@ static UINT STDMETHODCALLTYPE d3d12_swapchain_GetCurrentBackBufferIndex(IDXGISwa
TRACE("iface %p.\n", iface);
TRACE("Current back buffer index %u.\n", swapchain->current_buffer_index);
return swapchain->current_buffer_index;
}
@ -2603,6 +2610,7 @@ static BOOL init_vk_funcs(struct dxgi_vk_funcs *dxgi, VkInstance vk_instance, Vk
LOAD_DEVICE_PFN(vkDestroySwapchainKHR)
LOAD_DEVICE_PFN(vkEndCommandBuffer)
LOAD_DEVICE_PFN(vkFreeMemory)
LOAD_DEVICE_PFN(vkResetCommandBuffer)
LOAD_DEVICE_PFN(vkGetImageMemoryRequirements)
LOAD_DEVICE_PFN(vkGetSwapchainImagesKHR)
LOAD_DEVICE_PFN(vkQueuePresentKHR)
@ -2730,6 +2738,7 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGI
}
swapchain->vk_fence = vk_fence;
swapchain->current_buffer_index = 0;
if ((vr = d3d12_swapchain_acquire_next_image(swapchain)) < 0)
{
ERR("Failed to acquire Vulkan image, vr %d.\n", vr);