diff options
author | Hans-Kristian Arntzen <post@arntzen-software.no> | 2022-10-18 17:42:18 +0300 |
---|---|---|
committer | Hans-Kristian Arntzen <post@arntzen-software.no> | 2022-11-11 18:49:31 +0300 |
commit | 89c8e522cf8663d98521bed8e305f9afade3e959 (patch) | |
tree | a817e2aff05e27c321ba38031226d8ecaf52c110 | |
parent | 094c517757542131ff844d8a6f7e78f79f14a442 (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.c | 107 |
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); |