Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/HansKristian-Work/vkd3d-proton.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans-Kristian Arntzen <post@arntzen-software.no>2022-10-18 17:42:18 +0300
committerHans-Kristian Arntzen <post@arntzen-software.no>2022-11-11 18:49:31 +0300
commit89c8e522cf8663d98521bed8e305f9afade3e959 (patch)
treea817e2aff05e27c321ba38031226d8ecaf52c110
parent094c517757542131ff844d8a6f7e78f79f14a442 (diff)
vkd3d: Add concept of internal latency handle.
Some applications apparently "forget" to acquire their latency handles, so latency is consistently very high. Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
-rw-r--r--libs/vkd3d/swapchain_new.c107
1 files changed, 90 insertions, 17 deletions
diff --git a/libs/vkd3d/swapchain_new.c b/libs/vkd3d/swapchain_new.c
index 1c2bef0f..595308fc 100644
--- a/libs/vkd3d/swapchain_new.c
+++ b/libs/vkd3d/swapchain_new.c
@@ -70,6 +70,7 @@ struct dxgi_vk_swap_chain
DXGI_SWAP_CHAIN_DESC1 desc;
HANDLE frame_latency_event;
+ HANDLE frame_latency_event_internal;
UINT frame_latency;
VkSurfaceKHR vk_surface;
@@ -220,6 +221,8 @@ static void dxgi_vk_swap_chain_cleanup(struct dxgi_vk_swap_chain *chain)
ID3D12Fence1_Release(chain->present.frame_latency_fence);
if (chain->frame_latency_event)
CloseHandle(chain->frame_latency_event);
+ if (chain->frame_latency_event_internal)
+ CloseHandle(chain->frame_latency_event_internal);
VK_CALL(vkDestroySemaphore(chain->queue->device->vk_device, chain->present.vk_blit_semaphore, NULL));
VK_CALL(vkDestroyCommandPool(chain->queue->device->vk_device, chain->present.vk_blit_command_pool, NULL));
@@ -333,9 +336,12 @@ static HANDLE STDMETHODCALLTYPE dxgi_vk_swap_chain_GetFrameLatencyEvent(IDXGIVkS
TRACE("iface %p.\n", iface);
+ if (!swapchain->frame_latency_event)
+ return INVALID_HANDLE_VALUE;
+
if (!DuplicateHandle(GetCurrentProcess(), swapchain->frame_latency_event,
- GetCurrentProcess(), &duplicated_handle,
- 0, FALSE, DUPLICATE_SAME_ACCESS))
+ GetCurrentProcess(), &duplicated_handle,
+ 0, FALSE, DUPLICATE_SAME_ACCESS))
{
ERR("Failed to duplicate waitable handle.\n");
return INVALID_HANDLE_VALUE;
@@ -647,8 +653,9 @@ static HRESULT STDMETHODCALLTYPE dxgi_vk_swap_chain_Present(IDXGIVkSwapChain *if
chain->user.blit_count += 1;
d3d12_command_queue_enqueue_callback(chain->queue, dxgi_vk_swap_chain_present_callback, chain);
- if (!(chain->desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
- WaitForSingleObject(chain->frame_latency_event, INFINITE);
+ if (chain->frame_latency_event_internal)
+ WaitForSingleObject(chain->frame_latency_event_internal, INFINITE);
+
chain->user.index = (chain->user.index + 1) % chain->desc.BufferCount;
/* For latency debug purposes. Consider a frame to begin when we return from Present() with the next user index set. */
@@ -774,31 +781,64 @@ static HRESULT dxgi_vk_swap_chain_init_sync_objects(struct dxgi_vk_swap_chain *c
VkSemaphoreTypeCreateInfoKHR type_info;
VkFenceCreateInfo fence_create_info;
VkSemaphoreCreateInfo create_info;
+ uint32_t latency_frames;
VkResult vr;
+ char env[8];
HRESULT hr;
if (FAILED(hr = ID3D12Device9_CreateFence(&chain->queue->device->ID3D12Device_iface, DXGI_MAX_SWAP_CHAIN_BUFFERS,
- 0, &IID_ID3D12Fence1, (void**)&chain->present.frame_latency_fence)))
+ 0, &IID_ID3D12Fence1, (void**)&chain->present.frame_latency_fence)))
{
WARN("Failed to create frame latency fence, hr %#x.\n", hr);
return hr;
}
#define DEFAULT_FRAME_LATENCY 3
+ latency_frames = DEFAULT_FRAME_LATENCY;
if (chain->desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)
+ {
+ INFO("Enabling frame latency handles.\n");
chain->frame_latency = 1;
+ if (!(chain->frame_latency_event = CreateSemaphore(NULL, chain->frame_latency, DXGI_MAX_SWAP_CHAIN_BUFFERS, NULL)))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ WARN("Failed to create frame latency semaphore, hr %#x.\n", hr);
+ return hr;
+ }
+ }
else
{
/* On the first frame, we are supposed to acquire,
* but we only acquire after a Present, so do the implied one here. */
- chain->frame_latency = DEFAULT_FRAME_LATENCY - 1;
+ chain->frame_latency = latency_frames;
}
- if (!(chain->frame_latency_event = CreateSemaphore(NULL, chain->frame_latency, DXGI_MAX_SWAP_CHAIN_BUFFERS, NULL)))
+ /* Applications can easily forget to increment their latency handles.
+ * This means we don't keep latency objects in sync anymore. */
+ if (vkd3d_get_env_var("VKD3D_SWAPCHAIN_LATENCY_FRAMES", env, sizeof(env)))
{
- hr = HRESULT_FROM_WIN32(GetLastError());
- WARN("Failed to create frame latency semaphore, hr %#x.\n", hr);
- return hr;
+ latency_frames = strtoul(env, NULL, 0);
+ }
+ else if (chain->frame_latency_event && !chain->queue->device->device_info.present_wait_features.presentWait)
+ {
+ /* If we don't have present_wait and we have app latency object,
+ * it's meaningless to add this by default. */
+ latency_frames = 0;
+ }
+
+ if (latency_frames >= 1 && latency_frames < DXGI_MAX_SWAP_CHAIN_BUFFERS)
+ {
+ INFO("Ensure maximum latency of %u frames.\n", latency_frames);
+
+ /* We consume a count after Present(), i.e. start of next frame,
+ * starting with one less takes care of this. */
+ if (!(chain->frame_latency_event_internal = CreateSemaphore(NULL, latency_frames - 1,
+ latency_frames, NULL)))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ WARN("Failed to create internal frame latency semaphore, hr %#x.\n", hr);
+ return hr;
+ }
}
create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
@@ -1471,11 +1511,24 @@ static void dxgi_vk_swap_chain_signal_waitable_handle(struct dxgi_vk_swap_chain
chain->present.frame_latency_count += 1;
d3d12_command_queue_signal_inline(chain->queue, chain->present.frame_latency_fence, chain->present.frame_latency_count);
- if (FAILED(hr = d3d12_fence_set_event_on_completion(impl_from_ID3D12Fence1(chain->present.frame_latency_fence),
- chain->present.frame_latency_count, chain->frame_latency_event, VKD3D_WAITING_EVENT_TYPE_SEMAPHORE)))
+ if (chain->frame_latency_event)
{
- ERR("Failed to enqueue frame latency event, hr %#x.\n", hr);
- ReleaseSemaphore(chain->frame_latency_event, 1, NULL);
+ if (FAILED(hr = d3d12_fence_set_event_on_completion(impl_from_ID3D12Fence1(chain->present.frame_latency_fence),
+ chain->present.frame_latency_count, chain->frame_latency_event, VKD3D_WAITING_EVENT_TYPE_SEMAPHORE)))
+ {
+ ERR("Failed to enqueue frame latency event, hr %#x.\n", hr);
+ ReleaseSemaphore(chain->frame_latency_event, 1, NULL);
+ }
+ }
+
+ if (chain->frame_latency_event_internal)
+ {
+ if (FAILED(hr = d3d12_fence_set_event_on_completion(impl_from_ID3D12Fence1(chain->present.frame_latency_fence),
+ chain->present.frame_latency_count, chain->frame_latency_event_internal, VKD3D_WAITING_EVENT_TYPE_SEMAPHORE)))
+ {
+ ERR("Failed to enqueue frame latency event, hr %#x.\n", hr);
+ ReleaseSemaphore(chain->frame_latency_event_internal, 1, NULL);
+ }
}
}
}
@@ -1529,6 +1582,7 @@ static void *dxgi_vk_swap_chain_wait_worker(void *chain_)
uint64_t begin_frame_time_ns = 0;
uint64_t end_frame_time_ns = 0;
uint64_t next_wait_id = 0;
+ LONG previous_semaphore;
vkd3d_set_thread_name("vkd3d-swapchain-sync");
@@ -1547,10 +1601,28 @@ static void *dxgi_vk_swap_chain_wait_worker(void *chain_)
/* We don't really care if we observed OUT_OF_DATE or something here. */
VK_CALL(vkWaitForPresentKHR(chain->queue->device->vk_device, chain->present.vk_swapchain,
- next_wait_id, UINT64_MAX));
+ next_wait_id, UINT64_MAX));
+
if (begin_frame_time_ns)
end_frame_time_ns = vkd3d_get_current_time_ns();
- ReleaseSemaphore(chain->frame_latency_event, 1, NULL);
+
+ if (chain->frame_latency_event)
+ {
+ if (ReleaseSemaphore(chain->frame_latency_event, 1, &previous_semaphore))
+ {
+ if (previous_semaphore >= (LONG)chain->frame_latency)
+ {
+ WARN("Incrementing frame latency semaphore beyond max latency. "
+ "Did application forget to acquire? (new count = %ld, max latency = %u)\n",
+ previous_semaphore + 1, chain->frame_latency);
+ }
+ }
+ else
+ WARN("Failed to increment swapchain semaphore. Did application forget to acquire?\n");
+ }
+
+ if (chain->frame_latency_event_internal)
+ ReleaseSemaphore(chain->frame_latency_event_internal, 1, NULL);
if (begin_frame_time_ns)
INFO("vkWaitForPresentKHR frame latency: %.3f ms.\n", 1e-6 * (end_frame_time_ns - begin_frame_time_ns));
@@ -1559,7 +1631,8 @@ static void *dxgi_vk_swap_chain_wait_worker(void *chain_)
* We must have completed all outstanding waits touching VkSwapchainKHR. */
pthread_mutex_lock(&chain->wait_thread.lock);
chain->wait_thread.wait_queue_count -= 1;
- memmove(chain->wait_thread.wait_queue, chain->wait_thread.wait_queue + 1, chain->wait_thread.wait_queue_count * sizeof(*chain->wait_thread.wait_queue));
+ memmove(chain->wait_thread.wait_queue, chain->wait_thread.wait_queue + 1,
+ chain->wait_thread.wait_queue_count * sizeof(*chain->wait_thread.wait_queue));
if (chain->wait_thread.wait_queue_count == 0)
pthread_cond_signal(&chain->wait_thread.cond);
pthread_mutex_unlock(&chain->wait_thread.lock);