diff --git a/src/common/settings.h b/src/common/settings.h index 31e54e3be1..d6d3b5e26d 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -546,6 +546,15 @@ struct Values { Category::RendererExtensions, Specialization::Scalar}; + SwitchableSetting vertex_input_dynamic_state{linkage, +#if defined (ANDROID) + false, // Disabled by default on Android (some drivers have issues) +#else + false, // Disabled by default on desktop (some drivers have issues) +#endif + "vertex_input_dynamic_state", + Category::RendererExtensions}; + SwitchableSetting provoking_vertex{linkage, false, "provoking_vertex", Category::RendererExtensions}; SwitchableSetting descriptor_indexing{linkage, false, "descriptor_indexing", Category::RendererExtensions}; SwitchableSetting sample_shading{linkage, false, "sample_shading", Category::RendererExtensions, Specialization::Paired}; diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index e643e98ead..2ecdba70a0 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -58,12 +58,41 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe const auto topology_ = maxwell3d.draw_manager->GetDrawState().topology; raw1 = 0; + raw1_eds3_extended = 0; + + // EDS1 extended_dynamic_state.Assign(features.has_extended_dynamic_state ? 1 : 0); + + // EDS2 extended_dynamic_state_2.Assign(features.has_extended_dynamic_state_2 ? 1 : 0); - extended_dynamic_state_2_extra.Assign(features.has_extended_dynamic_state_2_extra ? 1 : 0); + extended_dynamic_state_2_logic_op.Assign(features.has_extended_dynamic_state_2_logic_op ? 1 : 0); + extended_dynamic_state_2_patch_control_points.Assign(features.has_extended_dynamic_state_2_patch_control_points ? 1 : 0); + + // EDS3 - Blending/Enables extended_dynamic_state_3_blend.Assign(features.has_extended_dynamic_state_3_blend ? 1 : 0); extended_dynamic_state_3_enables.Assign(features.has_extended_dynamic_state_3_enables ? 1 : 0); + + // EDS3 - Granular features + extended_dynamic_state_3_depth_clamp.Assign(features.has_extended_dynamic_state_3_depth_clamp ? 1 : 0); + extended_dynamic_state_3_logic_op_enable.Assign(features.has_extended_dynamic_state_3_logic_op_enable ? 1 : 0); + extended_dynamic_state_3_tessellation_domain_origin.Assign(features.has_extended_dynamic_state_3_tessellation_domain_origin ? 1 : 0); + extended_dynamic_state_3_polygon_mode.Assign(features.has_extended_dynamic_state_3_polygon_mode ? 1 : 0); + extended_dynamic_state_3_rasterization_samples.Assign(features.has_extended_dynamic_state_3_rasterization_samples ? 1 : 0); + extended_dynamic_state_3_sample_mask.Assign(features.has_extended_dynamic_state_3_sample_mask ? 1 : 0); + extended_dynamic_state_3_alpha_to_coverage_enable.Assign(features.has_extended_dynamic_state_3_alpha_to_coverage_enable ? 1 : 0); + extended_dynamic_state_3_alpha_to_one_enable.Assign(features.has_extended_dynamic_state_3_alpha_to_one_enable ? 1 : 0); + extended_dynamic_state_3_depth_clip_enable.Assign(features.has_extended_dynamic_state_3_depth_clip_enable ? 1 : 0); + extended_dynamic_state_3_depth_clip_negative_one_to_one.Assign(features.has_extended_dynamic_state_3_depth_clip_negative_one_to_one ? 1 : 0); + extended_dynamic_state_3_line_rasterization_mode.Assign(features.has_extended_dynamic_state_3_line_rasterization_mode ? 1 : 0); + extended_dynamic_state_3_line_stipple_enable.Assign(features.has_extended_dynamic_state_3_line_stipple_enable ? 1 : 0); + extended_dynamic_state_3_provoking_vertex_mode.Assign(features.has_extended_dynamic_state_3_provoking_vertex_mode ? 1 : 0); + extended_dynamic_state_3_conservative_rasterization_mode.Assign(features.has_extended_dynamic_state_3_conservative_rasterization_mode ? 1 : 0); + extended_dynamic_state_3_sample_locations_enable.Assign(features.has_extended_dynamic_state_3_sample_locations_enable ? 1 : 0); + extended_dynamic_state_3_rasterization_stream.Assign(features.has_extended_dynamic_state_3_rasterization_stream ? 1 : 0); + + // Vertex Input dynamic_vertex_input.Assign(features.has_dynamic_vertex_input ? 1 : 0); + xfb_enabled.Assign(regs.transform_feedback_enabled != 0); ndc_minus_one_to_one.Assign(regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1 : 0); polygon_mode.Assign(PackPolygonMode(VideoCore::EffectivePolygonMode(regs))); diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index f0b021ca08..ca25fbaaf8 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h @@ -18,11 +18,35 @@ namespace Vulkan { using Maxwell = Tegra::Engines::Maxwell3D::Regs; struct DynamicFeatures { + // VK_EXT_extended_dynamic_state (EDS1) - All-or-nothing bool has_extended_dynamic_state; - bool has_extended_dynamic_state_2; - bool has_extended_dynamic_state_2_extra; - bool has_extended_dynamic_state_3_blend; - bool has_extended_dynamic_state_3_enables; + + // VK_EXT_extended_dynamic_state2 (EDS2) - Granular features + bool has_extended_dynamic_state_2; // Core EDS2 (RasterizerDiscard, DepthBias, PrimitiveRestart) + bool has_extended_dynamic_state_2_logic_op; // LogicOp support + bool has_extended_dynamic_state_2_patch_control_points; // TessellationPatchControlPoints + + // VK_EXT_extended_dynamic_state3 (EDS3) - Highly granular features + bool has_extended_dynamic_state_3_blend; // ColorBlendEnable + ColorBlendEquation + ColorWriteMask + bool has_extended_dynamic_state_3_enables; // DepthClampEnable + LogicOpEnable + bool has_extended_dynamic_state_3_depth_clamp; // DepthClampEnable only + bool has_extended_dynamic_state_3_logic_op_enable; // LogicOpEnable only + bool has_extended_dynamic_state_3_tessellation_domain_origin; // TessellationDomainOrigin + bool has_extended_dynamic_state_3_polygon_mode; // PolygonMode + bool has_extended_dynamic_state_3_rasterization_samples; // RasterizationSamples + bool has_extended_dynamic_state_3_sample_mask; // SampleMask + bool has_extended_dynamic_state_3_alpha_to_coverage_enable; // AlphaToCoverageEnable + bool has_extended_dynamic_state_3_alpha_to_one_enable; // AlphaToOneEnable + bool has_extended_dynamic_state_3_depth_clip_enable; // DepthClipEnable + bool has_extended_dynamic_state_3_depth_clip_negative_one_to_one; // DepthClipNegativeOneToOne + bool has_extended_dynamic_state_3_line_rasterization_mode; // LineRasterizationMode + bool has_extended_dynamic_state_3_line_stipple_enable; // LineStippleEnable + bool has_extended_dynamic_state_3_provoking_vertex_mode; // ProvokingVertexMode + bool has_extended_dynamic_state_3_conservative_rasterization_mode; // ConservativeRasterizationMode + bool has_extended_dynamic_state_3_sample_locations_enable; // SampleLocationsEnable + bool has_extended_dynamic_state_3_rasterization_stream; // RasterizationStream + + // VK_EXT_vertex_input_dynamic_state bool has_dynamic_vertex_input; }; @@ -184,23 +208,56 @@ struct FixedPipelineState { union { u32 raw1; + // EDS1 - Bit 0 BitField<0, 1, u32> extended_dynamic_state; + + // EDS2 - Bits 1-3 BitField<1, 1, u32> extended_dynamic_state_2; - BitField<2, 1, u32> extended_dynamic_state_2_extra; - BitField<3, 1, u32> extended_dynamic_state_3_blend; - BitField<4, 1, u32> extended_dynamic_state_3_enables; - BitField<5, 1, u32> dynamic_vertex_input; - BitField<6, 1, u32> xfb_enabled; - BitField<7, 1, u32> ndc_minus_one_to_one; - BitField<8, 2, u32> polygon_mode; - BitField<10, 2, u32> tessellation_primitive; - BitField<12, 2, u32> tessellation_spacing; - BitField<14, 1, u32> tessellation_clockwise; - BitField<15, 5, u32> patch_control_points_minus_one; - + BitField<2, 1, u32> extended_dynamic_state_2_logic_op; + BitField<3, 1, u32> extended_dynamic_state_2_patch_control_points; + + // EDS3 Blending/Enables - Bits 4-5 + BitField<4, 1, u32> extended_dynamic_state_3_blend; + BitField<5, 1, u32> extended_dynamic_state_3_enables; + + // Vertex Input - Bit 6 + BitField<6, 1, u32> dynamic_vertex_input; + + // Other state - Bits 7-19 + BitField<7, 1, u32> xfb_enabled; + BitField<8, 1, u32> ndc_minus_one_to_one; + BitField<9, 2, u32> polygon_mode; + BitField<11, 2, u32> tessellation_primitive; + BitField<13, 2, u32> tessellation_spacing; + BitField<15, 1, u32> tessellation_clockwise; + BitField<16, 5, u32> patch_control_points_minus_one; + + // Topology and MSAA - Bits 24-31 BitField<24, 4, Maxwell::PrimitiveTopology> topology; BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode; }; + + union { + u32 raw1_eds3_extended; + // EDS3 Additional Features - Bits 0-15 + BitField<0, 1, u32> extended_dynamic_state_3_depth_clamp; + BitField<1, 1, u32> extended_dynamic_state_3_logic_op_enable; + BitField<2, 1, u32> extended_dynamic_state_3_tessellation_domain_origin; + BitField<3, 1, u32> extended_dynamic_state_3_polygon_mode; + BitField<4, 1, u32> extended_dynamic_state_3_rasterization_samples; + BitField<5, 1, u32> extended_dynamic_state_3_sample_mask; + BitField<6, 1, u32> extended_dynamic_state_3_alpha_to_coverage_enable; + BitField<7, 1, u32> extended_dynamic_state_3_alpha_to_one_enable; + BitField<8, 1, u32> extended_dynamic_state_3_depth_clip_enable; + BitField<9, 1, u32> extended_dynamic_state_3_depth_clip_negative_one_to_one; + BitField<10, 1, u32> extended_dynamic_state_3_line_rasterization_mode; + BitField<11, 1, u32> extended_dynamic_state_3_line_stipple_enable; + BitField<12, 1, u32> extended_dynamic_state_3_provoking_vertex_mode; + BitField<13, 1, u32> extended_dynamic_state_3_conservative_rasterization_mode; + BitField<14, 1, u32> extended_dynamic_state_3_sample_locations_enable; + BitField<15, 1, u32> extended_dynamic_state_3_rasterization_stream; + }; + union { u32 raw2; BitField<1, 3, u32> alpha_test_func; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 13ed1b585e..1ed1014515 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -837,13 +837,38 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .pAttachments = cb_attachments.data(), .blendConstants = {} }; - static_vector dynamic_states{ - VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, - VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS, - VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, - VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, - VK_DYNAMIC_STATE_LINE_WIDTH, - }; + // Base Vulkan Dynamic States - Always active (independent of EDS) + // Granular fallback: Each state added only if device supports it (protection against broken drivers) + static_vector dynamic_states; + if (device.SupportsDynamicViewport()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); + } + if (device.SupportsDynamicScissor()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR); + } + if (device.SupportsDynamicLineWidth()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_WIDTH); + } + if (device.SupportsDynamicDepthBias()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS); + } + if (device.SupportsDynamicBlendConstants()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_BLEND_CONSTANTS); + } + if (device.SupportsDynamicDepthBounds()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS); + } + if (device.SupportsDynamicStencilCompareMask()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK); + } + if (device.SupportsDynamicStencilWriteMask()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK); + } + if (device.SupportsDynamicStencilReference()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE); + } + + // EDS1 - Extended Dynamic State (12 states) if (key.state.extended_dynamic_state) { static constexpr std::array extended{ VK_DYNAMIC_STATE_CULL_MODE_EXT, @@ -856,49 +881,59 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT, VK_DYNAMIC_STATE_STENCIL_OP_EXT, }; - if (key.state.dynamic_vertex_input) { - dynamic_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT); - } dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end()); - if (key.state.extended_dynamic_state_2) { - static constexpr std::array extended2{ - VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT, - VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT, - VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT, - }; - dynamic_states.insert(dynamic_states.end(), extended2.begin(), extended2.end()); - } - if (key.state.extended_dynamic_state_2_extra) { - dynamic_states.push_back(VK_DYNAMIC_STATE_LOGIC_OP_EXT); - } - if (key.state.extended_dynamic_state_3_blend) { - static constexpr std::array extended3{ - VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT, - VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT, - VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT, - - // VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT, - }; - dynamic_states.insert(dynamic_states.end(), extended3.begin(), extended3.end()); - } - if (key.state.extended_dynamic_state_3_enables) { - static constexpr std::array extended3{ - VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT, - VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT, - - // additional state3 extensions - VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT, - - VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT, - - VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT, - VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT, - VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT, - VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT, - VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT, - }; - dynamic_states.insert(dynamic_states.end(), extended3.begin(), extended3.end()); - } + } + + // Vertex Input Dynamic State (independent toggle) + if (key.state.dynamic_vertex_input) { + dynamic_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT); + } + + // EDS2 - Extended Dynamic State 2 Core (3 states) + if (key.state.extended_dynamic_state_2) { + static constexpr std::array extended2{ + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT, + }; + dynamic_states.insert(dynamic_states.end(), extended2.begin(), extended2.end()); + } + + // EDS2 - Logic Op (granular feature) + if (key.state.extended_dynamic_state_2_extra) { + dynamic_states.push_back(VK_DYNAMIC_STATE_LOGIC_OP_EXT); + } + + // EDS3 - Blending (composite: ColorBlendEnable + Equation + WriteMask) + if (key.state.extended_dynamic_state_3_blend) { + static constexpr std::array extended3{ + VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT, + VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT, + VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT, + + // VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT, + }; + dynamic_states.insert(dynamic_states.end(), extended3.begin(), extended3.end()); + } + + // EDS3 - Enables (granular: DepthClamp + LogicOpEnable + ...) + if (key.state.extended_dynamic_state_3_enables) { + static constexpr std::array extended3{ + VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT, + VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT, + + // additional state3 extensions + VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT, + + VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT, + + VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT, + VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT, + VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT, + VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT, + VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT, + }; + dynamic_states.insert(dynamic_states.end(), extended3.begin(), extended3.end()); } const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 333400f74c..76d6ee554e 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -425,12 +425,37 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, LOG_INFO(Render_Vulkan, "DynamicState value is set to {}", (u32) dynamic_state); dynamic_features = DynamicFeatures{ + // EDS1 - All-or-nothing (enabled if driver supports AND setting > 0) .has_extended_dynamic_state = device.IsExtExtendedDynamicStateSupported() && dynamic_state > 0, + + // EDS2 - Core features (enabled if driver supports AND setting > 1) .has_extended_dynamic_state_2 = device.IsExtExtendedDynamicState2Supported() && dynamic_state > 1, - .has_extended_dynamic_state_2_extra = device.IsExtExtendedDynamicState2ExtrasSupported() && dynamic_state > 1, + .has_extended_dynamic_state_2_logic_op = device.IsExtExtendedDynamicState2LogicOpSupported() && dynamic_state > 1, + .has_extended_dynamic_state_2_patch_control_points = device.IsExtExtendedDynamicState2PatchControlPointsSupported() && dynamic_state > 1, + + // EDS3 - Granular features (enabled if driver supports AND setting > 2) .has_extended_dynamic_state_3_blend = device.IsExtExtendedDynamicState3BlendingSupported() && dynamic_state > 2, .has_extended_dynamic_state_3_enables = device.IsExtExtendedDynamicState3EnablesSupported() && dynamic_state > 2, - .has_dynamic_vertex_input = device.IsExtVertexInputDynamicStateSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_depth_clamp = device.IsExtExtendedDynamicState3DepthClampEnableSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_logic_op_enable = device.IsExtExtendedDynamicState3LogicOpEnableSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_tessellation_domain_origin = device.IsExtExtendedDynamicState3TessellationDomainOriginSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_polygon_mode = device.IsExtExtendedDynamicState3PolygonModeSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_rasterization_samples = device.IsExtExtendedDynamicState3RasterizationSamplesSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_sample_mask = device.IsExtExtendedDynamicState3SampleMaskSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_alpha_to_coverage_enable = device.IsExtExtendedDynamicState3AlphaToCoverageEnableSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_alpha_to_one_enable = device.IsExtExtendedDynamicState3AlphaToOneEnableSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_depth_clip_enable = device.IsExtExtendedDynamicState3DepthClipEnableSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_depth_clip_negative_one_to_one = device.IsExtExtendedDynamicState3DepthClipNegativeOneToOneSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_line_rasterization_mode = device.IsExtExtendedDynamicState3LineRasterizationModeSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_line_stipple_enable = device.IsExtExtendedDynamicState3LineStippleEnableSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_provoking_vertex_mode = device.IsExtExtendedDynamicState3ProvokingVertexModeSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_conservative_rasterization_mode = device.IsExtExtendedDynamicState3ConservativeRasterizationModeSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_sample_locations_enable = device.IsExtExtendedDynamicState3SampleLocationsEnableSupported() && dynamic_state > 2, + .has_extended_dynamic_state_3_rasterization_stream = device.IsExtExtendedDynamicState3RasterizationStreamSupported() && dynamic_state > 2, + + // Vertex input dynamic state + .has_dynamic_vertex_input = device.IsExtVertexInputDynamicStateSupported() && + Settings::values.vertex_input_dynamic_state.GetValue(), }; } @@ -532,16 +557,29 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading GraphicsPipelineCacheKey key; file.read(reinterpret_cast(&key), sizeof(key)); - if ((key.state.extended_dynamic_state != 0) != - dynamic_features.has_extended_dynamic_state || - (key.state.extended_dynamic_state_2 != 0) != - dynamic_features.has_extended_dynamic_state_2 || - (key.state.extended_dynamic_state_2_extra != 0) != - dynamic_features.has_extended_dynamic_state_2_extra || - (key.state.extended_dynamic_state_3_blend != 0) != - dynamic_features.has_extended_dynamic_state_3_blend || - (key.state.extended_dynamic_state_3_enables != 0) != - dynamic_features.has_extended_dynamic_state_3_enables || + // Validate dynamic features compatibility - granular per-feature check + if ((key.state.extended_dynamic_state != 0) != dynamic_features.has_extended_dynamic_state || + (key.state.extended_dynamic_state_2 != 0) != dynamic_features.has_extended_dynamic_state_2 || + (key.state.extended_dynamic_state_2_logic_op != 0) != dynamic_features.has_extended_dynamic_state_2_logic_op || + (key.state.extended_dynamic_state_2_patch_control_points != 0) != dynamic_features.has_extended_dynamic_state_2_patch_control_points || + (key.state.extended_dynamic_state_3_blend != 0) != dynamic_features.has_extended_dynamic_state_3_blend || + (key.state.extended_dynamic_state_3_enables != 0) != dynamic_features.has_extended_dynamic_state_3_enables || + (key.state.extended_dynamic_state_3_depth_clamp != 0) != dynamic_features.has_extended_dynamic_state_3_depth_clamp || + (key.state.extended_dynamic_state_3_logic_op_enable != 0) != dynamic_features.has_extended_dynamic_state_3_logic_op_enable || + (key.state.extended_dynamic_state_3_tessellation_domain_origin != 0) != dynamic_features.has_extended_dynamic_state_3_tessellation_domain_origin || + (key.state.extended_dynamic_state_3_polygon_mode != 0) != dynamic_features.has_extended_dynamic_state_3_polygon_mode || + (key.state.extended_dynamic_state_3_rasterization_samples != 0) != dynamic_features.has_extended_dynamic_state_3_rasterization_samples || + (key.state.extended_dynamic_state_3_sample_mask != 0) != dynamic_features.has_extended_dynamic_state_3_sample_mask || + (key.state.extended_dynamic_state_3_alpha_to_coverage_enable != 0) != dynamic_features.has_extended_dynamic_state_3_alpha_to_coverage_enable || + (key.state.extended_dynamic_state_3_alpha_to_one_enable != 0) != dynamic_features.has_extended_dynamic_state_3_alpha_to_one_enable || + (key.state.extended_dynamic_state_3_depth_clip_enable != 0) != dynamic_features.has_extended_dynamic_state_3_depth_clip_enable || + (key.state.extended_dynamic_state_3_depth_clip_negative_one_to_one != 0) != dynamic_features.has_extended_dynamic_state_3_depth_clip_negative_one_to_one || + (key.state.extended_dynamic_state_3_line_rasterization_mode != 0) != dynamic_features.has_extended_dynamic_state_3_line_rasterization_mode || + (key.state.extended_dynamic_state_3_line_stipple_enable != 0) != dynamic_features.has_extended_dynamic_state_3_line_stipple_enable || + (key.state.extended_dynamic_state_3_provoking_vertex_mode != 0) != dynamic_features.has_extended_dynamic_state_3_provoking_vertex_mode || + (key.state.extended_dynamic_state_3_conservative_rasterization_mode != 0) != dynamic_features.has_extended_dynamic_state_3_conservative_rasterization_mode || + (key.state.extended_dynamic_state_3_sample_locations_enable != 0) != dynamic_features.has_extended_dynamic_state_3_sample_locations_enable || + (key.state.extended_dynamic_state_3_rasterization_stream != 0) != dynamic_features.has_extended_dynamic_state_3_rasterization_stream || (key.state.dynamic_vertex_input != 0) != dynamic_features.has_dynamic_vertex_input) { return; } diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index 7909bd8cf0..b9b4d5cc64 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -113,6 +113,10 @@ public: void LoadDiskResources(u64 title_id, std::stop_token stop_loading, const VideoCore::DiskResourceLoadCallback& callback); + [[nodiscard]] const DynamicFeatures& GetDynamicFeatures() const noexcept { + return dynamic_features; + } + private: [[nodiscard]] GraphicsPipeline* CurrentGraphicsPipelineSlowPath(); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 44fe42ce9e..c45ecd0040 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -954,9 +954,10 @@ void RasterizerVulkan::UpdateDynamicStates() { UpdateStencilFaces(regs); UpdateLineWidth(regs); - const u8 dynamic_state = Settings::values.dyna_state.GetValue(); + const auto& dynamic_features = pipeline_cache.GetDynamicFeatures(); - if (device.IsExtExtendedDynamicStateSupported() && dynamic_state > 0) { + // EDS1 - Extended Dynamic State 1 + if (dynamic_features.has_extended_dynamic_state) { UpdateCullMode(regs); UpdateDepthCompareOp(regs); UpdateFrontFace(regs); @@ -966,40 +967,78 @@ void RasterizerVulkan::UpdateDynamicStates() { UpdateDepthTestEnable(regs); UpdateDepthWriteEnable(regs); UpdateStencilTestEnable(regs); - if (device.IsExtExtendedDynamicState2Supported() && dynamic_state > 1) { - UpdatePrimitiveRestartEnable(regs); - UpdateRasterizerDiscardEnable(regs); - UpdateDepthBiasEnable(regs); - } - if (device.IsExtExtendedDynamicState3EnablesSupported() && dynamic_state > 2) { - using namespace Tegra::Engines; - if (device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_OPEN_SOURCE || device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_PROPRIETARY) { - struct In { - const Maxwell3D::Regs::VertexAttribute::Type d; - In(Maxwell3D::Regs::VertexAttribute::Type n) : d(n) {} - bool operator()(Maxwell3D::Regs::VertexAttribute n) const { - return n.type == d; - } - }; - auto has_float = std::any_of(regs.vertex_attrib_format.begin(), regs.vertex_attrib_format.end(), In(Maxwell3D::Regs::VertexAttribute::Type::Float)); - if (regs.logic_op.enable) { - regs.logic_op.enable = static_cast(!has_float); + } + } + + // EDS2 - Extended Dynamic State 2 Core + if (dynamic_features.has_extended_dynamic_state_2) { + if (state_tracker.TouchStateEnable()) { + UpdatePrimitiveRestartEnable(regs); + UpdateRasterizerDiscardEnable(regs); + UpdateDepthBiasEnable(regs); + } + } + + // EDS2 - LogicOp (granular feature) + if (dynamic_features.has_extended_dynamic_state_2_logic_op) { + UpdateLogicOp(regs); + } + + // EDS3 - Depth Clamp Enable (granular) + if (dynamic_features.has_extended_dynamic_state_3_depth_clamp || + dynamic_features.has_extended_dynamic_state_3_enables) { + if (state_tracker.TouchStateEnable()) { + UpdateDepthClampEnable(regs); + } + } + + // EDS3 - Logic Op Enable (granular) + if (dynamic_features.has_extended_dynamic_state_3_logic_op_enable || + dynamic_features.has_extended_dynamic_state_3_enables) { + if (state_tracker.TouchStateEnable()) { + using namespace Tegra::Engines; + // AMD workaround for logic op with float vertex attributes + if (device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_OPEN_SOURCE || + device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_PROPRIETARY) { + struct In { + const Maxwell3D::Regs::VertexAttribute::Type d; + In(Maxwell3D::Regs::VertexAttribute::Type n) : d(n) {} + bool operator()(Maxwell3D::Regs::VertexAttribute n) const { + return n.type == d; } + }; + auto has_float = std::any_of(regs.vertex_attrib_format.begin(), + regs.vertex_attrib_format.end(), + In(Maxwell3D::Regs::VertexAttribute::Type::Float)); + if (regs.logic_op.enable) { + regs.logic_op.enable = static_cast(!has_float); } - UpdateLogicOpEnable(regs); - UpdateDepthClampEnable(regs); - UpdateLineStippleEnable(regs); - UpdateConservativeRasterizationMode(regs); } + UpdateLogicOpEnable(regs); } - if (device.IsExtExtendedDynamicState2ExtrasSupported() && dynamic_state > 1) { - UpdateLogicOp(regs); + } + + // EDS3 - Line Stipple Enable (granular) + if (dynamic_features.has_extended_dynamic_state_3_line_stipple_enable) { + if (state_tracker.TouchStateEnable()) { + UpdateLineStippleEnable(regs); } - if (device.IsExtExtendedDynamicState3BlendingSupported() && dynamic_state > 2) { - UpdateBlending(regs); + } + + // EDS3 - Conservative Rasterization Mode (granular) + if (dynamic_features.has_extended_dynamic_state_3_conservative_rasterization_mode) { + if (state_tracker.TouchStateEnable()) { + UpdateConservativeRasterizationMode(regs); } } - if (device.IsExtVertexInputDynamicStateSupported() && dynamic_state > 2) { + + // EDS3 - Blending (composite feature: ColorBlendEnable + ColorBlendEquation + ColorWriteMask) + if (dynamic_features.has_extended_dynamic_state_3_blend) { + UpdateBlending(regs); + } + + // Vertex Input Dynamic State + if (dynamic_features.has_dynamic_vertex_input) { if (auto* gp = pipeline_cache.CurrentGraphicsPipeline(); gp && gp->HasDynamicVertexInput()) { UpdateVertexInput(regs); } diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 2f02c24b74..28bcd8b059 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -843,11 +843,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); - RemoveExtensionFeature(extensions.vertex_input_dynamic_state, features.vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); dynamic_state3_blending = false; dynamic_state3_enables = false; LOG_INFO(Render_Vulkan, "Extended dynamic state is fully disabled"); + // Note: vertex_input_dynamic_state has its own independent toggle and is NOT affected by dyna_state = 0 } #ifdef ANDROID @@ -1481,11 +1481,18 @@ void Device::RemoveUnsuitableExtensions() { RemoveExtensionIfUnsuitable(extensions.swapchain_maintenance1, VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME); // VK_EXT_vertex_input_dynamic_state - extensions.vertex_input_dynamic_state = - features.vertex_input_dynamic_state.vertexInputDynamicState; - RemoveExtensionFeatureIfUnsuitable(extensions.vertex_input_dynamic_state, - features.vertex_input_dynamic_state, - VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); + if (Settings::values.vertex_input_dynamic_state.GetValue()) { + extensions.vertex_input_dynamic_state = + features.vertex_input_dynamic_state.vertexInputDynamicState; + RemoveExtensionFeatureIfUnsuitable(extensions.vertex_input_dynamic_state, + features.vertex_input_dynamic_state, + VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); + } else { + RemoveExtensionFeature(extensions.vertex_input_dynamic_state, + features.vertex_input_dynamic_state, + VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); + LOG_INFO(Render_Vulkan, "Vertex Input Dynamic State disabled by user setting"); + } // VK_KHR_pipeline_executable_properties if (Settings::values.renderer_shader_feedback.GetValue()) { diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 07f4446197..38647298c4 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -548,6 +548,21 @@ public: return extensions.custom_border_color; } + /// Base Vulkan Dynamic State support checks. + /// These provide granular control over each base dynamic state, allowing individual states + /// to be disabled if broken driver implementations are detected at device initialization. + /// By default all states are enabled. If a specific driver has issues with certain states, + /// they can be disabled in vulkan_device.cpp constructor (see has_broken_compute pattern). + bool SupportsDynamicViewport() const { return supports_dynamic_viewport; } + bool SupportsDynamicScissor() const { return supports_dynamic_scissor; } + bool SupportsDynamicLineWidth() const { return supports_dynamic_line_width; } + bool SupportsDynamicDepthBias() const { return supports_dynamic_depth_bias; } + bool SupportsDynamicBlendConstants() const { return supports_dynamic_blend_constants; } + bool SupportsDynamicDepthBounds() const { return supports_dynamic_depth_bounds; } + bool SupportsDynamicStencilCompareMask() const { return supports_dynamic_stencil_compare; } + bool SupportsDynamicStencilWriteMask() const { return supports_dynamic_stencil_write; } + bool SupportsDynamicStencilReference() const { return supports_dynamic_stencil_reference; } + /// Returns true if the device supports VK_EXT_extended_dynamic_state. bool IsExtExtendedDynamicStateSupported() const { return extensions.extended_dynamic_state; @@ -582,6 +597,98 @@ public: return dynamic_state3_enables; } + // EDS2 granular feature checks + bool IsExtExtendedDynamicState2LogicOpSupported() const { + return extensions.extended_dynamic_state2 && + features.extended_dynamic_state2.extendedDynamicState2LogicOp; + } + + bool IsExtExtendedDynamicState2PatchControlPointsSupported() const { + return extensions.extended_dynamic_state2 && + features.extended_dynamic_state2.extendedDynamicState2PatchControlPoints; + } + + // EDS3 granular feature checks + bool IsExtExtendedDynamicState3DepthClampEnableSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3DepthClampEnable; + } + + bool IsExtExtendedDynamicState3LogicOpEnableSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable; + } + + bool IsExtExtendedDynamicState3TessellationDomainOriginSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3TessellationDomainOrigin; + } + + bool IsExtExtendedDynamicState3PolygonModeSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3PolygonMode; + } + + bool IsExtExtendedDynamicState3RasterizationSamplesSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3RasterizationSamples; + } + + bool IsExtExtendedDynamicState3SampleMaskSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3SampleMask; + } + + bool IsExtExtendedDynamicState3AlphaToCoverageEnableSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3AlphaToCoverageEnable; + } + + bool IsExtExtendedDynamicState3AlphaToOneEnableSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3AlphaToOneEnable; + } + + bool IsExtExtendedDynamicState3DepthClipEnableSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3DepthClipEnable; + } + + bool IsExtExtendedDynamicState3DepthClipNegativeOneToOneSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3DepthClipNegativeOneToOne; + } + + bool IsExtExtendedDynamicState3LineRasterizationModeSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3LineRasterizationMode; + } + + bool IsExtExtendedDynamicState3LineStippleEnableSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3LineStippleEnable; + } + + bool IsExtExtendedDynamicState3ProvokingVertexModeSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3ProvokingVertexMode; + } + + bool IsExtExtendedDynamicState3ConservativeRasterizationModeSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3ConservativeRasterizationMode; + } + + bool IsExtExtendedDynamicState3SampleLocationsEnableSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3SampleLocationsEnable; + } + + bool IsExtExtendedDynamicState3RasterizationStreamSupported() const { + return extensions.extended_dynamic_state3 && + features.extended_dynamic_state3.extendedDynamicState3RasterizationStream; + } + /// Returns true if the device supports VK_EXT_filter_cubic bool IsExtFilterCubicSupported() const { return extensions.filter_cubic; @@ -918,6 +1025,22 @@ private: bool dynamic_state3_blending{}; ///< Has all blending features of dynamic_state3. bool dynamic_state3_enables{}; ///< Has all enables features of dynamic_state3. bool supports_conditional_barriers{}; ///< Allows barriers in conditional control flow. + + /// Base Vulkan Dynamic State support flags (granular fallback for broken drivers). + /// All default to true. These can be individually disabled in vulkan_device.cpp + /// if specific broken driver implementations are detected during initialization. + /// This provides emergency protection against drivers that report support but crash/misbehave. + /// Pattern: Check driver/device and set to false in vulkan_device.cpp constructor. + bool supports_dynamic_viewport{true}; ///< VK_DYNAMIC_STATE_VIEWPORT + bool supports_dynamic_scissor{true}; ///< VK_DYNAMIC_STATE_SCISSOR + bool supports_dynamic_line_width{true}; ///< VK_DYNAMIC_STATE_LINE_WIDTH + bool supports_dynamic_depth_bias{true}; ///< VK_DYNAMIC_STATE_DEPTH_BIAS + bool supports_dynamic_blend_constants{true}; ///< VK_DYNAMIC_STATE_BLEND_CONSTANTS + bool supports_dynamic_depth_bounds{true}; ///< VK_DYNAMIC_STATE_DEPTH_BOUNDS + bool supports_dynamic_stencil_compare{true}; ///< VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK + bool supports_dynamic_stencil_write{true}; ///< VK_DYNAMIC_STATE_STENCIL_WRITE_MASK + bool supports_dynamic_stencil_reference{true};///< VK_DYNAMIC_STATE_STENCIL_REFERENCE + u64 device_access_memory{}; ///< Total size of device local memory in bytes. u32 sets_per_pool{}; ///< Sets per Description Pool NvidiaArchitecture nvidia_arch{NvidiaArchitecture::Arch_AmpereOrNewer};