/ src / Ryujinx.Graphics.Gpu / Shader / GpuChannelGraphicsState.cs
GpuChannelGraphicsState.cs
  1  using Ryujinx.Common.Memory;
  2  using Ryujinx.Graphics.GAL;
  3  using Ryujinx.Graphics.Gpu.Engine.Threed;
  4  using Ryujinx.Graphics.Shader;
  5  
  6  namespace Ryujinx.Graphics.Gpu.Shader
  7  {
  8      /// <summary>
  9      /// State used by the <see cref="GpuAccessor"/>.
 10      /// </summary>
 11      struct GpuChannelGraphicsState
 12      {
 13          // New fields should be added to the end of the struct to keep disk shader cache compatibility.
 14  
 15          /// <summary>
 16          /// Early Z force enable.
 17          /// </summary>
 18          public bool EarlyZForce;
 19  
 20          /// <summary>
 21          /// Primitive topology of current draw.
 22          /// </summary>
 23          public PrimitiveTopology Topology;
 24  
 25          /// <summary>
 26          /// Tessellation mode.
 27          /// </summary>
 28          public TessMode TessellationMode;
 29  
 30          /// <summary>
 31          /// Indicates whether alpha-to-coverage is enabled.
 32          /// </summary>
 33          public bool AlphaToCoverageEnable;
 34  
 35          /// <summary>
 36          /// Indicates whether alpha-to-coverage dithering is enabled.
 37          /// </summary>
 38          public bool AlphaToCoverageDitherEnable;
 39  
 40          /// <summary>
 41          /// Indicates whether the viewport transform is disabled.
 42          /// </summary>
 43          public bool ViewportTransformDisable;
 44  
 45          /// <summary>
 46          /// Depth mode zero to one or minus one to one.
 47          /// </summary>
 48          public bool DepthMode;
 49  
 50          /// <summary>
 51          /// Indicates if the point size is set on the shader or is fixed.
 52          /// </summary>
 53          public bool ProgramPointSizeEnable;
 54  
 55          /// <summary>
 56          /// Point size used if <see cref="ProgramPointSizeEnable" /> is false.
 57          /// </summary>
 58          public float PointSize;
 59  
 60          /// <summary>
 61          /// Indicates whether alpha test is enabled.
 62          /// </summary>
 63          public bool AlphaTestEnable;
 64  
 65          /// <summary>
 66          /// When alpha test is enabled, indicates the comparison that decides if the fragment should be discarded.
 67          /// </summary>
 68          public CompareOp AlphaTestCompare;
 69  
 70          /// <summary>
 71          /// When alpha test is enabled, indicates the value to compare with the fragment output alpha.
 72          /// </summary>
 73          public float AlphaTestReference;
 74  
 75          /// <summary>
 76          /// Type of the vertex attributes consumed by the shader.
 77          /// </summary>
 78          public Array32<AttributeType> AttributeTypes;
 79  
 80          /// <summary>
 81          /// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
 82          /// </summary>
 83          public bool HasConstantBufferDrawParameters;
 84  
 85          /// <summary>
 86          /// Indicates that any storage buffer use is unaligned.
 87          /// </summary>
 88          public bool HasUnalignedStorageBuffer;
 89  
 90          /// <summary>
 91          /// Type of the fragment shader outputs.
 92          /// </summary>
 93          public Array8<AttributeType> FragmentOutputTypes;
 94  
 95          /// <summary>
 96          /// Indicates whether dual source blend is enabled.
 97          /// </summary>
 98          public bool DualSourceBlendEnable;
 99  
100          /// <summary>
101          /// Indicates whether Y negate of the fragment coordinates is enabled.
102          /// </summary>
103          public bool YNegateEnabled;
104  
105          /// <summary>
106          /// Creates a new graphics state from this state that can be used for shader generation.
107          /// </summary>
108          /// <param name="hostSupportsAlphaTest">Indicates if the host API supports alpha test operations</param>
109          /// <param name="hostSupportsQuads">Indicates if the host API supports quad primitives</param>
110          /// <param name="hasGeometryShader">Indicates if a geometry shader is used</param>
111          /// <param name="originUpperLeft">If true, indicates that the fragment origin is the upper left corner of the viewport, otherwise it is the lower left corner</param>
112          /// <returns>GPU graphics state that can be used for shader translation</returns>
113          public readonly GpuGraphicsState CreateShaderGraphicsState(bool hostSupportsAlphaTest, bool hostSupportsQuads, bool hasGeometryShader, bool originUpperLeft)
114          {
115              AlphaTestOp alphaTestOp;
116  
117              if (hostSupportsAlphaTest || !AlphaTestEnable)
118              {
119                  alphaTestOp = AlphaTestOp.Always;
120              }
121              else
122              {
123                  alphaTestOp = AlphaTestCompare switch
124                  {
125                      CompareOp.Never or CompareOp.NeverGl => AlphaTestOp.Never,
126                      CompareOp.Less or CompareOp.LessGl => AlphaTestOp.Less,
127                      CompareOp.Equal or CompareOp.EqualGl => AlphaTestOp.Equal,
128                      CompareOp.LessOrEqual or CompareOp.LessOrEqualGl => AlphaTestOp.LessOrEqual,
129                      CompareOp.Greater or CompareOp.GreaterGl => AlphaTestOp.Greater,
130                      CompareOp.NotEqual or CompareOp.NotEqualGl => AlphaTestOp.NotEqual,
131                      CompareOp.GreaterOrEqual or CompareOp.GreaterOrEqualGl => AlphaTestOp.GreaterOrEqual,
132                      _ => AlphaTestOp.Always,
133                  };
134              }
135  
136              bool isQuad = Topology == PrimitiveTopology.Quads || Topology == PrimitiveTopology.QuadStrip;
137              bool halvePrimitiveId = !hostSupportsQuads && !hasGeometryShader && isQuad;
138  
139              return new GpuGraphicsState(
140                  EarlyZForce,
141                  ConvertToInputTopology(Topology, TessellationMode),
142                  TessellationMode.UnpackCw(),
143                  TessellationMode.UnpackPatchType(),
144                  TessellationMode.UnpackSpacing(),
145                  AlphaToCoverageEnable,
146                  AlphaToCoverageDitherEnable,
147                  ViewportTransformDisable,
148                  DepthMode,
149                  ProgramPointSizeEnable,
150                  PointSize,
151                  alphaTestOp,
152                  AlphaTestReference,
153                  in AttributeTypes,
154                  HasConstantBufferDrawParameters,
155                  in FragmentOutputTypes,
156                  DualSourceBlendEnable,
157                  YNegateEnabled,
158                  originUpperLeft,
159                  halvePrimitiveId);
160          }
161  
162          /// <summary>
163          /// Converts the Maxwell primitive topology to the shader translator topology.
164          /// </summary>
165          /// <param name="topology">Maxwell primitive topology</param>
166          /// <param name="tessellationMode">Maxwell tessellation mode</param>
167          /// <returns>Shader translator topology</returns>
168          private static InputTopology ConvertToInputTopology(PrimitiveTopology topology, TessMode tessellationMode)
169          {
170              return topology switch
171              {
172                  PrimitiveTopology.Points => InputTopology.Points,
173                  PrimitiveTopology.Lines or
174                  PrimitiveTopology.LineLoop or
175                  PrimitiveTopology.LineStrip => InputTopology.Lines,
176                  PrimitiveTopology.LinesAdjacency or
177                  PrimitiveTopology.LineStripAdjacency => InputTopology.LinesAdjacency,
178                  PrimitiveTopology.Triangles or
179                  PrimitiveTopology.TriangleStrip or
180                  PrimitiveTopology.TriangleFan => InputTopology.Triangles,
181                  PrimitiveTopology.TrianglesAdjacency or
182                  PrimitiveTopology.TriangleStripAdjacency => InputTopology.TrianglesAdjacency,
183                  PrimitiveTopology.Patches => tessellationMode.UnpackPatchType() == TessPatchType.Isolines
184                      ? InputTopology.Lines
185                      : InputTopology.Triangles,
186                  _ => InputTopology.Points,
187              };
188          }
189      }
190  }