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@codeweavers.com --- 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 f09cd1b0fae..a47eb1758ac 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 aae7fbdddba..0a35f193f0f 100644 --- a/dlls/wined3d/context_gl.c +++ b/dlls/wined3d/context_gl.c @@ -2942,7 +2942,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)); @@ -3209,6 +3220,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 74e23bbb5e1..23d94fd32d2 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 ed5b289b8d8..5d3a2cc9076 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -22,6 +22,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);
@@ -3080,7 +3081,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) @@ -3096,13 +3097,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; }
@@ -3138,14 +3155,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 807a002b1f1..253986db18d 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; };
@@ -3937,6 +3940,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; @@ -3958,6 +3963,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;