[PATCH v2 7/7] wined3d: Handle NOOVERWRITE maps on persistently mapped Vulkan buffers from the client thread.

Zebediah Figura zfigura at codeweavers.com
Tue Oct 12 16:15:48 CDT 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/wined3d/adapter_gl.c      |  7 +++
 dlls/wined3d/adapter_vk.c      | 44 ++++++++++++------
 dlls/wined3d/buffer.c          |  1 +
 dlls/wined3d/cs.c              | 85 ++++++++++++++++++++++++++++++++--
 dlls/wined3d/directx.c         |  6 +++
 dlls/wined3d/wined3d_private.h | 21 +++++++++
 6 files changed, 146 insertions(+), 18 deletions(-)

diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c
index 3a6ff54eec2..33ec38ba6fc 100644
--- a/dlls/wined3d/adapter_gl.c
+++ b/dlls/wined3d/adapter_gl.c
@@ -4598,6 +4598,12 @@ static void adapter_gl_copy_bo_address(struct wined3d_context *context,
     wined3d_context_gl_copy_bo_address(wined3d_context_gl(context), dst, src, size);
 }
 
+static void adapter_gl_flush_bo_address(struct wined3d_context *context,
+        const struct wined3d_const_bo_address *data, size_t size)
+{
+    FIXME("context %p, data %s, size %zu, stub!\n", context, debug_const_bo_address(data), size);
+}
+
 static HRESULT adapter_gl_create_swapchain(struct wined3d_device *device,
         struct wined3d_swapchain_desc *desc, struct wined3d_swapchain_state_parent *state_parent,
         void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_swapchain **swapchain)
@@ -5050,6 +5056,7 @@ static const struct wined3d_adapter_ops wined3d_adapter_gl_ops =
     .adapter_map_bo_address = adapter_gl_map_bo_address,
     .adapter_unmap_bo_address = adapter_gl_unmap_bo_address,
     .adapter_copy_bo_address = adapter_gl_copy_bo_address,
+    .adapter_flush_bo_address = adapter_gl_flush_bo_address,
     .adapter_create_swapchain = adapter_gl_create_swapchain,
     .adapter_destroy_swapchain = adapter_gl_destroy_swapchain,
     .adapter_create_buffer = adapter_gl_create_buffer,
diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c
index c7005835d16..a983a05f300 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -1008,34 +1008,35 @@ map:
     return (uint8_t *)map_ptr + bo->b.memory_offset + (uintptr_t)data->addr;
 }
 
