[PATCH 3/3] wined3d: Handle NOOVERWRITE maps on persistently mapped Vulkan buffers from the client thread.
Zebediah Figura
zfigura at codeweavers.com
Wed Oct 6 21:04:33 CDT 2021
Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
And I'm sure there's a lot to complain about here ;-)
dlls/wined3d/adapter_gl.c | 15 ++++++
dlls/wined3d/adapter_vk.c | 68 ++++++++++++++++++++++++++
dlls/wined3d/buffer.c | 10 ++++
dlls/wined3d/cs.c | 88 +++++++++++++++++++++++++++++++---
dlls/wined3d/directx.c | 14 ++++++
dlls/wined3d/texture.c | 9 ++++
dlls/wined3d/wined3d_private.h | 32 +++++++++++++
7 files changed, 230 insertions(+), 6 deletions(-)
diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c
index bba728e2fb5..228e64b5a56 100644
--- a/dlls/wined3d/adapter_gl.c
+++ b/dlls/wined3d/adapter_gl.c
@@ -4597,6 +4597,19 @@ 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 void *adapter_gl_alloc_upload_bo(struct wined3d_device *device, struct wined3d_resource *resource,
+ unsigned int sub_resource_idx, const struct wined3d_box *box, unsigned int *row_pitch,
+ unsigned int *slice_pitch, uint32_t flags, struct upload_bo *upload_bo)
+{
+ return NULL;
+}
+
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)
@@ -5049,6 +5062,8 @@ 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_alloc_upload_bo = adapter_gl_alloc_upload_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 91a6b92b4aa..9596bef3cd5 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -1169,6 +1169,72 @@ 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);
+ const struct wined3d_vk_info *vk_info;
+ struct wined3d_device_vk *device_vk;
+ VkMappedMemoryRange range;
+ struct wined3d_bo_vk *bo;
+
+ if (!(bo = (struct wined3d_bo_vk *)data->buffer_object))
+ return;
+
+ vk_info = context_vk->vk_info;
+ device_vk = wined3d_device_vk(context->device);
+
+ range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
+ range.pNext = NULL;
+ range.memory = bo->vk_memory;
+ range.offset = bo->memory_offset + (uintptr_t)data->addr;
+ range.size = size;
+ VK_CALL(vkFlushMappedMemoryRanges(device_vk->vk_device, 1, &range));
+}
+
+static void *adapter_vk_alloc_upload_bo(struct wined3d_device *device, struct wined3d_resource *resource,
+ unsigned int sub_resource_idx, const struct wined3d_box *box, unsigned int *row_pitch,
+ unsigned int *slice_pitch, uint32_t flags, struct upload_bo *upload_bo)
+{
+ wined3d_not_from_cs(device->cs);
+
+ /* 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_sub_resource *sub_resource;
+ const struct wined3d_bo_vk *bo_vk;
+ uint8_t *map_ptr;
+
+ sub_resource = wined3d_resource_get_client_sub_resource(resource, sub_resource_idx);
+
+ bo_vk = (const struct wined3d_bo_vk *)sub_resource->addr.buffer_object;
+ map_ptr = bo_vk ? bo_vk->map_ptr : NULL;
+ map_ptr += (uintptr_t)sub_resource->addr.addr;
+
+ if (!map_ptr)
+ {
+ TRACE("Sub-resource is not persistently mapped.\n");
+ return NULL;
+ }
+
+ wined3d_resource_get_sub_resource_map_pitch(resource, sub_resource_idx, row_pitch, slice_pitch);
+
+ upload_bo->addr = *wined3d_const_bo_address(&sub_resource->addr);
+ upload_bo->flags = 0;
+ if (bo_vk)
+ map_ptr += bo_vk->memory_offset;
+ map_ptr = resource_offset_map_pointer(resource, sub_resource_idx, map_ptr, box);
+
+ if (!(bo_vk->memory_type & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
+ upload_bo->flags |= UPLOAD_BO_FLUSH_ON_UNMAP;
+
+ return map_ptr;
+ }
+
+ return NULL;
+}
+
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 +1886,8 @@ 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_alloc_upload_bo = adapter_vk_alloc_upload_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 3ea3bf4b180..c090a24ceb6 100644
--- a/dlls/wined3d/buffer.c
+++ b/dlls/wined3d/buffer.c
@@ -840,6 +840,14 @@ struct wined3d_resource * CDECL wined3d_buffer_get_resource(struct wined3d_buffe
return &buffer->resource;
}
+static struct wined3d_client_sub_resource *buffer_resource_get_client_sub_resource(struct wined3d_resource *resource,
+ unsigned int sub_resource_idx)
+{
+ struct wined3d_buffer *buffer = buffer_from_resource(resource);
+
+ return &buffer->client;
+}
+
static HRESULT buffer_resource_sub_resource_get_desc(struct wined3d_resource *resource,
unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc)
{
@@ -938,6 +946,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->client.addr = addr;
if (((DWORD_PTR)buffer->map_ptr) & (RESOURCE_ALIGNMENT - 1))
{
@@ -1099,6 +1108,7 @@ static const struct wined3d_resource_ops buffer_resource_ops =
buffer_resource_decref,
buffer_resource_preload,
buffer_resource_unload,
+ buffer_resource_get_client_sub_resource,
buffer_resource_sub_resource_get_desc,
buffer_resource_sub_resource_get_map_pitch,
buffer_resource_sub_resource_map,
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index c35e85c3cc2..3e83b78999e 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -116,6 +116,14 @@ ULONG CDECL wined3d_command_list_decref(struct wined3d_command_list *list)
return refcount;
}
+static void invalidate_persistent_map(struct wined3d_resource *resource, unsigned int sub_resource_idx)
+{
+ struct wined3d_client_sub_resource *sub_resource;
+
+ sub_resource = wined3d_resource_get_client_sub_resource(resource, sub_resource_idx);
+ memset(&sub_resource->addr, 0, sizeof(sub_resource->addr));
+}
+
enum wined3d_cs_op
{
WINED3D_CS_OP_NOP,
@@ -2404,6 +2412,13 @@ 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)
+ {
+ const struct wined3d_deferred_upload *upload = &list->uploads[i];
+
+ invalidate_persistent_map(upload->resource, upload->sub_resource_idx);
+ }
}
static void wined3d_cs_exec_preload_resource(struct wined3d_cs *cs, const void *data)
@@ -2441,6 +2456,19 @@ void wined3d_cs_emit_unload_resource(struct wined3d_cs *cs, struct wined3d_resou
{
struct wined3d_cs_unload_resource *op;
+ if (resource->type == WINED3D_RTYPE_BUFFER)
+ {
+ invalidate_persistent_map(resource, 0);
+ }
+ else
+ {
+ struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
+ unsigned int i;
+
+ for (i = 0; i < texture->layer_count * texture->level_count; ++i)
+ invalidate_persistent_map(resource, i);
+ }
+
op = wined3d_device_context_require_space(&cs->c, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
op->opcode = WINED3D_CS_OP_UNLOAD_RESOURCE;
op->resource = resource;
@@ -2511,6 +2539,9 @@ HRESULT wined3d_device_context_emit_map(struct wined3d_device_context *context,
wined3d_resource_wait_idle(resource);
+ /* We might end up loading the resource into sysmem. */
+ invalidate_persistent_map(resource, sub_resource_idx);
+
if (!(op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_MAP)))
return E_OUTOFMEMORY;
op->opcode = WINED3D_CS_OP_MAP;
@@ -2554,7 +2585,7 @@ HRESULT wined3d_device_context_emit_unmap(struct wined3d_device_context *context
unsigned int row_pitch, slice_pitch;
wined3d_resource_get_sub_resource_map_pitch(resource, sub_resource_idx, &row_pitch, &slice_pitch);
- if (bo.flags & UPLOAD_BO_UPLOAD_ON_UNMAP)
+ if (bo.flags & (UPLOAD_BO_UPLOAD_ON_UNMAP | UPLOAD_BO_FLUSH_ON_UNMAP))
wined3d_device_context_upload_bo(context, resource, sub_resource_idx, &box, &bo, row_pitch, slice_pitch);
return WINED3D_OK;
}
@@ -2581,8 +2612,7 @@ static void wined3d_cs_exec_blt_sub_resource(struct wined3d_cs *cs, const void *
if (op->dst_resource->type == WINED3D_RTYPE_BUFFER)
{
wined3d_buffer_copy(buffer_from_resource(op->dst_resource), op->dst_box.left,
- buffer_from_resource(op->src_resource), op->src_box.left,
- op->src_box.right - op->src_box.left);
+ buffer_from_resource(op->src_resource), op->src_box.left, op->src_box.right - op->src_box.left);
}
else if (op->dst_resource->type == WINED3D_RTYPE_TEXTURE_3D)
{
@@ -2688,6 +2718,10 @@ void wined3d_device_context_emit_blt_sub_resource(struct wined3d_device_context
{
struct wined3d_cs_blt_sub_resource *op;
+ /* This might result in an implicit discard. */
+ if (dst_resource->type == WINED3D_RTYPE_BUFFER && dst_box->right - dst_box->left == dst_resource->size)
+ invalidate_persistent_map(dst_resource, 0);
+
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;
@@ -2727,8 +2761,22 @@ 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.flags & UPLOAD_BO_FLUSH_ON_UNMAP)
+ {
+ 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;
+ }
+
+ if (op->bo.flags & UPLOAD_BO_FLUSH_ON_UNMAP)
+ {
+ wined3d_context_flush_bo_address(context, &op->bo.addr, resource->size);
goto done;
}
@@ -2770,6 +2818,10 @@ void wined3d_device_context_emit_update_sub_resource(struct wined3d_device_conte
struct upload_bo bo;
void *map_ptr;
+ /* This might result in an implicit discard. */
+ if (resource->type == WINED3D_RTYPE_BUFFER && box->right - box->left == resource->size)
+ invalidate_persistent_map(resource, 0);
+
if ((map_ptr = context->ops->map_upload_bo(context, resource, sub_resource_idx, box,
&dst_row_pitch, &dst_slice_pitch, WINED3D_MAP_WRITE)))
{
@@ -3094,13 +3146,37 @@ static void *wined3d_cs_map_upload_bo(struct wined3d_device_context *context, st
unsigned int sub_resource_idx, const struct wined3d_box *box, unsigned int *row_pitch,
unsigned int *slice_pitch, uint32_t flags)
{
- /* FIXME: We would like to return mapped or newly allocated memory here. */
- return NULL;
+ struct wined3d_client_sub_resource *sub_resource;
+ struct upload_bo bo;
+ void *map_ptr;
+
+ if ((map_ptr = context->device->adapter->adapter_ops->adapter_alloc_upload_bo(context->device,
+ resource, sub_resource_idx, box, row_pitch, slice_pitch, flags, &bo)))
+ {
+ sub_resource = wined3d_resource_get_client_sub_resource(resource, sub_resource_idx);
+ sub_resource->upload_bo = bo;
+ sub_resource->upload_box = *box;
+ TRACE("Returning map pointer %p, bo %s, flags %#x, row pitch %u, slice pitch %u.\n", map_ptr,
+ debug_const_bo_address(&bo.addr), bo.flags, *row_pitch, *slice_pitch);
+ }
+ return map_ptr;
}
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)
{
+ struct wined3d_client_sub_resource *sub_resource;
+
+ sub_resource = wined3d_resource_get_client_sub_resource(resource, sub_resource_idx);
+ if (sub_resource->upload_bo.addr.buffer_object || sub_resource->upload_bo.addr.addr)
+ {
+ *bo = sub_resource->upload_bo;
+ *box = sub_resource->upload_box;
+ memset(&sub_resource->upload_bo, 0, sizeof(sub_resource->upload_bo));
+ memset(&sub_resource->upload_box, 0, sizeof(sub_resource->upload_box));
+ return true;
+ }
+
return false;
}
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 990164fd68d..884eec4ac92 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -2798,6 +2798,18 @@ 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 void *adapter_no3d_alloc_upload_bo(struct wined3d_device *device, struct wined3d_resource *resource,
+ unsigned int sub_resource_idx, const struct wined3d_box *box, unsigned int *row_pitch,
+ unsigned int *slice_pitch, uint32_t flags, struct upload_bo *upload_bo)
+{
+ return NULL;
+}
+
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 +3079,8 @@ 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_alloc_upload_bo = adapter_no3d_alloc_upload_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/texture.c b/dlls/wined3d/texture.c
index 339bf4e205a..d96492fc9e9 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -3438,6 +3438,14 @@ static void texture_resource_unload(struct wined3d_resource *resource)
resource_unload(&texture->resource);
}
+static struct wined3d_client_sub_resource *texture_resource_get_client_sub_resource(struct wined3d_resource *resource,
+ unsigned int sub_resource_idx)
+{
+ const struct wined3d_texture *texture = texture_from_resource(resource);
+
+ return &texture->sub_resources[sub_resource_idx].client;
+}
+
static HRESULT texture_resource_sub_resource_get_desc(struct wined3d_resource *resource,
unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc)
{
@@ -3603,6 +3611,7 @@ static const struct wined3d_resource_ops texture_resource_ops =
texture_resource_decref,
texture_resource_preload,
texture_resource_unload,
+ texture_resource_get_client_sub_resource,
texture_resource_sub_resource_get_desc,
texture_resource_sub_resource_get_map_pitch,
texture_resource_sub_resource_map,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 87d69b7b6fe..216bffabc90 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -3329,6 +3329,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_FLUSH_ON_UNMAP 0x2
struct upload_bo
{
@@ -3359,6 +3360,11 @@ 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);
+ void *(*adapter_alloc_upload_bo)(struct wined3d_device *device, struct wined3d_resource *resource,
+ unsigned int sub_resource_idx, const struct wined3d_box *box, unsigned int *row_pitch,
+ unsigned int *slice_pitch, uint32_t flags, struct upload_bo *upload_bo);
HRESULT (*adapter_create_swapchain)(struct wined3d_device *device,
struct wined3d_swapchain_desc *desc,
struct wined3d_swapchain_state_parent *state_parent, void *parent,
@@ -4107,6 +4113,14 @@ 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_sub_resource
+{
+ struct wined3d_bo_address addr;
+
+ struct upload_bo upload_bo;
+ struct wined3d_box upload_box;
+};
+
static inline BOOL wined3d_resource_access_is_managed(unsigned int access)
{
return !(~access & (WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_CPU));
@@ -4118,6 +4132,8 @@ struct wined3d_resource_ops
ULONG (*resource_decref)(struct wined3d_resource *resource);
void (*resource_preload)(struct wined3d_resource *resource);
void (*resource_unload)(struct wined3d_resource *resource);
+ struct wined3d_client_sub_resource *(*resource_get_client_sub_resource)(struct wined3d_resource *resource,
+ unsigned int sub_resource_idx);
HRESULT (*resource_sub_resource_get_desc)(struct wined3d_resource *resource,
unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc);
void (*resource_sub_resource_get_map_pitch)(struct wined3d_resource *resource,
@@ -4183,6 +4199,12 @@ static inline void wined3d_resource_release(struct wined3d_resource *resource)
assert(refcount >= 0);
}
+static inline struct wined3d_client_sub_resource *wined3d_resource_get_client_sub_resource(
+ struct wined3d_resource *resource, unsigned int sub_resource_idx)
+{
+ return resource->resource_ops->resource_get_client_sub_resource(resource, sub_resource_idx);
+}
+
static inline HRESULT wined3d_resource_get_sub_resource_desc(struct wined3d_resource *resource,
unsigned int sub_resource_idx, struct wined3d_sub_resource_desc *desc)
{
@@ -4337,6 +4359,8 @@ struct wined3d_texture
struct wined3d_texture_sub_resource
{
+ struct wined3d_client_sub_resource client;
+
void *parent;
const struct wined3d_parent_ops *parent_ops;
@@ -4978,6 +5002,8 @@ struct wined3d_buffer
void *map_ptr;
uintptr_t buffer_object;
+ struct wined3d_client_sub_resource client;
+
struct wined3d_range *maps;
SIZE_T maps_size, modified_areas;
@@ -6227,6 +6253,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