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