wined3d: Implement stream output for the Vulkan adapter.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2020-10-07 16:27:12 +03:30 committed by Alexandre Julliard
parent 3ee141b81d
commit cee2e53c3b
5 changed files with 181 additions and 8 deletions

View file

@ -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)
{

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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,
};