Signed-off-by: Henri Verbeet hverbeet@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 5d88d4463f9..e4eee88a37e 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; };