/ src / Ryujinx.Graphics.Shader / Translation / Transforms / VectorComponentSelect.cs
VectorComponentSelect.cs
 1  using Ryujinx.Graphics.Shader.IntermediateRepresentation;
 2  using Ryujinx.Graphics.Shader.StructuredIr;
 3  using System.Collections.Generic;
 4  
 5  using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
 6  
 7  namespace Ryujinx.Graphics.Shader.Translation.Transforms
 8  {
 9      class VectorComponentSelect : ITransformPass
10      {
11          public static bool IsEnabled(IGpuAccessor gpuAccessor, ShaderStage stage, TargetLanguage targetLanguage, FeatureFlags usedFeatures)
12          {
13              return gpuAccessor.QueryHostHasVectorIndexingBug();
14          }
15  
16          public static LinkedListNode<INode> RunPass(TransformContext context, LinkedListNode<INode> node)
17          {
18              Operation operation = (Operation)node.Value;
19  
20              if (operation.Inst != Instruction.Load ||
21                  operation.StorageKind != StorageKind.ConstantBuffer ||
22                  operation.SourcesCount < 3)
23              {
24                  return node;
25              }
26  
27              Operand bindingIndex = operation.GetSource(0);
28              Operand fieldIndex = operation.GetSource(1);
29              Operand elemIndex = operation.GetSource(operation.SourcesCount - 1);
30  
31              if (bindingIndex.Type != OperandType.Constant ||
32                  fieldIndex.Type != OperandType.Constant ||
33                  elemIndex.Type == OperandType.Constant)
34              {
35                  return node;
36              }
37  
38              BufferDefinition buffer = context.ResourceManager.Properties.ConstantBuffers[bindingIndex.Value];
39              StructureField field = buffer.Type.Fields[fieldIndex.Value];
40  
41              int elemCount = (field.Type & AggregateType.ElementCountMask) switch
42              {
43                  AggregateType.Vector2 => 2,
44                  AggregateType.Vector3 => 3,
45                  AggregateType.Vector4 => 4,
46                  _ => 1
47              };
48  
49              if (elemCount == 1)
50              {
51                  return node;
52              }
53  
54              Operand result = null;
55  
56              for (int i = 0; i < elemCount; i++)
57              {
58                  Operand value = Local();
59                  Operand[] inputs = new Operand[operation.SourcesCount];
60  
61                  for (int srcIndex = 0; srcIndex < inputs.Length - 1; srcIndex++)
62                  {
63                      inputs[srcIndex] = operation.GetSource(srcIndex);
64                  }
65  
66                  inputs[^1] = Const(i);
67  
68                  Operation loadOp = new(Instruction.Load, StorageKind.ConstantBuffer, value, inputs);
69  
70                  node.List.AddBefore(node, loadOp);
71  
72                  if (i == 0)
73                  {
74                      result = value;
75                  }
76                  else
77                  {
78                      Operand isCurrentIndex = Local();
79                      Operand selection = Local();
80  
81                      Operation compareOp = new(Instruction.CompareEqual, isCurrentIndex, new Operand[] { elemIndex, Const(i) });
82                      Operation selectOp = new(Instruction.ConditionalSelect, selection, new Operand[] { isCurrentIndex, value, result });
83  
84                      node.List.AddBefore(node, compareOp);
85                      node.List.AddBefore(node, selectOp);
86  
87                      result = selection;
88                  }
89              }
90  
91              operation.TurnIntoCopy(result);
92  
93              return node;
94          }
95      }
96  }