[PATCH 5/6] wined3d: Implement mapping Vulkan buffers.

Henri Verbeet hverbeet at codeweavers.com
Fri Jan 24 10:02:07 CST 2020


Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 dlls/wined3d/adapter_vk.c      |  56 ++++++++++--
 dlls/wined3d/context.c         | 195 ++++++++++++++++++++++++++++++++++++++++-
 dlls/wined3d/resource.c        |  26 ++++++
 dlls/wined3d/wined3d_private.h |  23 +++++
 4 files changed, 293 insertions(+), 7 deletions(-)

diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c
index 7d501b4b08f..87e21b0b41f 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -233,6 +233,7 @@ static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wi
 
     device_vk->vk_device = vk_device;
     VK_CALL(vkGetDeviceQueue(vk_device, queue_family_index, 0, &device_vk->vk_queue));
+    device_vk->vk_queue_family_index = queue_family_index;
 
     device_vk->vk_info = *vk_info;
 #define LOAD_DEVICE_PFN(name) \
@@ -490,20 +491,65 @@ static void adapter_vk_uninit_3d(struct wined3d_device *device)
 static void *adapter_vk_map_bo_address(struct wined3d_context *context,
         const struct wined3d_bo_address *data, size_t size, uint32_t bind_flags, uint32_t map_flags)
 {
-    if (data->buffer_object)
+    struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
+    const struct wined3d_vk_info *vk_info;
+    struct wined3d_device_vk *device_vk;
+    VkCommandBuffer vk_command_buffer;
+    VkBufferMemoryBarrier vk_barrier;
+    struct wined3d_bo_vk *bo;
+    void *map_ptr;
+    VkResult vr;
+
+    if (!(bo = (struct wined3d_bo_vk *)data->buffer_object))
+        return data->addr;
+
+    vk_info = context_vk->vk_info;
+    device_vk = wined3d_device_vk(context->device);
+
+    if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
+    {
+        ERR("Failed to get command buffer.\n");
+        return NULL;
+    }
+
+    vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
+    vk_barrier.pNext = NULL;
+    vk_barrier.srcAccessMask = vk_access_mask_from_bind_flags(bind_flags);
+    vk_barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
+    vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    vk_barrier.buffer = bo->vk_buffer;
+    vk_barrier.offset = (uintptr_t)data->addr;
+    vk_barrier.size = size;
+    VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+            VK_PIPELINE_STAGE_HOST_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL));
+
+    wined3d_context_vk_submit_command_buffer(context_vk);
+    wined3d_context_vk_wait_command_buffer(context_vk, context_vk->current_command_buffer.id - 1);
+
+    if ((vr = VK_CALL(vkMapMemory(device_vk->vk_device, bo->vk_memory,
+            (uintptr_t)data->addr, size, 0, &map_ptr))) < 0)
     {
-        ERR("Unsupported buffer object %#lx.\n", data->buffer_object);
+        ERR("Failed to map buffer, vr %s.\n", wined3d_debug_vkresult(vr));
         return NULL;
     }
 
