[PATCH v2 7/7] wined3d: Try to allocate new Vulkan BOs from the client thread for DISCARD maps.

Zebediah Figura zfigura at codeweavers.com
Wed Nov 3 23:47:01 CDT 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/wined3d/adapter_gl.c      |  7 ++++
 dlls/wined3d/adapter_vk.c      | 49 +++++++++++++++++++++++++
 dlls/wined3d/buffer.c          | 65 ++++++++++++++++++++++++++++++++--
 dlls/wined3d/cs.c              | 16 ++++++++-
 dlls/wined3d/directx.c         |  7 ++++
 dlls/wined3d/wined3d_private.h | 18 ++++++++++
 6 files changed, 159 insertions(+), 3 deletions(-)

diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c
index f1cdbffe718..37f055662ea 100644
--- a/dlls/wined3d/adapter_gl.c
+++ b/dlls/wined3d/adapter_gl.c
@@ -4604,6 +4604,12 @@ static void adapter_gl_flush_bo_address(struct wined3d_context *context,
     wined3d_context_gl_flush_bo_address(wined3d_context_gl(context), data, size);
 }
 
+static bool adapter_gl_alloc_bo(struct wined3d_device *device, struct wined3d_resource *resource,
+        unsigned int sub_resource_idx, struct wined3d_bo_address *addr)
+{
+    return false;
+}
+
 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)
@@ -5057,6 +5063,7 @@ static const struct wined3d_adapter_ops wined3d_adapter_gl_ops =
     .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_alloc_bo = adapter_gl_alloc_bo,
     .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 f8fa9b78811..372d49d6e3d 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -23,6 +23,7 @@
 #include "wine/vulkan_driver.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
+WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
 
 static const struct wined3d_state_entry_template misc_state_template_vk[] =
 {
@@ -1216,6 +1217,53 @@ static void adapter_vk_flush_bo_address(struct wined3d_context *context,
     flush_bo_range(context_vk, bo, (uintptr_t)data->addr, size);
 }
 
+struct wined3d_client_bo_vk_map_ctx
+{
+    struct wined3d_device *device;
+    struct wined3d_client_bo_vk *client_bo;
+};
+
+static bool adapter_vk_alloc_bo(struct wined3d_device *device, struct wined3d_resource *resource,
+        unsigned int sub_resource_idx, struct wined3d_bo_address *addr)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(device);
+    struct wined3d_context_vk *context_vk = &device_vk->context_vk;
+
+    wined3d_not_from_cs(device->cs);
+    assert(device->context_count);
+
+    if (resource->type == WINED3D_RTYPE_BUFFER)
+    {
+        struct wined3d_client_bo_vk *client_bo;
+
+        if (!(client_bo = heap_alloc(sizeof(*client_bo))))
+            return false;
+
+        if (!(wined3d_context_vk_create_bo(context_vk, resource->size,
+                vk_buffer_usage_from_bind_flags(resource->bind_flags),
+                vk_memory_type_from_access_flags(resource->access, resource->usage), &client_bo->bo)))
+        {
+            WARN("Failed to create Vulkan buffer.\n");
+            return FALSE;
+        }
+
+        if (!client_bo->bo.b.map_ptr)
+        {
+            WARN_(d3d_perf)("BO %p (chunk %p, slab %p) is not persistently mapped.\n", &client_bo->bo,
+                    client_bo->bo.memory ? client_bo->bo.memory->chunk : NULL, client_bo->bo.slab);
+
+            if (!wined3d_bo_vk_map(&client_bo->bo, context_vk))
+                ERR("Failed to map bo.\n");
+        }
+
+        addr->buffer_object = (uintptr_t)&client_bo->bo;
+        addr->addr = NULL;
+        return true;
+    }
+
+    return false;
+}
+
 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)
@@ -1868,6 +1916,7 @@ static const struct wined3d_adapter_ops wined3d_adapter_vk_ops =
     .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_alloc_bo = adapter_vk_alloc_bo,
     .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 0a72f19935b..d0ec4d5aef3 100644
--- a/dlls/wined3d/buffer.c
+++ b/dlls/wined3d/buffer.c
@@ -1061,6 +1061,16 @@ static HRESULT buffer_resource_sub_resource_unmap(struct wined3d_resource *resou
     return WINED3D_OK;
 }
 
