From 6f43f450c8863e2229a1209c8fc677493a2510ad Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Tue, 2 Nov 2021 12:35:21 +0100 Subject: [PATCH] vkd3d: Disable primitive restart when using non-compatible topologies. Primitive restart is only used for strip primitive types, and must be ignored for lists. Use and require extended_dynamic_state2 for this purpose. Signed-off-by: Hans-Kristian Arntzen --- README.md | 1 + libs/vkd3d/command.c | 11 ++++++++++- libs/vkd3d/device.c | 17 +++++++++++++++++ libs/vkd3d/state.c | 6 +++++- libs/vkd3d/vkd3d_private.h | 20 +++++++++++++++++++- libs/vkd3d/vulkan_procs.h | 3 +++ 6 files changed, 55 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index caaa15b3..de5eca4a 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ There are some hard requirements on drivers to be able to implement D3D12 in a r - `VK_KHR_copy_commands2` - `VK_KHR_dynamic_rendering` - `VK_EXT_extended_dynamic_state` +- `VK_EXT_extended_dynamic_state2` Some notable extensions that **should** be supported for optimal or correct behavior. These extensions will likely become mandatory later. diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 25a983c8..979d366a 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -5254,6 +5254,15 @@ static void d3d12_command_list_update_dynamic_state(struct d3d12_command_list *l dyn_state->vk_primitive_topology)); } + if (dyn_state->dirty_flags & VKD3D_DYNAMIC_STATE_PRIMITIVE_RESTART) + { + /* The primitive restart dynamic state is only present if the PSO + * has a strip cut value, so we only need to check if the + * current primitive topology is a strip type. */ + VK_CALL(vkCmdSetPrimitiveRestartEnableEXT(list->vk_command_buffer, + vk_primitive_topology_supports_restart(dyn_state->vk_primitive_topology))); + } + if (dyn_state->dirty_flags & VKD3D_DYNAMIC_STATE_VERTEX_BUFFER_STRIDE) { update_vbos = (dyn_state->dirty_vbos | dyn_state->dirty_vbo_strides) & list->state->graphics.vertex_buffer_mask; @@ -6796,7 +6805,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_IASetPrimitiveTopology(d3d12_co dyn_state->primitive_topology = topology; dyn_state->vk_primitive_topology = vk_topology_from_d3d12_topology(topology); d3d12_command_list_invalidate_current_pipeline(list, false); - dyn_state->dirty_flags |= VKD3D_DYNAMIC_STATE_TOPOLOGY; + dyn_state->dirty_flags |= VKD3D_DYNAMIC_STATE_TOPOLOGY | VKD3D_DYNAMIC_STATE_PRIMITIVE_RESTART; } static void STDMETHODCALLTYPE d3d12_command_list_RSSetViewports(d3d12_command_list_iface *iface, diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 18b8517b..c66ee0ab 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -102,6 +102,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] = VK_EXTENSION(EXT_TRANSFORM_FEEDBACK, EXT_transform_feedback), VK_EXTENSION(EXT_VERTEX_ATTRIBUTE_DIVISOR, EXT_vertex_attribute_divisor), VK_EXTENSION(EXT_EXTENDED_DYNAMIC_STATE, EXT_extended_dynamic_state), + VK_EXTENSION(EXT_EXTENDED_DYNAMIC_STATE_2, EXT_extended_dynamic_state2), VK_EXTENSION(EXT_EXTERNAL_MEMORY_HOST, EXT_external_memory_host), VK_EXTENSION(EXT_4444_FORMATS, EXT_4444_formats), VK_EXTENSION(EXT_SHADER_IMAGE_ATOMIC_INT64, EXT_shader_image_atomic_int64), @@ -1253,6 +1254,12 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i vk_prepend_struct(&info->features2, &info->extended_dynamic_state_features); } + if (vulkan_info->EXT_extended_dynamic_state2) + { + info->extended_dynamic_state2_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; + vk_prepend_struct(&info->features2, &info->extended_dynamic_state2_features); + } + if (vulkan_info->EXT_external_memory_host) { info->external_memory_host_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT; @@ -1920,6 +1927,10 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, acceleration_structure = &physical_device_info->acceleration_structure_features; acceleration_structure->accelerationStructureCaptureReplay = VK_FALSE; + /* Don't need or require these. */ + physical_device_info->extended_dynamic_state2_features.extendedDynamicState2LogicOp = VK_FALSE; + physical_device_info->extended_dynamic_state2_features.extendedDynamicState2PatchControlPoints = VK_FALSE; + if (!physical_device_info->descriptor_indexing_properties.robustBufferAccessUpdateAfterBind) { /* Generally, we cannot enable robustness if this is not supported, @@ -1991,6 +2002,12 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, return E_INVALIDARG; } + if (!physical_device_info->extended_dynamic_state2_features.extendedDynamicState2) + { + ERR("EXT_extended_dynamic_state2 is not supported by this implementation. This is required for correct operation.\n"); + return E_INVALIDARG; + } + return S_OK; } diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 7912d702..4f62f84f 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -2822,6 +2822,7 @@ static uint32_t d3d12_graphics_pipeline_state_init_dynamic_state(struct d3d12_pi { VKD3D_DYNAMIC_STATE_TOPOLOGY, VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT }, { VKD3D_DYNAMIC_STATE_VERTEX_BUFFER_STRIDE, VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT }, { VKD3D_DYNAMIC_STATE_FRAGMENT_SHADING_RATE, VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR }, + { VKD3D_DYNAMIC_STATE_PRIMITIVE_RESTART, VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT }, }; dynamic_state_flags = 0; @@ -2866,6 +2867,9 @@ static uint32_t d3d12_graphics_pipeline_state_init_dynamic_state(struct d3d12_pi if (d3d12_device_supports_variable_shading_rate_tier_1(state->device) && graphics->rt_count) dynamic_state_flags |= VKD3D_DYNAMIC_STATE_FRAGMENT_SHADING_RATE; + if (graphics->index_buffer_strip_cut_value) + dynamic_state_flags |= VKD3D_DYNAMIC_STATE_PRIMITIVE_RESTART; + /* Build dynamic state create info */ for (i = 0, count = 0; i < ARRAY_SIZE(dynamic_state_list); i++) { @@ -4144,7 +4148,7 @@ VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_sta /* Try to keep as much dynamic state as possible so we don't have to rebind state unnecessarily. */ if (graphics->primitive_topology_type != D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH && - graphics->primitive_topology_type != D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED) + graphics->primitive_topology_type != D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED) pipeline_key.dynamic_topology = true; else pipeline_key.topology = dyn_state->primitive_topology; diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 5564e3c9..09a08f0d 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -149,6 +149,7 @@ struct vkd3d_vulkan_info bool EXT_transform_feedback; bool EXT_vertex_attribute_divisor; bool EXT_extended_dynamic_state; + bool EXT_extended_dynamic_state2; bool EXT_external_memory_host; bool EXT_4444_formats; bool EXT_shader_image_atomic_int64; @@ -1416,7 +1417,7 @@ HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device, VkDescriptorSetLayoutCreateFlags flags, unsigned int binding_count, const VkDescriptorSetLayoutBinding *bindings, VkDescriptorSetLayout *set_layout); -#define VKD3D_MAX_DYNAMIC_STATE_COUNT (7) +#define VKD3D_MAX_DYNAMIC_STATE_COUNT (8) enum vkd3d_dynamic_state_flag { @@ -1429,6 +1430,7 @@ enum vkd3d_dynamic_state_flag VKD3D_DYNAMIC_STATE_VERTEX_BUFFER = (1 << 6), VKD3D_DYNAMIC_STATE_VERTEX_BUFFER_STRIDE = (1 << 7), VKD3D_DYNAMIC_STATE_FRAGMENT_SHADING_RATE = (1 << 8), + VKD3D_DYNAMIC_STATE_PRIMITIVE_RESTART = (1 << 9), }; struct vkd3d_shader_debug_ring_spec_constants @@ -1608,6 +1610,21 @@ HRESULT vkd3d_pipeline_state_desc_from_d3d12_compute_desc(struct d3d12_pipeline_ HRESULT vkd3d_pipeline_state_desc_from_d3d12_stream_desc(struct d3d12_pipeline_state_desc *desc, const D3D12_PIPELINE_STATE_STREAM_DESC *d3d12_desc, VkPipelineBindPoint *vk_bind_point); +static inline bool vk_primitive_topology_supports_restart(VkPrimitiveTopology topology) +{ + switch (topology) + { + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: + case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: + case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: + return true; + + default: + return false; + } +} + struct vkd3d_pipeline_key { D3D12_PRIMITIVE_TOPOLOGY topology; @@ -2958,6 +2975,7 @@ struct vkd3d_physical_device_info VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR subgroup_extended_types_features; VkPhysicalDeviceRobustness2FeaturesEXT robustness2_features; VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extended_dynamic_state_features; + VkPhysicalDeviceExtendedDynamicState2FeaturesEXT extended_dynamic_state2_features; VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE mutable_descriptor_features; VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray_tracing_pipeline_features; VkPhysicalDeviceAccelerationStructureFeaturesKHR acceleration_structure_features; diff --git a/libs/vkd3d/vulkan_procs.h b/libs/vkd3d/vulkan_procs.h index 8d5ac50e..36e3f4c8 100644 --- a/libs/vkd3d/vulkan_procs.h +++ b/libs/vkd3d/vulkan_procs.h @@ -245,6 +245,9 @@ VK_DEVICE_EXT_PFN(vkCmdSetPrimitiveTopologyEXT) VK_DEVICE_EXT_PFN(vkCmdSetScissorWithCountEXT) VK_DEVICE_EXT_PFN(vkCmdSetViewportWithCountEXT) +/* VK_EXT_extended_dynamic_state2 */ +VK_DEVICE_EXT_PFN(vkCmdSetPrimitiveRestartEnableEXT) + /* VK_EXT_external_memory_host */ VK_DEVICE_EXT_PFN(vkGetMemoryHostPointerPropertiesEXT)