using Ryujinx.Common.Memory; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu.Engine.Threed; using Ryujinx.Graphics.Shader; namespace Ryujinx.Graphics.Gpu.Shader { /// /// State used by the . /// struct GpuChannelGraphicsState { // New fields should be added to the end of the struct to keep disk shader cache compatibility. /// /// Early Z force enable. /// public bool EarlyZForce; /// /// Primitive topology of current draw. /// public PrimitiveTopology Topology; /// /// Tessellation mode. /// public TessMode TessellationMode; /// /// Indicates whether alpha-to-coverage is enabled. /// public bool AlphaToCoverageEnable; /// /// Indicates whether alpha-to-coverage dithering is enabled. /// public bool AlphaToCoverageDitherEnable; /// /// Indicates whether the viewport transform is disabled. /// public bool ViewportTransformDisable; /// /// Depth mode zero to one or minus one to one. /// public bool DepthMode; /// /// Indicates if the point size is set on the shader or is fixed. /// public bool ProgramPointSizeEnable; /// /// Point size used if is false. /// public float PointSize; /// /// Indicates whether alpha test is enabled. /// public bool AlphaTestEnable; /// /// When alpha test is enabled, indicates the comparison that decides if the fragment should be discarded. /// public CompareOp AlphaTestCompare; /// /// When alpha test is enabled, indicates the value to compare with the fragment output alpha. /// public float AlphaTestReference; /// /// Type of the vertex attributes consumed by the shader. /// public Array32 AttributeTypes; /// /// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0. /// public bool HasConstantBufferDrawParameters; /// /// Indicates that any storage buffer use is unaligned. /// public bool HasUnalignedStorageBuffer; /// /// Type of the fragment shader outputs. /// public Array8 FragmentOutputTypes; /// /// Indicates whether dual source blend is enabled. /// public bool DualSourceBlendEnable; /// /// Indicates whether Y negate of the fragment coordinates is enabled. /// public bool YNegateEnabled; /// /// Creates a new graphics state from this state that can be used for shader generation. /// /// Indicates if the host API supports alpha test operations /// Indicates if the host API supports quad primitives /// Indicates if a geometry shader is used /// If true, indicates that the fragment origin is the upper left corner of the viewport, otherwise it is the lower left corner /// GPU graphics state that can be used for shader translation public readonly GpuGraphicsState CreateShaderGraphicsState(bool hostSupportsAlphaTest, bool hostSupportsQuads, bool hasGeometryShader, bool originUpperLeft) { AlphaTestOp alphaTestOp; if (hostSupportsAlphaTest || !AlphaTestEnable) { alphaTestOp = AlphaTestOp.Always; } else { alphaTestOp = AlphaTestCompare switch { CompareOp.Never or CompareOp.NeverGl => AlphaTestOp.Never, CompareOp.Less or CompareOp.LessGl => AlphaTestOp.Less, CompareOp.Equal or CompareOp.EqualGl => AlphaTestOp.Equal, CompareOp.LessOrEqual or CompareOp.LessOrEqualGl => AlphaTestOp.LessOrEqual, CompareOp.Greater or CompareOp.GreaterGl => AlphaTestOp.Greater, CompareOp.NotEqual or CompareOp.NotEqualGl => AlphaTestOp.NotEqual, CompareOp.GreaterOrEqual or CompareOp.GreaterOrEqualGl => AlphaTestOp.GreaterOrEqual, _ => AlphaTestOp.Always, }; } bool isQuad = Topology == PrimitiveTopology.Quads || Topology == PrimitiveTopology.QuadStrip; bool halvePrimitiveId = !hostSupportsQuads && !hasGeometryShader && isQuad; return new GpuGraphicsState( EarlyZForce, ConvertToInputTopology(Topology, TessellationMode), TessellationMode.UnpackCw(), TessellationMode.UnpackPatchType(), TessellationMode.UnpackSpacing(), AlphaToCoverageEnable, AlphaToCoverageDitherEnable, ViewportTransformDisable, DepthMode, ProgramPointSizeEnable, PointSize, alphaTestOp, AlphaTestReference, in AttributeTypes, HasConstantBufferDrawParameters, in FragmentOutputTypes, DualSourceBlendEnable, YNegateEnabled, originUpperLeft, halvePrimitiveId); } /// /// Converts the Maxwell primitive topology to the shader translator topology. /// /// Maxwell primitive topology /// Maxwell tessellation mode /// Shader translator topology private static InputTopology ConvertToInputTopology(PrimitiveTopology topology, TessMode tessellationMode) { return topology switch { PrimitiveTopology.Points => InputTopology.Points, PrimitiveTopology.Lines or PrimitiveTopology.LineLoop or PrimitiveTopology.LineStrip => InputTopology.Lines, PrimitiveTopology.LinesAdjacency or PrimitiveTopology.LineStripAdjacency => InputTopology.LinesAdjacency, PrimitiveTopology.Triangles or PrimitiveTopology.TriangleStrip or PrimitiveTopology.TriangleFan => InputTopology.Triangles, PrimitiveTopology.TrianglesAdjacency or PrimitiveTopology.TriangleStripAdjacency => InputTopology.TrianglesAdjacency, PrimitiveTopology.Patches => tessellationMode.UnpackPatchType() == TessPatchType.Isolines ? InputTopology.Lines : InputTopology.Triangles, _ => InputTopology.Points, }; } } }