From c115a25b8aba4ade5fa04cfb469b030eb29b941a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20D=C3=B6singer?= <stefan@codeweavers.com>
Date: Thu, 4 Jul 2013 23:33:14 +0200
Subject: wined3d: Replace the linked lists with a ringbuffer

---
 dlls/wined3d/cs.c              | 362 ++++++++++++++++++-----------------------
 dlls/wined3d/wined3d_private.h |  20 +--
 2 files changed, 162 insertions(+), 220 deletions(-)

diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 6204e57..66c784b 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -22,20 +22,10 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
 
-#define WINED3D_INITIAL_CS_SIZE 4096
-
-static CRITICAL_SECTION wined3d_cs_list_mutex;
-static CRITICAL_SECTION_DEBUG wined3d_cs_list_mutex_debug =
-{
-    0, 0, &wined3d_cs_list_mutex,
-    {&wined3d_cs_list_mutex_debug.ProcessLocksList,
-    &wined3d_cs_list_mutex_debug.ProcessLocksList},
-    0, 0, {(DWORD_PTR)(__FILE__ ": wined3d_cs_list_mutex")}
-};
-static CRITICAL_SECTION wined3d_cs_list_mutex = {&wined3d_cs_list_mutex_debug, -1, 0, 0, 0, 0};
-
 enum wined3d_cs_op
 {
+    WINED3D_CS_OP_NOP,
+    WINED3D_CS_OP_SKIP,
     WINED3D_CS_OP_FENCE,
     WINED3D_CS_OP_PRESENT,
     WINED3D_CS_OP_CLEAR,
@@ -378,99 +368,30 @@ struct wined3d_cs_resource_unmap
     struct wined3d_resource *resource;
 };
 
-/* FIXME: The list synchronization probably isn't particularly fast. */
-static void wined3d_cs_list_enqueue(struct wined3d_cs_list *list, struct wined3d_cs_block *block)
-{
-    EnterCriticalSection(&wined3d_cs_list_mutex);
-    list_add_tail(&list->blocks, &block->entry);
-    LeaveCriticalSection(&wined3d_cs_list_mutex);
-}
-
-static struct wined3d_cs_block *wined3d_cs_list_dequeue(struct wined3d_cs_list *list)
-{
-    struct list *head;
-
-    EnterCriticalSection(&wined3d_cs_list_mutex);
-    if (!(head = list_head(&list->blocks)))
-    {
-        LeaveCriticalSection(&wined3d_cs_list_mutex);
-        return NULL;
-    }
-    list_remove(head);
-    LeaveCriticalSection(&wined3d_cs_list_mutex);
-
-    return LIST_ENTRY(head, struct wined3d_cs_block, entry);
-}
-
-static struct wined3d_cs_block *wined3d_cs_list_dequeue_blocking(struct wined3d_cs_list *list)
-{
-    struct wined3d_cs_block *block;
-
-    /* FIXME: Use an event to wait after a couple of spins. */
-    for (;;)
-    {
-        if ((block = wined3d_cs_list_dequeue(list)))
-            return block;
-    }
-}
-
-static void wined3d_cs_list_init(struct wined3d_cs_list *list)
-{
-    list_init(&list->blocks);
-}
-
-static struct wined3d_cs_block *wined3d_cs_get_thread_block(const struct wined3d_cs *cs)
-{
-    return TlsGetValue(cs->tls_idx);
-}
-
-static void wined3d_cs_set_thread_block(const struct wined3d_cs *cs, struct wined3d_cs_block *block)
+struct wined3d_cs_skip
 {
-    if (!TlsSetValue(cs->tls_idx, block))
-        ERR("Failed to set thread block.\n");
-}
+    enum wined3d_cs_op opcode;
+    DWORD size;
+};
 
-static void wined3d_cs_flush(struct wined3d_cs *cs)
+static void wined3d_cs_submit(struct wined3d_cs *cs, size_t size)
 {
-    wined3d_cs_list_enqueue(&cs->exec_list, wined3d_cs_get_thread_block(cs));
-    wined3d_cs_set_thread_block(cs, NULL);
+    LONG new_val = (cs->queue.head + size) & (WINED3D_CS_QUEUE_SIZE - 1);
+    /* There is only one thread writing to queue.head, InterlockedExchange
+     * is used for the memory barrier. */
+    InterlockedExchange(&cs->queue.head, new_val);
 }
 
