Skip to content

Instantly share code, notes, and snippets.

@laino
Last active August 5, 2016 17:19
Show Gist options
  • Save laino/efa26c7cbd6fb70c6cb94eeb2219c25e to your computer and use it in GitHub Desktop.
Save laino/efa26c7cbd6fb70c6cb94eeb2219c25e to your computer and use it in GitHub Desktop.
Wine CSMT patches
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 44d5f8a..c7c80c6 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -2495,7 +2495,10 @@ static UINT wined3d_cs_exec_set_light(struct wined3d_cs *cs, const void *data)
TRACE("Adding new light\n");
object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
if (!object)
- return E_OUTOFMEMORY;
+ {
+ ERR("Out of memory!\n");
+ return sizeof(*op);
+ }
list_add_head(&cs->state.light_map[hash_idx], &object->entry);
object->glIndex = -1;
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 34085d3..44d5f8a 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -80,6 +80,7 @@ enum wined3d_cs_op
WINED3D_CS_OP_TEXTURE_CHANGED,
WINED3D_CS_OP_TEXTURE_MAP,
WINED3D_CS_OP_TEXTURE_UNMAP,
+ WINED3D_CS_OP_TEXTURE_ADD_DIRTY_REGION,
WINED3D_CS_OP_BUFFER_SWAP_MEM,
WINED3D_CS_OP_BUFFER_INVALIDATE_RANGE,
WINED3D_CS_OP_BUFFER_PRELOAD,
@@ -425,6 +426,13 @@ struct wined3d_cs_texture_unmap
unsigned int sub_resource_idx;
};
+struct wined3d_cs_texture_add_dirty_region
+{
+ enum wined3d_cs_op opcode;
+ struct wined3d_texture *texture;
+ unsigned int sub_resource_idx;
+};
+
struct wined3d_cs_texture_changed
{
enum wined3d_cs_op opcode;
@@ -2760,6 +2771,49 @@ void wined3d_cs_emit_texture_unmap(struct wined3d_cs *cs, struct wined3d_texture
cs->ops->submit_prio(cs, sizeof(*op));
}
+static UINT wined3d_cs_exec_texture_add_dirty_region(struct wined3d_cs *cs, const void *data)
+{
+ const struct wined3d_cs_texture_add_dirty_region *op = data;
+
+ struct wined3d_texture *texture = op->texture;
+ struct wined3d_context *context = context_acquire(cs->device, NULL);
+
+ if (!wined3d_texture_load_location(texture, op->sub_resource_idx, context, texture->resource.map_binding))
+ {
+ ERR("Failed to load location %s.\n", wined3d_debug_location(texture->resource.map_binding));
+ }
+ else
+ {
+ wined3d_texture_invalidate_location(texture, op->sub_resource_idx, ~texture->resource.map_binding);
+ }
+
+ context_release(context);
+
+ wined3d_resource_release(&texture->resource);
+
+ return sizeof(*op);
+}
+
+void wined3d_cs_emit_texture_add_dirty_region(struct wined3d_cs *cs,
+ struct wined3d_texture *texture, unsigned int sub_resource_idx,
+ const struct wined3d_box *dirty_region)
+{
+
+ if (dirty_region)
+ WARN("Ignoring dirty_region %s.\n", debug_box(dirty_region));
+
+ struct wined3d_cs_texture_add_dirty_region *op;
+
+ op = cs->ops->require_space(cs, sizeof(*op));
+ op->opcode = WINED3D_CS_OP_TEXTURE_ADD_DIRTY_REGION;
+ op->texture = texture;
+ op->sub_resource_idx = sub_resource_idx;
+
+ wined3d_resource_acquire(&texture->resource);
+
+ cs->ops->submit(cs, sizeof(*op));
+}
+
static UINT wined3d_cs_exec_texture_preload(struct wined3d_cs *cs, const void *data)
{
const struct wined3d_cs_texture_preload *op = data;
@@ -3237,6 +3291,7 @@ static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
/* WINED3D_CS_OP_TEXTURE_CHANGED */ wined3d_cs_exec_texture_changed,
/* WINED3D_CS_OP_TEXTURE_MAP */ wined3d_cs_exec_texture_map,
/* WINED3D_CS_OP_TEXTURE_UNMAP */ wined3d_cs_exec_texture_unmap,
+ /* WINED3D_CS_OP_TEXTURE_ADD_DIRTY_REGION */ wined3d_cs_exec_texture_add_dirty_region,
/* WINED3D_CS_OP_BUFFER_SWAP_MEM */ wined3d_cs_exec_buffer_swap_mem,
/* WINED3D_CS_OP_BUFFER_INVALIDATE_RANGE */ wined3d_cs_exec_buffer_invalidate_bo_range,
/* WINED3D_CS_OP_BUFFER_PRELOAD */ wined3d_cs_exec_buffer_preload,
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index a4380e6..2cbee1c 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -1693,6 +1693,9 @@ HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
}
sub_resource_idx = layer * texture->level_count;
+#if defined(STAGING_CSMT)
+ wined3d_cs_emit_texture_add_dirty_region(texture->resource.device->cs, texture, sub_resource_idx, dirty_region);
+#else
if (dirty_region)
WARN("Ignoring dirty_region %s.\n", debug_box(dirty_region));
@@ -1705,6 +1708,7 @@ HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
}
wined3d_texture_invalidate_location(texture, sub_resource_idx, ~texture->resource.map_binding);
context_release(context);
+#endif
return WINED3D_OK;
}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index ecb728a..224189c 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -3314,6 +3332,8 @@ void *wined3d_cs_emit_texture_map(struct wined3d_cs *cs, struct wined3d_texture
unsigned int sub_resource_idx, DWORD flags) DECLSPEC_HIDDEN;
void wined3d_cs_emit_texture_unmap(struct wined3d_cs *cs, struct wined3d_texture *texture,
unsigned int sub_resource_idx) DECLSPEC_HIDDEN;
+void wined3d_cs_emit_texture_add_dirty_region(struct wined3d_cs *cs, struct wined3d_texture *texture,
+ unsigned int sub_resource_idx, const struct wined3d_box *dirty_region) DECLSPEC_HIDDEN;
void wined3d_cs_emit_texture_preload(struct wined3d_cs *cs, struct wined3d_texture *texture) DECLSPEC_HIDDEN;
void wined3d_cs_emit_update_texture(struct wined3d_cs *cs, struct wined3d_texture *src,
struct wined3d_texture *dst) DECLSPEC_HIDDEN;
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 34085d3..44d5f8a 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -669,7 +677,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();
pending = InterlockedCompareExchange(&cs->pending_presents, 0, 0);
+ }
}
static UINT wined3d_cs_exec_clear(struct wined3d_cs *cs, const void *data)
@@ -3338,7 +3393,8 @@ static void wined3d_cs_mt_finish(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();
}
static void wined3d_cs_mt_finish_prio(struct wined3d_cs *cs)
@@ -3360,7 +3416,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();
}
static const struct wined3d_cs_ops wined3d_cs_mt_ops =
@@ -3478,7 +3535,9 @@ 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_time, now, diff;
+ spin_time.QuadPart = 0;
TRACE("Started.\n");
@@ -3501,19 +3560,37 @@ 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))
+ NtQuerySystemTime(&now);
+
+ if (spin_time.QuadPart == 0)
+ {
+ spin_time.QuadPart = now.QuadPart;
+ }
+
+ diff.QuadPart = now.QuadPart - spin_time.QuadPart;
+
+ if (diff.QuadPart < WINED3D_CS_SPIN_TIME ||
+ !list_empty(&cs->query_poll_list))
+ {
+ wined3d_cs_mt_yield();
+ }
+ else
+ {
wined3d_cs_wait_event(cs);
+ }
continue;
}
- spin_count = 0;
+ spin_time.QuadPart = 0;
tail = queue->tail;
opcode = *(const enum wined3d_cs_op *)&queue->data[tail];
diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c
index ac6aa6e..f262fca 100644
--- a/dlls/wined3d/wined3d_main.c
+++ b/dlls/wined3d/wined3d_main.c
@@ -93,6 +93,7 @@ struct wined3d_settings wined3d_settings =
FALSE, /* 3D support enabled by default. */
#if defined(STAGING_CSMT)
TRUE, /* Multithreaded CS by default. */
+ 2, /* 0 = Busy wait, 1 = usleep, 2 = SwitchToThread */
#endif /* STAGING_CSMT */
};
@@ -346,6 +347,22 @@ static BOOL wined3d_dll_init(HINSTANCE hInstDLL)
TRACE("Disabling multithreaded command stream.\n");
wined3d_settings.cs_multithreaded = FALSE;
}
+ if (!get_config_key(hkey, appkey, "CSMTYield", buffer, size))
+ {
+ if (!strcmp(buffer, "nothing"))
+ {
+ TRACE("CSMT will use busy-wait loops.\n");
+ wined3d_settings.cs_multithreaded_yield = 0;
+ } else if (!strcmp(buffer, "usleep"))
+ {
+ TRACE("CSMT will use usleep in wait loops.\n");
+ wined3d_settings.cs_multithreaded_yield = 1;
+ } else if (!strcmp(buffer, "SwitchToThread"))
+ {
+ TRACE("CSMT will use SwitchToThread in wait loops.\n");
+ wined3d_settings.cs_multithreaded_yield = 2;
+ }
+ }
}
FIXME_(winediag)("Experimental wined3d CSMT feature is currently %s.\n",
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index ecb728a..224189c 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -315,6 +315,7 @@ struct wined3d_settings
BOOL no_3d;
#if defined(STAGING_CSMT)
BOOL cs_multithreaded;
+ int cs_multithreaded_yield;
#endif /* STAGING_CSMT */
};
@@ -2678,9 +2679,26 @@ static inline void wined3d_resource_release(struct wined3d_resource *resource)
InterlockedDecrement(&resource->access_count);
}
+#if defined(STAGING_CSMT)
+static inline void wined3d_cs_mt_yield(void)
+{
+ int yield_strategy = wined3d_settings.cs_multithreaded_yield;
+
+ if (yield_strategy == 1)
+ usleep(0);
+ else if (yield_strategy == 2)
+ SwitchToThread();
+}
+#endif /* STAGING_CSMT */
+
static inline void wined3d_resource_wait_idle(struct wined3d_resource *resource)
{
- while (InterlockedCompareExchange(&resource->access_count, 0, 0));
+ while (InterlockedCompareExchange(&resource->access_count, 0, 0))
+ {
+#if defined(STAGING_CSMT)
+ wined3d_cs_mt_yield();
+#endif /* STAGING_CSMT */
+ }
}
void resource_cleanup(struct wined3d_resource *resource) DECLSPEC_HIDDEN;
@@ -3169,7 +3187,7 @@ struct wined3d_cs_list
};
#define WINED3D_CS_QUEUE_SIZE 0x100000
-#define WINED3D_CS_SPIN_COUNT 10000000
+#define WINED3D_CS_SPIN_TIME 40000 /* 10000 = 1 millisecond */
struct wined3d_cs_queue
{
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment