Zebediah Figura : wined3d: Keep a client reference count for the BO map pointer.

Alexandre Julliard julliard at winehq.org
Mon Feb 14 15:41:32 CST 2022


Module: wine
Branch: master
Commit: 831ff102008e2ba93a403344646b5ed67258eaeb
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=831ff102008e2ba93a403344646b5ed67258eaeb

Author: Zebediah Figura <zfigura at codeweavers.com>
Date:   Fri Feb 11 19:42:03 2022 -0600

wined3d: Keep a client reference count for the BO map pointer.

Currently this has no effect. Depending on whether wined3d_map_persistent()
returns true, either the client thread doesn't access the map pointer outside of
d3d map requests, or the BO is never unmapped. However, we'd like to be able to
let NOOVERWRITE maps be accelerated while still being able to unmap arbitrary
BOs at arbitrary times from the CS thread.

Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/wined3d/adapter_vk.c      | 11 +++++++++++
 dlls/wined3d/context_gl.c      | 12 ++++++++++++
 dlls/wined3d/context_vk.c      |  2 ++
 dlls/wined3d/cs.c              | 38 ++++++++++++++++++++++++++++++++------
 dlls/wined3d/device.c          |  4 ++++
 dlls/wined3d/wined3d_private.h | 15 +++++++++++++++
 6 files changed, 76 insertions(+), 6 deletions(-)

diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c
index 53591cdcaa6..239cd7cca8d 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -831,7 +831,18 @@ static void wined3d_bo_vk_unmap(struct wined3d_bo_vk *bo, struct wined3d_context
         return;
     }
 
+    wined3d_device_bo_map_lock(context_vk->c.device);
+    /* The mapping is still in use by the client (viz. for an accelerated
+     * NOOVERWRITE map). The client will trigger another unmap request when the
+     * d3d application requests to unmap the BO. */
+    if (bo->b.client_map_count)
+    {
+        wined3d_device_bo_map_unlock(context_vk->c.device);
+        TRACE("BO %p is still in use by a client thread; not unmapping.\n", bo);
+        return;
+    }
     bo->b.map_ptr = NULL;
+    wined3d_device_bo_map_unlock(context_vk->c.device);
 
     if ((slab = bo->slab))
     {
diff --git a/dlls/wined3d/context_gl.c b/dlls/wined3d/context_gl.c
index c6816d97c63..23bac4de133 100644
--- a/dlls/wined3d/context_gl.c
+++ b/dlls/wined3d/context_gl.c
@@ -2953,7 +2953,18 @@ static void wined3d_bo_gl_unmap(struct wined3d_bo_gl *bo, struct wined3d_context
         return;
     }
 
+    wined3d_device_bo_map_lock(context_gl->c.device);
+    /* The mapping is still in use by the client (viz. for an accelerated
+     * NOOVERWRITE map). The client will trigger another unmap request when the
+     * d3d application requests to unmap the BO. */
+    if (bo->b.client_map_count)
+    {
+        wined3d_device_bo_map_unlock(context_gl->c.device);
+        TRACE("BO %p is still in use by a client thread; not unmapping.\n", bo);
+        return;
+    }
     bo->b.map_ptr = NULL;
+    wined3d_device_bo_map_unlock(context_gl->c.device);
 
     wined3d_context_gl_bind_bo(context_gl, bo->binding, bo->id);
     GL_EXTCALL(glUnmapBuffer(bo->binding));
@@ -3220,6 +3231,7 @@ bool wined3d_context_gl_create_bo(struct wined3d_context_gl *context_gl, GLsizei
     bo->b.buffer_offset = buffer_offset;
     bo->b.memory_offset = bo->b.buffer_offset;
     bo->b.map_ptr = NULL;
+    bo->b.client_map_count = 0;
 
     return true;
 }
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c
index 98610d65c5d..61056a7f8cb 100644
--- a/dlls/wined3d/context_vk.c
+++ b/dlls/wined3d/context_vk.c
@@ -463,6 +463,7 @@ static bool wined3d_context_vk_create_slab_bo(struct wined3d_context_vk *context
     *bo = slab->bo;
     bo->memory = NULL;
     bo->slab = slab;
+    bo->b.client_map_count = 0;
     bo->b.map_ptr = NULL;
     bo->b.buffer_offset = idx * object_size;
     bo->b.memory_offset = slab->bo.b.memory_offset + bo->b.buffer_offset;
@@ -541,6 +542,7 @@ BOOL wined3d_context_vk_create_bo(struct wined3d_context_vk *context_vk, VkDevic
         return FALSE;
     }
 
+    bo->b.client_map_count = 0;
     bo->b.map_ptr = NULL;
     bo->b.buffer_offset = 0;
     bo->size = size;
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 27a597d0b74..ed8a41c778b 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -20,6 +20,7 @@
 #include "wined3d_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
+WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
 WINE_DECLARE_DEBUG_CHANNEL(d3d_sync);
 WINE_DECLARE_DEBUG_CHANNEL(fps);
 
@@ -3079,7 +3080,7 @@ static bool wined3d_cs_map_upload_bo(struct wined3d_device_context *context, str
         struct wined3d_client_resource *client = &resource->client;
         struct wined3d_device *device = context->device;
         struct wined3d_bo_address addr;
-        const struct wined3d_bo *bo;
+        struct wined3d_bo *bo;
         uint8_t *map_ptr;
 
         if (flags & WINED3D_MAP_DISCARD)
@@ -3095,13 +3096,29 @@ static bool wined3d_cs_map_upload_bo(struct wined3d_device_context *context, str
             addr = client->addr;
         }
 
-        bo = addr.buffer_object;
-        map_ptr = bo ? bo->map_ptr : NULL;
+        map_ptr = NULL;
+        if ((bo = addr.buffer_object))
+        {
+            wined3d_device_bo_map_lock(device);
+            if ((map_ptr = bo->map_ptr))
+                ++bo->client_map_count;
+            wined3d_device_bo_map_unlock(device);
+
+            if (!map_ptr)
+            {
+                /* adapter_alloc_bo() should have given us a mapped BO if we are
+                 * discarding. */
+                assert(flags & WINED3D_MAP_NOOVERWRITE);
+                WARN_(d3d_perf)("Not accelerating a NOOVERWRITE map because the BO is not mapped.\n");
+                return false;
+            }
+        }
         map_ptr += (uintptr_t)addr.addr;
 
         if (!map_ptr)
         {
-            TRACE("Sub-resource is not mapped.\n");
+            assert(flags & WINED3D_MAP_NOOVERWRITE);
+            WARN_(d3d_perf)("Not accelerating a NOOVERWRITE map because the sub-resource has no valid address.\n");
             return false;
         }
 
@@ -3140,14 +3157,23 @@ static bool wined3d_bo_address_is_null(struct wined3d_const_bo_address *addr)
 }
 
 static bool wined3d_cs_unmap_upload_bo(struct wined3d_device_context *context, struct wined3d_resource *resource,
-        unsigned int sub_resource_idx, struct wined3d_box *box, struct upload_bo *bo)
+        unsigned int sub_resource_idx, struct wined3d_box *box, struct upload_bo *upload_bo)
 {
     struct wined3d_client_resource *client = &resource->client;
+    struct wined3d_device *device = context->device;
+    struct wined3d_bo *bo;
 
     if (wined3d_bo_address_is_null(&client->mapped_upload.addr))
         return false;
 
-    *bo = client->mapped_upload;
+    if ((bo = client->mapped_upload.addr.buffer_object))
+    {
+        wined3d_device_bo_map_lock(device);
+        --bo->client_map_count;
+        wined3d_device_bo_map_unlock(device);
+    }
+
+    *upload_bo = client->mapped_upload;
     *box = client->mapped_box;
     memset(&client->mapped_upload, 0, sizeof(client->mapped_upload));
     memset(&client->mapped_box, 0, sizeof(client->mapped_box));
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 09be992dd2f..4dac9220f0f 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -246,6 +246,8 @@ void wined3d_device_cleanup(struct wined3d_device *device)
     wine_rb_destroy(&device->depth_stencil_states, device_leftover_depth_stencil_state, NULL);
     wine_rb_destroy(&device->so_descs, device_free_so_desc, NULL);
 
+    wined3d_lock_cleanup(&device->bo_map_lock);
+
     wined3d_decref(device->wined3d);
     device->wined3d = NULL;
 }
@@ -5971,6 +5973,8 @@ HRESULT wined3d_device_init(struct wined3d_device *device, struct wined3d *wined
         goto err;
     }
 
+    wined3d_lock_init(&device->bo_map_lock, "wined3d_device.bo_map_lock");
+
     return WINED3D_OK;
 
 err:
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index dd0a49db3b5..d0e4f0cdfaf 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1605,10 +1605,13 @@ do {                                                                \
 
 struct wined3d_bo
 {
+    /* client_map_count and map_ptr are accessed from both the client and CS
+     * threads, and protected by wined3d_device.bo_map_lock. */
     struct list users;
     void *map_ptr;
     size_t buffer_offset;
     size_t memory_offset;
+    unsigned int client_map_count;
     bool coherent;
 };
 
@@ -3946,6 +3949,8 @@ struct wined3d_device
     /* Context management */
     struct wined3d_context **contexts;
     UINT context_count;
+
+    CRITICAL_SECTION bo_map_lock;
 };
 
 void wined3d_device_cleanup(struct wined3d_device *device) DECLSPEC_HIDDEN;
@@ -3967,6 +3972,16 @@ HRESULT wined3d_device_set_implicit_swapchain(struct wined3d_device *device,
         struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
 void wined3d_device_uninit_3d(struct wined3d_device *device) DECLSPEC_HIDDEN;
 
+static inline void wined3d_device_bo_map_lock(struct wined3d_device *device)
+{
+    EnterCriticalSection(&device->bo_map_lock);
+}
+
+static inline void wined3d_device_bo_map_unlock(struct wined3d_device *device)
+{
+    LeaveCriticalSection(&device->bo_map_lock);
+}
+
 struct wined3d_device_no3d
 {
     struct wined3d_device d;




More information about the wine-cvs mailing list