-static struct wined3d_cs_block *wined3d_cs_get_block(struct wined3d_cs *cs)
+static UINT wined3d_cs_exec_nop(struct wined3d_cs *cs, const void *data)
 {
-    struct wined3d_cs_block *block;
-
-    if (!(block = wined3d_cs_list_dequeue(&cs->free_list)))
-    {
-        if (!(block = HeapAlloc(GetProcessHeap(), 0, sizeof(*block))))
-        {
-            ERR("Failed to get new block.\n");
-            return NULL;
-        }
-    }
-
-    block->pos = 0;
-
-    return block;
+    return sizeof(enum wined3d_cs_op);
 }
 
-static void *wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size)
+static UINT wined3d_cs_exec_skip(struct wined3d_cs *cs, const void *data)
 {
-    struct wined3d_cs_block *block = wined3d_cs_get_thread_block(cs);
-    void *data;
-
-    if (!block || block->pos + size > sizeof(block->data))
-    {
-        if (block)
-            wined3d_cs_flush(cs);
-        block = wined3d_cs_get_block(cs);
-        wined3d_cs_set_thread_block(cs, block);
-    }
+    const struct wined3d_cs_skip *op = data;
 
-    data = &block->data[block->pos];
-    block->pos += size;
-
-    return data;
+    return op->size;
 }
 
 static UINT wined3d_cs_exec_fence(struct wined3d_cs *cs, const void *data)
@@ -491,14 +412,14 @@ static void wined3d_cs_emit_fence(struct wined3d_cs *cs, BOOL *signalled)
     op = cs->ops->require_space(cs, sizeof(*op));
     op->opcode = WINED3D_CS_OP_FENCE;
     op->signalled = signalled;
+    cs->ops->submit(cs, sizeof(*op));
 }
 
-static void wined3d_cs_flush_and_wait(struct wined3d_cs *cs)
+static void wined3d_cs_finish(struct wined3d_cs *cs)
 {
     BOOL fence;
 
     wined3d_cs_emit_fence(cs, &fence);
-    wined3d_cs_flush(cs);
 
     /* A busy wait should be fine, we're not supposed to have to wait very
      * long. */
@@ -556,7 +477,7 @@ void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *sw
 
     pending = InterlockedIncrement(&cs->pending_presents);
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 
     while (pending > 1)
         pending = InterlockedCompareExchange(&cs->pending_presents, 0, 0);
@@ -583,8 +504,9 @@ void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *
 {
     struct wined3d_cs_clear *op;
     unsigned int extra_rects = rect_count ? rect_count - 1 : 0;
+    size_t size = sizeof(*op) + sizeof(*op->rects) * extra_rects;
 
-    op = cs->ops->require_space(cs, sizeof(*op) + sizeof(*op->rects) * extra_rects);
+    op = cs->ops->require_space(cs, size);
     op->opcode = WINED3D_CS_OP_CLEAR;
     op->rect_count = rect_count;
     if (rect_count)
@@ -594,7 +516,7 @@ void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *
     op->depth = depth;
     op->stencil = stencil;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, size);
 }
 
 static UINT wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data)
