mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-02-21 16:43:35 +00:00
SPIR-V: Implement attribute indexing and StoreAttribute
This commit is contained in:
parent
2ef7622126
commit
95d5a50042
3 changed files with 163 additions and 35 deletions
|
@ -23,6 +23,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
public Instruction StorageBuffersArray { get; set; }
|
||||
public Instruction LocalMemory { get; set; }
|
||||
public Instruction SharedMemory { get; set; }
|
||||
public Instruction InputsArray { get; set; }
|
||||
public Instruction OutputsArray { get; set; }
|
||||
public Dictionary<TextureMeta, (Instruction, Instruction, Instruction)> Samplers { get; } = new Dictionary<TextureMeta, (Instruction, Instruction, Instruction)>();
|
||||
public Dictionary<TextureMeta, (Instruction, Instruction)> Images { get; } = new Dictionary<TextureMeta, (Instruction, Instruction)>();
|
||||
public Dictionary<int, Instruction> Inputs { get; } = new Dictionary<int, Instruction>();
|
||||
|
@ -144,7 +146,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
|
||||
public Instruction[] GetMainInterface()
|
||||
{
|
||||
return Inputs.Values.Concat(Outputs.Values).ToArray();
|
||||
var mainInterface = Inputs.Values.Concat(Outputs.Values);
|
||||
|
||||
if (InputsArray != null)
|
||||
{
|
||||
mainInterface = mainInterface.Append(InputsArray);
|
||||
}
|
||||
|
||||
if (OutputsArray != null)
|
||||
{
|
||||
mainInterface = mainInterface.Append(OutputsArray);
|
||||
}
|
||||
|
||||
return mainInterface.ToArray();
|
||||
}
|
||||
|
||||
public void DeclareLocal(AstOperand local, Instruction spvLocal)
|
||||
|
@ -211,23 +225,39 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
throw new NotImplementedException(node.GetType().Name);
|
||||
}
|
||||
|
||||
public Instruction GetAttributeVectorPointer(AstOperand operand, bool isOutAttr)
|
||||
{
|
||||
var attrInfo = AttributeInfo.From(Config, operand.Value, isOutAttr);
|
||||
|
||||
return isOutAttr ? Outputs[attrInfo.BaseValue] : Inputs[attrInfo.BaseValue];
|
||||
}
|
||||
|
||||
public Instruction GetAttributeElemPointer(int attr, bool isOutAttr, Instruction index, out AggregateType elemType)
|
||||
{
|
||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||
var attrInfo = AttributeInfo.From(Config, attr, isOutAttr);
|
||||
|
||||
elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
|
||||
int attrOffset = attrInfo.BaseValue;
|
||||
AggregateType type = attrInfo.Type;
|
||||
|
||||
Instruction ioVariable, elemIndex;
|
||||
|
||||
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
||||
|
||||
if (isUserAttr &&
|
||||
((!isOutAttr && Config.UsedFeatures.HasFlag(FeatureFlags.IaIndexing)) ||
|
||||
(isOutAttr && Config.UsedFeatures.HasFlag(FeatureFlags.OaIndexing))))
|
||||
{
|
||||
elemType = AggregateType.FP32;
|
||||
ioVariable = isOutAttr ? OutputsArray : InputsArray;
|
||||
elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
||||
var vecIndex = Constant(TypeU32(), (attr - AttributeConsts.UserAttributeBase) >> 4);
|
||||
|
||||
if (Config.Stage == ShaderStage.Geometry && !isOutAttr)
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, vecIndex, elemIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, vecIndex, elemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
|
||||
if (isUserAttr && Config.TransformFeedbackEnabled &&
|
||||
((isOutAttr && Config.Stage != ShaderStage.Fragment) ||
|
||||
(!isOutAttr && Config.Stage != ShaderStage.Vertex)))
|
||||
|
@ -236,15 +266,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
type = elemType;
|
||||
}
|
||||
|
||||
var ioVariable = isOutAttr ? Outputs[attrOffset] : Inputs[attrOffset];
|
||||
ioVariable = isOutAttr ? Outputs[attrOffset] : Inputs[attrOffset];
|
||||
|
||||
if ((type & (AggregateType.Array | AggregateType.Vector)) == 0)
|
||||
{
|
||||
return ioVariable;
|
||||
}
|
||||
|
||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||
var elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
||||
elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
||||
|
||||
if (Config.Stage == ShaderStage.Geometry && !isOutAttr && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
|
||||
{
|
||||
|
@ -256,12 +285,37 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
}
|
||||
}
|
||||
|
||||
public Instruction GetAttributeElemPointer(Instruction attrIndex, bool isOutAttr, Instruction index, out AggregateType elemType)
|
||||
{
|
||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||
|
||||
elemType = AggregateType.FP32;
|
||||
var ioVariable = isOutAttr ? OutputsArray : InputsArray;
|
||||
var vecIndex = ShiftRightLogical(TypeS32(), attrIndex, Constant(TypeS32(), 2));
|
||||
var elemIndex = BitwiseAnd(TypeS32(), attrIndex, Constant(TypeS32(), 3));
|
||||
|
||||
if (Config.Stage == ShaderStage.Geometry && !isOutAttr)
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, vecIndex, elemIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, vecIndex, elemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public Instruction GetAttribute(AggregateType type, int attr, bool isOutAttr, Instruction index = null)
|
||||
{
|
||||
var elemPointer = GetAttributeElemPointer(attr, isOutAttr, index, out var elemType);
|
||||
return BitcastIfNeeded(type, elemType, Load(GetType(elemType), elemPointer));
|
||||
}
|
||||
|
||||
public Instruction GetAttribute(AggregateType type, Instruction attr, bool isOutAttr, Instruction index = null)
|
||||
{
|
||||
var elemPointer = GetAttributeElemPointer(attr, isOutAttr, index, out var elemType);
|
||||
return BitcastIfNeeded(type, elemType, Load(GetType(elemType), elemPointer));
|
||||
}
|
||||
|
||||
public Instruction GetConstant(AggregateType type, AstOperand operand)
|
||||
{
|
||||
return type switch
|
||||
|
|
|
@ -331,41 +331,82 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
|
||||
private static void DeclareInputAttributes(CodeGenContext context, StructuredProgramInfo info)
|
||||
{
|
||||
bool iaIndexing = context.Config.UsedFeatures.HasFlag(FeatureFlags.IaIndexing);
|
||||
|
||||
foreach (int attr in info.Inputs)
|
||||
{
|
||||
PixelImap iq = PixelImap.Unused;
|
||||
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Fragment &&
|
||||
attr >= AttributeConsts.UserAttributeBase &&
|
||||
attr < AttributeConsts.UserAttributeEnd)
|
||||
if (iaIndexing && isUserAttr)
|
||||
{
|
||||
iq = context.Config.ImapTypes[(attr - AttributeConsts.UserAttributeBase) / 16].GetFirstUsedType();
|
||||
}
|
||||
if (context.InputsArray == null)
|
||||
{
|
||||
var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4);
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes));
|
||||
|
||||
DeclareInputOrOutput(context, attr, false, iq);
|
||||
if (context.Config.Stage == ShaderStage.Geometry)
|
||||
{
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)context.InputVertices));
|
||||
}
|
||||
|
||||
var spvType = context.TypePointer(StorageClass.Input, attrType);
|
||||
var spvVar = context.Variable(spvType, StorageClass.Input);
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0);
|
||||
|
||||
context.AddGlobalVariable(spvVar);
|
||||
context.InputsArray = spvVar;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PixelImap iq = PixelImap.Unused;
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Fragment &&
|
||||
attr >= AttributeConsts.UserAttributeBase &&
|
||||
attr < AttributeConsts.UserAttributeEnd)
|
||||
{
|
||||
iq = context.Config.ImapTypes[(attr - AttributeConsts.UserAttributeBase) / 16].GetFirstUsedType();
|
||||
}
|
||||
|
||||
DeclareInputOrOutput(context, attr, false, iq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info)
|
||||
{
|
||||
bool oaIndexing = context.Config.UsedFeatures.HasFlag(FeatureFlags.OaIndexing);
|
||||
|
||||
foreach (int attr in info.Outputs)
|
||||
{
|
||||
DeclareOutputAttribute(context, attr);
|
||||
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
||||
|
||||
if (oaIndexing && isUserAttr)
|
||||
{
|
||||
if (context.OutputsArray == null)
|
||||
{
|
||||
var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4);
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes));
|
||||
|
||||
var spvType = context.TypePointer(StorageClass.Output, attrType);
|
||||
var spvVar = context.Variable(spvType, StorageClass.Output);
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0);
|
||||
|
||||
context.AddGlobalVariable(spvVar);
|
||||
context.OutputsArray = spvVar;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DeclareOutputAttribute(context, attr);
|
||||
}
|
||||
}
|
||||
|
||||
if (context.Config.Stage != ShaderStage.Compute &&
|
||||
context.Config.Stage != ShaderStage.Fragment &&
|
||||
!context.Config.GpPassthrough)
|
||||
if (context.Config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
for (int attr = 0; attr < MaxAttributes; attr++)
|
||||
{
|
||||
DeclareOutputAttribute(context, AttributeConsts.UserAttributeBase + attr * 16);
|
||||
}
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
DeclareOutputAttribute(context, AttributeConsts.PositionX);
|
||||
}
|
||||
DeclareOutputAttribute(context, AttributeConsts.PositionX);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -121,6 +121,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
Add(Instruction.ShuffleXor, GenerateShuffleXor);
|
||||
Add(Instruction.Sine, GenerateSine);
|
||||
Add(Instruction.SquareRoot, GenerateSquareRoot);
|
||||
Add(Instruction.StoreAttribute, GenerateStoreAttribute);
|
||||
Add(Instruction.StoreLocal, GenerateStoreLocal);
|
||||
Add(Instruction.StoreShared, GenerateStoreShared);
|
||||
Add(Instruction.StoreStorage, GenerateStoreStorage);
|
||||
|
@ -864,11 +865,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
|
||||
{
|
||||
int attrOffset = baseAttr.Value + (operand.Value << 2);
|
||||
return new OperationResult(resultType, context.GetAttribute(resultType, attrOffset, false, index));
|
||||
return new OperationResult(resultType, context.GetAttribute(resultType, attrOffset, isOutAttr: false, index));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var attr = context.Get(AggregateType.S32, src2);
|
||||
return new OperationResult(resultType, context.GetAttribute(resultType, attr, isOutAttr: false, index));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1244,6 +1246,37 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||
return GenerateUnary(context, operation, context.Delegates.GlslSqrt, null);
|
||||
}
|
||||
|
||||
private static OperationResult GenerateStoreAttribute(CodeGenContext context, AstOperation operation)
|
||||
{
|
||||
var src1 = operation.GetSource(0);
|
||||
var src2 = operation.GetSource(1);
|
||||
var src3 = operation.GetSource(2);
|
||||
|
||||
if (!(src1 is AstOperand baseAttr) || baseAttr.Type != OperandType.Constant)
|
||||
{
|
||||
throw new InvalidOperationException($"First input of {nameof(Instruction.StoreAttribute)} must be a constant operand.");
|
||||
}
|
||||
|
||||
SpvInstruction elemPointer;
|
||||
AggregateType elemType;
|
||||
|
||||
if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
|
||||
{
|
||||
int attrOffset = baseAttr.Value + (operand.Value << 2);
|
||||
elemPointer = context.GetAttributeElemPointer(attrOffset, isOutAttr: true, index: null, out elemType);
|
||||
}
|
||||
else
|
||||
{
|
||||
var attr = context.Get(AggregateType.S32, src2);
|
||||
elemPointer = context.GetAttributeElemPointer(attr, isOutAttr: true, index: null, out elemType);
|
||||
}
|
||||
|
||||
var value = context.Get(elemType, src3);
|
||||
context.Store(elemPointer, value);
|
||||
|
||||
return OperationResult.Invalid;
|
||||
}
|
||||
|
||||
private static OperationResult GenerateStoreLocal(CodeGenContext context, AstOperation operation)
|
||||
{
|
||||
return GenerateStoreLocalOrShared(context, operation, StorageClass.Private, context.LocalMemory);
|
||||
|
|
Loading…
Reference in a new issue