Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save laino/25c2cfa60d81155650acad5f1995b9ef to your computer and use it in GitHub Desktop.
Save laino/25c2cfa60d81155650acad5f1995b9ef to your computer and use it in GitHub Desktop.
From 5e89ce2476b3e516c19afc58b1b14a156acd2f43 Mon Sep 17 00:00:00 2001
From: Nils Kuhnhenn <kuhnhenn.nils@gmail.com>
Date: Sat, 6 Aug 2016 16:25:27 +0200
Subject: [PATCH] wined3d: use SwitchToThread() and calls to select() in
busy-loops
---
dlls/wined3d/cs.c | 39 +++++++++++++++++++++++++++++++--------
dlls/wined3d/wined3d_private.h | 42 ++++++++++++++++++++++++++++++++++++++++--
2 files changed, 71 insertions(+), 10 deletions(-)
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 505661d..a099c33 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -642,6 +642,8 @@ void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *sw
unsigned int i;
#if defined(STAGING_CSMT)
LONG pending;
+ LARGE_INTEGER spin_start;
+ spin_start.QuadPart = 0;
#endif /* STAGING_CSMT */
op = cs->ops->require_space(cs, sizeof(*op));
@@ -677,7 +679,10 @@ static void wined3d_cs_exec_clear(struct wined3d_cs *cs, const void *data)
* In Counter-Strike: Source a frame difference of 3 causes noticable
* input delay that makes the game unplayable. */
while (pending > 1)
+ {
+ wined3d_cs_mt_yield(&spin_start);
pending = InterlockedCompareExchange(&cs->pending_presents, 0, 0);
+ }
}
static UINT wined3d_cs_exec_clear(struct wined3d_cs *cs, const void *data)
@@ -3389,17 +3394,25 @@ static void wined3d_cs_emit_stop(struct wined3d_cs *cs)
static void wined3d_cs_mt_finish(struct wined3d_cs *cs)
{
BOOL fence;
+
+ LARGE_INTEGER spin_start;
+ spin_start.QuadPart = 0;
+
wined3d_cs_emit_fence(cs, &fence);
/* A busy wait should be fine, we're not supposed to have to wait very
* long. */
- while (!InterlockedCompareExchange(&fence, TRUE, TRUE));
+ while (!InterlockedCompareExchange(&fence, TRUE, TRUE))
+ wined3d_cs_mt_yield(&spin_start);
}
static void wined3d_cs_mt_finish_prio(struct wined3d_cs *cs)
{
BOOL fence;
+ LARGE_INTEGER spin_start;
+ spin_start.QuadPart = 0;
+
if (cs->thread_id == GetCurrentThreadId())
{
static BOOL once;
@@ -3415,7 +3428,8 @@ static void wined3d_cs_mt_finish_prio(struct wined3d_cs *cs)
/* A busy wait should be fine, we're not supposed to have to wait very
* long. */
- while (!InterlockedCompareExchange(&fence, TRUE, TRUE));
+ while (!InterlockedCompareExchange(&fence, TRUE, TRUE))
+ wined3d_cs_mt_yield(&spin_start);
}
static const struct wined3d_cs_ops wined3d_cs_mt_ops =
@@ -3533,7 +3547,11 @@ static DWORD WINAPI wined3d_cs_run(void *thread_param)
LONG tail;
char poll = 0;
struct wined3d_cs_queue *queue;
- unsigned int spin_count = 0;
+
+ LARGE_INTEGER spin_start;
+ spin_start.QuadPart = 0;
+
+ BOOL spin_time_exeeded = FALSE;
TRACE("Started.\n");
@@ -3556,19 +3574,24 @@ static DWORD WINAPI wined3d_cs_run(void *thread_param)
else if (!queue_is_empty(&cs->queue))
{
queue = &cs->queue;
- if (!queue_is_empty(&cs->prio_queue))
- queue = &cs->prio_queue;
+ }
+ else if (poll != 0)
+ {
+ poll = 10;
+ continue;
}
else
{
- spin_count++;
- if (spin_count >= WINED3D_CS_SPIN_COUNT && list_empty(&cs->query_poll_list))
+ if (!spin_time_exeeded || !list_empty(&cs->query_poll_list))
+ spin_time_exeeded = wined3d_cs_mt_yield(&spin_start).QuadPart > WINED3D_CS_SPIN_TIME;
+ else
wined3d_cs_wait_event(cs);
continue;
}
- spin_count = 0;
+ spin_start.QuadPart = 0;
+ spin_time_exeeded = FALSE;
tail = queue->tail;
opcode = *(const enum wined3d_cs_op *)&queue->data[tail];
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 4247449..b119f73 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2678,9 +2678,47 @@ static inline void wined3d_resource_release(struct wined3d_resource *resource)
InterlockedDecrement(&resource->access_count);
}
+#if defined(STAGING_CSMT)
+#define WINED3D_YIELD_SPIN_TIME 1000 /* 1000 = 0.1 milliseconds = 100 microseconds */
+
+static LARGE_INTEGER wined3d_cs_mt_yield(LARGE_INTEGER *spin_start)
+{
+ struct timeval tv;
+ LARGE_INTEGER now, diff;
+
+ NtQuerySystemTime(&now);
+
+ if (spin_start->QuadPart <= 0)
+ spin_start->QuadPart = now.QuadPart;
+
+ diff.QuadPart = now.QuadPart - spin_start->QuadPart;
+
+ if (diff.QuadPart > WINED3D_YIELD_SPIN_TIME)
+ {
+ tv.tv_sec = 0;
+ tv.tv_usec = 9;
+ select( 0, NULL, NULL, NULL, &tv);
+ }
+ else
+ SwitchToThread();
+
+ return diff;
+}
+#endif /* STAGING_CSMT */
+
static inline void wined3d_resource_wait_idle(struct wined3d_resource *resource)
{
- while (InterlockedCompareExchange(&resource->access_count, 0, 0));
+#if defined(STAGING_CSMT)
+ LARGE_INTEGER spin_start;
+ spin_start.QuadPart = 0;
+#endif /* STAGING_CSMT */
+
+ while (InterlockedCompareExchange(&resource->access_count, 0, 0))
+ {
+#if defined(STAGING_CSMT)
+ wined3d_cs_mt_yield(&spin_start);
+#endif /* STAGING_CSMT */
+ }
}
void resource_cleanup(struct wined3d_resource *resource) DECLSPEC_HIDDEN;
@@ -3169,7 +3207,7 @@ struct wined3d_cs_list
};
#define WINED3D_CS_QUEUE_SIZE 0x100000
-#define WINED3D_CS_SPIN_COUNT 10000000
+#define WINED3D_CS_SPIN_TIME 200000 /* 20000 = 20 milliseconds */
struct wined3d_cs_queue
{
--
2.9.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment