diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs index 83dad8e82..1f8677b81 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -696,7 +696,7 @@ namespace Ryujinx.Graphics.Vulkan var oldStencilTestEnable = _supportExtDynamic ? DynamicState.StencilTestEnable : _newState.StencilTestEnable; var oldDepthTestEnable = _supportExtDynamic ? DynamicState.DepthTestEnable : _newState.DepthTestEnable; var oldDepthWriteEnable = _supportExtDynamic ? DynamicState.DepthWriteEnable : _newState.DepthWriteEnable; - var oldTopology = _newState.Topology; + var oldTopology = _supportExtDynamic ? DynamicState.Topology : _newState.Topology; var oldViewports = DynamicState.Viewports; var oldViewportsCount = _supportExtDynamic ? DynamicState.ViewportsCount : _newState.ViewportsCount; @@ -729,6 +729,7 @@ namespace Ryujinx.Graphics.Vulkan DynamicState.SetCullMode(oldCullMode); DynamicState.SetStencilTest(oldStencilTestEnable); DynamicState.SetDepthTestBool(oldDepthTestEnable, oldDepthWriteEnable); + DynamicState.SetPrimitiveTopology(oldTopology); } else { @@ -737,10 +738,9 @@ namespace Ryujinx.Graphics.Vulkan _newState.DepthTestEnable = oldDepthTestEnable; _newState.DepthWriteEnable = oldDepthWriteEnable; _newState.ViewportsCount = oldViewportsCount; + _newState.Topology = oldTopology; } - _newState.Topology = oldTopology; - DynamicState.SetViewports(ref oldViewports, oldViewportsCount); SignalStateChange(); @@ -1094,11 +1094,52 @@ namespace Ryujinx.Graphics.Vulkan var vkTopology = Gd.TopologyRemap(topology).Convert(); - _newState.Topology = vkTopology; + var currentTopologyClass = GetTopologyClass(_newState.Topology); + var newTopologyClass = GetTopologyClass(vkTopology); + + if (_supportExtDynamic) + { + DynamicState.SetPrimitiveTopology(vkTopology); + if (currentTopologyClass != newTopologyClass) + { + _newState.Topology = vkTopology; + } + } + else + { + _newState.Topology = vkTopology; + } SignalStateChange(); } + private TopologyClass GetTopologyClass(Silk.NET.Vulkan.PrimitiveTopology topology) + { + return topology switch + { + Silk.NET.Vulkan.PrimitiveTopology.PointList => TopologyClass.Point, + Silk.NET.Vulkan.PrimitiveTopology.LineList => TopologyClass.Line, + Silk.NET.Vulkan.PrimitiveTopology.LineStrip => TopologyClass.Line, + Silk.NET.Vulkan.PrimitiveTopology.LineListWithAdjacency => TopologyClass.Line, + Silk.NET.Vulkan.PrimitiveTopology.LineStripWithAdjacency => TopologyClass.Line, + Silk.NET.Vulkan.PrimitiveTopology.TriangleList => TopologyClass.Triangle, + Silk.NET.Vulkan.PrimitiveTopology.TriangleStrip => TopologyClass.Triangle, + Silk.NET.Vulkan.PrimitiveTopology.TriangleFan => TopologyClass.Triangle, + Silk.NET.Vulkan.PrimitiveTopology.TriangleListWithAdjacency => TopologyClass.Triangle, + Silk.NET.Vulkan.PrimitiveTopology.TriangleStripWithAdjacency => TopologyClass.Triangle, + Silk.NET.Vulkan.PrimitiveTopology.PatchList => TopologyClass.Patch, + _ => throw new ArgumentOutOfRangeException(nameof(topology), topology, null) + }; + } + + private enum TopologyClass + { + Point, + Line, + Triangle, + Patch + } + public void SetProgram(IProgram program) { var internalProgram = (ShaderCollection)program; diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs index 63527c472..d421086dd 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs @@ -54,6 +54,8 @@ namespace Ryujinx.Graphics.Vulkan private uint _patchControlPoints; + public PrimitiveTopology Topology; + private bool _primitiveRestartEnable; [Flags] @@ -75,8 +77,9 @@ namespace Ryujinx.Graphics.Vulkan LogicOp = 1 << 12, PatchControlPoints = 1 << 13, PrimitiveRestart = 1 << 14, + PrimitiveTopology = 1 << 15, Standard = Blend | DepthBias | Scissor | Stencil | Viewport | LineWidth, - Extended = CullMode | FrontFace | DepthTestBool | DepthTestCompareOp | StencilTestEnable, + Extended = CullMode | FrontFace | DepthTestBool | DepthTestCompareOp | StencilTestEnable | PrimitiveTopology, Extended2 = RasterDiscard | LogicOp | PatchControlPoints | PrimitiveRestart, } @@ -203,6 +206,12 @@ namespace Ryujinx.Graphics.Vulkan _dirty |= DirtyFlags.PrimitiveRestart; } + public void SetPrimitiveTopology(PrimitiveTopology primitiveTopology) + { + Topology = primitiveTopology; + _dirty |= DirtyFlags.PrimitiveTopology; + } + public void SetLogicOp(LogicOp op) { _logicOp = op; @@ -312,9 +321,9 @@ namespace Ryujinx.Graphics.Vulkan RecordPrimitiveRestartEnable(gd, commandBuffer); } - if (_dirty.HasFlag(DirtyFlags.PrimitiveRestart)) + if (_dirty.HasFlag(DirtyFlags.PrimitiveTopology)) { - RecordPrimitiveRestartEnable(gd, commandBuffer); + RecordPrimitiveTopology(gd, commandBuffer); } if (_dirty.HasFlag(DirtyFlags.LogicOp)) @@ -443,6 +452,11 @@ namespace Ryujinx.Graphics.Vulkan gd.ExtendedDynamicState2Api.CmdSetPrimitiveRestartEnable(commandBuffer, _primitiveRestartEnable); } + private readonly void RecordPrimitiveTopology(VulkanRenderer gd, CommandBuffer commandBuffer) + { + gd.ExtendedDynamicStateApi.CmdSetPrimitiveTopology(commandBuffer, Topology); + } + private readonly void RecordLogicOp(VulkanRenderer gd, CommandBuffer commandBuffer) { gd.ExtendedDynamicState2Api.CmdSetLogicOp(commandBuffer, _logicOp); diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs index f1ed68c8c..fa66e9fd8 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs @@ -592,7 +592,7 @@ namespace Ryujinx.Graphics.Vulkan if (supportsExtDynamicState) { - additionalDynamicStatesCount += isMoltenVk ? 7 : 8; + additionalDynamicStatesCount += isMoltenVk ? 8 : 9; } if (supportsExtDynamicState2) @@ -643,6 +643,7 @@ namespace Ryujinx.Graphics.Vulkan dynamicStates[currentIndex++] = DynamicState.DepthCompareOpExt; dynamicStates[currentIndex++] = DynamicState.StencilTestEnableExt; dynamicStates[currentIndex++] = DynamicState.StencilOpExt; + dynamicStates[currentIndex++] = DynamicState.PrimitiveTopologyExt; } if (supportsExtDynamicState2)