-    return data->addr;
+    return map_ptr;
 }
 
 static void adapter_vk_unmap_bo_address(struct wined3d_context *context, const struct wined3d_bo_address *data,
         uint32_t bind_flags, unsigned int range_count, const struct wined3d_map_range *ranges)
 {
-    if (data->buffer_object)
-        ERR("Unsupported buffer object %#lx.\n", data->buffer_object);
+    const struct wined3d_vk_info *vk_info;
+    struct wined3d_device_vk *device_vk;
+    struct wined3d_bo_vk *bo;
+
+    if (!(bo = (struct wined3d_bo_vk *)data->buffer_object))
+        return;
+
+    vk_info = wined3d_context_vk(context)->vk_info;
+    device_vk = wined3d_device_vk(context->device);
+    VK_CALL(vkUnmapMemory(device_vk->vk_device, bo->vk_memory));
 }
 
 static void adapter_vk_copy_bo_address(struct wined3d_context *context,
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 7d66fab0a26..27c9d37f5df 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -1561,8 +1561,52 @@ void wined3d_context_vk_destroy_bo(struct wined3d_context_vk *context_vk, const
     VK_CALL(vkFreeMemory(device_vk->vk_device, bo->vk_memory, NULL));
 }
 
+static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *context_vk)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    struct wined3d_command_buffer_vk *buffer;
+    SIZE_T i = 0;
+
+    while (i < context_vk->submitted.buffer_count)
+    {
+        buffer = &context_vk->submitted.buffers[i];
+        if (VK_CALL(vkGetFenceStatus(device_vk->vk_device, buffer->vk_fence)) == VK_NOT_READY)
+        {
+            ++i;
+            continue;
+        }
+
+        TRACE("Command buffer %p with id 0x%s has finished.\n",
+                buffer->vk_command_buffer, wine_dbgstr_longlong(buffer->id));
+        VK_CALL(vkDestroyFence(device_vk->vk_device, buffer->vk_fence, NULL));
+        VK_CALL(vkFreeCommandBuffers(device_vk->vk_device,
+                context_vk->vk_command_pool, 1, &buffer->vk_command_buffer));
+
+        if (buffer->id > context_vk->completed_command_buffer_id)
+            context_vk->completed_command_buffer_id = buffer->id;
+        *buffer = context_vk->submitted.buffers[--context_vk->submitted.buffer_count];
+    }
+}
+
 void wined3d_context_vk_cleanup(struct wined3d_context_vk *context_vk)
 {
+    struct wined3d_command_buffer_vk *buffer = &context_vk->current_command_buffer;
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+
+    if (buffer->vk_command_buffer)
+    {
+        VK_CALL(vkFreeCommandBuffers(device_vk->vk_device,
+                context_vk->vk_command_pool, 1, &buffer->vk_command_buffer));
+        buffer->vk_command_buffer = VK_NULL_HANDLE;
+    }
+    VK_CALL(vkDestroyCommandPool(device_vk->vk_device, context_vk->vk_command_pool, NULL));
+
+    wined3d_context_vk_wait_command_buffer(context_vk, buffer->id - 1);
+    context_vk->completed_command_buffer_id = buffer->id;
+    wined3d_context_vk_cleanup_resources(context_vk);
+    heap_free(context_vk->submitted.buffers);
     wined3d_context_cleanup(&context_vk->c);
 }
 
@@ -1965,6 +2009,135 @@ HGLRC context_create_wgl_attribs(const struct wined3d_gl_info *gl_info, HDC hdc,
     return ctx;
 }
 
