ShaderDefinitions.cs
1 using Ryujinx.Graphics.Shader.IntermediateRepresentation; 2 using System; 3 using System.Collections.Generic; 4 using System.Numerics; 5 6 namespace Ryujinx.Graphics.Shader.Translation 7 { 8 class ShaderDefinitions 9 { 10 private readonly GpuGraphicsState _graphicsState; 11 12 public ShaderStage Stage { get; } 13 14 public int ComputeLocalSizeX { get; } 15 public int ComputeLocalSizeY { get; } 16 public int ComputeLocalSizeZ { get; } 17 18 public bool TessCw => _graphicsState.TessCw; 19 public TessPatchType TessPatchType => _graphicsState.TessPatchType; 20 public TessSpacing TessSpacing => _graphicsState.TessSpacing; 21 22 public bool AlphaToCoverageDitherEnable => _graphicsState.AlphaToCoverageEnable && _graphicsState.AlphaToCoverageDitherEnable; 23 public bool ViewportTransformDisable => _graphicsState.ViewportTransformDisable; 24 25 public bool DepthMode => _graphicsState.DepthMode; 26 27 public float PointSize => _graphicsState.PointSize; 28 29 public AlphaTestOp AlphaTestCompare => _graphicsState.AlphaTestCompare; 30 public float AlphaTestReference => _graphicsState.AlphaTestReference; 31 32 public bool GpPassthrough { get; } 33 public bool LastInVertexPipeline { get; set; } 34 35 public int ThreadsPerInputPrimitive { get; private set; } 36 37 public InputTopology InputTopology => _graphicsState.Topology; 38 public OutputTopology OutputTopology { get; } 39 40 public int MaxOutputVertices { get; } 41 42 public bool DualSourceBlend => _graphicsState.DualSourceBlendEnable; 43 public bool EarlyZForce => _graphicsState.EarlyZForce; 44 45 public bool YNegateEnabled => _graphicsState.YNegateEnabled; 46 public bool OriginUpperLeft => _graphicsState.OriginUpperLeft; 47 48 public bool HalvePrimitiveId => _graphicsState.HalvePrimitiveId; 49 50 public ImapPixelType[] ImapTypes { get; } 51 public bool IaIndexing { get; private set; } 52 public bool OaIndexing { get; private set; } 53 54 public int OmapTargets { get; } 55 public bool OmapSampleMask { get; } 56 public bool OmapDepth { get; } 57 58 public bool SupportsScaledVertexFormats { get; } 59 60 public bool TransformFeedbackEnabled { get; } 61 62 private readonly TransformFeedbackOutput[] _transformFeedbackOutputs; 63 64 readonly struct TransformFeedbackVariable : IEquatable<TransformFeedbackVariable> 65 { 66 public IoVariable IoVariable { get; } 67 public int Location { get; } 68 public int Component { get; } 69 70 public TransformFeedbackVariable(IoVariable ioVariable, int location = 0, int component = 0) 71 { 72 IoVariable = ioVariable; 73 Location = location; 74 Component = component; 75 } 76 77 public override bool Equals(object other) 78 { 79 return other is TransformFeedbackVariable tfbVar && Equals(tfbVar); 80 } 81 82 public bool Equals(TransformFeedbackVariable other) 83 { 84 return IoVariable == other.IoVariable && 85 Location == other.Location && 86 Component == other.Component; 87 } 88 89 public override int GetHashCode() 90 { 91 return (int)IoVariable | (Location << 8) | (Component << 16); 92 } 93 94 public override string ToString() 95 { 96 return $"{IoVariable}.{Location}.{Component}"; 97 } 98 } 99 100 private readonly Dictionary<TransformFeedbackVariable, TransformFeedbackOutput> _transformFeedbackDefinitions; 101 102 public ShaderDefinitions(ShaderStage stage, ulong transformFeedbackVecMap, TransformFeedbackOutput[] transformFeedbackOutputs) 103 { 104 Stage = stage; 105 TransformFeedbackEnabled = transformFeedbackOutputs != null; 106 _transformFeedbackOutputs = transformFeedbackOutputs; 107 _transformFeedbackDefinitions = new(); 108 109 PopulateTransformFeedbackDefinitions(transformFeedbackVecMap, transformFeedbackOutputs); 110 } 111 112 public ShaderDefinitions( 113 ShaderStage stage, 114 int computeLocalSizeX, 115 int computeLocalSizeY, 116 int computeLocalSizeZ) 117 { 118 Stage = stage; 119 ComputeLocalSizeX = computeLocalSizeX; 120 ComputeLocalSizeY = computeLocalSizeY; 121 ComputeLocalSizeZ = computeLocalSizeZ; 122 } 123 124 public ShaderDefinitions( 125 ShaderStage stage, 126 GpuGraphicsState graphicsState, 127 bool gpPassthrough, 128 int threadsPerInputPrimitive, 129 OutputTopology outputTopology, 130 int maxOutputVertices) 131 { 132 Stage = stage; 133 _graphicsState = graphicsState; 134 GpPassthrough = gpPassthrough; 135 ThreadsPerInputPrimitive = threadsPerInputPrimitive; 136 OutputTopology = outputTopology; 137 MaxOutputVertices = maxOutputVertices; 138 } 139 140 public ShaderDefinitions( 141 ShaderStage stage, 142 GpuGraphicsState graphicsState, 143 bool gpPassthrough, 144 int threadsPerInputPrimitive, 145 OutputTopology outputTopology, 146 int maxOutputVertices, 147 ImapPixelType[] imapTypes, 148 int omapTargets, 149 bool omapSampleMask, 150 bool omapDepth, 151 bool supportsScaledVertexFormats, 152 ulong transformFeedbackVecMap, 153 TransformFeedbackOutput[] transformFeedbackOutputs) 154 { 155 Stage = stage; 156 _graphicsState = graphicsState; 157 GpPassthrough = gpPassthrough; 158 ThreadsPerInputPrimitive = threadsPerInputPrimitive; 159 OutputTopology = outputTopology; 160 MaxOutputVertices = gpPassthrough ? graphicsState.Topology.ToInputVerticesNoAdjacency() : maxOutputVertices; 161 ImapTypes = imapTypes; 162 OmapTargets = omapTargets; 163 OmapSampleMask = omapSampleMask; 164 OmapDepth = omapDepth; 165 LastInVertexPipeline = stage < ShaderStage.Fragment; 166 SupportsScaledVertexFormats = supportsScaledVertexFormats; 167 TransformFeedbackEnabled = transformFeedbackOutputs != null; 168 _transformFeedbackOutputs = transformFeedbackOutputs; 169 _transformFeedbackDefinitions = new(); 170 171 PopulateTransformFeedbackDefinitions(transformFeedbackVecMap, transformFeedbackOutputs); 172 } 173 174 private void PopulateTransformFeedbackDefinitions(ulong transformFeedbackVecMap, TransformFeedbackOutput[] transformFeedbackOutputs) 175 { 176 while (transformFeedbackVecMap != 0) 177 { 178 int vecIndex = BitOperations.TrailingZeroCount(transformFeedbackVecMap); 179 180 for (int subIndex = 0; subIndex < 4; subIndex++) 181 { 182 int wordOffset = vecIndex * 4 + subIndex; 183 int byteOffset = wordOffset * 4; 184 185 if (transformFeedbackOutputs[wordOffset].Valid) 186 { 187 IoVariable ioVariable = Instructions.AttributeMap.GetIoVariable(this, byteOffset, out int location); 188 int component = 0; 189 190 if (HasPerLocationInputOrOutputComponent(ioVariable, location, subIndex, isOutput: true)) 191 { 192 component = subIndex; 193 } 194 195 var transformFeedbackVariable = new TransformFeedbackVariable(ioVariable, location, component); 196 _transformFeedbackDefinitions.TryAdd(transformFeedbackVariable, transformFeedbackOutputs[wordOffset]); 197 } 198 } 199 200 transformFeedbackVecMap &= ~(1UL << vecIndex); 201 } 202 } 203 204 public void EnableInputIndexing() 205 { 206 IaIndexing = true; 207 } 208 209 public void EnableOutputIndexing() 210 { 211 OaIndexing = true; 212 } 213 214 public bool TryGetTransformFeedbackOutput(IoVariable ioVariable, int location, int component, out TransformFeedbackOutput transformFeedbackOutput) 215 { 216 if (!HasTransformFeedbackOutputs()) 217 { 218 transformFeedbackOutput = default; 219 return false; 220 } 221 222 var transformFeedbackVariable = new TransformFeedbackVariable(ioVariable, location, component); 223 return _transformFeedbackDefinitions.TryGetValue(transformFeedbackVariable, out transformFeedbackOutput); 224 } 225 226 private bool HasTransformFeedbackOutputs() 227 { 228 return TransformFeedbackEnabled && (LastInVertexPipeline || Stage == ShaderStage.Fragment); 229 } 230 231 public bool HasTransformFeedbackOutputs(bool isOutput) 232 { 233 return TransformFeedbackEnabled && ((isOutput && LastInVertexPipeline) || (!isOutput && Stage == ShaderStage.Fragment)); 234 } 235 236 public bool HasPerLocationInputOrOutput(IoVariable ioVariable, bool isOutput) 237 { 238 if (ioVariable == IoVariable.UserDefined) 239 { 240 return (!isOutput && !IaIndexing) || (isOutput && !OaIndexing); 241 } 242 243 return ioVariable == IoVariable.FragmentOutputColor; 244 } 245 246 public bool HasPerLocationInputOrOutputComponent(IoVariable ioVariable, int location, int component, bool isOutput) 247 { 248 if (ioVariable != IoVariable.UserDefined || !HasTransformFeedbackOutputs(isOutput)) 249 { 250 return false; 251 } 252 253 return GetTransformFeedbackOutputComponents(location, component) == 1; 254 } 255 256 public TransformFeedbackOutput GetTransformFeedbackOutput(int wordOffset) 257 { 258 return _transformFeedbackOutputs[wordOffset]; 259 } 260 261 public TransformFeedbackOutput GetTransformFeedbackOutput(int location, int component) 262 { 263 return GetTransformFeedbackOutput((AttributeConsts.UserAttributeBase / 4) + location * 4 + component); 264 } 265 266 public int GetTransformFeedbackOutputComponents(int location, int component) 267 { 268 int baseIndex = (AttributeConsts.UserAttributeBase / 4) + location * 4; 269 int index = baseIndex + component; 270 int count = 1; 271 272 for (; count < 4; count++) 273 { 274 ref var prev = ref _transformFeedbackOutputs[baseIndex + count - 1]; 275 ref var curr = ref _transformFeedbackOutputs[baseIndex + count]; 276 277 int prevOffset = prev.Offset; 278 int currOffset = curr.Offset; 279 280 if (!prev.Valid || !curr.Valid || prevOffset + 4 != currOffset) 281 { 282 break; 283 } 284 } 285 286 if (baseIndex + count <= index) 287 { 288 return 1; 289 } 290 291 return count; 292 } 293 294 public AggregateType GetFragmentOutputColorType(int location) 295 { 296 return AggregateType.Vector4 | _graphicsState.FragmentOutputTypes[location].ToAggregateType(); 297 } 298 299 public AggregateType GetUserDefinedType(int location, bool isOutput) 300 { 301 if ((!isOutput && IaIndexing) || (isOutput && OaIndexing)) 302 { 303 return AggregateType.Array | AggregateType.Vector4 | AggregateType.FP32; 304 } 305 306 AggregateType type = AggregateType.Vector4; 307 308 if (Stage == ShaderStage.Vertex && !isOutput) 309 { 310 type |= _graphicsState.AttributeTypes[location].ToAggregateType(SupportsScaledVertexFormats); 311 } 312 else 313 { 314 type |= AggregateType.FP32; 315 } 316 317 return type; 318 } 319 320 public AttributeType GetAttributeType(int location) 321 { 322 return _graphicsState.AttributeTypes[location]; 323 } 324 325 public bool IsAttributeSint(int location) 326 { 327 return (_graphicsState.AttributeTypes[location] & ~AttributeType.AnyPacked) == AttributeType.Sint; 328 } 329 330 public bool IsAttributePacked(int location) 331 { 332 return _graphicsState.AttributeTypes[location].HasFlag(AttributeType.Packed); 333 } 334 335 public bool IsAttributePackedRgb10A2Signed(int location) 336 { 337 return _graphicsState.AttributeTypes[location].HasFlag(AttributeType.PackedRgb10A2Signed); 338 } 339 340 public int GetGeometryOutputIndexBufferStridePerInstance() 341 { 342 return MaxOutputVertices + OutputTopology switch 343 { 344 OutputTopology.LineStrip => MaxOutputVertices / 2, 345 OutputTopology.TriangleStrip => MaxOutputVertices / 3, 346 _ => MaxOutputVertices, 347 }; 348 } 349 350 public int GetGeometryOutputIndexBufferStride() 351 { 352 return GetGeometryOutputIndexBufferStridePerInstance() * ThreadsPerInputPrimitive; 353 } 354 } 355 }