[PATCH 6/7] wined3d: Implement stream output for the Vulkan adapter.

Henri Verbeet hverbeet at codeweavers.com
Wed Oct 7 07:57:12 CDT 2020


Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 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,
 };
 
-- 
2.20.1




More information about the wine-devel mailing list