diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index d3a73a6d1e..a36d483f03 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -735,13 +735,18 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .lineWidth = 1.0f, // TODO(alekpop): Transfer from regs }; + const bool smooth_lines_supported = + device.IsExtLineRasterizationSupported() && device.SupportsSmoothLines(); + const bool stippled_lines_supported = + device.IsExtLineRasterizationSupported() && device.SupportsStippledRectangularLines(); VkPipelineRasterizationLineStateCreateInfoEXT line_state{ .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT, .pNext = nullptr, - .lineRasterizationMode = key.state.smooth_lines != 0 + .lineRasterizationMode = key.state.smooth_lines != 0 && smooth_lines_supported ? VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT : VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT, - .stippledLineEnable = dynamic.line_stipple_enable ? VK_TRUE : VK_FALSE, + .stippledLineEnable = + (dynamic.line_stipple_enable && stippled_lines_supported) ? VK_TRUE : VK_FALSE, .lineStippleFactor = key.state.line_stipple_factor, .lineStipplePattern = static_cast(key.state.line_stipple_pattern), }; @@ -773,6 +778,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { } const bool supports_alpha_output = fragment_has_color0_output; + const bool alpha_to_one_supported = device.SupportsAlphaToOne(); const VkPipelineMultisampleStateCreateInfo multisample_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pNext = nullptr, @@ -783,8 +789,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .pSampleMask = nullptr, .alphaToCoverageEnable = supports_alpha_output && key.state.alpha_to_coverage_enabled != 0 ? VK_TRUE : VK_FALSE, - .alphaToOneEnable = - supports_alpha_output && key.state.alpha_to_one_enabled != 0 ? VK_TRUE : VK_FALSE, + .alphaToOneEnable = supports_alpha_output && alpha_to_one_supported && + key.state.alpha_to_one_enabled != 0 ? VK_TRUE : VK_FALSE, }; const VkPipelineDepthStencilStateCreateInfo depth_stencil_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, @@ -899,18 +905,29 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { dynamic_states.insert(dynamic_states.end(), extended3.begin(), extended3.end()); } - // EDS3 - Enables (composite: 9 states) + // EDS3 - Enables (composite: per-feature) 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, - 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, - }; - dynamic_states.insert(dynamic_states.end(), extended3.begin(), extended3.end()); + if (device.SupportsDynamicState3DepthClampEnable()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT); + } + if (device.SupportsDynamicState3LogicOpEnable()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT); + } + if (device.SupportsDynamicState3LineRasterizationMode()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT); + } + if (device.SupportsDynamicState3ConservativeRasterizationMode()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT); + } + if (device.SupportsDynamicState3LineStippleEnable()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT); + } + if (device.SupportsDynamicState3AlphaToCoverageEnable()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT); + } + if (device.SupportsDynamicState3AlphaToOneEnable()) { + dynamic_states.push_back(VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT); + } } const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 85e22c6477..ed388f9426 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1418,6 +1418,10 @@ void RasterizerVulkan::UpdateConservativeRasterizationMode(Tegra::Engines::Maxwe return; } + if (!device.SupportsDynamicState3ConservativeRasterizationMode()) { + return; + } + scheduler.Record([enable = regs.conservative_raster_enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetConservativeRasterizationModeEXT( enable ? VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT @@ -1430,6 +1434,10 @@ void RasterizerVulkan::UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs& return; } + if (!device.SupportsDynamicState3LineStippleEnable()) { + return; + } + scheduler.Record([enable = regs.line_stipple_enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetLineStippleEnableEXT(enable); }); @@ -1443,9 +1451,30 @@ void RasterizerVulkan::UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Re return; } - const VkLineRasterizationModeEXT mode = - regs.line_anti_alias_enable != 0 ? VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT - : VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT; + if (!device.SupportsDynamicState3LineRasterizationMode()) { + static std::once_flag warn_missing_rect; + std::call_once(warn_missing_rect, [] { + LOG_WARNING(Render_Vulkan, + "Driver lacks rectangular line rasterization support; skipping dynamic " + "line state updates"); + }); + return; + } + + const bool wants_smooth = regs.line_anti_alias_enable != 0; + VkLineRasterizationModeEXT mode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT; + if (wants_smooth) { + if (device.SupportsSmoothLines()) { + mode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT; + } else { + static std::once_flag warn_missing_smooth; + std::call_once(warn_missing_smooth, [] { + LOG_WARNING(Render_Vulkan, + "Line anti-aliasing requested but smoothLines feature unavailable; " + "using rectangular rasterization"); + }); + } + } scheduler.Record([mode](vk::CommandBuffer cmdbuf) { cmdbuf.SetLineRasterizationModeEXT(mode); }); @@ -1490,6 +1519,9 @@ void RasterizerVulkan::UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs if (!state_tracker.TouchLogicOpEnable()) { return; } + if (!device.SupportsDynamicState3LogicOpEnable()) { + return; + } scheduler.Record([enable = regs.logic_op.enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetLogicOpEnableEXT(enable != 0); }); @@ -1499,6 +1531,9 @@ void RasterizerVulkan::UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& r if (!state_tracker.TouchDepthClampEnable()) { return; } + if (!device.SupportsDynamicState3DepthClampEnable()) { + return; + } bool is_enabled = !(regs.viewport_clip_control.geometry_clip == Maxwell::ViewportClipControl::GeometryClip::Passthrough || regs.viewport_clip_control.geometry_clip == @@ -1513,6 +1548,9 @@ void RasterizerVulkan::UpdateAlphaToCoverageEnable(Tegra::Engines::Maxwell3D::Re if (!state_tracker.TouchAlphaToCoverageEnable()) { return; } + if (!device.SupportsDynamicState3AlphaToCoverageEnable()) { + return; + } GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline(); const bool enable = pipeline != nullptr && pipeline->SupportsAlphaToCoverage() && regs.anti_alias_alpha_control.alpha_to_coverage != 0; @@ -1525,6 +1563,14 @@ void RasterizerVulkan::UpdateAlphaToOneEnable(Tegra::Engines::Maxwell3D::Regs& r if (!state_tracker.TouchAlphaToOneEnable()) { return; } + if (!device.SupportsDynamicState3AlphaToOneEnable()) { + static std::once_flag warn_alpha_to_one; + std::call_once(warn_alpha_to_one, [] { + LOG_WARNING(Render_Vulkan, + "Alpha-to-one is not supported on this device; forcing it disabled"); + }); + return; + } GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline(); const bool enable = pipeline != nullptr && pipeline->SupportsAlphaToOne() && regs.anti_alias_alpha_control.alpha_to_one != 0; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 6a2231d6fe..f69dfc777e 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1259,26 +1259,45 @@ void Device::RemoveUnsuitableExtensions() { features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable; const bool supports_line_raster_mode = features.extended_dynamic_state3.extendedDynamicState3LineRasterizationMode && - extensions.line_rasterization; + extensions.line_rasterization && features.line_rasterization.rectangularLines; const bool supports_conservative_raster_mode = features.extended_dynamic_state3.extendedDynamicState3ConservativeRasterizationMode && extensions.conservative_rasterization; const bool supports_line_stipple_enable = features.extended_dynamic_state3.extendedDynamicState3LineStippleEnable && - extensions.line_rasterization; + extensions.line_rasterization && features.line_rasterization.stippledRectangularLines; const bool supports_alpha_to_coverage = features.extended_dynamic_state3.extendedDynamicState3AlphaToCoverageEnable; const bool supports_alpha_to_one = - features.extended_dynamic_state3.extendedDynamicState3AlphaToOneEnable; - - dynamic_state3_enables = supports_depth_clamp_enable && supports_logic_op_enable && - supports_line_raster_mode && supports_conservative_raster_mode && - supports_line_stipple_enable && supports_alpha_to_coverage && - supports_alpha_to_one; + features.extended_dynamic_state3.extendedDynamicState3AlphaToOneEnable && + features.features.alphaToOne; + + dynamic_state3_depth_clamp_enable = supports_depth_clamp_enable; + dynamic_state3_logic_op_enable = supports_logic_op_enable; + dynamic_state3_line_raster_mode = supports_line_raster_mode; + dynamic_state3_conservative_raster_mode = supports_conservative_raster_mode; + dynamic_state3_line_stipple_enable = supports_line_stipple_enable; + dynamic_state3_alpha_to_coverage = supports_alpha_to_coverage; + dynamic_state3_alpha_to_one = supports_alpha_to_one; + + dynamic_state3_enables = dynamic_state3_depth_clamp_enable || dynamic_state3_logic_op_enable || + dynamic_state3_line_raster_mode || + dynamic_state3_conservative_raster_mode || + dynamic_state3_line_stipple_enable || + dynamic_state3_alpha_to_coverage || dynamic_state3_alpha_to_one; extensions.extended_dynamic_state3 = dynamic_state3_blending || dynamic_state3_enables; - dynamic_state3_blending = dynamic_state3_blending && extensions.extended_dynamic_state3; - dynamic_state3_enables = dynamic_state3_enables && extensions.extended_dynamic_state3; + if (!extensions.extended_dynamic_state3) { + dynamic_state3_blending = false; + dynamic_state3_enables = false; + dynamic_state3_depth_clamp_enable = false; + dynamic_state3_logic_op_enable = false; + dynamic_state3_line_raster_mode = false; + dynamic_state3_conservative_raster_mode = false; + dynamic_state3_line_stipple_enable = false; + dynamic_state3_alpha_to_coverage = false; + dynamic_state3_alpha_to_one = false; + } RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state3, features.extended_dynamic_state3, VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 8f200fcff4..170fb20c6c 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -638,6 +638,50 @@ public: return extensions.line_rasterization; } + bool SupportsRectangularLines() const { + return features.line_rasterization.rectangularLines != VK_FALSE; + } + + bool SupportsSmoothLines() const { + return features.line_rasterization.smoothLines != VK_FALSE; + } + + bool SupportsStippledRectangularLines() const { + return features.line_rasterization.stippledRectangularLines != VK_FALSE; + } + + bool SupportsAlphaToOne() const { + return features.features.alphaToOne != VK_FALSE; + } + + bool SupportsDynamicState3DepthClampEnable() const { + return dynamic_state3_depth_clamp_enable; + } + + bool SupportsDynamicState3LogicOpEnable() const { + return dynamic_state3_logic_op_enable; + } + + bool SupportsDynamicState3LineRasterizationMode() const { + return dynamic_state3_line_raster_mode; + } + + bool SupportsDynamicState3ConservativeRasterizationMode() const { + return dynamic_state3_conservative_raster_mode; + } + + bool SupportsDynamicState3LineStippleEnable() const { + return dynamic_state3_line_stipple_enable; + } + + bool SupportsDynamicState3AlphaToCoverageEnable() const { + return dynamic_state3_alpha_to_coverage; + } + + bool SupportsDynamicState3AlphaToOneEnable() const { + return dynamic_state3_alpha_to_one; + } + /// Returns true if the device supports VK_EXT_vertex_input_dynamic_state. bool IsExtVertexInputDynamicStateSupported() const { return extensions.vertex_input_dynamic_state; @@ -986,8 +1030,15 @@ private: bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting. bool must_emulate_scaled_formats{}; ///< Requires scaled vertex format emulation bool must_emulate_bgr565{}; ///< Emulates BGR565 by swizzling RGB565 format. - bool dynamic_state3_blending{}; ///< Has all blending features of dynamic_state3. - bool dynamic_state3_enables{}; ///< Has all enables features of dynamic_state3. + bool dynamic_state3_blending{}; ///< Has blending features of dynamic_state3. + bool dynamic_state3_enables{}; ///< Has at least one enable feature of dynamic_state3. + bool dynamic_state3_depth_clamp_enable{}; + bool dynamic_state3_logic_op_enable{}; + bool dynamic_state3_line_raster_mode{}; + bool dynamic_state3_conservative_raster_mode{}; + bool dynamic_state3_line_stipple_enable{}; + bool dynamic_state3_alpha_to_coverage{}; + bool dynamic_state3_alpha_to_one{}; bool supports_conditional_barriers{}; ///< Allows barriers in conditional control flow. u64 device_access_memory{}; ///< Total size of device local memory in bytes. u32 sets_per_pool{}; ///< Sets per Description Pool