From cee2e53c3bdb93fb9e9c269c24a8060ac04bc9e7 Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Wed, 7 Oct 2020 16:27:12 +0330 Subject: [PATCH] wined3d: Implement stream output for the Vulkan adapter. Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard --- dlls/wined3d/adapter_vk.c | 86 +++++++++++++++++++++++++++++++--- dlls/wined3d/buffer.c | 13 ++++- dlls/wined3d/context_vk.c | 74 +++++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 7 ++- dlls/wined3d/wined3d_vk.h | 9 ++++ 5 files changed, 181 insertions(+), 8 deletions(-) diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c index e589699bcd9..5c219d45d3e 100644 --- a/dlls/wined3d/adapter_vk.c +++ b/dlls/wined3d/adapter_vk.c @@ -311,6 +311,7 @@ static HRESULT wined3d_select_vulkan_queue_family(const struct wined3d_adapter_v struct wined3d_physical_device_info { + VkPhysicalDeviceTransformFeedbackFeaturesEXT xfb_features; VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_divisor_features; VkPhysicalDeviceFeatures2 features2; @@ -406,6 +407,7 @@ static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wi const struct wined3d_adapter_vk *adapter_vk = wined3d_adapter_vk_const(adapter); VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *vertex_divisor_features; const struct wined3d_vk_info *vk_info = &adapter_vk->vk_info; + VkPhysicalDeviceTransformFeedbackFeaturesEXT *xfb_features; struct wined3d_physical_device_info physical_device_info; static const float priorities[] = {1.0f}; VkPhysicalDeviceFeatures2 *features2; @@ -429,8 +431,12 @@ static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wi memset(&physical_device_info, 0, sizeof(physical_device_info)); + xfb_features = &physical_device_info.xfb_features; + xfb_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT; + vertex_divisor_features = &physical_device_info.vertex_divisor_features; vertex_divisor_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT; + vertex_divisor_features->pNext = xfb_features; features2 = &physical_device_info.features2; features2->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; @@ -482,15 +488,17 @@ static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wi device_vk->timestamp_bits = timestamp_bits; device_vk->vk_info = *vk_info; -#define LOAD_DEVICE_PFN(name) \ +#define VK_DEVICE_PFN(name) \ if (!(device_vk->vk_info.vk_ops.name = (void *)VK_CALL(vkGetDeviceProcAddr(vk_device, #name)))) \ { \ WARN("Could not get device proc addr for '" #name "'.\n"); \ hr = E_FAIL; \ goto fail; \ } -#define VK_DEVICE_PFN LOAD_DEVICE_PFN +#define VK_DEVICE_EXT_PFN(name) \ + device_vk->vk_info.vk_ops.name = (void *)VK_CALL(vkGetDeviceProcAddr(vk_device, #name)); VK_DEVICE_FUNCS() +#undef VK_DEVICE_EXT_PFN #undef VK_DEVICE_PFN if (!wined3d_allocator_init(&device_vk->allocator, @@ -838,6 +846,11 @@ static VkAccessFlags vk_access_mask_from_buffer_usage(VkBufferUsageFlags usage) flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; if (usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT) flags |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + if (usage & VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT) + flags |= VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT; + if (usage & VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT) + flags |= VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT + | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT; return flags; } @@ -1572,6 +1585,7 @@ static void adapter_vk_draw_primitive(struct wined3d_device *device, struct wined3d_context_vk *context_vk; VkCommandBuffer vk_command_buffer; uint32_t instance_count; + unsigned int i; TRACE("device %p, state %p, parameters %p.\n", device, state, parameters); @@ -1589,6 +1603,30 @@ static void adapter_vk_draw_primitive(struct wined3d_device *device, return; } + if (context_vk->c.transform_feedback_active) + { + if (!context_vk->vk_so_counter_bo.vk_buffer) + { + struct wined3d_bo_vk *bo = &context_vk->vk_so_counter_bo; + + if (!wined3d_context_vk_create_bo(context_vk, ARRAY_SIZE(context_vk->vk_so_counters) * sizeof(uint32_t) * 2, + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bo)) + ERR("Failed to create counter BO.\n"); + for (i = 0; i < ARRAY_SIZE(context_vk->vk_so_counters); ++i) + { + context_vk->vk_so_counters[i] = bo->vk_buffer; + context_vk->vk_so_offsets[i] = bo->buffer_offset + i * sizeof(uint32_t) * 2; + } + } + + wined3d_context_vk_reference_bo(context_vk, &context_vk->vk_so_counter_bo); + if (context_vk->c.transform_feedback_paused) + VK_CALL(vkCmdBeginTransformFeedbackEXT(vk_command_buffer, 0, ARRAY_SIZE(context_vk->vk_so_counters), + context_vk->vk_so_counters, context_vk->vk_so_offsets)); + else + VK_CALL(vkCmdBeginTransformFeedbackEXT(vk_command_buffer, 0, 0, NULL, NULL)); + } + if (parameters->indirect) { struct wined3d_bo_vk *bo = &indirect_vk->bo; @@ -1627,6 +1665,14 @@ static void adapter_vk_draw_primitive(struct wined3d_device *device, parameters->u.direct.start_idx, parameters->u.direct.start_instance)); } + if (context_vk->c.transform_feedback_active) + { + VK_CALL(vkCmdEndTransformFeedbackEXT(vk_command_buffer, 0, ARRAY_SIZE(context_vk->vk_so_counters), + context_vk->vk_so_counters, context_vk->vk_so_offsets)); + context_vk->c.transform_feedback_paused = 1; + context_vk->c.transform_feedback_active = 0; + } + context_release(&context_vk->c); } @@ -1882,11 +1928,13 @@ static BOOL wined3d_init_vulkan(struct wined3d_vk_info *vk_info) #define VK_INSTANCE_PFN LOAD_INSTANCE_PFN #define VK_INSTANCE_EXT_PFN LOAD_INSTANCE_OPT_PFN #define VK_DEVICE_PFN LOAD_INSTANCE_PFN +#define VK_DEVICE_EXT_PFN LOAD_INSTANCE_OPT_PFN VK_INSTANCE_FUNCS() VK_DEVICE_FUNCS() #undef VK_INSTANCE_PFN #undef VK_INSTANCE_EXT_PFN #undef VK_DEVICE_PFN +#undef VK_DEVICE_EXT_PFN #define MAP_INSTANCE_FUNCTION(core_pfn, ext_pfn) \ if (!vk_ops->core_pfn) \ @@ -2087,13 +2135,25 @@ static bool wined3d_adapter_vk_init_device_extensions(struct wined3d_adapter_vk { const char *name; unsigned int core_since_version; + bool required; } info[] = { - {VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, ~0u}, - {VK_KHR_MAINTENANCE1_EXTENSION_NAME, VK_API_VERSION_1_1}, - {VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, VK_API_VERSION_1_1}, - {VK_KHR_SWAPCHAIN_EXTENSION_NAME, ~0u}, + {VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, ~0u}, + {VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, ~0u, true}, + {VK_KHR_MAINTENANCE1_EXTENSION_NAME, VK_API_VERSION_1_1, true}, + {VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, VK_API_VERSION_1_1, true}, + {VK_KHR_SWAPCHAIN_EXTENSION_NAME, ~0u, true}, + }; + + static const struct + { + const char *name; + enum wined3d_vk_extension extension; + } + map[] = + { + {VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, WINED3D_VK_EXT_TRANSFORM_FEEDBACK}, }; if ((vr = VK_CALL(vkEnumerateDeviceExtensionProperties(physical_device, NULL, &count, NULL))) < 0) @@ -2130,6 +2190,8 @@ static bool wined3d_adapter_vk_init_device_extensions(struct wined3d_adapter_vk if (!found) { + if (!info[i].required) + continue; WARN("Required extension '%s' is not available.\n", info[i].name); goto done; } @@ -2145,6 +2207,18 @@ static bool wined3d_adapter_vk_init_device_extensions(struct wined3d_adapter_vk } success = true; + for (i = 0; i < ARRAY_SIZE(map); ++i) + { + for (j = 0; j < enable_count; ++j) + { + if (!strcmp(enabled_extensions[j], map[i].name)) + { + vk_info->supported[map[i].extension] = TRUE; + break; + } + } + } + done: if (success) { diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c index b32d0160cc1..f2817eeee04 100644 --- a/dlls/wined3d/buffer.c +++ b/dlls/wined3d/buffer.c @@ -1579,11 +1579,13 @@ static BOOL wined3d_buffer_vk_create_buffer_object(struct wined3d_buffer_vk *buf usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; if (bind_flags & WINED3D_BIND_SHADER_RESOURCE) usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; + if (bind_flags & WINED3D_BIND_STREAM_OUTPUT) + usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; if (bind_flags & WINED3D_BIND_UNORDERED_ACCESS) usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; if (bind_flags & WINED3D_BIND_INDIRECT_BUFFER) usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; - if (bind_flags & (WINED3D_BIND_STREAM_OUTPUT | WINED3D_BIND_RENDER_TARGET | WINED3D_BIND_DEPTH_STENCIL)) + if (bind_flags & (WINED3D_BIND_RENDER_TARGET | WINED3D_BIND_DEPTH_STENCIL)) FIXME("Ignoring some bind flags %#x.\n", bind_flags); memory_type = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; @@ -1711,9 +1713,18 @@ HRESULT wined3d_buffer_vk_init(struct wined3d_buffer_vk *buffer_vk, struct wined const struct wined3d_buffer_desc *desc, const struct wined3d_sub_resource_data *data, void *parent, const struct wined3d_parent_ops *parent_ops) { + const struct wined3d_vk_info *vk_info = &wined3d_adapter_vk(device->adapter)->vk_info; + TRACE("buffer_vk %p, device %p, desc %p, data %p, parent %p, parent_ops %p.\n", buffer_vk, device, desc, data, parent, parent_ops); + if ((desc->bind_flags & WINED3D_BIND_STREAM_OUTPUT) + && !vk_info->supported[WINED3D_VK_EXT_TRANSFORM_FEEDBACK]) + { + WARN("The Vulkan implementation does not support transform feedback.\n"); + return WINED3DERR_INVALIDCALL; + } + if (desc->access & WINED3D_RESOURCE_ACCESS_GPU) buffer_vk->b.flags |= WINED3D_BUFFER_USE_BO; diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index 20a4522df56..a4e394e811f 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -1297,6 +1297,8 @@ void wined3d_context_vk_cleanup(struct wined3d_context_vk *context_vk) if (context_vk->vk_framebuffer) VK_CALL(vkDestroyFramebuffer(device_vk->vk_device, context_vk->vk_framebuffer, NULL)); VK_CALL(vkDestroyCommandPool(device_vk->vk_device, context_vk->vk_command_pool, NULL)); + if (context_vk->vk_so_counter_bo.vk_buffer) + wined3d_context_vk_destroy_bo(context_vk, &context_vk->vk_so_counter_bo); wined3d_context_vk_cleanup_resources(context_vk); wined3d_context_vk_destroy_query_pools(context_vk, &context_vk->free_occlusion_query_pools); wined3d_context_vk_destroy_query_pools(context_vk, &context_vk->free_timestamp_query_pools); @@ -1466,6 +1468,7 @@ void wined3d_context_vk_submit_command_buffer(struct wined3d_context_vk *context wined3d_context_vk_end_current_render_pass(context_vk); context_vk->graphics.vk_pipeline = VK_NULL_HANDLE; context_vk->update_compute_pipeline = 1; + context_vk->update_stream_output = 1; context_vk->c.update_shader_resource_bindings = 1; context_vk->c.update_compute_shader_resource_bindings = 1; context_vk->c.update_unordered_access_view_bindings = 1; @@ -2238,6 +2241,51 @@ static void wined3d_context_vk_bind_vertex_buffers(struct wined3d_context_vk *co VK_CALL(vkCmdBindVertexBuffers(vk_command_buffer, first, count, buffers, offsets)); } +static void wined3d_context_vk_bind_stream_output_buffers(struct wined3d_context_vk *context_vk, + VkCommandBuffer vk_command_buffer, const struct wined3d_state *state, const struct wined3d_vk_info *vk_info) +{ + VkDeviceSize offsets[ARRAY_SIZE(state->stream_output)]; + VkDeviceSize sizes[ARRAY_SIZE(state->stream_output)]; + VkBuffer buffers[ARRAY_SIZE(state->stream_output)]; + const struct wined3d_stream_output *stream; + const VkDescriptorBufferInfo *buffer_info; + struct wined3d_buffer_vk *buffer_vk; + struct wined3d_buffer *buffer; + unsigned int i, first, count; + + first = 0; + count = 0; + for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i) + { + stream = &state->stream_output[i]; + + if ((buffer = stream->buffer)) + { + buffer_vk = wined3d_buffer_vk(buffer); + buffer_info = wined3d_buffer_vk_get_buffer_info(buffer_vk); + wined3d_context_vk_reference_bo(context_vk, &buffer_vk->bo); + buffers[count] = buffer_info->buffer; + if ((offsets[count] = stream->offset) == ~0u) + { + FIXME("Appending to stream output buffers not implemented.\n"); + offsets[count] = 0; + } + sizes[count] = buffer_info->range - offsets[count]; + offsets[count] += buffer_info->offset; + ++count; + continue; + } + + if (count) + VK_CALL(vkCmdBindTransformFeedbackBuffersEXT(vk_command_buffer, first, count, buffers, offsets, sizes)); + first = i + 1; + count = 0; + } + + if (count) + VK_CALL(vkCmdBindTransformFeedbackBuffersEXT(vk_command_buffer, first, count, buffers, offsets, sizes)); +} + static VkResult wined3d_context_vk_create_descriptor_pool(struct wined3d_device_vk *device_vk, const struct wined3d_vk_info *vk_info, VkDescriptorPool *vk_pool) { @@ -2892,6 +2940,21 @@ VkCommandBuffer wined3d_context_vk_apply_draw_state(struct wined3d_context_vk *c context_invalidate_state(&context_vk->c, STATE_STREAMSRC); } + if (use_transform_feedback(state) && vk_info->supported[WINED3D_VK_EXT_TRANSFORM_FEEDBACK]) + { + for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i) + { + if (!(buffer = state->stream_output[i].buffer)) + continue; + + wined3d_buffer_load(buffer, &context_vk->c, state); + wined3d_buffer_invalidate_location(buffer, ~WINED3D_LOCATION_BUFFER); + if (!wined3d_buffer_vk(buffer)->bo_user.valid) + context_vk->update_stream_output = 1; + } + context_vk->c.transform_feedback_active = 1; + } + if (indexed || (wined3d_context_is_graphics_state_dirty(&context_vk->c, STATE_INDEXBUFFER) && state->index_buffer)) { wined3d_buffer_load(state->index_buffer, &context_vk->c, state); @@ -2932,6 +2995,17 @@ VkCommandBuffer wined3d_context_vk_apply_draw_state(struct wined3d_context_vk *c if (wined3d_context_is_graphics_state_dirty(&context_vk->c, STATE_STREAMSRC)) wined3d_context_vk_bind_vertex_buffers(context_vk, vk_command_buffer, state, vk_info); + if (wined3d_context_is_graphics_state_dirty(&context_vk->c, STATE_STREAM_OUTPUT)) + { + context_vk->update_stream_output = 1; + context_vk->c.transform_feedback_paused = 0; + } + if (context_vk->c.transform_feedback_active && context_vk->update_stream_output) + { + wined3d_context_vk_bind_stream_output_buffers(context_vk, vk_command_buffer, state, vk_info); + context_vk->update_stream_output = 0; + } + if (wined3d_context_is_graphics_state_dirty(&context_vk->c, STATE_INDEXBUFFER) && state->index_buffer) { struct wined3d_buffer_vk *buffer_vk = wined3d_buffer_vk(state->index_buffer); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 778b26a6757..ae16545a772 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2465,7 +2465,8 @@ struct wined3d_context_vk const struct wined3d_vk_info *vk_info; uint32_t update_compute_pipeline : 1; - uint32_t padding : 31; + uint32_t update_stream_output : 1; + uint32_t padding : 30; struct { @@ -2505,6 +2506,10 @@ struct wined3d_context_vk VkSampleCountFlagBits sample_count; unsigned int rt_count; + VkBuffer vk_so_counters[WINED3D_MAX_STREAM_OUTPUT_BUFFERS]; + VkDeviceSize vk_so_offsets[WINED3D_MAX_STREAM_OUTPUT_BUFFERS]; + struct wined3d_bo_vk vk_so_counter_bo; + struct list active_queries; struct wined3d_pending_queries_vk pending_queries; struct list free_occlusion_query_pools; diff --git a/dlls/wined3d/wined3d_vk.h b/dlls/wined3d/wined3d_vk.h index ae81fe945ee..0b6748ed0cf 100644 --- a/dlls/wined3d/wined3d_vk.h +++ b/dlls/wined3d/wined3d_vk.h @@ -172,6 +172,12 @@ VK_DEVICE_PFN(vkUnmapMemory) \ VK_DEVICE_PFN(vkUpdateDescriptorSets) \ VK_DEVICE_PFN(vkWaitForFences) \ + /* VK_EXT_transform_feedback */ \ + VK_DEVICE_EXT_PFN(vkCmdBeginQueryIndexedEXT) \ + VK_DEVICE_EXT_PFN(vkCmdBeginTransformFeedbackEXT) \ + VK_DEVICE_EXT_PFN(vkCmdBindTransformFeedbackBuffersEXT) \ + VK_DEVICE_EXT_PFN(vkCmdEndQueryIndexedEXT) \ + VK_DEVICE_EXT_PFN(vkCmdEndTransformFeedbackEXT) \ /* VK_KHR_swapchain */ \ VK_DEVICE_PFN(vkAcquireNextImageKHR) \ VK_DEVICE_PFN(vkCreateSwapchainKHR) \ @@ -186,11 +192,13 @@ struct vulkan_ops #define VK_INSTANCE_PFN DECLARE_VK_PFN #define VK_INSTANCE_EXT_PFN DECLARE_VK_PFN #define VK_DEVICE_PFN DECLARE_VK_PFN +#define VK_DEVICE_EXT_PFN DECLARE_VK_PFN VK_DEVICE_FUNCS() VK_INSTANCE_FUNCS() #undef VK_INSTANCE_PFN #undef VK_INSTANCE_EXT_PFN #undef VK_DEVICE_PFN +#undef VK_DEVICE_EXT_PFN PFN_vkCreateInstance vkCreateInstance; PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; @@ -199,6 +207,7 @@ struct vulkan_ops enum wined3d_vk_extension { WINED3D_VK_EXT_NONE, + WINED3D_VK_EXT_TRANSFORM_FEEDBACK, WINED3D_VK_EXT_COUNT, };