+static void flush_buffer_range(struct wined3d_context_vk *context_vk,
+        struct wined3d_bo_vk *bo, unsigned int offset, unsigned int size)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    VkMappedMemoryRange range;
+
+    range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
+    range.pNext = NULL;
+    range.memory = bo->vk_memory;
+    range.offset = bo->b.memory_offset + offset;
+    range.size = size;
+    VK_CALL(vkFlushMappedMemoryRanges(device_vk->vk_device, 1, &range));
+}
+
 static void adapter_vk_unmap_bo_address(struct wined3d_context *context,
         const struct wined3d_bo_address *data, unsigned int range_count, const struct wined3d_range *ranges)
 {
     struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
-    const struct wined3d_vk_info *vk_info;
-    struct wined3d_device_vk *device_vk;
-    VkMappedMemoryRange range;
     struct wined3d_bo_vk *bo;
     unsigned int i;
 
     if (!(bo = (struct wined3d_bo_vk *)data->buffer_object))
         return;
 
-    vk_info = context_vk->vk_info;
-    device_vk = wined3d_device_vk(context->device);
-
     if (!bo->b.coherent)
     {
-        range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
-        range.pNext = NULL;
-        range.memory = bo->vk_memory;
-
         for (i = 0; i < range_count; ++i)
-        {
-            range.offset = bo->b.memory_offset + ranges[i].offset;
-            range.size = ranges[i].size;
-            VK_CALL(vkFlushMappedMemoryRanges(device_vk->vk_device, 1, &range));
-        }
+            flush_buffer_range(context_vk, bo, ranges[i].offset, ranges[i].size);
     }
 
     wined3d_bo_vk_unmap(bo, context_vk);
@@ -1169,6 +1170,18 @@ void adapter_vk_copy_bo_address(struct wined3d_context *context,
     adapter_vk_unmap_bo_address(context, src, 0, NULL);
 }
 
+static void adapter_vk_flush_bo_address(struct wined3d_context *context,
+        const struct wined3d_const_bo_address *data, size_t size)
+{
+    struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
+    struct wined3d_bo_vk *bo;
+
+    if (!(bo = (struct wined3d_bo_vk *)data->buffer_object))
+        return;
+
+    flush_buffer_range(context_vk, bo, (uintptr_t)data->addr, size);
+}
+
 static HRESULT adapter_vk_create_swapchain(struct wined3d_device *device,
         struct wined3d_swapchain_desc *desc, struct wined3d_swapchain_state_parent *state_parent,
         void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_swapchain **swapchain)
@@ -1820,6 +1833,7 @@ static const struct wined3d_adapter_ops wined3d_adapter_vk_ops =
     .adapter_map_bo_address = adapter_vk_map_bo_address,
     .adapter_unmap_bo_address = adapter_vk_unmap_bo_address,
     .adapter_copy_bo_address = adapter_vk_copy_bo_address,
+    .adapter_flush_bo_address = adapter_vk_flush_bo_address,
     .adapter_create_swapchain = adapter_vk_create_swapchain,
     .adapter_destroy_swapchain = adapter_vk_destroy_swapchain,
     .adapter_create_buffer = adapter_vk_create_buffer,
diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c
index e1a5ec26c29..35c17cb8b65 100644
--- a/dlls/wined3d/buffer.c
+++ b/dlls/wined3d/buffer.c
@@ -938,6 +938,7 @@ static HRESULT buffer_resource_sub_resource_map(struct wined3d_resource *resourc
                 addr.buffer_object = buffer->buffer_object;
                 addr.addr = 0;
                 buffer->map_ptr = wined3d_context_map_bo_address(context, &addr, resource->size, flags);
+                buffer->resource.client.addr = addr;
 
                 if (((DWORD_PTR)buffer->map_ptr) & (RESOURCE_ALIGNMENT - 1))
                 {
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 5ffa27f5ce0..40935c9cdd8 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -118,6 +118,13 @@ ULONG CDECL wined3d_command_list_decref(struct wined3d_command_list *list)
     return refcount;
 }
 
+static void invalidate_client_address(struct wined3d_resource *resource)
+{
+    struct wined3d_client_resource *client = &resource->client;
+
+    memset(&client->addr, 0, sizeof(client->addr));
+}
+
 enum wined3d_cs_op
 {
     WINED3D_CS_OP_NOP,
@@ -2412,6 +2419,9 @@ static void wined3d_cs_acquire_command_list(struct wined3d_device_context *conte
 
     for (i = 0; i < list->command_list_count; ++i)
         wined3d_cs_acquire_command_list(context, list->command_lists[i]);
+
+    for (i = 0; i < list->upload_count; ++i)
+        invalidate_client_address(list->uploads[i].resource);
 }
 
 static void wined3d_cs_exec_preload_resource(struct wined3d_cs *cs, const void *data)
@@ -2449,6 +2459,8 @@ void wined3d_cs_emit_unload_resource(struct wined3d_cs *cs, struct wined3d_resou
 {
     struct wined3d_cs_unload_resource *op;
 
+    invalidate_client_address(resource);
+
     op = wined3d_device_context_require_space(&cs->c, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
     op->opcode = WINED3D_CS_OP_UNLOAD_RESOURCE;
     op->resource = resource;
@@ -2512,6 +2524,9 @@ HRESULT wined3d_device_context_emit_map(struct wined3d_device_context *context,
 
     wined3d_resource_wait_idle(resource);
 
+    /* We might end up invalidating the resource on the CS thread. */
+    invalidate_client_address(resource);
+
     if (!(op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_MAP)))
         return E_OUTOFMEMORY;
     op->opcode = WINED3D_CS_OP_MAP;
@@ -2686,6 +2701,11 @@ void wined3d_device_context_emit_blt_sub_resource(struct wined3d_device_context
 {
     struct wined3d_cs_blt_sub_resource *op;
 
+    /* If we are replacing the whole resource, the CS thread might discard and
+     * rename the buffer object, in which case ours is no longer valid. */
+    if (dst_resource->type == WINED3D_RTYPE_BUFFER && dst_box->right - dst_box->left == dst_resource->size)
+        invalidate_client_address(dst_resource);
+
     op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
     op->opcode = WINED3D_CS_OP_BLT_SUB_RESOURCE;
     op->dst_resource = dst_resource;
@@ -2725,8 +2745,12 @@ static void wined3d_cs_exec_update_sub_resource(struct wined3d_cs *cs, const voi
     if (resource->type == WINED3D_RTYPE_BUFFER)
     {
         struct wined3d_buffer *buffer = buffer_from_resource(resource);
+        size_t size = box->right - box->left;
 
-        wined3d_buffer_copy_bo_address(buffer, context, box->left, &op->bo.addr, box->right - box->left);
+        if (op->bo.addr.buffer_object && op->bo.addr.buffer_object == buffer->buffer_object)
+            wined3d_context_flush_bo_address(context, &op->bo.addr, size);
+        else
+            wined3d_buffer_copy_bo_address(buffer, context, box->left, &op->bo.addr, size);
         goto done;
     }
 
@@ -2767,6 +2791,11 @@ void wined3d_device_context_emit_update_sub_resource(struct wined3d_device_conte
     struct wined3d_box dummy_box;
     struct upload_bo bo;
 
+    /* If we are replacing the whole resource, the CS thread might discard and
+     * rename the buffer object, in which case ours is no longer valid. */
+    if (resource->type == WINED3D_RTYPE_BUFFER && box->right - box->left == resource->size)
+        invalidate_client_address(resource);
+
     if (context->ops->map_upload_bo(context, resource, sub_resource_idx, &map_desc, box, WINED3D_MAP_WRITE))
     {
         wined3d_format_copy_data(resource->format, data, row_pitch, slice_pitch, map_desc.data, map_desc.row_pitch,
@@ -3090,14 +3119,64 @@ static void wined3d_cs_st_finish(struct wined3d_device_context *context, enum wi
 static bool wined3d_cs_map_upload_bo(struct wined3d_device_context *context, struct wined3d_resource *resource,
         unsigned int sub_resource_idx, struct wined3d_map_desc *map_desc, const struct wined3d_box *box, uint32_t flags)
 {
-    /* FIXME: We would like to return mapped or newly allocated memory here. */
+    /* Limit NOOVERWRITE maps to buffers for now; there are too many ways that
+     * a texture can be invalidated to even count. */
+    if (wined3d_map_persistent() && resource->type == WINED3D_RTYPE_BUFFER && (flags & WINED3D_MAP_NOOVERWRITE))
+    {
+        struct wined3d_client_resource *client = &resource->client;
+        const struct wined3d_bo *bo;
+        uint8_t *map_ptr;
+
+        bo = (const struct wined3d_bo *)client->addr.buffer_object;
+        map_ptr = bo ? bo->map_ptr : NULL;
+        map_ptr += (uintptr_t)client->addr.addr;
+
+        if (!map_ptr)
+        {
+            TRACE("Sub-resource is not persistently mapped.\n");
+            return false;
+        }
+
+        wined3d_resource_get_sub_resource_map_pitch(resource, sub_resource_idx,
+                &map_desc->row_pitch, &map_desc->slice_pitch);
+
+        client->mapped_upload.addr = *wined3d_const_bo_address(&client->addr);
+        client->mapped_upload.flags = 0;
+        if (bo)
+            map_ptr += bo->memory_offset;
+        map_desc->data = resource_offset_map_pointer(resource, sub_resource_idx, map_ptr, box);
+
+        if (!bo->coherent)
+            client->mapped_upload.flags |= UPLOAD_BO_UPLOAD_ON_UNMAP;
+
+        client->mapped_box = *box;
+
+        TRACE("Returning bo %s, flags %#x.\n", debug_const_bo_address(&client->mapped_upload.addr),
+                client->mapped_upload.flags);
+        return true;
+    }
+
     return false;
 }
 
+static bool wined3d_bo_address_is_null(struct wined3d_const_bo_address *addr)
+{
+    return !addr->buffer_object && !addr->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)
 {
-    return false;
+    struct wined3d_client_resource *client = &resource->client;
+
+    if (wined3d_bo_address_is_null(&client->mapped_upload.addr))
+        return false;
+
+    *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));
+    return true;
 }
 
 static const struct wined3d_device_context_ops wined3d_cs_st_ops =
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 990164fd68d..58aaf44fc45 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -2798,6 +2798,11 @@ static void adapter_no3d_copy_bo_address(struct wined3d_context *context,
     memcpy(dst->addr, src->addr, size);
 }
 
+static void adapter_no3d_flush_bo_address(struct wined3d_context *context,
+        const struct wined3d_const_bo_address *data, size_t size)
+{
+}
+
 static HRESULT adapter_no3d_create_swapchain(struct wined3d_device *device,
         struct wined3d_swapchain_desc *desc, struct wined3d_swapchain_state_parent *state_parent,
         void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_swapchain **swapchain)
@@ -3067,6 +3072,7 @@ static const struct wined3d_adapter_ops wined3d_adapter_no3d_ops =
     .adapter_map_bo_address = adapter_no3d_map_bo_address,
     .adapter_unmap_bo_address = adapter_no3d_unmap_bo_address,
     .adapter_copy_bo_address = adapter_no3d_copy_bo_address,
+    .adapter_flush_bo_address = adapter_no3d_flush_bo_address,
     .adapter_create_swapchain = adapter_no3d_create_swapchain,
     .adapter_destroy_swapchain = adapter_no3d_destroy_swapchain,
     .adapter_create_buffer = adapter_no3d_create_buffer,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 73d8aab56be..609dd3c6f9c 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -3366,6 +3366,8 @@ struct wined3d_adapter_ops
             unsigned int range_count, const struct wined3d_range *ranges);
     void (*adapter_copy_bo_address)(struct wined3d_context *context,
             const struct wined3d_bo_address *dst, const struct wined3d_bo_address *src, size_t size);
+    void (*adapter_flush_bo_address)(struct wined3d_context *context,
+            const struct wined3d_const_bo_address *data, size_t size);
     HRESULT (*adapter_create_swapchain)(struct wined3d_device *device,
             struct wined3d_swapchain_desc *desc,
             struct wined3d_swapchain_state_parent *state_parent, void *parent,
@@ -4113,6 +4115,17 @@ const char *wined3d_debug_view_desc(const struct wined3d_view_desc *d,
         const struct wined3d_resource *resource) DECLSPEC_HIDDEN;
 const char *wined3d_debug_vkresult(VkResult vr) DECLSPEC_HIDDEN;
 
+struct wined3d_client_resource
+{
+    /* The resource's persistently mapped address, which we may use to perform
+     * NOOVERWRITE maps from the client thread. */
+    struct wined3d_bo_address addr;
+
+    /* The currently mapped upload BO, if applicable, and box. */
+    struct upload_bo mapped_upload;
+    struct wined3d_box mapped_box;
+};
+
 static inline BOOL wined3d_resource_access_is_managed(unsigned int access)
 {
     return !(~access & (WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_CPU));
@@ -4158,6 +4171,8 @@ struct wined3d_resource
     DWORD priority;
     void *heap_memory;
 
+    struct wined3d_client_resource client;
+
     void *parent;
     const struct wined3d_parent_ops *parent_ops;
     const struct wined3d_resource_ops *resource_ops;
@@ -6233,6 +6248,12 @@ static inline void wined3d_context_copy_bo_address(struct wined3d_context *conte
     context->device->adapter->adapter_ops->adapter_copy_bo_address(context, dst, src, size);
 }
 
+static inline void wined3d_context_flush_bo_address(struct wined3d_context *context,
+        const struct wined3d_const_bo_address *data, size_t size)
+{
+    context->device->adapter->adapter_ops->adapter_flush_bo_address(context, data, size);
+}
+
 static inline void wined3d_context_vk_reference_bo(const struct wined3d_context_vk *context_vk,
         struct wined3d_bo_vk *bo)
 {
-- 
2.33.0




More information about the wine-devel mailing list