From 3084ea826966e7a282ac0343d12792cbdc9c3cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zef=20Kucia?= Date: Mon, 6 May 2019 11:46:01 +0200 Subject: [PATCH] dxgi: Make Vulkan swapchain image count independent of DXGI buffer count. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vulkan can create more swapchain images than requested. Signed-off-by: Józef Kucia Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard --- 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 54a5178f713..b4404e250b5 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);