diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs index ab35da99c2..10cf41cc48 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -129,7 +129,7 @@ namespace Ryujinx.Graphics.Vulkan _supportExtDynamic2 = gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2; - _newState.Initialize(); + _newState.Initialize(_supportExtDynamic, gd.Capabilities.SupportsExtendedDynamicState2); } public void Initialize() diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs b/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs index 3e330ee7f5..1c7836da71 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs @@ -154,8 +154,11 @@ namespace Ryujinx.Graphics.Vulkan public static PipelineState ToVulkanPipelineState(this ProgramPipelineState state, VulkanRenderer gd) { + var extendedDynamicState2 = gd.Capabilities.SupportsExtendedDynamicState2; + var extendedDynamicState = gd.Capabilities.SupportsExtendedDynamicState; + PipelineState pipeline = new(); - pipeline.Initialize(); + pipeline.Initialize(extendedDynamicState, extendedDynamicState2); // It is assumed that Dynamic State is enabled when this conversion is used. pipeline.DepthBoundsTestEnable = false; // Not implemented. @@ -169,62 +172,66 @@ namespace Ryujinx.Graphics.Vulkan pipeline.PolygonMode = PolygonMode.Fill; // Not implemented. - if (!gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2) - { - pipeline.PrimitiveRestartEnable = state.PrimitiveRestartEnable; - pipeline.RasterizerDiscardEnable = state.RasterizerDiscard; - pipeline.DepthBiasEnable = state.BiasEnable != 0; - } + pipeline.PrimitiveRestartEnable = extendedDynamicState2.ExtendedDynamicState2 ? false : state.PrimitiveRestartEnable; + pipeline.RasterizerDiscardEnable = extendedDynamicState2.ExtendedDynamicState2 ? false : state.RasterizerDiscard; + pipeline.DepthBiasEnable = extendedDynamicState2.ExtendedDynamicState2 ? false : state.BiasEnable != 0; - if (!gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2LogicOp) + + if (!extendedDynamicState2.ExtendedDynamicState2LogicOp) { pipeline.LogicOp = state.LogicOpEnable ? state.LogicOp.Convert() : default; } - - if (!gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints) + else { - pipeline.PatchControlPoints = state.PatchControlPoints; + pipeline.LogicOp = 0; } + pipeline.PatchControlPoints = extendedDynamicState2.ExtendedDynamicState2PatchControlPoints ? 0 : state.PatchControlPoints; + pipeline.SamplesCount = (uint)state.SamplesCount; - // Stencil masks and ref are dynamic, so are 0 in the Vulkan pipeline. - if (!gd.Capabilities.SupportsExtendedDynamicState) + pipeline.DepthTestEnable = !extendedDynamicState && state.DepthTest.TestEnable; + pipeline.DepthWriteEnable = !extendedDynamicState && state.DepthTest.WriteEnable && state.DepthTest.TestEnable; + + if (!extendedDynamicState) { - pipeline.DepthTestEnable = state.DepthTest.TestEnable; - pipeline.DepthWriteEnable = state.DepthTest.WriteEnable && state.DepthTest.TestEnable; - pipeline.DepthCompareOp = state.DepthTest.TestEnable ? state.DepthTest.Func.Convert() : default; - pipeline.CullMode = state.CullEnable ? state.CullMode.Convert() : CullModeFlags.None; - - pipeline.FrontFace = state.FrontFace.Convert(); - - if (gd.Capabilities.SupportsMultiView) - { - pipeline.ScissorsCount = Constants.MaxViewports; - pipeline.ViewportsCount = Constants.MaxViewports; - } - else - { - pipeline.ScissorsCount = 1; - pipeline.ViewportsCount = 1; - } - - pipeline.StencilFrontFailOp = state.StencilTest.FrontSFail.Convert(); - pipeline.StencilFrontPassOp = state.StencilTest.FrontDpPass.Convert(); - pipeline.StencilFrontDepthFailOp = state.StencilTest.FrontDpFail.Convert(); - pipeline.StencilFrontCompareOp = state.StencilTest.FrontFunc.Convert(); - - pipeline.StencilBackFailOp = state.StencilTest.BackSFail.Convert(); - pipeline.StencilBackPassOp = state.StencilTest.BackDpPass.Convert(); - pipeline.StencilBackDepthFailOp = state.StencilTest.BackDpFail.Convert(); - pipeline.StencilBackCompareOp = state.StencilTest.BackFunc.Convert(); - - pipeline.StencilTestEnable = state.StencilTest.TestEnable; + } + else + { + pipeline.DepthCompareOp = 0; + pipeline.CullMode = 0; } - pipeline.Topology = gd.TopologyRemap(state.Topology).Convert(); + pipeline.FrontFace = extendedDynamicState ? 0 : state.FrontFace.Convert(); + + if (gd.Capabilities.SupportsMultiView) + { + pipeline.ScissorsCount = (uint)(extendedDynamicState ? 0 : Constants.MaxViewports); + pipeline.ViewportsCount = (uint)(extendedDynamicState ? 0 : Constants.MaxViewports); + } + else + { + pipeline.ScissorsCount = (uint)(extendedDynamicState ? 0 : 1); + pipeline.ViewportsCount = (uint)(extendedDynamicState ? 0 : 1); + } + + pipeline.StencilTestEnable = !extendedDynamicState && state.StencilTest.TestEnable; + + pipeline.StencilFrontFailOp = extendedDynamicState ? 0 : state.StencilTest.FrontSFail.Convert(); + pipeline.StencilFrontPassOp = extendedDynamicState ? 0 : state.StencilTest.FrontDpPass.Convert(); + pipeline.StencilFrontDepthFailOp = extendedDynamicState ? 0 : state.StencilTest.FrontDpFail.Convert(); + pipeline.StencilFrontCompareOp = extendedDynamicState ? 0 : state.StencilTest.FrontFunc.Convert(); + + pipeline.StencilBackFailOp = extendedDynamicState ? 0 : state.StencilTest.BackSFail.Convert(); + pipeline.StencilBackPassOp = extendedDynamicState ? 0 : state.StencilTest.BackDpPass.Convert(); + pipeline.StencilBackDepthFailOp = extendedDynamicState ? 0 : state.StencilTest.BackDpFail.Convert(); + pipeline.StencilBackCompareOp = extendedDynamicState ? 0 : state.StencilTest.BackFunc.Convert(); + + var vkTopology = gd.TopologyRemap(state.Topology).Convert(); + + pipeline.Topology = extendedDynamicState ? vkTopology.ConvertToClass() : vkTopology; int vaCount = Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount); int vbCount = Math.Min(Constants.MaxVertexBuffers, state.VertexBufferCount); diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs index 14ee61c029..9679dd8af6 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs @@ -246,7 +246,12 @@ namespace Ryujinx.Graphics.Vulkan private Array32 _vertexAttributeDescriptions2; - public void Initialize() + private bool _supportsExtDynamicState; + private PhysicalDeviceExtendedDynamicState2FeaturesEXT _supportsExtDynamicState2; + + + public void Initialize(bool supportsExtDynamicState, + PhysicalDeviceExtendedDynamicState2FeaturesEXT extendedDynamicState2) { HasTessellationControlShader = false; Stages = new NativeArray(Constants.MaxShaderStages); @@ -257,6 +262,50 @@ namespace Ryujinx.Graphics.Vulkan SamplesCount = 1; DepthMode = true; + + _supportsExtDynamicState = supportsExtDynamicState; + _supportsExtDynamicState2 = extendedDynamicState2; + + if (_supportsExtDynamicState) + { + StencilFrontFailOp = 0; + StencilFrontPassOp = 0; + StencilFrontDepthFailOp = 0; + StencilFrontCompareOp = 0; + + StencilBackFailOp = 0; + StencilBackPassOp = 0; + StencilBackDepthFailOp = 0; + StencilBackCompareOp = 0; + + ViewportsCount = 0; + ScissorsCount = 0; + + CullMode = 0; + FrontFace = 0; + DepthTestEnable = false; + DepthWriteEnable = false; + DepthCompareOp = 0; + StencilTestEnable = false; + + } + + if (_supportsExtDynamicState2.ExtendedDynamicState2) + { + PrimitiveRestartEnable = false; + DepthBiasEnable = false; + RasterizerDiscardEnable = false; + } + + if (_supportsExtDynamicState2.ExtendedDynamicState2LogicOp) + { + LogicOp = 0; + } + + if (_supportsExtDynamicState2.ExtendedDynamicState2PatchControlPoints) + { + PatchControlPoints = 0; + } } public unsafe Auto CreateComputePipeline( @@ -340,9 +389,6 @@ namespace Ryujinx.Graphics.Vulkan UpdateVertexAttributeDescriptions(gd); } - bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState; - bool supportsExtDynamicState2 = gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2; - fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions = &Internal.VertexAttributeDescriptions[0]) fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions2 = &_vertexAttributeDescriptions2[0]) fixed (VertexInputBindingDescription* pVertexBindingDescriptions = &Internal.VertexBindingDescriptions[0]) @@ -410,7 +456,7 @@ namespace Ryujinx.Graphics.Vulkan DepthBoundsTestEnable = false, }; - if (!supportsExtDynamicState) + if (!_supportsExtDynamicState) { rasterizationState.CullMode = CullMode; rasterizationState.FrontFace = FrontFace; @@ -438,7 +484,7 @@ namespace Ryujinx.Graphics.Vulkan depthStencilState.DepthCompareOp = DepthCompareOp; } - if (!supportsExtDynamicState2) + if (!_supportsExtDynamicState2.ExtendedDynamicState2) { inputAssemblyState.PrimitiveRestartEnable = PrimitiveRestartEnable; rasterizationState.DepthBiasEnable = DepthBiasEnable; @@ -518,7 +564,7 @@ namespace Ryujinx.Graphics.Vulkan dynamicStates[currentIndex++] = DynamicState.LineWidth; } - if (supportsExtDynamicState) + if (_supportsExtDynamicState) { if (!isMoltenVk) { @@ -538,17 +584,17 @@ namespace Ryujinx.Graphics.Vulkan dynamicStates[currentIndex++] = DynamicState.PrimitiveTopologyExt; } - if (supportsExtDynamicState2) + if (_supportsExtDynamicState2.ExtendedDynamicState2) { dynamicStates[currentIndex++] = DynamicState.DepthBiasEnableExt; dynamicStates[currentIndex++] = DynamicState.RasterizerDiscardEnableExt; dynamicStates[currentIndex++] = DynamicState.PrimitiveRestartEnableExt; - if (gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2LogicOp) + if (_supportsExtDynamicState2.ExtendedDynamicState2LogicOp) { dynamicStates[currentIndex++] = DynamicState.LogicOpExt; } - if (gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints) + if (_supportsExtDynamicState2.ExtendedDynamicState2PatchControlPoints) { dynamicStates[currentIndex++] = DynamicState.PatchControlPointsExt; } diff --git a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs index c9aab4018b..5338030d98 100644 --- a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs +++ b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs @@ -528,7 +528,7 @@ namespace Ryujinx.Graphics.Vulkan public void CreateBackgroundComputePipeline() { PipelineState pipeline = new(); - pipeline.Initialize(); + pipeline.Initialize(_gd.Capabilities.SupportsExtendedDynamicState, _gd.Capabilities.SupportsExtendedDynamicState2); pipeline.Stages[0] = _shaders[0].GetInfo(); pipeline.StagesCount = 1; diff --git a/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs b/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs index 94269dd765..44063da70d 100644 --- a/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs +++ b/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs @@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Vulkan { if (_count != 0) { - if (_gd.Capabilities.SupportsExtendedDynamicState) + if (_gd.Capabilities.SupportsExtendedDynamicState && !_gd.IsMoltenVk) { _gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2( cbs.CommandBuffer,