+VkCommandBuffer wined3d_context_vk_get_command_buffer(struct wined3d_context_vk *context_vk)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    VkCommandBufferAllocateInfo command_buffer_info;
+    struct wined3d_command_buffer_vk *buffer;
+    VkCommandBufferBeginInfo begin_info;
+    VkResult vr;
+
+    TRACE("context_vk %p.\n", context_vk);
+
+    buffer = &context_vk->current_command_buffer;
+    if (buffer->vk_command_buffer)
+    {
+        TRACE("Returning existing command buffer %p with id 0x%s.\n",
+                buffer->vk_command_buffer, wine_dbgstr_longlong(buffer->id));
+        return buffer->vk_command_buffer;
+    }
+
+    command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    command_buffer_info.pNext = NULL;
+    command_buffer_info.commandPool = context_vk->vk_command_pool;
+    command_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    command_buffer_info.commandBufferCount = 1;
+    if ((vr = VK_CALL(vkAllocateCommandBuffers(device_vk->vk_device,
+            &command_buffer_info, &buffer->vk_command_buffer))) < 0)
+    {
+        WARN("Failed to allocate Vulkan command buffer, vr %s.\n", wined3d_debug_vkresult(vr));
+        return VK_NULL_HANDLE;
+    }
+
+    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    begin_info.pNext = NULL;
+    begin_info.flags = 0;
+    begin_info.pInheritanceInfo = NULL;
+    if ((vr = VK_CALL(vkBeginCommandBuffer(buffer->vk_command_buffer, &begin_info))) < 0)
+    {
+        WARN("Failed to begin command buffer, vr %s.\n", wined3d_debug_vkresult(vr));
+        VK_CALL(vkFreeCommandBuffers(device_vk->vk_device, context_vk->vk_command_pool,
+                1, &buffer->vk_command_buffer));
+        return buffer->vk_command_buffer = VK_NULL_HANDLE;
+    }
+
+    TRACE("Created new command buffer %p with id 0x%s.\n",
+            buffer->vk_command_buffer, wine_dbgstr_longlong(buffer->id));
+
+    return buffer->vk_command_buffer;
+}
+
+void wined3d_context_vk_submit_command_buffer(struct wined3d_context_vk *context_vk)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    struct wined3d_command_buffer_vk *buffer;
+    VkFenceCreateInfo fence_desc;
+    VkSubmitInfo submit_info;
+    VkResult vr;
+
+    TRACE("context_vk %p.\n", context_vk);
+
+    buffer = &context_vk->current_command_buffer;
+    if (!buffer->vk_command_buffer)
+        return;
+
+    TRACE("Submitting command buffer %p with id 0x%s.\n",
+            buffer->vk_command_buffer, wine_dbgstr_longlong(buffer->id));
+
+    VK_CALL(vkEndCommandBuffer(buffer->vk_command_buffer));
+
+    fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+    fence_desc.pNext = NULL;
+    fence_desc.flags = 0;
+    if ((vr = VK_CALL(vkCreateFence(device_vk->vk_device, &fence_desc, NULL, &buffer->vk_fence))) < 0)
+        ERR("Failed to create fence, vr %s.\n", wined3d_debug_vkresult(vr));
+
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.pNext = NULL;
+    submit_info.waitSemaphoreCount = 0;
+    submit_info.pWaitSemaphores = NULL;
+    submit_info.pWaitDstStageMask = NULL;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &buffer->vk_command_buffer;
+    submit_info.signalSemaphoreCount = 0;
+    submit_info.pSignalSemaphores = NULL;
+
+    if ((vr = VK_CALL(vkQueueSubmit(device_vk->vk_queue, 1, &submit_info, buffer->vk_fence))) < 0)
+        ERR("Failed to submit command buffer %p, vr %s.\n",
+                buffer->vk_command_buffer, wined3d_debug_vkresult(vr));
+
+    if (!wined3d_array_reserve((void **)&context_vk->submitted.buffers, &context_vk->submitted.buffers_size,
+            context_vk->submitted.buffer_count + 1, sizeof(*context_vk->submitted.buffers)))
+        ERR("Failed to grow submitted command buffer array.\n");
+
+    context_vk->submitted.buffers[context_vk->submitted.buffer_count++] = *buffer;
+
+    buffer->vk_command_buffer = VK_NULL_HANDLE;
+    /* We don't expect this to ever happen, but handle it anyway. */
+    if (!++buffer->id)
+    {
+        wined3d_context_vk_wait_command_buffer(context_vk, buffer->id - 1);
+        context_vk->completed_command_buffer_id = 0;
+        buffer->id = 1;
+    }
+    wined3d_context_vk_cleanup_resources(context_vk);
+}
+
+void wined3d_context_vk_wait_command_buffer(struct wined3d_context_vk *context_vk, uint64_t id)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    SIZE_T i;
+
+    if (id <= context_vk->completed_command_buffer_id)
+        return;
+
+    for (i = 0; i < context_vk->submitted.buffer_count; ++i)
+    {
+        if (context_vk->submitted.buffers[i].id != id)
+            continue;
+
+        VK_CALL(vkWaitForFences(device_vk->vk_device, 1,
+                &context_vk->submitted.buffers[i].vk_fence, VK_TRUE, UINT64_MAX));
+        wined3d_context_vk_cleanup_resources(context_vk);
+        return;
+    }
+
+    ERR("Failed to find fence for command buffer with id 0x%s.\n", wine_dbgstr_longlong(id));
+}
+
 static void wined3d_context_init(struct wined3d_context *context, struct wined3d_swapchain *swapchain)
 {
     struct wined3d_device *device = swapchain->device;
@@ -2412,13 +2585,31 @@ fail:
 
 HRESULT wined3d_context_vk_init(struct wined3d_context_vk *context_vk, struct wined3d_swapchain *swapchain)
 {
+    VkCommandPoolCreateInfo command_pool_info;
+    const struct wined3d_vk_info *vk_info;
     struct wined3d_adapter_vk *adapter_vk;
+    struct wined3d_device_vk *device_vk;
+    VkResult vr;
 
     TRACE("context_vk %p, swapchain %p.\n", context_vk, swapchain);
 
     wined3d_context_init(&context_vk->c, swapchain);
-    adapter_vk = wined3d_adapter_vk(swapchain->device->adapter);
-    context_vk->vk_info = &adapter_vk->vk_info;
+    device_vk = wined3d_device_vk(swapchain->device);
+    adapter_vk = wined3d_adapter_vk(device_vk->d.adapter);
+    context_vk->vk_info = vk_info = &adapter_vk->vk_info;
+
+    command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+    command_pool_info.pNext = NULL;
+    command_pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
+    command_pool_info.queueFamilyIndex = device_vk->vk_queue_family_index;
+    if ((vr = VK_CALL(vkCreateCommandPool(device_vk->vk_device,
+            &command_pool_info, NULL, &context_vk->vk_command_pool))) < 0)
+    {
+        ERR("Failed to create Vulkan command pool, vr %s.\n", wined3d_debug_vkresult(vr));
+        wined3d_context_cleanup(&context_vk->c);
+        return E_FAIL;
+    }
+    context_vk->current_command_buffer.id = 1;
 
     return WINED3D_OK;
 }
diff --git a/dlls/wined3d/resource.c b/dlls/wined3d/resource.c
index bba940f42cb..bbb892b328d 100644
--- a/dlls/wined3d/resource.c
+++ b/dlls/wined3d/resource.c
@@ -549,3 +549,29 @@ unsigned int wined3d_resource_get_sample_count(const struct wined3d_resource *re
 
     return resource->multisample_type;
 }
+
+VkAccessFlags vk_access_mask_from_bind_flags(uint32_t bind_flags)
+{
+    VkAccessFlags flags = 0;
+
+    if (bind_flags & WINED3D_BIND_VERTEX_BUFFER)
+        flags |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
+    if (bind_flags & WINED3D_BIND_INDEX_BUFFER)
+        flags |= VK_ACCESS_INDEX_READ_BIT;
+    if (bind_flags & WINED3D_BIND_CONSTANT_BUFFER)
+        flags |= VK_ACCESS_UNIFORM_READ_BIT;
+    if (bind_flags & WINED3D_BIND_SHADER_RESOURCE)
+        flags |= VK_ACCESS_SHADER_READ_BIT;
+    if (bind_flags & WINED3D_BIND_UNORDERED_ACCESS)
+        flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+    if (bind_flags & WINED3D_BIND_INDIRECT_BUFFER)
+        flags |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
+    if (bind_flags & WINED3D_BIND_RENDER_TARGET)
+        flags |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+    if (bind_flags & WINED3D_BIND_DEPTH_STENCIL)
+        flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+    if (bind_flags & WINED3D_BIND_STREAM_OUTPUT)
+        FIXME("Ignoring some bind flags %#x.\n", bind_flags);
+
+    return flags;
+}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 934a422ede1..5beaa927d77 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -294,6 +294,7 @@ extern const struct min_lookup minMipLookup[WINED3D_TEXF_LINEAR + 1] DECLSPEC_HI
 extern const GLenum magLookup[WINED3D_TEXF_LINEAR + 1] DECLSPEC_HIDDEN;
 
 GLenum wined3d_gl_compare_func(enum wined3d_cmp_func f) DECLSPEC_HIDDEN;
+VkAccessFlags vk_access_mask_from_bind_flags(uint32_t bind_flags) DECLSPEC_HIDDEN;
 
 static inline enum wined3d_cmp_func wined3d_sanitize_cmp_func(enum wined3d_cmp_func func)
 {
@@ -2158,11 +2159,29 @@ void wined3d_context_gl_unmap_bo_address(struct wined3d_context_gl *context_gl,
 void wined3d_context_gl_update_stream_sources(struct wined3d_context_gl *context_gl,
         const struct wined3d_state *state) DECLSPEC_HIDDEN;
 
+struct wined3d_command_buffer_vk
+{
+    uint64_t id;
+    VkCommandBuffer vk_command_buffer;
+    VkFence vk_fence;
+};
+
 struct wined3d_context_vk
 {
     struct wined3d_context c;
 
     const struct wined3d_vk_info *vk_info;
+
+    VkCommandPool vk_command_pool;
+    struct wined3d_command_buffer_vk current_command_buffer;
+    uint64_t completed_command_buffer_id;
+
+    struct
+    {
+        struct wined3d_command_buffer_vk *buffers;
+        SIZE_T buffers_size;
+        SIZE_T buffer_count;
+    } submitted;
 };
 
 static inline struct wined3d_context_vk *wined3d_context_vk(struct wined3d_context *context)
@@ -2175,8 +2194,11 @@ BOOL wined3d_context_vk_create_bo(struct wined3d_context_vk *context_vk, VkDevic
         VkBufferUsageFlags usage, VkMemoryPropertyFlags memory_type, struct wined3d_bo_vk *bo) DECLSPEC_HIDDEN;
 void wined3d_context_vk_destroy_bo(struct wined3d_context_vk *context_vk,
         const struct wined3d_bo_vk *bo) DECLSPEC_HIDDEN;
+VkCommandBuffer wined3d_context_vk_get_command_buffer(struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
 HRESULT wined3d_context_vk_init(struct wined3d_context_vk *context_vk,
         struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
+void wined3d_context_vk_submit_command_buffer(struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
+void wined3d_context_vk_wait_command_buffer(struct wined3d_context_vk *context_vk, uint64_t id) DECLSPEC_HIDDEN;
 
 typedef void (*APPLYSTATEFUNC)(struct wined3d_context *ctx, const struct wined3d_state *state, DWORD state_id);
 
@@ -3350,6 +3372,7 @@ struct wined3d_device_vk
 
     VkDevice vk_device;
     VkQueue vk_queue;
+    uint32_t vk_queue_family_index;
 
     struct wined3d_vk_info vk_info;
 };
-- 
2.11.0




More information about the wine-devel mailing list