diff --git a/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs b/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs index 8c7089aa5..952867642 100644 --- a/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs +++ b/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs @@ -31,6 +31,7 @@ namespace Ryujinx.Graphics.Vulkan public readonly bool SupportsShaderStorageImageMultisample; public readonly bool SupportsConditionalRendering; public readonly bool SupportsExtendedDynamicState; + public readonly bool SupportsExtendedDynamicState2; public readonly bool SupportsMultiView; public readonly bool SupportsNullDescriptors; public readonly bool SupportsPushDescriptors; @@ -70,6 +71,7 @@ namespace Ryujinx.Graphics.Vulkan bool supportsShaderStorageImageMultisample, bool supportsConditionalRendering, bool supportsExtendedDynamicState, + bool supportsExtendedDynamicState2, bool supportsMultiView, bool supportsNullDescriptors, bool supportsPushDescriptors, @@ -108,6 +110,7 @@ namespace Ryujinx.Graphics.Vulkan SupportsShaderStorageImageMultisample = supportsShaderStorageImageMultisample; SupportsConditionalRendering = supportsConditionalRendering; SupportsExtendedDynamicState = supportsExtendedDynamicState; + SupportsExtendedDynamicState2 = supportsExtendedDynamicState2; SupportsMultiView = supportsMultiView; SupportsNullDescriptors = supportsNullDescriptors; SupportsPushDescriptors = supportsPushDescriptors; diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs index 0fee64770..631800881 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -85,6 +85,7 @@ namespace Ryujinx.Graphics.Vulkan private bool _tfActive; private bool _supportExtDynamic; + private bool _supportExtDynamic2; private readonly PipelineColorBlendAttachmentState[] _storedBlend; @@ -125,6 +126,9 @@ namespace Ryujinx.Graphics.Vulkan _storedBlend = new PipelineColorBlendAttachmentState[Constants.MaxRenderTargets]; _supportExtDynamic = gd.Capabilities.SupportsExtendedDynamicState; + + _supportExtDynamic2 = gd.Capabilities.SupportsExtendedDynamicState2; + _newState.Initialize(); } @@ -868,9 +872,13 @@ namespace Ryujinx.Graphics.Vulkan public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp) { - DynamicState.SetDepthBias(factor, units, clamp); + DynamicState.SetDepthBias(factor, units, clamp, (enables != 0)); - _newState.DepthBiasEnable = enables != 0; + if (!_supportExtDynamic2) + { + _newState.DepthBiasEnable = enables != 0; + } + SignalStateChange(); } @@ -983,6 +991,7 @@ namespace Ryujinx.Graphics.Vulkan { _newState.LogicOpEnable = enable; _newState.LogicOp = op.Convert(); + SignalStateChange(); } @@ -1071,7 +1080,14 @@ namespace Ryujinx.Graphics.Vulkan public void SetRasterizerDiscard(bool discard) { - _newState.RasterizerDiscardEnable = discard; + if (!_supportExtDynamic2) + { + _newState.RasterizerDiscardEnable = discard; + } + else + { + DynamicState.SetRasterizerDiscard(discard); + } SignalStateChange(); } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs index b6bb954fb..efee04b10 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs @@ -10,6 +10,7 @@ namespace Ryujinx.Graphics.Vulkan private float _depthBiasSlopeFactor; private float _depthBiasConstantFactor; private float _depthBiasClamp; + private bool _depthBiasEnable; public int ScissorsCount; private Array16 _scissors; @@ -47,6 +48,8 @@ namespace Ryujinx.Graphics.Vulkan public CullModeFlags CullMode; public FrontFace FrontFace; + private bool _discard; + [Flags] private enum DirtyFlags { @@ -62,8 +65,10 @@ namespace Ryujinx.Graphics.Vulkan DepthTestCompareOp = 1 << 8, StencilTestEnable = 1 << 9, LineWidth = 1 << 10, + RasterDiscard = 1 << 11, Standard = Blend | DepthBias | Scissor | Stencil | Viewport | LineWidth, Extended = CullMode | FrontFace | DepthTestBool | DepthTestCompareOp | StencilTestEnable, + Extended2 = RasterDiscard, } private DirtyFlags _dirty; @@ -78,11 +83,12 @@ namespace Ryujinx.Graphics.Vulkan _dirty |= DirtyFlags.Blend; } - public void SetDepthBias(float slopeFactor, float constantFactor, float clamp) + public void SetDepthBias(float slopeFactor, float constantFactor, float clamp, bool enable) { _depthBiasSlopeFactor = slopeFactor; _depthBiasConstantFactor = constantFactor; _depthBiasClamp = clamp; + _depthBiasEnable = enable; _dirty |= DirtyFlags.DepthBias; } @@ -195,6 +201,13 @@ namespace Ryujinx.Graphics.Vulkan _dirty |= DirtyFlags.LineWidth; } + + public void SetRasterizerDiscard(bool discard) + { + _discard = discard; + + _dirty |= DirtyFlags.RasterDiscard; + } public void ForceAllDirty(VulkanRenderer gd) { @@ -205,6 +218,11 @@ namespace Ryujinx.Graphics.Vulkan _dirty = DirtyFlags.Standard | DirtyFlags.Extended; } + if (gd.Capabilities.SupportsExtendedDynamicState2) + { + _dirty = DirtyFlags.Standard | DirtyFlags.Extended | DirtyFlags.Extended2; + } + if (gd.IsMoltenVk) { _dirty &= ~DirtyFlags.LineWidth; @@ -220,7 +238,7 @@ namespace Ryujinx.Graphics.Vulkan if (_dirty.HasFlag(DirtyFlags.DepthBias)) { - RecordDepthBias(gd.Api, commandBuffer); + RecordDepthBias(gd, commandBuffer); } if (_dirty.HasFlag(DirtyFlags.Scissor)) @@ -267,7 +285,12 @@ namespace Ryujinx.Graphics.Vulkan { RecordLineWidth(gd.Api, commandBuffer); } - + + if (_dirty.HasFlag(DirtyFlags.RasterDiscard)) + { + RecordRasterizationDiscard(gd, commandBuffer); + } + _dirty = DirtyFlags.None; } @@ -276,9 +299,14 @@ namespace Ryujinx.Graphics.Vulkan api.CmdSetBlendConstants(commandBuffer, _blendConstants.AsSpan()); } - private readonly void RecordDepthBias(Vk api, CommandBuffer commandBuffer) + private readonly void RecordDepthBias(VulkanRenderer gd, CommandBuffer commandBuffer) { - api.CmdSetDepthBias(commandBuffer, _depthBiasConstantFactor, _depthBiasClamp, _depthBiasSlopeFactor); + gd.Api.CmdSetDepthBias(commandBuffer, _depthBiasConstantFactor, _depthBiasClamp, _depthBiasSlopeFactor); + + if (gd.Capabilities.SupportsExtendedDynamicState2) + { + gd.ExtendedDynamicState2Api.CmdSetDepthBiasEnable(commandBuffer, _depthBiasEnable); + } } private void RecordScissor(VulkanRenderer gd, CommandBuffer commandBuffer) @@ -363,6 +391,11 @@ namespace Ryujinx.Graphics.Vulkan api.CmdSetDepthCompareOp(commandBuffer, _depthCompareOp); } + private void RecordRasterizationDiscard(VulkanRenderer gd, CommandBuffer commandBuffer) + { + gd.ExtendedDynamicState2Api.CmdSetRasterizerDiscardEnable(commandBuffer, _discard); + } + private void RecordLineWidth(Vk api, CommandBuffer commandBuffer) { if (!OperatingSystem.IsMacOS()) diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs index f7a63a5da..94bab99e6 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs @@ -406,6 +406,8 @@ namespace Ryujinx.Graphics.Vulkan } bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState; + bool supportsExtDynamicState2 = gd.Capabilities.SupportsExtendedDynamicState2; + fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions = &Internal.VertexAttributeDescriptions[0]) fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions2 = &_vertexAttributeDescriptions2[0]) @@ -473,9 +475,7 @@ namespace Ryujinx.Graphics.Vulkan { SType = StructureType.PipelineRasterizationStateCreateInfo, DepthClampEnable = DepthClampEnable, - RasterizerDiscardEnable = RasterizerDiscardEnable, PolygonMode = PolygonMode, - DepthBiasEnable = DepthBiasEnable, }; if (isMoltenVk) @@ -488,6 +488,12 @@ namespace Ryujinx.Graphics.Vulkan rasterizationState.CullMode = CullMode; rasterizationState.FrontFace = FrontFace; } + + if (!supportsExtDynamicState2) + { + rasterizationState.DepthBiasEnable = DepthBiasEnable; + rasterizationState.RasterizerDiscardEnable = RasterizerDiscardEnable; + } var viewportState = new PipelineViewportStateCreateInfo { @@ -590,7 +596,7 @@ namespace Ryujinx.Graphics.Vulkan AttachmentCount = ColorBlendAttachmentStateCount, PAttachments = pColorBlendAttachmentState, }; - + PipelineColorBlendAdvancedStateCreateInfoEXT colorBlendAdvancedState; if (!AdvancedBlendSrcPreMultiplied || @@ -608,7 +614,7 @@ namespace Ryujinx.Graphics.Vulkan colorBlendState.PNext = &colorBlendAdvancedState; } - int dynamicStatesCount = supportsExtDynamicState ? (isMoltenVk ? 17 : 18) : (isMoltenVk ? 7 : 8); + int dynamicStatesCount = supportsExtDynamicState ? (isMoltenVk ? 18 : 19) : (isMoltenVk ? 7 : 8); DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount]; @@ -642,6 +648,12 @@ namespace Ryujinx.Graphics.Vulkan dynamicStates[index] = DynamicState.StencilOpExt; } + if (supportsExtDynamicState2) + { + dynamicStates[16] = DynamicState.DepthBiasEnableExt; + dynamicStates[17] = DynamicState.RasterizerDiscardEnableExt; + } + var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo { SType = StructureType.PipelineDynamicStateCreateInfo, diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs b/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs index a8de50f6d..b12f48202 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs @@ -23,6 +23,7 @@ namespace Ryujinx.Graphics.Vulkan private static readonly string[] _desirableExtensions = { ExtConditionalRendering.ExtensionName, ExtExtendedDynamicState.ExtensionName, + ExtExtendedDynamicState2.ExtensionName, ExtTransformFeedback.ExtensionName, KhrDrawIndirectCount.ExtensionName, KhrPushDescriptor.ExtensionName, @@ -290,7 +291,7 @@ namespace Ryujinx.Graphics.Vulkan { SType = StructureType.PhysicalDeviceFeatures2, }; - + PhysicalDeviceVulkan11Features supportedFeaturesVk11 = new() { SType = StructureType.PhysicalDeviceVulkan11Features, @@ -438,6 +439,15 @@ namespace Ryujinx.Graphics.Vulkan }; pExtendedFeatures = &featuresExtendedDynamicState; + + var featuresExtendedDynamicState2 = new PhysicalDeviceExtendedDynamicState2FeaturesEXT() + { + SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt, + PNext = pExtendedFeatures, + ExtendedDynamicState2 = physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState2.ExtensionName), + }; + + pExtendedFeatures = &featuresExtendedDynamicState2; var featuresVk11 = new PhysicalDeviceVulkan11Features { diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index e8dd766a0..c75c4a39f 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -35,6 +35,8 @@ namespace Ryujinx.Graphics.Vulkan internal KhrSwapchain SwapchainApi { get; private set; } internal ExtConditionalRendering ConditionalRenderingApi { get; private set; } internal ExtExtendedDynamicState ExtendedDynamicStateApi { get; private set; } + internal ExtExtendedDynamicState2 ExtendedDynamicState2Api { get; private set; } + internal KhrPushDescriptor PushDescriptorApi { get; private set; } internal ExtTransformFeedback TransformFeedbackApi { get; private set; } internal KhrDrawIndirectCount DrawIndirectCountApi { get; private set; } @@ -131,6 +133,11 @@ namespace Ryujinx.Graphics.Vulkan { ExtendedDynamicStateApi = extendedDynamicStateApi; } + + if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtExtendedDynamicState2 extendedDynamicState2Api)) + { + ExtendedDynamicState2Api = extendedDynamicState2Api; + } if (Api.TryGetDeviceExtension(_instance.Instance, _device, out KhrPushDescriptor pushDescriptorApi)) { @@ -382,6 +389,7 @@ namespace Ryujinx.Graphics.Vulkan features2.Features.ShaderStorageImageMultisample, _physicalDevice.IsDeviceExtensionPresent(ExtConditionalRendering.ExtensionName), _physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState.ExtensionName), + _physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState2.ExtensionName), features2.Features.MultiViewport && !(IsMoltenVk && Vendor == Vendor.Amd), // Workaround for AMD on MoltenVK issue featuresRobustness2.NullDescriptor || IsMoltenVk, supportsPushDescriptors && !IsMoltenVk,