From: Matteo Bruni mbruni@codeweavers.com
Avoid busy spinning for a potentially long time. --- dlls/wined3d/cs.c | 25 ++++++++++++++++++++++++- dlls/wined3d/wined3d_private.h | 3 ++- 2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 6a09ec2a35a..14f2ca9bb4a 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -724,6 +724,8 @@ static void wined3d_cs_exec_present(struct wined3d_cs *cs, const void *data) }
InterlockedDecrement(&cs->pending_presents); + if (InterlockedCompareExchange(&cs->waiting_for_present, FALSE, TRUE)) + SetEvent(cs->present_event); }
void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain, @@ -734,6 +736,8 @@ void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *sw unsigned int i; LONG pending;
+ wined3d_not_from_cs(cs); + op = wined3d_device_context_require_space(&cs->c, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT); op->opcode = WINED3D_CS_OP_PRESENT; op->dst_window_override = dst_window_override; @@ -757,8 +761,17 @@ void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *sw * ahead of the worker thread. */ while (pending >= swapchain->max_frame_latency) { - YieldProcessor(); + InterlockedExchange(&cs->waiting_for_present, TRUE); + pending = InterlockedCompareExchange(&cs->pending_presents, 0, 0); + if (pending >= swapchain->max_frame_latency || !InterlockedCompareExchange(&cs->waiting_for_present, FALSE, TRUE)) + { + TRACE_(d3d_perf)("Reached latency limit (%u frames), blocking to wait.\n", swapchain->max_frame_latency); + wined3d_mutex_unlock(); + WaitForSingleObject(cs->present_event, INFINITE); + wined3d_mutex_lock(); + TRACE_(d3d_perf)("Woken up from the wait.\n"); + } } }
@@ -3472,11 +3485,18 @@ struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device, heap_free(cs->data); goto fail; } + if (!(cs->present_event = CreateEventW(NULL, FALSE, FALSE, NULL))) + { + ERR("Failed to create command stream present event.\n"); + heap_free(cs->data); + goto fail; + }
if (!(GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR *)wined3d_cs_run, &cs->wined3d_module))) { ERR("Failed to get wined3d module handle.\n"); + CloseHandle(cs->present_event); CloseHandle(cs->event); heap_free(cs->data); goto fail; @@ -3486,6 +3506,7 @@ struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device, { ERR("Failed to create wined3d command stream thread.\n"); FreeLibrary(cs->wined3d_module); + CloseHandle(cs->present_event); CloseHandle(cs->event); heap_free(cs->data); goto fail; @@ -3508,6 +3529,8 @@ void wined3d_cs_destroy(struct wined3d_cs *cs) { wined3d_cs_emit_stop(cs); CloseHandle(cs->thread); + if (!CloseHandle(cs->present_event)) + ERR("Closing present event failed.\n"); if (!CloseHandle(cs->event)) ERR("Closing event failed.\n"); } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index be576fcfbde..c71ac59270b 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -5131,8 +5131,9 @@ struct wined3d_cs struct list query_poll_list; BOOL queries_flushed;
- HANDLE event; + HANDLE event, present_event; LONG waiting_for_event; + LONG waiting_for_present; LONG pending_presents; };