From 1cef78c738df6bffaeb1674962f5793444747119 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20D=C3=B6singer?= <stefan@codeweavers.com>
Date: Thu, 4 Apr 2013 11:50:09 +0200
Subject: wined3d: Request a glFinish before modifying resources outside the cs

---
 dlls/wined3d/buffer.c          | 17 +++++++++++++++++
 dlls/wined3d/cs.c              | 30 ++++++++++++++++++++++++++++++
 dlls/wined3d/device.c          | 35 +++++++++++++++++++++++++++++++++++
 dlls/wined3d/resource.c        |  7 +++++++
 dlls/wined3d/surface.c         |  7 +++++++
 dlls/wined3d/wined3d_private.h |  1 +
 6 files changed, 97 insertions(+)

diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c
index 6271307..87d0b91 100644
--- a/dlls/wined3d/buffer.c
+++ b/dlls/wined3d/buffer.c
@@ -931,6 +931,15 @@ void buffer_internal_preload(struct wined3d_buffer *buffer, struct wined3d_conte
 void CDECL wined3d_buffer_preload(struct wined3d_buffer *buffer)
 {
     struct wined3d_context *context;
+    struct wined3d_device *device = buffer->resource.device;
+
+    if (wined3d_settings.cs_multithreaded)
+    {
+        FIXME("Waiting for cs.\n");
+        wined3d_cs_emit_glfinish(device->cs);
+        device->cs->ops->finish(device->cs);
+    }
+
     context = context_acquire(buffer->resource.device, NULL);
     buffer_internal_preload(buffer, context, NULL);
     context_release(context);
@@ -947,9 +956,17 @@ HRESULT CDECL wined3d_buffer_map(struct wined3d_buffer *buffer, UINT offset, UIN
 {
     LONG count;
     BYTE *base;
+    struct wined3d_device *device = buffer->resource.device;
 
     TRACE("buffer %p, offset %u, size %u, data %p, flags %#x\n", buffer, offset, size, data, flags);
 
+    if (wined3d_settings.cs_multithreaded)
+    {
+        FIXME("Waiting for cs.\n");
+        wined3d_cs_emit_glfinish(device->cs);
+        device->cs->ops->finish(device->cs);
+    }
+
     flags = wined3d_resource_sanitize_map_flags(&buffer->resource, flags);
     /* Filter redundant WINED3D_MAP_DISCARD maps. The 3DMark2001 multitexture
      * fill rate test seems to depend on this. When we map a buffer with
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index a675ce9..e42cbe0 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -66,6 +66,7 @@ enum wined3d_cs_op
     WINED3D_CS_OP_STATEBLOCK,
     WINED3D_CS_OP_SET_VS_CONSTS_F,
     WINED3D_CS_OP_SET_PS_CONSTS_F,
+    WINED3D_CS_OP_GLFINISH,
     WINED3D_CS_OP_STOP,
 };
 
@@ -294,6 +295,11 @@ struct wined3d_cs_set_consts_f
     float constants[4];
 };
 
+struct wined3d_cs_finish
+{
+    enum wined3d_cs_op opcode;
+};
+
 /* 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)
 {
@@ -1364,6 +1370,29 @@ void wined3d_cs_emit_reset_state(struct wined3d_cs *cs)
     cs->ops->submit(cs);
 }
 
+static UINT wined3d_cs_exec_glfinish(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_finish *op = data;
+    struct wined3d_device *device = cs->device;
+    struct wined3d_context *context;
+
+    context = context_acquire(device, NULL);
+    context->gl_info->gl_ops.gl.p_glFinish();
+    context_release(context);
+
+    return sizeof(*op);
+}
+
+void wined3d_cs_emit_glfinish(struct wined3d_cs *cs)
+{
+    struct wined3d_cs_finish *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_GLFINISH;
+
+    cs->ops->submit(cs);
+}
+
 static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
 {
     /* WINED3D_CS_OP_FENCE                      */ wined3d_cs_exec_fence,
@@ -1396,6 +1425,7 @@ static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
     /* WINED3D_CS_OP_STATEBLOCK                 */ wined3d_cs_exec_transfer_stateblock,
     /* WINED3D_CS_OP_SET_VS_CONSTS_F            */ wined3d_cs_exec_set_vs_consts_f,
     /* WINED3D_CS_OP_SET_PS_CONSTS_F            */ wined3d_cs_exec_set_ps_consts_f,
+    /* WINED3D_CS_OP_GLFINISH                   */ wined3d_cs_exec_glfinish,
 };
 
 static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 533df12..7cc2574 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -2857,6 +2857,13 @@ static HRESULT process_vertices_strided(const struct wined3d_device *device, DWO
         return hr;
     }
 
+    if (wined3d_settings.cs_multithreaded)
+    {
+        FIXME("Waiting for cs.\n");
+        wined3d_cs_emit_glfinish(device->cs);
+        device->cs->ops->finish(device->cs);
+    }
+
     wined3d_device_get_transform(device, WINED3D_TS_VIEW, &view_mat);
     wined3d_device_get_transform(device, WINED3D_TS_PROJECTION, &proj_mat);
     wined3d_device_get_transform(device, WINED3D_TS_WORLD_MATRIX(0), &world_mat);
@@ -3644,6 +3651,13 @@ HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
         ++src_skip_levels;
     }
 
+    if (wined3d_settings.cs_multithreaded)
+    {
+        FIXME("Waiting for cs.\n");
+        wined3d_cs_emit_glfinish(device->cs);
+        device->cs->ops->finish(device->cs);
+    }
+
     /* Make sure that the destination texture is loaded. */
     context = context_acquire(device, NULL);
     wined3d_texture_load(dst_texture, context, FALSE);
@@ -4131,6 +4145,13 @@ HRESULT CDECL wined3d_device_clear_rendertarget_view(struct wined3d_device *devi
         rect = &r;
     }
 
+    if (wined3d_settings.cs_multithreaded)
+    {
+        FIXME("Waiting for cs.\n");
+        wined3d_cs_emit_glfinish(device->cs);
+        device->cs->ops->finish(device->cs);
+    }
+
     resource = wined3d_texture_get_sub_resource(wined3d_texture_from_resource(resource), view->sub_resource_idx);
 
     return surface_color_fill(surface_from_resource(resource), rect, color);
@@ -4454,6 +4475,13 @@ void CDECL wined3d_device_evict_managed_resources(struct wined3d_device *device)
 
     TRACE("device %p.\n", device);
 
+    if (wined3d_settings.cs_multithreaded)
+    {
+        FIXME("Waiting for cs.\n");
+        wined3d_cs_emit_glfinish(device->cs);
+        device->cs->ops->finish(device->cs);
+    }
+
     LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
     {
         TRACE("Checking resource %p for eviction.\n", resource);
@@ -4579,6 +4607,13 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
     TRACE("device %p, swapchain_desc %p, mode %p, callback %p, reset_state %#x.\n",
             device, swapchain_desc, mode, callback, reset_state);
 
+    if (wined3d_settings.cs_multithreaded)
+    {
+        FIXME("Waiting for cs.\n");
+        wined3d_cs_emit_glfinish(device->cs);
+        device->cs->ops->finish(device->cs);
+    }
+
     if (!(swapchain = wined3d_device_get_swapchain(device, 0)))
     {
         ERR("Failed to get the first implicit swapchain.\n");
diff --git a/dlls/wined3d/resource.c b/dlls/wined3d/resource.c
index 8d372b9..fb84a0f 100644
--- a/dlls/wined3d/resource.c
+++ b/dlls/wined3d/resource.c
@@ -812,6 +812,13 @@ HRESULT wined3d_resource_map(struct wined3d_resource *resource,
 
     flags = wined3d_resource_sanitize_map_flags(resource, flags);
 
+    if (wined3d_settings.cs_multithreaded)
+    {
+        FIXME("Waiting for cs.\n");
+        wined3d_cs_emit_glfinish(device->cs);
+        device->cs->ops->finish(device->cs);
+    }
+
     if (device->d3d_initialized)
         context = context_acquire(device, NULL);
 
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 3fc06c5..ca4209d 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -4728,6 +4728,13 @@ HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst
         flags &= ~WINED3D_BLT_DO_NOT_WAIT;
     }
 
+    if (wined3d_settings.cs_multithreaded)
+    {
+        FIXME("Waiting for cs.\n");
+        wined3d_cs_emit_glfinish(device->cs);
+        device->cs->ops->finish(device->cs);
+    }
+
     if (!device->d3d_initialized)
     {
         WARN("D3D not initialized, using fallback.\n");
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index f6bd5b9..6deba20 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2827,6 +2827,7 @@ void wined3d_cs_emit_set_vertex_declaration(struct wined3d_cs *cs,
 void wined3d_cs_emit_set_viewport(struct wined3d_cs *cs, const struct wined3d_viewport *viewport) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_set_consts_f(struct wined3d_cs *cs, UINT start_register, const float *constants,
         UINT vector4f_count, enum wined3d_shader_type type) DECLSPEC_HIDDEN;
+void wined3d_cs_emit_glfinish(struct wined3d_cs *cs) DECLSPEC_HIDDEN;
 
 /* Direct3D terminology with little modifications. We do not have an issued state
  * because only the driver knows about it, but we have a created state because d3d
-- 
2.7.1

