vkd3d: Handle frame latency without WAITABLE_OBJECT

Documentation says that this should always be 3 without WAITABLE_OBJECT
unlike in D3D11 where it will use the DXGI device's frame latency.

This stops runaway presentations in the non-blocking acquire image case
with the new semaphore setup.

Signed-off-by: Joshua Ashton <joshua@froggi.es>
This commit is contained in:
Joshua Ashton 2021-06-01 21:11:11 +01:00 committed by Hans-Kristian Arntzen
parent 582138b063
commit c33cfd048b
1 changed files with 49 additions and 27 deletions

View File

@ -1757,7 +1757,6 @@ static VkResult d3d12_swapchain_queue_present(struct d3d12_swapchain *swapchain,
static HRESULT d3d12_swapchain_present(struct d3d12_swapchain *swapchain,
unsigned int sync_interval, unsigned int flags)
{
HANDLE frame_latency_event;
VkQueue vk_queue;
VkResult vr;
HRESULT hr;
@ -1819,24 +1818,42 @@ static HRESULT d3d12_swapchain_present(struct d3d12_swapchain *swapchain,
return hresult_from_vk_result(vr);
}
if ((frame_latency_event = swapchain->frame_latency_event))
++swapchain->frame_number;
if (FAILED(hr = ID3D12CommandQueue_Signal(d3d12_swapchain_queue_iface(swapchain),
swapchain->frame_latency_fence, swapchain->frame_number)))
{
++swapchain->frame_number;
if (FAILED(hr = ID3D12CommandQueue_Signal(d3d12_swapchain_queue_iface(swapchain),
swapchain->frame_latency_fence, swapchain->frame_number)))
{
ERR("Failed to signal frame latency fence, hr %#x.\n", hr);
return hr;
}
ERR("Failed to signal frame latency fence, hr %#x.\n", hr);
return hr;
}
if (swapchain->desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)
{
if (FAILED(hr = ID3D12Fence_SetEventOnCompletion(swapchain->frame_latency_fence,
swapchain->frame_number - swapchain->frame_latency, frame_latency_event)))
swapchain->frame_number - swapchain->frame_latency, swapchain->frame_latency_event)))
{
ERR("Failed to enqueue frame latency event, hr %#x.\n", hr);
return hr;
}
}
else
{
const uint32_t sync_latency = min(swapchain->frame_latency, swapchain->desc.BufferCount + 1);
const uint64_t frame_target = swapchain->frame_number - sync_latency;
if (ID3D12Fence_GetCompletedValue(swapchain->frame_latency_fence) < frame_target)
{
/* Wait on the latency. */
if (FAILED(hr = ID3D12Fence_SetEventOnCompletion(swapchain->frame_latency_fence,
frame_target, swapchain->frame_latency_event)))
{
ERR("Failed to enqueue frame latency event (internal), hr %#x.\n", hr);
return hr;
}
WaitForSingleObject(swapchain->frame_latency_event, INFINITE);
}
}
swapchain->current_buffer_index = (swapchain->current_buffer_index + 1) % swapchain->desc.BufferCount;
return hresult_from_vk_result(vr);
@ -2295,6 +2312,8 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetMaximumFrameLatency(dxgi_swa
TRACE("iface %p, max_latency %u.\n", iface, max_latency);
EnterCriticalSection(&swapchain->mutex);
/* Max frame latency without WAITABLE_OBJECT is always 3,
* even if set on the device, according to docs. */
if (!(swapchain->desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
{
WARN("DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT not set for swap chain %p.\n", iface);
@ -2339,6 +2358,9 @@ static HANDLE STDMETHODCALLTYPE d3d12_swapchain_GetFrameLatencyWaitableObject(dx
TRACE("iface %p.\n", iface);
if (!(swapchain->desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
return NULL;
return swapchain->frame_latency_event;
}
@ -2671,26 +2693,26 @@ static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IDXGIFact
swapchain->current_buffer_index = 0;
swapchain->frame_number = DXGI_MAX_SWAP_CHAIN_BUFFERS;
swapchain->frame_latency = 3;
if (swapchain_desc->Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)
{
swapchain->frame_number = DXGI_MAX_SWAP_CHAIN_BUFFERS;
swapchain->frame_latency = 1;
if (FAILED(hr = ID3D12Device6_CreateFence(d3d12_swapchain_device_iface(swapchain), DXGI_MAX_SWAP_CHAIN_BUFFERS,
0, &IID_ID3D12Fence, (void **)&swapchain->frame_latency_fence)))
{
WARN("Failed to create frame latency fence, hr %#x.\n", hr);
d3d12_swapchain_destroy(swapchain);
return hr;
}
if (FAILED(hr = ID3D12Device6_CreateFence(d3d12_swapchain_device_iface(swapchain), DXGI_MAX_SWAP_CHAIN_BUFFERS,
0, &IID_ID3D12Fence, (void **)&swapchain->frame_latency_fence)))
{
WARN("Failed to create frame latency fence, hr %#x.\n", hr);
d3d12_swapchain_destroy(swapchain);
return hr;
}
if (!(swapchain->frame_latency_event = CreateEventW(NULL, FALSE, TRUE, NULL)))
{
hr = HRESULT_FROM_WIN32(GetLastError());
WARN("Failed to create frame latency event, hr %#x.\n", hr);
d3d12_swapchain_destroy(swapchain);
return hr;
}
if (!(swapchain->frame_latency_event = CreateEventW(NULL, FALSE, TRUE, NULL)))
{
hr = HRESULT_FROM_WIN32(GetLastError());
WARN("Failed to create frame latency event, hr %#x.\n", hr);
d3d12_swapchain_destroy(swapchain);
return hr;
}
if (FAILED(hr = d3d12_swapchain_set_fullscreen(swapchain, target, TRUE)))