Merge branch 'frame_latency_1' into 'master'

dxgi: Fix some d3d12 swapchain issues.

See merge request wine/wine!5830
This commit is contained in:
Conor McCarthy 2024-11-19 22:25:51 +00:00
commit 6033e3ab6e

View file

@ -1170,6 +1170,7 @@ struct d3d12_swapchain
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];
VkFence vk_buffer_fences[DXGI_MAX_SWAP_CHAIN_BUFFERS];
unsigned int vk_swapchain_width;
unsigned int vk_swapchain_height;
VkPresentModeKHR present_mode;
@ -1214,7 +1215,8 @@ struct d3d12_swapchain_op
{
unsigned int sync_interval;
VkImage vk_image;
unsigned int frame_number;
uint64_t frame_number;
unsigned int buffer_index;
} present;
struct
{
@ -2020,6 +2022,18 @@ static ULONG STDMETHODCALLTYPE d3d12_swapchain_AddRef(IDXGISwapChain4 *iface)
return refcount;
}
static void d3d12_swapchain_destroy_buffer_fences(struct d3d12_swapchain *swapchain)
{
const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
size_t i;
for (i = 0; i < ARRAY_SIZE(swapchain->vk_buffer_fences); ++i)
{
vk_funcs->p_vkDestroyFence(swapchain->vk_device, swapchain->vk_buffer_fences[i], NULL);
swapchain->vk_buffer_fences[i] = VK_NULL_HANDLE;
}
}
static void d3d12_swapchain_destroy(struct d3d12_swapchain *swapchain)
{
const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
@ -2068,6 +2082,7 @@ static void d3d12_swapchain_destroy(struct d3d12_swapchain *swapchain)
if (swapchain->vk_device)
{
vk_funcs->p_vkDestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL);
d3d12_swapchain_destroy_buffer_fences(swapchain);
vk_funcs->p_vkDestroySwapchainKHR(swapchain->vk_device, swapchain->vk_swapchain, NULL);
}
@ -2193,7 +2208,7 @@ static HRESULT d3d12_swapchain_set_sync_interval(struct d3d12_swapchain *swapcha
}
static VkResult d3d12_swapchain_queue_present(struct d3d12_swapchain *swapchain, VkImage vk_src_image,
uint64_t frame_number)
uint64_t frame_number, unsigned int buffer_index)
{
const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
VkPresentInfoKHR present_info;
@ -2243,7 +2258,7 @@ static VkResult d3d12_swapchain_queue_present(struct d3d12_swapchain *swapchain,
submit_info.signalSemaphoreCount = 1;
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)
if ((vr = vk_funcs->p_vkQueueSubmit(vk_queue, 1, &submit_info, swapchain->vk_buffer_fences[buffer_index])) < 0)
{
ERR("Failed to blit swapchain buffer, vr %d.\n", vr);
vkd3d_release_vk_queue(swapchain->command_queue);
@ -2275,7 +2290,8 @@ static HRESULT d3d12_swapchain_op_present_execute(struct d3d12_swapchain *swapch
if (FAILED(hr = d3d12_swapchain_set_sync_interval(swapchain, op->present.sync_interval)))
return hr;
vr = d3d12_swapchain_queue_present(swapchain, op->present.vk_image, op->present.frame_number);
vr = d3d12_swapchain_queue_present(swapchain, op->present.vk_image, op->present.frame_number,
op->present.buffer_index);
if (vr == VK_ERROR_OUT_OF_DATE_KHR)
{
TRACE("Recreating Vulkan swapchain.\n");
@ -2284,7 +2300,8 @@ static HRESULT d3d12_swapchain_op_present_execute(struct d3d12_swapchain *swapch
if (FAILED(hr = d3d12_swapchain_create_vulkan_resources(swapchain)))
return hr;
if ((vr = d3d12_swapchain_queue_present(swapchain, op->present.vk_image, op->present.frame_number)) < 0)
if ((vr = d3d12_swapchain_queue_present(swapchain, op->present.vk_image, op->present.frame_number,
op->present.buffer_index)) < 0)
ERR("Failed to present after recreating swapchain, vr %d.\n", vr);
}
@ -2314,8 +2331,12 @@ static HRESULT d3d12_swapchain_op_present_execute(struct d3d12_swapchain *swapch
static HRESULT d3d12_swapchain_present(struct d3d12_swapchain *swapchain,
unsigned int sync_interval, unsigned int flags)
{
const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
VkDevice vk_device = swapchain->vk_device;
struct d3d12_swapchain_op *op;
HANDLE frame_latency_event;
VkFence vk_fence;
VkResult vr;
HRESULT hr;
if (sync_interval > 4)
@ -2338,15 +2359,29 @@ static HRESULT d3d12_swapchain_present(struct d3d12_swapchain *swapchain,
return E_OUTOFMEMORY;
}
if (!(vk_fence = swapchain->vk_buffer_fences[swapchain->current_buffer_index]))
{
VkFenceCreateInfo fence_desc;
fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_desc.pNext = NULL;
fence_desc.flags = 0;
if ((vr = vk_funcs->p_vkCreateFence(vk_device, &fence_desc, NULL, &vk_fence)) < 0)
ERR("Failed to create Vulkan fence, vr %d.\n", vr);
else
swapchain->vk_buffer_fences[swapchain->current_buffer_index] = vk_fence;
}
op->type = D3D12_SWAPCHAIN_OP_PRESENT;
op->present.sync_interval = sync_interval;
op->present.buffer_index = swapchain->current_buffer_index;
op->present.vk_image = swapchain->vk_images[swapchain->current_buffer_index];
op->present.frame_number = swapchain->frame_number;
EnterCriticalSection(&swapchain->worker_cs);
list_add_tail(&swapchain->worker_ops, &op->entry);
WakeAllConditionVariable(&swapchain->worker_cv);
LeaveCriticalSection(&swapchain->worker_cs);
WakeAllConditionVariable(&swapchain->worker_cv);
++swapchain->frame_number;
if ((frame_latency_event = swapchain->frame_latency_event))
@ -2371,6 +2406,18 @@ static HRESULT d3d12_swapchain_present(struct d3d12_swapchain *swapchain,
}
swapchain->current_buffer_index = (swapchain->current_buffer_index + 1) % swapchain->desc.BufferCount;
/* Prevent the client from overwriting the new current buffer before a pending blit is done.
* After Present() returns, it is expected the client will render to the next buffer in sequence,
* so Present() is the last place where it is possible to wait for a pending read from that buffer. */
if ((vk_fence = swapchain->vk_buffer_fences[swapchain->current_buffer_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);
if ((vr = vk_funcs->p_vkResetFences(vk_device, 1, &vk_fence)) < 0)
ERR("Failed to reset fence, vr %d.\n", vr);
}
return S_OK;
}
@ -2611,6 +2658,7 @@ static HRESULT d3d12_swapchain_resize_buffers(struct d3d12_swapchain *swapchain,
if (desc->Width == new_desc.Width && desc->Height == new_desc.Height
&& desc->Format == new_desc.Format && desc->BufferCount == new_desc.BufferCount)
{
d3d12_swapchain_destroy_buffer_fences(swapchain);
swapchain->current_buffer_index = 0;
return S_OK;
}
@ -2630,9 +2678,10 @@ static HRESULT d3d12_swapchain_resize_buffers(struct d3d12_swapchain *swapchain,
EnterCriticalSection(&swapchain->worker_cs);
list_add_tail(&swapchain->worker_ops, &op->entry);
WakeAllConditionVariable(&swapchain->worker_cv);
LeaveCriticalSection(&swapchain->worker_cs);
WakeAllConditionVariable(&swapchain->worker_cv);
d3d12_swapchain_destroy_buffer_fences(swapchain);
swapchain->current_buffer_index = 0;
d3d12_swapchain_destroy_d3d12_resources(swapchain);