From 593ea392aa3b805c14e6a1a9cf3fb3e9e5b077d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20D=C3=B6singer?= <stefan@codeweavers.com>
Date: Sat, 6 Jul 2013 17:05:12 +0200
Subject: wined3d: Access the buffer dirty areas through the CS

This avoids the following issues:

1) The worker thread uploading a dirtified area before the application
unlocks the buffer and marking it clean

2) The worker thread uploading data from the old memory and marking the
area clean although the data was written to a new block of memory.

However, this adds more synchronization than necessary. The first
problem could be solved by moving dirtification to unmap, e.g. via a
flag in each dirty area. The second problem can be fixed by not
dirtifying in map if map_mem != resource.allocatedMemory and dirtifying
the entire buffer in buffer_swap_memory (DISCARD dirtifies the entire
buffer anyway, and this could be the reason why).

If one of those ideas is used, access to the dirty area array needs to
be protected by locks.
---
 dlls/wined3d/buffer.c          |  6 +++---
 dlls/wined3d/cs.c              | 31 +++++++++++++++++++++++++++++++
 dlls/wined3d/wined3d_private.h |  3 +++
 3 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c
index 7d1a532..9b6ccc8 100644
--- a/dlls/wined3d/buffer.c
+++ b/dlls/wined3d/buffer.c
@@ -41,7 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d);
 #define VB_MAXFULLCONVERSIONS 5       /* Number of full conversions before we stop converting */
 #define VB_RESETFULLCONVS     20      /* Reset full conversion counts after that number of draws */
 
-static void buffer_invalidate_bo_range(struct wined3d_buffer *buffer, UINT offset, UINT size)
+void buffer_invalidate_bo_range(struct wined3d_buffer *buffer, UINT offset, UINT size)
 {
     if (!offset && !size)
         goto invalidate_all;
@@ -979,9 +979,9 @@ HRESULT CDECL wined3d_buffer_map(struct wined3d_buffer *buffer, UINT offset, UIN
          * being uploaded in that case. Two such applications are Port Royale
          * and Darkstar One. */
         if (flags & WINED3D_MAP_DISCARD)
-            buffer_invalidate_bo_range(buffer, 0, 0);
+            wined3d_cs_emit_buffer_invalidate_bo_range(device->cs, buffer, 0, 0);
         else if (!(flags & WINED3D_MAP_READONLY))
-            buffer_invalidate_bo_range(buffer, offset, size);
+            wined3d_cs_emit_buffer_invalidate_bo_range(device->cs, buffer, offset, size);
 
         if (!(buffer->flags & WINED3D_BUFFER_DOUBLEBUFFER))
         {
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index cd234d3..5fe0092 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -70,6 +70,7 @@ enum wined3d_cs_op
     WINED3D_CS_OP_RESOURCE_MAP,
     WINED3D_CS_OP_RESOURCE_UNMAP,
     WINED3D_CS_OP_BUFFER_SWAP_MEM,
+    WINED3D_CS_OP_BUFFER_INVALIDATE_RANGE,
     WINED3D_CS_OP_QUERY_ISSUE,
     WINED3D_CS_OP_QUERY_DESTROY,
     WINED3D_CS_OP_TEXTURE_PRELOAD,
@@ -390,6 +391,13 @@ struct wined3d_cs_buffer_swap_mem
     BYTE *mem;
 };
 
+struct wined3d_cs_buffer_invalidate_bo_range
+{
+    enum wined3d_cs_op opcode;
+    struct wined3d_buffer *buffer;
+    UINT offset, size;
+};
+
 struct wined3d_cs_skip
 {
     enum wined3d_cs_op opcode;
@@ -2176,6 +2184,28 @@ void wined3d_cs_emit_buffer_swap_mem(struct wined3d_cs *cs, struct wined3d_buffe
     cs->ops->submit(cs, sizeof(*op));
 }
 
+static UINT wined3d_cs_exec_buffer_invalidate_bo_range(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_buffer_invalidate_bo_range *op = data;
+
+    buffer_invalidate_bo_range(op->buffer, op->offset, op->size);
+    return sizeof(*op);
+}
+
+void wined3d_cs_emit_buffer_invalidate_bo_range(struct wined3d_cs *cs,
+        struct wined3d_buffer *buffer, UINT offset, UINT size)
+{
+    struct wined3d_cs_buffer_invalidate_bo_range *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_BUFFER_INVALIDATE_RANGE;
+    op->buffer = buffer;
+    op->offset = offset;
+    op->size = size;
+
+    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,
@@ -2224,6 +2254,7 @@ static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
     /* WINED3D_CS_OP_RESOURCE_MAP               */ wined3d_cs_exec_resource_map,
     /* WINED3D_CS_OP_RESOURCE_UNMAP             */ wined3d_cs_exec_resource_unmap,
     /* 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_QUERY_ISSUE                */ wined3d_cs_exec_query_issue,
     /* WINED3D_CS_OP_QUERY_DESTROY              */ wined3d_cs_exec_query_destroy,
     /* WINED3D_CS_OP_TEXTURE_PRELOAD            */ wined3d_cs_exec_texture_preload,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b0390e3..4335a6a 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2904,6 +2904,8 @@ void wined3d_cs_emit_update_texture(struct wined3d_cs *cs, struct wined3d_textur
 void wined3d_cs_emit_evict_resource(struct wined3d_cs *cs, struct wined3d_resource *resource) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_buffer_swap_mem(struct wined3d_cs *cs, struct wined3d_buffer *buffer,
         BYTE *mem) DECLSPEC_HIDDEN;
+void wined3d_cs_emit_buffer_invalidate_bo_range(struct wined3d_cs *cs,
+        struct wined3d_buffer *buffer, UINT offset, UINT size) 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
@@ -2989,6 +2991,7 @@ void buffer_get_memory(struct wined3d_buffer *buffer, struct wined3d_context *co
 BYTE *buffer_get_sysmem(struct wined3d_buffer *This, struct wined3d_context *context) DECLSPEC_HIDDEN;
 void buffer_internal_preload(struct wined3d_buffer *buffer, struct wined3d_context *context,
         const struct wined3d_state *state) DECLSPEC_HIDDEN;
+void buffer_invalidate_bo_range(struct wined3d_buffer *This, UINT offset, UINT size) DECLSPEC_HIDDEN;
 HRESULT wined3d_buffer_upload_data(struct wined3d_buffer *buffer,
         const struct wined3d_box *box, const void *data) DECLSPEC_HIDDEN;
 
-- 
2.7.0

