[PATCH 2/4] dxgi: Make Vulkan swapchain image count independent of DXGI buffer count.

Józef Kucia jkucia at codeweavers.com
Mon May 6 04:46:01 CDT 2019


Vulkan can create more swapchain images than requested.

Signed-off-by: Józef Kucia <jkucia at codeweavers.com>
---
 dlls/dxgi/swapchain.c | 111 +++++++++++++++++++++++-------------------
 1 file changed, 60 insertions(+), 51 deletions(-)

diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index 54a5178f7136..b4404e250b53 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -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);
-- 
2.21.0




More information about the wine-devel mailing list