+void wined3d_buffer_set_bo(struct wined3d_buffer *buffer, struct wined3d_context *context, struct wined3d_bo *bo)
+{
+    TRACE("buffer %p, context %p, bo %p.\n", buffer, context, bo);
+
+    buffer->buffer_ops->buffer_set_bo(buffer, context, bo);
+    buffer->buffer_object = (uintptr_t)bo;
+    wined3d_buffer_validate_location(buffer, WINED3D_LOCATION_BUFFER);
+    wined3d_buffer_invalidate_location(buffer, ~WINED3D_LOCATION_BUFFER);
+}
+
 void wined3d_buffer_copy_bo_address(struct wined3d_buffer *dst_buffer, struct wined3d_context *context,
         unsigned int dst_offset, const struct wined3d_const_bo_address *src_addr, unsigned int size)
 {
@@ -1256,12 +1266,19 @@ static void wined3d_buffer_no3d_download_ranges(struct wined3d_buffer *buffer, s
     FIXME("Not implemented.\n");
 }
 
+static void wined3d_buffer_no3d_set_bo(struct wined3d_buffer *buffer,
+        struct wined3d_context *context, struct wined3d_bo *bo)
+{
+    FIXME("Not implemented.\n");
+}
+
 static const struct wined3d_buffer_ops wined3d_buffer_no3d_ops =
 {
     wined3d_buffer_no3d_prepare_location,
     wined3d_buffer_no3d_unload_location,
     wined3d_buffer_no3d_upload_ranges,
     wined3d_buffer_no3d_download_ranges,
+    wined3d_buffer_no3d_set_bo,
 };
 
 HRESULT wined3d_buffer_no3d_init(struct wined3d_buffer *buffer_no3d, struct wined3d_device *device,
@@ -1366,12 +1383,19 @@ static void wined3d_buffer_gl_download_ranges(struct wined3d_buffer *buffer, str
     checkGLcall("buffer download");
 }
 
+static void wined3d_buffer_gl_set_bo(struct wined3d_buffer *buffer,
+        struct wined3d_context *context, struct wined3d_bo *bo)
+{
+    FIXME("Not implemented.\n");
+}
+
 static const struct wined3d_buffer_ops wined3d_buffer_gl_ops =
 {
     wined3d_buffer_gl_prepare_location,
     wined3d_buffer_gl_unload_location,
     wined3d_buffer_gl_upload_ranges,
     wined3d_buffer_gl_download_ranges,
+    wined3d_buffer_gl_set_bo,
 };
 
 HRESULT wined3d_buffer_gl_init(struct wined3d_buffer_gl *buffer_gl, struct wined3d_device *device,
@@ -1399,7 +1423,7 @@ HRESULT wined3d_buffer_gl_init(struct wined3d_buffer_gl *buffer_gl, struct wined
     return wined3d_buffer_init(&buffer_gl->b, device, desc, data, parent, parent_ops, &wined3d_buffer_gl_ops);
 }
 
-static VkBufferUsageFlags vk_buffer_usage_from_bind_flags(uint32_t bind_flags)
+VkBufferUsageFlags vk_buffer_usage_from_bind_flags(uint32_t bind_flags)
 {
     VkBufferUsageFlags usage;
 
@@ -1423,7 +1447,7 @@ static VkBufferUsageFlags vk_buffer_usage_from_bind_flags(uint32_t bind_flags)
     return usage;
 }
 
-static VkMemoryPropertyFlags vk_memory_type_from_access_flags(uint32_t access, uint32_t usage)
+VkMemoryPropertyFlags vk_memory_type_from_access_flags(uint32_t access, uint32_t usage)
 {
     VkMemoryPropertyFlags memory_type = 0;
 
@@ -1577,12 +1601,49 @@ static void wined3d_buffer_vk_download_ranges(struct wined3d_buffer *buffer, str
     FIXME("Not implemented.\n");
 }
 
+static void wined3d_buffer_vk_set_bo(struct wined3d_buffer *buffer,
+        struct wined3d_context *context, struct wined3d_bo *bo)
+{
+    struct wined3d_bo_vk *prev_bo = (struct wined3d_bo_vk *)buffer->buffer_object;
+    struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
+    struct wined3d_buffer_vk *buffer_vk = wined3d_buffer_vk(buffer);
+    struct wined3d_bo_vk *bo_vk = wined3d_bo_vk(bo);
+
+    /* We can't just copy the contents of bo_vk into buffer_vk->bo, because the
+     * new BO might still be in use by the client thread. We could allow both to
+     * be valid, although knowing when to destroy a BO then becomes tricky, and
+     * ensuring it's not mapped more than once also becomes tricky. */
+
+    if (prev_bo)
+    {
+        struct wined3d_bo_user *bo_user;
+
+        LIST_FOR_EACH_ENTRY(bo_user, &prev_bo->b.users, struct wined3d_bo_user, entry)
+            bo_user->valid = false;
+        assert(list_empty(&bo_vk->b.users));
+        list_move_head(&bo_vk->b.users, &prev_bo->b.users);
+
+        if (prev_bo != &buffer_vk->bo)
+        {
+            struct wined3d_client_bo_vk *client_bo = CONTAINING_RECORD(prev_bo, struct wined3d_client_bo_vk, bo);
+
+            wined3d_context_vk_destroy_bo(context_vk, &client_bo->bo);
+            heap_free(client_bo);
+        }
+    }
+    else
+    {
+        list_add_head(&bo_vk->b.users, &buffer_vk->b.bo_user.entry);
+    }
+}
+
 static const struct wined3d_buffer_ops wined3d_buffer_vk_ops =
 {
     wined3d_buffer_vk_prepare_location,
     wined3d_buffer_vk_unload_location,
     wined3d_buffer_vk_upload_ranges,
     wined3d_buffer_vk_download_ranges,
+    wined3d_buffer_vk_set_bo,
 };
 
 HRESULT wined3d_buffer_vk_init(struct wined3d_buffer_vk *buffer_vk, struct wined3d_device *device,
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index e6ff448b028..fbbfce006ff 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -2747,6 +2747,9 @@ static void wined3d_cs_exec_update_sub_resource(struct wined3d_cs *cs, const voi
         struct wined3d_buffer *buffer = buffer_from_resource(resource);
         size_t size = box->right - box->left;
 
+        if (op->bo.flags & UPLOAD_BO_RENAME_ON_UNMAP)
+            wined3d_buffer_set_bo(buffer, context, (struct wined3d_bo *)op->bo.addr.buffer_object);
+
         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
@@ -3121,12 +3124,20 @@ static bool wined3d_cs_map_upload_bo(struct wined3d_device_context *context, str
 {
     /* 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))
+    if (wined3d_map_persistent() && resource->type == WINED3D_RTYPE_BUFFER
+            && (flags & (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE)))
     {
         struct wined3d_client_resource *client = &resource->client;
+        struct wined3d_device *device = context->device;
         const struct wined3d_bo *bo;
         uint8_t *map_ptr;
 
+        if (flags & WINED3D_MAP_DISCARD)
+        {
+            if (!device->adapter->adapter_ops->adapter_alloc_bo(device, resource, sub_resource_idx, &client->addr))
+                return NULL;
+        }
+
         bo = (const struct wined3d_bo *)client->addr.buffer_object;
         map_ptr = bo ? bo->map_ptr : NULL;
         map_ptr += (uintptr_t)client->addr.addr;
@@ -3150,6 +3161,9 @@ static bool wined3d_cs_map_upload_bo(struct wined3d_device_context *context, str
         }
         map_desc->data = resource_offset_map_pointer(resource, sub_resource_idx, map_ptr, box);
 
+        if (flags & WINED3D_MAP_DISCARD)
+            client->mapped_upload.flags |= UPLOAD_BO_UPLOAD_ON_UNMAP | UPLOAD_BO_RENAME_ON_UNMAP;
+
         client->mapped_box = *box;
 
         TRACE("Returning bo %s, flags %#x.\n", debug_const_bo_address(&client->mapped_upload.addr),
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index c265bdc8c95..f14f57fd3f4 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -2805,6 +2805,12 @@ static void adapter_no3d_flush_bo_address(struct wined3d_context *context,
 {
 }
 
+static bool adapter_no3d_alloc_bo(struct wined3d_device *device, struct wined3d_resource *resource,
+        unsigned int sub_resource_idx, struct wined3d_bo_address *addr)
+{
+    return false;
+}
+
 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)
@@ -3075,6 +3081,7 @@ static const struct wined3d_adapter_ops wined3d_adapter_no3d_ops =
     .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_alloc_bo = adapter_no3d_alloc_bo,
     .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 d8f680f50f4..1c25876719c 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -328,6 +328,8 @@ VkPipelineStageFlags vk_pipeline_stage_mask_from_bind_flags(uint32_t bind_flags)
 VkShaderStageFlagBits vk_shader_stage_from_wined3d(enum wined3d_shader_type shader_type) DECLSPEC_HIDDEN;
 VkAccessFlags vk_access_mask_from_buffer_usage(VkBufferUsageFlags usage) DECLSPEC_HIDDEN;
 VkPipelineStageFlags vk_pipeline_stage_mask_from_buffer_usage(VkBufferUsageFlags usage) DECLSPEC_HIDDEN;
+VkBufferUsageFlags vk_buffer_usage_from_bind_flags(uint32_t bind_flags) DECLSPEC_HIDDEN;
+VkMemoryPropertyFlags vk_memory_type_from_access_flags(uint32_t access, uint32_t usage) DECLSPEC_HIDDEN;
 
 static inline enum wined3d_cmp_func wined3d_sanitize_cmp_func(enum wined3d_cmp_func func)
 {
@@ -1639,6 +1641,16 @@ struct wined3d_bo_vk
     bool host_synced;
 };
 
+static inline struct wined3d_bo_vk *wined3d_bo_vk(struct wined3d_bo *bo)
+{
+    return CONTAINING_RECORD(bo, struct wined3d_bo_vk, b);
+}
+
+struct wined3d_client_bo_vk
+{
+    struct wined3d_bo_vk bo;
+};
+
 struct wined3d_bo_slab_vk_key
 {
     VkMemoryPropertyFlags memory_type;
@@ -3338,6 +3350,7 @@ bool wined3d_driver_info_init(struct wined3d_driver_info *driver_info,
         UINT64 vram_bytes, UINT64 sysmem_bytes) DECLSPEC_HIDDEN;
 
 #define UPLOAD_BO_UPLOAD_ON_UNMAP   0x1
+#define UPLOAD_BO_RENAME_ON_UNMAP   0x2
 
 struct upload_bo
 {
@@ -3370,6 +3383,8 @@ struct wined3d_adapter_ops
             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);
+    bool (*adapter_alloc_bo)(struct wined3d_device *device, struct wined3d_resource *resource,
+            unsigned int sub_resource_idx, struct wined3d_bo_address *addr);
     HRESULT (*adapter_create_swapchain)(struct wined3d_device *device,
             struct wined3d_swapchain_desc *desc,
             struct wined3d_swapchain_state_parent *state_parent, void *parent,
@@ -5016,6 +5031,7 @@ struct wined3d_buffer_ops
             unsigned int data_offset, unsigned int range_count, const struct wined3d_range *ranges);
     void (*buffer_download_ranges)(struct wined3d_buffer *buffer, struct wined3d_context *context, void *data,
             unsigned int data_offset, unsigned int range_count, const struct wined3d_range *ranges);
+    void (*buffer_set_bo)(struct wined3d_buffer *buffer, struct wined3d_context *context, struct wined3d_bo *bo);
 };
 
 struct wined3d_buffer
@@ -5061,6 +5077,8 @@ BOOL wined3d_buffer_load_location(struct wined3d_buffer *buffer,
 BYTE *wined3d_buffer_load_sysmem(struct wined3d_buffer *buffer, struct wined3d_context *context) DECLSPEC_HIDDEN;
 BOOL wined3d_buffer_prepare_location(struct wined3d_buffer *buffer,
         struct wined3d_context *context, unsigned int location) DECLSPEC_HIDDEN;
+void wined3d_buffer_set_bo(struct wined3d_buffer *buffer,
+        struct wined3d_context *context, struct wined3d_bo *bo) DECLSPEC_HIDDEN;
 
 HRESULT wined3d_buffer_no3d_init(struct wined3d_buffer *buffer_no3d, struct wined3d_device *device,
         const struct wined3d_buffer_desc *desc, const struct wined3d_sub_resource_data *data,
-- 
2.33.0




More information about the wine-devel mailing list