dxgi: Acquire Vulkan image just before present when we have user images.

The current DXGI back buffer index is independent of the current Vulkan
image index when we have user images. We can use this fact to delay
calling vkAcquireNextImageKHR().

This increases GPU utilization from 84% to 100% in the main menu of
Metro Exouds on Nvidia.

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:03 +02:00 committed by Alexandre Julliard
parent 711e68c9b8
commit 086f263a9e
1 changed files with 45 additions and 15 deletions

View File

@ -989,6 +989,8 @@ static HRESULT hresult_from_vk_result(VkResult vr)
}
}
#define INVALID_VK_IMAGE_INDEX (~(uint32_t)0)
struct d3d12_swapchain
{
IDXGISwapChain3 IDXGISwapChain3_iface;
@ -1538,13 +1540,15 @@ static HRESULT d3d12_swapchain_create_buffers(struct d3d12_swapchain *swapchain,
return S_OK;
}
static VkResult d3d12_swapchain_acquire_next_image(struct d3d12_swapchain *swapchain)
static VkResult d3d12_swapchain_acquire_next_vulkan_image(struct d3d12_swapchain *swapchain)
{
const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
VkDevice vk_device = swapchain->vk_device;
VkFence vk_fence = swapchain->vk_fence;
VkResult vr;
swapchain->vk_image_index = INVALID_VK_IMAGE_INDEX;
if ((vr = vk_funcs->p_vkAcquireNextImageKHR(vk_device, swapchain->vk_swapchain, UINT64_MAX,
VK_NULL_HANDLE, vk_fence, &swapchain->vk_image_index)) < 0)
{
@ -1552,9 +1556,6 @@ static VkResult d3d12_swapchain_acquire_next_image(struct d3d12_swapchain *swapc
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);
@ -1566,6 +1567,23 @@ static VkResult d3d12_swapchain_acquire_next_image(struct d3d12_swapchain *swapc
return vr;
}
static VkResult d3d12_swapchain_acquire_next_back_buffer(struct d3d12_swapchain *swapchain)
{
VkResult vr;
/* If we don't have user images, we need to acquire a Vulkan image in order
* to get the correct value for the current back buffer index. */
if (d3d12_swapchain_has_user_images(swapchain))
return VK_SUCCESS;
if ((vr = d3d12_swapchain_acquire_next_vulkan_image(swapchain)) >= 0)
swapchain->current_buffer_index = swapchain->vk_image_index;
else
ERR("Failed to acquire Vulkan image, vr %d.\n", vr);
return vr;
}
static void d3d12_swapchain_destroy_buffers(struct d3d12_swapchain *swapchain, BOOL destroy_user_buffers)
{
const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
@ -1717,6 +1735,8 @@ static HRESULT d3d12_swapchain_create_vulkan_swapchain(struct d3d12_swapchain *s
swapchain->vk_swapchain_width = width;
swapchain->vk_swapchain_height = height;
swapchain->vk_image_index = INVALID_VK_IMAGE_INDEX;
return d3d12_swapchain_create_buffers(swapchain, vk_swapchain_format, vk_format);
}
@ -1725,16 +1745,17 @@ static HRESULT d3d12_swapchain_recreate_vulkan_swapchain(struct d3d12_swapchain
VkResult vr;
HRESULT hr;
if (FAILED(hr = d3d12_swapchain_create_vulkan_swapchain(swapchain)))
if (SUCCEEDED(hr = d3d12_swapchain_create_vulkan_swapchain(swapchain)))
{
vr = d3d12_swapchain_acquire_next_back_buffer(swapchain);
hr = hresult_from_vk_result(vr);
}
else
{
ERR("Failed to recreate Vulkan swapchain, hr %#x.\n", hr);
return hr;
}
if ((vr = d3d12_swapchain_acquire_next_image(swapchain)) < 0)
ERR("Failed to acquire Vulkan image after recreating swapchain, vr %d.\n", vr);
return hresult_from_vk_result(vr);
return hr;
}
static inline struct d3d12_swapchain *d3d12_swapchain_from_IDXGISwapChain3(IDXGISwapChain3 *iface)
@ -1921,6 +1942,14 @@ static VkResult d3d12_swapchain_queue_present(struct d3d12_swapchain *swapchain,
VkSubmitInfo submit_info;
VkResult vr;
if (swapchain->vk_image_index == INVALID_VK_IMAGE_INDEX)
{
if ((vr = d3d12_swapchain_acquire_next_vulkan_image(swapchain)) < 0)
return vr;
}
assert(swapchain->vk_image_index < swapchain->buffer_count);
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.pNext = NULL;
present_info.waitSemaphoreCount = 0;
@ -1967,7 +1996,10 @@ static VkResult d3d12_swapchain_queue_present(struct d3d12_swapchain *swapchain,
present_info.pWaitSemaphores = &swapchain->vk_semaphores[swapchain->vk_image_index];
}
return vk_funcs->p_vkQueuePresentKHR(vk_queue, &present_info);
if ((vr = vk_funcs->p_vkQueuePresentKHR(vk_queue, &present_info)) >= 0)
swapchain->vk_image_index = INVALID_VK_IMAGE_INDEX;
return vr;
}
static HRESULT d3d12_swapchain_present(struct d3d12_swapchain *swapchain,
@ -2036,8 +2068,7 @@ static HRESULT d3d12_swapchain_present(struct d3d12_swapchain *swapchain,
}
swapchain->current_buffer_index = (swapchain->current_buffer_index + 1) % swapchain->desc.BufferCount;
vr = d3d12_swapchain_acquire_next_image(swapchain);
vr = d3d12_swapchain_acquire_next_back_buffer(swapchain);
if (vr == VK_ERROR_OUT_OF_DATE_KHR)
{
if (!d3d12_swapchain_has_user_images(swapchain))
@ -2745,9 +2776,8 @@ 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)
if ((vr = d3d12_swapchain_acquire_next_back_buffer(swapchain)) < 0)
{
ERR("Failed to acquire Vulkan image, vr %d.\n", vr);
d3d12_swapchain_destroy(swapchain);
return hresult_from_vk_result(vr);
}