@@ -635,7 +557,7 @@ void wined3d_cs_emit_draw(struct wined3d_cs *cs, UINT start_idx, UINT index_coun
     op->instance_count = instance_count;
     op->indexed = indexed;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_predication(struct wined3d_cs *cs, const void *data)
@@ -657,7 +579,7 @@ void wined3d_cs_emit_set_predication(struct wined3d_cs *cs, struct wined3d_query
     op->predicate = predicate;
     op->value = value;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_viewport(struct wined3d_cs *cs, const void *data)
@@ -679,7 +601,7 @@ void wined3d_cs_emit_set_viewport(struct wined3d_cs *cs, const struct wined3d_vi
     op->opcode = WINED3D_CS_OP_SET_VIEWPORT;
     op->viewport = *viewport;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_scissor_rect(struct wined3d_cs *cs, const void *data)
@@ -700,7 +622,7 @@ void wined3d_cs_emit_set_scissor_rect(struct wined3d_cs *cs, const RECT *rect)
     op->opcode = WINED3D_CS_OP_SET_SCISSOR_RECT;
     op->rect = *rect;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_rendertarget_view(struct wined3d_cs *cs, const void *data)
@@ -723,7 +645,7 @@ void wined3d_cs_emit_set_rendertarget_view(struct wined3d_cs *cs, unsigned int v
     op->view_idx = view_idx;
     op->view = view;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_depth_stencil_view(struct wined3d_cs *cs, const void *data)
@@ -776,7 +698,7 @@ void wined3d_cs_emit_set_depth_stencil_view(struct wined3d_cs *cs, struct wined3
     op->opcode = WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW;
     op->view = view;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_vertex_declaration(struct wined3d_cs *cs, const void *data)
@@ -797,7 +719,7 @@ void wined3d_cs_emit_set_vertex_declaration(struct wined3d_cs *cs, struct wined3
     op->opcode = WINED3D_CS_OP_SET_VERTEX_DECLARATION;
     op->declaration = declaration;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_stream_source(struct wined3d_cs *cs, const void *data)
@@ -834,7 +756,7 @@ void wined3d_cs_emit_set_stream_source(struct wined3d_cs *cs, UINT stream_idx,
     op->offset = offset;
     op->stride = stride;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_stream_source_freq(struct wined3d_cs *cs, const void *data)
@@ -861,7 +783,7 @@ void wined3d_cs_emit_set_stream_source_freq(struct wined3d_cs *cs, UINT stream_i
     op->frequency = frequency;
     op->flags = flags;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_stream_output(struct wined3d_cs *cs, const void *data)
@@ -894,7 +816,7 @@ void wined3d_cs_emit_set_stream_output(struct wined3d_cs *cs, UINT stream_idx,
     op->buffer = buffer;
     op->offset = offset;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_index_buffer(struct wined3d_cs *cs, const void *data)
@@ -926,7 +848,7 @@ void wined3d_cs_emit_set_index_buffer(struct wined3d_cs *cs, struct wined3d_buff
     op->buffer = buffer;
     op->format_id = format_id;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_constant_buffer(struct wined3d_cs *cs, const void *data)
@@ -957,7 +879,7 @@ void wined3d_cs_emit_set_constant_buffer(struct wined3d_cs *cs, enum wined3d_sha
     op->cb_idx = cb_idx;
     op->buffer = buffer;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_texture(struct wined3d_cs *cs, const void *data)
@@ -1032,7 +954,7 @@ void wined3d_cs_emit_set_texture(struct wined3d_cs *cs, UINT stage, struct wined
     op->opcode = WINED3D_CS_OP_SET_TEXTURE;
     op->stage = stage;
     op->texture = texture;
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_shader_resource_view(struct wined3d_cs *cs, const void *data)
@@ -1056,7 +978,7 @@ void wined3d_cs_emit_set_shader_resource_view(struct wined3d_cs *cs, enum wined3
     op->view_idx = view_idx;
     op->view = view;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_sampler(struct wined3d_cs *cs, const void *data)
@@ -1080,7 +1002,7 @@ void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type
     op->sampler_idx = sampler_idx;
     op->sampler = sampler;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_shader(struct wined3d_cs *cs, const void *data)
@@ -1102,6 +1024,8 @@ void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type
     op->opcode = WINED3D_CS_OP_SET_SHADER;
     op->type = type;
     op->shader = shader;
+
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_vs_consts_f(struct wined3d_cs *cs, const void *data)
@@ -1137,8 +1061,9 @@ void wined3d_cs_emit_set_consts_f(struct wined3d_cs *cs, UINT start_register,
 {
     struct wined3d_cs_set_consts_f *op;
     UINT extra_space = vector4f_count - 1;
+    size_t size = sizeof(*op) + sizeof(op->constants) * extra_space;
 
-    op = cs->ops->require_space(cs, sizeof(*op) + sizeof(op->constants) * extra_space);
+    op = cs->ops->require_space(cs, size);
     switch (type)
     {
         case WINED3D_SHADER_TYPE_PIXEL:
@@ -1160,7 +1085,7 @@ void wined3d_cs_emit_set_consts_f(struct wined3d_cs *cs, UINT start_register,
     op->vector4f_count = vector4f_count;
     memcpy(op->constants, constants, sizeof(*constants) * 4 * vector4f_count);
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, size);
 }
 
 static UINT wined3d_cs_exec_set_render_state(struct wined3d_cs *cs, const void *data)
@@ -1182,8 +1107,8 @@ void wined3d_cs_emit_set_render_state(struct wined3d_cs *cs, enum wined3d_render
     op->state = state;
     op->value = value;
 
-    cs->ops->submit(cs);
-};
+    cs->ops->submit(cs, sizeof(*op));
+}
 
 static UINT wined3d_cs_exec_set_vs_consts_b(struct wined3d_cs *cs, const void *data)
 {
@@ -1216,8 +1141,9 @@ void wined3d_cs_emit_set_consts_b(struct wined3d_cs *cs, UINT start_register,
 {
     struct wined3d_cs_set_consts_b *op;
     UINT extra_space = bool_count - 1;
+    size_t size = sizeof(*op) + sizeof(op->constants) * extra_space;
 
-    op = cs->ops->require_space(cs, sizeof(*op) + sizeof(op->constants) * extra_space);
+    op = cs->ops->require_space(cs, size);
     switch (type)
     {
         case WINED3D_SHADER_TYPE_PIXEL:
@@ -1239,7 +1165,7 @@ void wined3d_cs_emit_set_consts_b(struct wined3d_cs *cs, UINT start_register,
     op->bool_count = bool_count;
     memcpy(op->constants, constants, sizeof(op->constants) * bool_count);
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, size);
 }
 
 static UINT wined3d_cs_exec_set_vs_consts_i(struct wined3d_cs *cs, const void *data)
@@ -1273,8 +1199,9 @@ void wined3d_cs_emit_set_consts_i(struct wined3d_cs *cs, UINT start_register,
 {
     struct wined3d_cs_set_consts_i *op;
     UINT extra_space = vector4i_count - 1;
+    size_t size = sizeof(*op) + sizeof(op->constants) * extra_space;
 
-    op = cs->ops->require_space(cs, sizeof(*op) + sizeof(op->constants) * extra_space);
+    op = cs->ops->require_space(cs, size);
     switch (type)
     {
         case WINED3D_SHADER_TYPE_PIXEL:
@@ -1296,7 +1223,7 @@ void wined3d_cs_emit_set_consts_i(struct wined3d_cs *cs, UINT start_register,
     op->vector4i_count = vector4i_count;
     memcpy(op->constants, constants, sizeof(op->constants) * vector4i_count);
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, size);
 }
 
 static UINT wined3d_cs_exec_set_texture_state(struct wined3d_cs *cs, const void *data)
@@ -1320,7 +1247,7 @@ void wined3d_cs_emit_set_texture_state(struct wined3d_cs *cs, UINT stage,
     op->state = state;
     op->value = value;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_sampler_state(struct wined3d_cs *cs, const void *data)
@@ -1344,7 +1271,7 @@ void wined3d_cs_emit_set_sampler_state(struct wined3d_cs *cs, UINT sampler_idx,
     op->state = state;
     op->value = value;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_transform(struct wined3d_cs *cs, const void *data)
@@ -1368,7 +1295,7 @@ void wined3d_cs_emit_set_transform(struct wined3d_cs *cs, enum wined3d_transform
     op->state = state;
     op->matrix = *matrix;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_clip_plane(struct wined3d_cs *cs, const void *data)
@@ -1390,7 +1317,7 @@ void wined3d_cs_emit_set_clip_plane(struct wined3d_cs *cs, UINT plane_idx, const
     op->plane_idx = plane_idx;
     op->plane = *plane;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_color_key(struct wined3d_cs *cs, const void *data)
@@ -1468,7 +1395,7 @@ void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture
     else
         op->set = 0;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_material(struct wined3d_cs *cs, const void *data)
@@ -1489,7 +1416,7 @@ void wined3d_cs_emit_set_material(struct wined3d_cs *cs, const struct wined3d_ma
     op->opcode = WINED3D_CS_OP_SET_MATERIAL;
     op->material = *material;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_reset_state(struct wined3d_cs *cs, const void *data)
@@ -1513,7 +1440,7 @@ void wined3d_cs_emit_reset_state(struct wined3d_cs *cs)
     op = cs->ops->require_space(cs, sizeof(*op));
     op->opcode = WINED3D_CS_OP_RESET_STATE;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_glfinish(struct wined3d_cs *cs, const void *data)
@@ -1539,7 +1466,7 @@ void wined3d_cs_emit_glfinish(struct wined3d_cs *cs)
     op = cs->ops->require_space(cs, sizeof(*op));
     op->opcode = WINED3D_CS_OP_GLFINISH;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_base_vertex_index(struct wined3d_cs *cs, const void *data)
@@ -1561,7 +1488,7 @@ void wined3d_cs_emit_set_base_vertex_index(struct wined3d_cs *cs,
     op->opcode = WINED3D_CS_OP_SET_BASE_VERTEX_INDEX;
     op->base_vertex_index = base_vertex_index;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_primitive_type(struct wined3d_cs *cs, const void *data)
@@ -1587,7 +1514,7 @@ void wined3d_cs_emit_set_primitive_type(struct wined3d_cs *cs, GLenum primitive_
     op->opcode = WINED3D_CS_OP_SET_PRIMITIVE_TYPE;
     op->gl_primitive_type = primitive_type;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_light(struct wined3d_cs *cs, const void *data)
@@ -1644,7 +1571,7 @@ void wined3d_cs_emit_set_light(struct wined3d_cs *cs, const struct wined3d_light
     op->opcode = WINED3D_CS_OP_SET_LIGHT;
     op->light = *light;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_set_light_enable(struct wined3d_cs *cs, const void *data)
@@ -1733,7 +1660,7 @@ void wined3d_cs_emit_set_light_enable(struct wined3d_cs *cs, UINT idx, BOOL enab
     op->idx = idx;
     op->enable = enable;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_blt(struct wined3d_cs *cs, const void *data)
@@ -1765,7 +1692,7 @@ void wined3d_cs_emit_blt(struct wined3d_cs *cs, struct wined3d_surface *dst_surf
     if (fx)
         op->fx = *fx;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_clear_rtv(struct wined3d_cs *cs, const void *data)
@@ -1791,7 +1718,7 @@ void wined3d_cs_emit_clear_rtv(struct wined3d_cs *cs, struct wined3d_rendertarge
     op->rect = *rect;
     op->color = *color;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT wined3d_cs_exec_resource_map(struct wined3d_cs *cs, const void *data)
@@ -1815,12 +1742,14 @@ void *wined3d_cs_emit_resource_map(struct wined3d_cs *cs, struct wined3d_resourc
     op->flags = flags;
     op->mem = &ret;
 
-    cs->ops->finish(cs);
+    cs->ops->submit(cs, sizeof(*op));
 
     if (flags & (WINED3D_MAP_NOOVERWRITE | WINED3D_MAP_DISCARD))
     {
         FIXME("Dynamic resource map is inefficient\n");
     }
+    cs->ops->finish(cs);
+
     return ret;
 }
 
@@ -1842,11 +1771,13 @@ void wined3d_cs_emit_resource_unmap(struct wined3d_cs *cs, struct wined3d_resour
     op->opcode = WINED3D_CS_OP_RESOURCE_UNMAP;
     op->resource = resource;
 
-    cs->ops->submit(cs);
+    cs->ops->submit(cs, sizeof(*op));
 }
 
 static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
 {
+    /* WINED3D_CS_OP_NOP                        */ wined3d_cs_exec_nop,
+    /* WINED3D_CS_OP_SKIP                       */ wined3d_cs_exec_skip,
     /* WINED3D_CS_OP_FENCE                      */ wined3d_cs_exec_fence,
     /* WINED3D_CS_OP_PRESENT                    */ wined3d_cs_exec_present,
     /* WINED3D_CS_OP_CLEAR                      */ wined3d_cs_exec_clear,
@@ -1891,42 +1822,59 @@ static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
     /* WINED3D_CS_OP_RESOURCE_UNMAP             */ wined3d_cs_exec_resource_unmap,
 };
 
-static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size)
+static void *wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size)
 {
-    if (size > cs->data_size)
+    struct wined3d_cs_queue *queue = &cs->queue;
+    size_t queue_size = sizeof(queue->data) / sizeof(*queue->data);
+
+    if (queue_size - size < queue->head)
     {
-        void *new_data;
+        struct wined3d_cs_skip *skip;
+        size_t nop_size = queue_size - queue->head;
 
-        size = max( size, cs->data_size * 2 );
-        if (!(new_data = HeapReAlloc(GetProcessHeap(), 0, cs->data, size)))
-            return NULL;
+        skip = wined3d_cs_mt_require_space(cs, nop_size);
+        if (nop_size < sizeof(*skip))
+        {
+            skip->opcode = WINED3D_CS_OP_NOP;
+        }
+        else
+        {
+            skip->opcode = WINED3D_CS_OP_SKIP;
+            skip->size = nop_size;
+        }
 
-        cs->data_size = size;
-        cs->data = new_data;
+        cs->ops->submit(cs, nop_size);
+        assert(!queue->head);
     }
 
-    return cs->data;
-}
+    while(1)
+    {
+        LONG head = queue->head;
+        LONG tail = *((volatile LONG *)&queue->tail);
+        LONG new_pos;
+        /* Empty */
+        if (head == tail)
+            break;
+        /* Head ahead of tail, take care of wrap-around */
+        new_pos = (head + size) & (WINED3D_CS_QUEUE_SIZE - 1);
+        if (head > tail && (new_pos || tail))
+            break;
+        /* Tail ahead of head, but still enough space */
+        if (new_pos < tail && new_pos)
+            break;
 
-static void wined3d_cs_st_submit(struct wined3d_cs *cs)
-{
-    enum wined3d_cs_op opcode = *(const enum wined3d_cs_op *)cs->data;
+        TRACE("Waiting for free space. Head %u, tail %u, want %u\n", head, tail,
+                (unsigned int) size);
+    }
 
-    wined3d_cs_op_handlers[opcode](cs, cs->data);
+    return &queue->data[queue->head];
 }
 
-static const struct wined3d_cs_ops wined3d_cs_st_ops =
-{
-    wined3d_cs_st_require_space,
-    wined3d_cs_st_submit,
-    wined3d_cs_st_submit,
-};
-
 static const struct wined3d_cs_ops wined3d_cs_mt_ops =
 {
     wined3d_cs_mt_require_space,
-    wined3d_cs_flush,
-    wined3d_cs_flush_and_wait,
+    wined3d_cs_submit,
+    wined3d_cs_finish,
 };
 
 /* FIXME: wined3d_device_uninit_3d() should either flush and wait, or be an
@@ -1938,9 +1886,38 @@ static void wined3d_cs_emit_stop(struct wined3d_cs *cs)
     op = wined3d_cs_mt_require_space(cs, sizeof(*op));
     op->opcode = WINED3D_CS_OP_STOP;
 
-    wined3d_cs_flush(cs);
+    wined3d_cs_submit(cs, sizeof(*op));
+}
+
+static void wined3d_cs_st_submit(struct wined3d_cs *cs, size_t size)
+{
+    enum wined3d_cs_op opcode = *(const enum wined3d_cs_op *)&cs->queue.data;
+
+    if (opcode >= WINED3D_CS_OP_STOP)
+    {
+        ERR("Invalid opcode %#x.\n", opcode);
+        return;
+    }
+
+    wined3d_cs_op_handlers[opcode](cs, &cs->queue.data);
 }
 
+static void wined3d_cs_st_finish(struct wined3d_cs *cs)
+{
+}
+
+static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size)
+{
+    return cs->queue.data;
+}
+
+static const struct wined3d_cs_ops wined3d_cs_st_ops =
+{
+    wined3d_cs_st_require_space,
+    wined3d_cs_st_submit,
+    wined3d_cs_st_finish,
+};
+
 void wined3d_cs_switch_onscreen_ds(struct wined3d_cs *cs,
         struct wined3d_context *context, struct wined3d_surface *depth_stencil)
 {
@@ -1960,31 +1937,32 @@ void wined3d_cs_switch_onscreen_ds(struct wined3d_cs *cs,
 static DWORD WINAPI wined3d_cs_run(void *thread_param)
 {
     struct wined3d_cs *cs = thread_param;
+    enum wined3d_cs_op opcode;
+    LONG tail;
 
     TRACE("Started.\n");
 
     cs->thread_id = GetCurrentThreadId();
     for (;;)
     {
-        struct wined3d_cs_block *block;
-        UINT pos = 0;
-
-        block = wined3d_cs_list_dequeue_blocking(&cs->exec_list);
-        while (pos < block->pos)
+        if (*((volatile LONG *)&cs->queue.head) == cs->queue.tail)
         {
-            enum wined3d_cs_op opcode = *(const enum wined3d_cs_op *)&block->data[pos];
+            continue;
+        }
 
-            if (opcode >= WINED3D_CS_OP_STOP)
-            {
-                if (opcode > WINED3D_CS_OP_STOP)
-                    ERR("Invalid opcode %#x.\n", opcode);
-                goto done;
-            }
+        tail = cs->queue.tail;
+        opcode = *(const enum wined3d_cs_op *)&cs->queue.data[tail];
 
-            pos += wined3d_cs_op_handlers[opcode](cs, &block->data[pos]);
+        if (opcode >= WINED3D_CS_OP_STOP)
+        {
+            if (opcode > WINED3D_CS_OP_STOP)
+                ERR("Invalid opcode %#x.\n", opcode);
+            goto done;
         }
 
-        wined3d_cs_list_enqueue(&cs->free_list, block);
+        tail += wined3d_cs_op_handlers[opcode](cs, &cs->queue.data[tail]);
+        tail &= (WINED3D_CS_QUEUE_SIZE - 1);
+        InterlockedExchange(&cs->queue.tail, tail);
     }
 
 done:
@@ -2009,25 +1987,10 @@ struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device)
     cs->ops = &wined3d_cs_st_ops;
     cs->device = device;
 
-    cs->data_size = WINED3D_INITIAL_CS_SIZE;
-    if (!(cs->data = HeapAlloc(GetProcessHeap(), 0, cs->data_size)))
-    {
-        goto err;
-    }
-
-    if ((cs->tls_idx = TlsAlloc()) == TLS_OUT_OF_INDEXES)
-    {
-        ERR("Failed to allocate cs TLS index, err %#x.\n", GetLastError());
-        goto err;
-    }
-
     if (wined3d_settings.cs_multithreaded)
     {
         cs->ops = &wined3d_cs_mt_ops;
 
-        wined3d_cs_list_init(&cs->free_list);
-        wined3d_cs_list_init(&cs->exec_list);
-
         if (!(cs->thread = CreateThread(NULL, 0, wined3d_cs_run, cs, 0, NULL)))
         {
             ERR("Failed to create wined3d command stream thread.\n");
@@ -2039,12 +2002,7 @@ struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device)
 
 err:
     if (cs)
-    {
         state_cleanup(&cs->state);
-        if (cs->tls_idx != TLS_OUT_OF_INDEXES && !TlsFree(cs->tls_idx))
-            ERR("Failed to free cs TLS index, err %#x.\n", GetLastError());
-        HeapFree(GetProcessHeap(), 0, cs->data);
-    }
     HeapFree(GetProcessHeap(), 0, cs);
     return NULL;
 }
@@ -2063,17 +2021,7 @@ void wined3d_cs_destroy(struct wined3d_cs *cs)
         CloseHandle(cs->thread);
         if (ret != WAIT_OBJECT_0)
             ERR("Wait failed (%#x).\n", ret);
-
-        /* FIXME: Cleanup the block lists on thread exit. */
-#if 0
-        wined3d_cs_list_cleanup(&cs->exec_list);
-        wined3d_cs_list_cleanup(&cs->free_list);
-#endif
     }
 
-    if (!TlsFree(cs->tls_idx))
-        ERR("Failed to free cs TLS index, err %#x.\n", GetLastError());
-
-    HeapFree(GetProcessHeap(), 0, cs->data);
     HeapFree(GetProcessHeap(), 0, cs);
 }
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index ed4d94b..35384e1 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -31,6 +31,7 @@
 #define WINE_GLAPI
 #endif
 
+#include <assert.h>
 #include <stdarg.h>
 #include <math.h>
 #include <limits.h>
@@ -2584,19 +2585,17 @@ struct wined3d_cs_list
     struct list blocks;
 };
 
-struct wined3d_cs_block
+#define WINED3D_CS_QUEUE_SIZE 0x100000
+struct wined3d_cs_queue
 {
-    struct list entry;
-    UINT pos;
-     /* FIXME? The size is somewhat arbitrary. It's big enough for huge
-      * shader constant set calls though */
-    BYTE data[sizeof(float) * 4 * 256 * 2];
+    LONG head, tail;
+    BYTE data[WINED3D_CS_QUEUE_SIZE];
 };
 
 struct wined3d_cs_ops
 {
     void *(*require_space)(struct wined3d_cs *cs, size_t size);
-    void (*submit)(struct wined3d_cs *cs);
+    void (*submit)(struct wined3d_cs *cs, size_t size);
     void (*finish)(struct wined3d_cs *cs);
 };
 
@@ -2607,14 +2606,9 @@ struct wined3d_cs
     struct wined3d_state state;
     HANDLE thread;
     DWORD thread_id;
-    DWORD tls_idx;
     struct wined3d_surface *onscreen_depth_stencil;
 
-    size_t data_size;
-    void *data;
-
-    struct wined3d_cs_list free_list;
-    struct wined3d_cs_list exec_list;
+    struct wined3d_cs_queue queue;
 
     LONG pending_presents;
 };
-- 
2.3.5

