mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-02-21 16:43:35 +00:00
SPIR-V: Geometry shader support
This commit is contained in:
parent
bd56998f4d
commit
e1d73cc560
12 changed files with 150 additions and 51 deletions
|
@ -69,7 +69,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum number of vertex attributes.
|
/// Maximum number of vertex attributes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int TotalVertexAttribs = 16;
|
public const int TotalVertexAttribs = 16; // FIXME: Should be 32, but OpenGL only supports 16.
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum number of vertex buffers.
|
/// Maximum number of vertex buffers.
|
||||||
|
|
|
@ -768,8 +768,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
public fixed uint Reserved10B0[18];
|
public fixed uint Reserved10B0[18];
|
||||||
public uint ClearFlags;
|
public uint ClearFlags;
|
||||||
public fixed uint Reserved10FC[25];
|
public fixed uint Reserved10FC[25];
|
||||||
public Array16<VertexAttribState> VertexAttribState;
|
public Array32<VertexAttribState> VertexAttribState;
|
||||||
public fixed uint Reserved11A0[31];
|
public fixed uint Reserved11E0[15];
|
||||||
public RtControl RtControl;
|
public RtControl RtControl;
|
||||||
public fixed uint Reserved1220[2];
|
public fixed uint Reserved1220[2];
|
||||||
public Size3D RtDepthStencilSize;
|
public Size3D RtDepthStencilSize;
|
||||||
|
|
|
@ -261,7 +261,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return gpShaders;
|
return gpShaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeType[] attributeTypes = new AttributeType[Constants.TotalVertexAttribs];
|
AttributeType[] attributeTypes = new AttributeType[32];
|
||||||
|
|
||||||
for (int location = 0; location < attributeTypes.Length; location++)
|
for (int location = 0; location < attributeTypes.Length; location++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -275,7 +275,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
string name = builtInAttr.Name;
|
string name = builtInAttr.Name;
|
||||||
|
|
||||||
if (!perPatch && IsArrayAttribute(config.Stage, isOutAttr) && IsArrayBuiltIn(value))
|
if (!perPatch && IsArrayAttribute(config.Stage, isOutAttr) && AttributeInfo.IsArrayBuiltIn(value))
|
||||||
{
|
{
|
||||||
name = isOutAttr ? $"gl_out[gl_InvocationID].{name}" : $"gl_in[{indexExpr}].{name}";
|
name = isOutAttr ? $"gl_out[gl_InvocationID].{name}" : $"gl_in[{indexExpr}].{name}";
|
||||||
}
|
}
|
||||||
|
@ -317,18 +317,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsArrayBuiltIn(int attr)
|
|
||||||
{
|
|
||||||
if (attr <= AttributeConsts.TessLevelInner1 ||
|
|
||||||
attr == AttributeConsts.TessCoordX ||
|
|
||||||
attr == AttributeConsts.TessCoordY)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (attr & AttributeConsts.SpecialMask) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetUbName(ShaderStage stage, int slot, bool cbIndexable)
|
public static string GetUbName(ShaderStage stage, int slot, bool cbIndexable)
|
||||||
{
|
{
|
||||||
if (cbIndexable)
|
if (cbIndexable)
|
||||||
|
|
|
@ -15,6 +15,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
{
|
{
|
||||||
public ShaderConfig Config { get; }
|
public ShaderConfig Config { get; }
|
||||||
|
|
||||||
|
public int InputVertices { get; }
|
||||||
|
|
||||||
public Dictionary<int, Instruction> UniformBuffers { get; } = new Dictionary<int, Instruction>();
|
public Dictionary<int, Instruction> UniformBuffers { get; } = new Dictionary<int, Instruction>();
|
||||||
public Instruction StorageBuffersArray { get; set; }
|
public Instruction StorageBuffersArray { get; set; }
|
||||||
public Instruction LocalMemory { get; set; }
|
public Instruction LocalMemory { get; set; }
|
||||||
|
@ -65,6 +67,21 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
{
|
{
|
||||||
Config = config;
|
Config = config;
|
||||||
|
|
||||||
|
if (config.Stage == ShaderStage.Geometry)
|
||||||
|
{
|
||||||
|
InputTopology inPrimitive = config.GpuAccessor.QueryPrimitiveTopology();
|
||||||
|
|
||||||
|
InputVertices = inPrimitive switch
|
||||||
|
{
|
||||||
|
InputTopology.Points => 1,
|
||||||
|
InputTopology.Lines => 2,
|
||||||
|
InputTopology.LinesAdjacency => 2,
|
||||||
|
InputTopology.Triangles => 3,
|
||||||
|
InputTopology.TrianglesAdjacency => 3,
|
||||||
|
_ => throw new InvalidOperationException($"Invalid input topology \"{inPrimitive}\".")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
AddCapability(Capability.Shader);
|
AddCapability(Capability.Shader);
|
||||||
AddCapability(Capability.Float64);
|
AddCapability(Capability.Float64);
|
||||||
|
|
||||||
|
@ -171,7 +188,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
return operand.Type switch
|
return operand.Type switch
|
||||||
{
|
{
|
||||||
IrOperandType.Argument => GetArgument(type, operand),
|
IrOperandType.Argument => GetArgument(type, operand),
|
||||||
IrOperandType.Attribute => GetAttribute(type, operand, false),
|
IrOperandType.Attribute => GetAttribute(type, operand.Value & AttributeConsts.Mask, (operand.Value & AttributeConsts.LoadOutputMask) != 0),
|
||||||
IrOperandType.Constant => GetConstant(type, operand),
|
IrOperandType.Constant => GetConstant(type, operand),
|
||||||
IrOperandType.ConstantBuffer => GetConstantBuffer(type, operand),
|
IrOperandType.ConstantBuffer => GetConstantBuffer(type, operand),
|
||||||
IrOperandType.LocalVariable => GetLocal(type, operand),
|
IrOperandType.LocalVariable => GetLocal(type, operand),
|
||||||
|
@ -190,16 +207,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
return isOutAttr ? Outputs[attrInfo.BaseValue] : Inputs[attrInfo.BaseValue];
|
return isOutAttr ? Outputs[attrInfo.BaseValue] : Inputs[attrInfo.BaseValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instruction GetAttributeElemPointer(AstOperand operand, bool isOutAttr, out AggregateType elemType)
|
public Instruction GetAttributeElemPointer(int attr, bool isOutAttr, Instruction index, out AggregateType elemType)
|
||||||
{
|
{
|
||||||
var attrInfo = AttributeInfo.From(Config, operand.Value);
|
var attrInfo = AttributeInfo.From(Config, attr);
|
||||||
if (attrInfo.BaseValue == AttributeConsts.PositionX && Config.Stage != ShaderStage.Fragment)
|
|
||||||
{
|
|
||||||
isOutAttr = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||||
|
|
||||||
|
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||||
|
|
||||||
|
var elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
||||||
|
|
||||||
var ioVariable = isOutAttr ? Outputs[attrInfo.BaseValue] : Inputs[attrInfo.BaseValue];
|
var ioVariable = isOutAttr ? Outputs[attrInfo.BaseValue] : Inputs[attrInfo.BaseValue];
|
||||||
|
|
||||||
if ((attrInfo.Type & (AggregateType.Array | AggregateType.Vector)) == 0)
|
if ((attrInfo.Type & (AggregateType.Array | AggregateType.Vector)) == 0)
|
||||||
|
@ -207,15 +224,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
return ioVariable;
|
return ioVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
if (Config.Stage == ShaderStage.Geometry && !isOutAttr && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
|
||||||
|
{
|
||||||
var elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, elemIndex);
|
||||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, elemIndex);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, elemIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instruction GetAttribute(AggregateType type, AstOperand operand, bool isOutAttr)
|
public Instruction GetAttribute(AggregateType type, int attr, bool isOutAttr, Instruction index = null)
|
||||||
{
|
{
|
||||||
var elemPointer = GetAttributeElemPointer(operand, isOutAttr, out var elemType);
|
var elemPointer = GetAttributeElemPointer(attr, isOutAttr, index, out var elemType);
|
||||||
return BitcastIfNeeded(type, elemType, Load(GetType(elemType), elemPointer));
|
return BitcastIfNeeded(type, elemType, Load(GetType(elemType), elemPointer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -391,19 +391,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
var dict = isOutAttr ? context.Outputs : context.Inputs;
|
var dict = isOutAttr ? context.Outputs : context.Inputs;
|
||||||
var attrInfo = AttributeInfo.From(context.Config, attr);
|
var attrInfo = AttributeInfo.From(context.Config, attr);
|
||||||
|
|
||||||
if (attrInfo.BaseValue == AttributeConsts.PositionX && context.Config.Stage != ShaderStage.Fragment)
|
|
||||||
{
|
|
||||||
isOutAttr = true;
|
|
||||||
dict = context.Outputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dict.ContainsKey(attrInfo.BaseValue))
|
if (dict.ContainsKey(attrInfo.BaseValue))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||||
var spvType = context.TypePointer(storageClass, context.GetType(attrInfo.Type, attrInfo.Length));
|
var attrType = context.GetType(attrInfo.Type, attrInfo.Length);
|
||||||
|
|
||||||
|
if (context.Config.Stage == ShaderStage.Geometry && !isOutAttr && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
|
||||||
|
{
|
||||||
|
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)context.InputVertices));
|
||||||
|
}
|
||||||
|
|
||||||
|
var spvType = context.TypePointer(storageClass, attrType);
|
||||||
var spvVar = context.Variable(spvType, storageClass);
|
var spvVar = context.Variable(spvType, storageClass);
|
||||||
|
|
||||||
if (attrInfo.IsBuiltin)
|
if (attrInfo.IsBuiltin)
|
||||||
|
|
|
@ -73,6 +73,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
Add(Instruction.Ddy, GenerateDdy);
|
Add(Instruction.Ddy, GenerateDdy);
|
||||||
Add(Instruction.Discard, GenerateDiscard);
|
Add(Instruction.Discard, GenerateDiscard);
|
||||||
Add(Instruction.Divide, GenerateDivide);
|
Add(Instruction.Divide, GenerateDivide);
|
||||||
|
Add(Instruction.EmitVertex, GenerateEmitVertex);
|
||||||
|
Add(Instruction.EndPrimitive, GenerateEndPrimitive);
|
||||||
Add(Instruction.ExponentB2, GenerateExponentB2);
|
Add(Instruction.ExponentB2, GenerateExponentB2);
|
||||||
Add(Instruction.FindLSB, GenerateFindLSB);
|
Add(Instruction.FindLSB, GenerateFindLSB);
|
||||||
Add(Instruction.FindMSBS32, GenerateFindMSBS32);
|
Add(Instruction.FindMSBS32, GenerateFindMSBS32);
|
||||||
|
@ -500,6 +502,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
return GenerateBinary(context, operation, context.FDiv, context.SDiv);
|
return GenerateBinary(context, operation, context.FDiv, context.SDiv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static OperationResult GenerateEmitVertex(CodeGenContext context, AstOperation operation)
|
||||||
|
{
|
||||||
|
context.EmitVertex();
|
||||||
|
|
||||||
|
return OperationResult.Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static OperationResult GenerateEndPrimitive(CodeGenContext context, AstOperation operation)
|
||||||
|
{
|
||||||
|
context.EndPrimitive();
|
||||||
|
|
||||||
|
return OperationResult.Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
private static OperationResult GenerateExponentB2(CodeGenContext context, AstOperation operation)
|
private static OperationResult GenerateExponentB2(CodeGenContext context, AstOperation operation)
|
||||||
{
|
{
|
||||||
return GenerateUnary(context, operation, context.GlslExp2, null);
|
return GenerateUnary(context, operation, context.GlslExp2, null);
|
||||||
|
@ -812,13 +828,25 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
{
|
{
|
||||||
var src1 = operation.GetSource(0);
|
var src1 = operation.GetSource(0);
|
||||||
var src2 = operation.GetSource(1);
|
var src2 = operation.GetSource(1);
|
||||||
|
var src3 = operation.GetSource(2);
|
||||||
|
|
||||||
if (src1 is not AstOperand oper || oper.Type != OperandType.Attribute)
|
if (!(src1 is AstOperand baseAttr) || baseAttr.Type != OperandType.Constant)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("First source of LoadAttribute must be a attribute.");
|
throw new InvalidOperationException($"First input of {nameof(Instruction.LoadAttribute)} must be a constant operand.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new OperationResult(AggregateType.FP32, context.GetAttribute(AggregateType.FP32, oper, false));
|
var index = context.Get(AggregateType.S32, src3);
|
||||||
|
var resultType = AggregateType.FP32;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OperationResult GenerateLoadConstant(CodeGenContext context, AstOperation operation)
|
private static OperationResult GenerateLoadConstant(CodeGenContext context, AstOperation operation)
|
||||||
|
@ -1081,7 +1109,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
var clampNotSegMask = context.BitwiseAnd(context.TypeU32(), clamp, notSegMask);
|
var clampNotSegMask = context.BitwiseAnd(context.TypeU32(), clamp, notSegMask);
|
||||||
var indexNotSegMask = context.BitwiseAnd(context.TypeU32(), index, notSegMask);
|
var indexNotSegMask = context.BitwiseAnd(context.TypeU32(), index, notSegMask);
|
||||||
|
|
||||||
var threadId = context.GetAttribute(AggregateType.U32, new AstOperand(OperandType.Attribute, AttributeConsts.LaneId), false);
|
var threadId = context.GetAttribute(AggregateType.U32, AttributeConsts.LaneId, false);
|
||||||
|
|
||||||
var minThreadId = context.BitwiseAnd(context.TypeU32(), threadId, segMask);
|
var minThreadId = context.BitwiseAnd(context.TypeU32(), threadId, segMask);
|
||||||
var maxThreadId = context.BitwiseOr(context.TypeU32(), minThreadId, clampNotSegMask);
|
var maxThreadId = context.BitwiseOr(context.TypeU32(), minThreadId, clampNotSegMask);
|
||||||
|
@ -1111,7 +1139,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
var notSegMask = context.Not(context.TypeU32(), segMask);
|
var notSegMask = context.Not(context.TypeU32(), segMask);
|
||||||
var clampNotSegMask = context.BitwiseAnd(context.TypeU32(), clamp, notSegMask);
|
var clampNotSegMask = context.BitwiseAnd(context.TypeU32(), clamp, notSegMask);
|
||||||
|
|
||||||
var threadId = context.GetAttribute(AggregateType.U32, new AstOperand(OperandType.Attribute, AttributeConsts.LaneId), false);
|
var threadId = context.GetAttribute(AggregateType.U32, AttributeConsts.LaneId, false);
|
||||||
|
|
||||||
var minThreadId = context.BitwiseAnd(context.TypeU32(), threadId, segMask);
|
var minThreadId = context.BitwiseAnd(context.TypeU32(), threadId, segMask);
|
||||||
var maxThreadId = context.BitwiseOr(context.TypeU32(), minThreadId, clampNotSegMask);
|
var maxThreadId = context.BitwiseOr(context.TypeU32(), minThreadId, clampNotSegMask);
|
||||||
|
@ -1138,7 +1166,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
var segMask = context.BitwiseAnd(context.TypeU32(), context.ShiftRightLogical(context.TypeU32(), mask, const8), const31);
|
var segMask = context.BitwiseAnd(context.TypeU32(), context.ShiftRightLogical(context.TypeU32(), mask, const8), const31);
|
||||||
|
|
||||||
var threadId = context.GetAttribute(AggregateType.U32, new AstOperand(OperandType.Attribute, AttributeConsts.LaneId), false);
|
var threadId = context.GetAttribute(AggregateType.U32, AttributeConsts.LaneId, false);
|
||||||
|
|
||||||
var minThreadId = context.BitwiseAnd(context.TypeU32(), threadId, segMask);
|
var minThreadId = context.BitwiseAnd(context.TypeU32(), threadId, segMask);
|
||||||
var srcThreadId = context.ISub(context.TypeU32(), threadId, index);
|
var srcThreadId = context.ISub(context.TypeU32(), threadId, index);
|
||||||
|
@ -1167,7 +1195,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
var notSegMask = context.Not(context.TypeU32(), segMask);
|
var notSegMask = context.Not(context.TypeU32(), segMask);
|
||||||
var clampNotSegMask = context.BitwiseAnd(context.TypeU32(), clamp, notSegMask);
|
var clampNotSegMask = context.BitwiseAnd(context.TypeU32(), clamp, notSegMask);
|
||||||
|
|
||||||
var threadId = context.GetAttribute(AggregateType.U32, new AstOperand(OperandType.Attribute, AttributeConsts.LaneId), false);
|
var threadId = context.GetAttribute(AggregateType.U32, AttributeConsts.LaneId, false);
|
||||||
|
|
||||||
var minThreadId = context.BitwiseAnd(context.TypeU32(), threadId, segMask);
|
var minThreadId = context.BitwiseAnd(context.TypeU32(), threadId, segMask);
|
||||||
var maxThreadId = context.BitwiseOr(context.TypeU32(), minThreadId, clampNotSegMask);
|
var maxThreadId = context.BitwiseOr(context.TypeU32(), minThreadId, clampNotSegMask);
|
||||||
|
|
|
@ -29,6 +29,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
context.AddCapability(Capability.SampledBuffer);
|
context.AddCapability(Capability.SampledBuffer);
|
||||||
context.AddCapability(Capability.SubgroupBallotKHR);
|
context.AddCapability(Capability.SubgroupBallotKHR);
|
||||||
context.AddCapability(Capability.SubgroupVoteKHR);
|
context.AddCapability(Capability.SubgroupVoteKHR);
|
||||||
|
|
||||||
|
if (config.Stage == ShaderStage.Geometry)
|
||||||
|
{
|
||||||
|
context.AddCapability(Capability.Geometry);
|
||||||
|
}
|
||||||
|
|
||||||
context.AddExtension("SPV_KHR_shader_ballot");
|
context.AddExtension("SPV_KHR_shader_ballot");
|
||||||
context.AddExtension("SPV_KHR_subgroup_vote");
|
context.AddExtension("SPV_KHR_subgroup_vote");
|
||||||
|
|
||||||
|
@ -97,7 +103,39 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
{
|
{
|
||||||
context.AddEntryPoint(context.Config.Stage.Convert(), spvFunc, "main", context.GetMainInterface());
|
context.AddEntryPoint(context.Config.Stage.Convert(), spvFunc, "main", context.GetMainInterface());
|
||||||
|
|
||||||
if (context.Config.Stage == ShaderStage.Fragment)
|
if (context.Config.Stage == ShaderStage.Geometry)
|
||||||
|
{
|
||||||
|
InputTopology inPrimitive = context.Config.GpuAccessor.QueryPrimitiveTopology();
|
||||||
|
|
||||||
|
switch (inPrimitive)
|
||||||
|
{
|
||||||
|
case InputTopology.Points:
|
||||||
|
context.AddExecutionMode(spvFunc, ExecutionMode.InputPoints);
|
||||||
|
break;
|
||||||
|
case InputTopology.Lines:
|
||||||
|
context.AddExecutionMode(spvFunc, ExecutionMode.InputLines);
|
||||||
|
break;
|
||||||
|
case InputTopology.LinesAdjacency:
|
||||||
|
context.AddExecutionMode(spvFunc, ExecutionMode.InputLinesAdjacency);
|
||||||
|
break;
|
||||||
|
case InputTopology.TrianglesAdjacency:
|
||||||
|
context.AddExecutionMode(spvFunc, ExecutionMode.InputTrianglesAdjacency);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.AddExecutionMode(spvFunc, ExecutionMode.Invocations, (SpvLiteralInteger)context.InputVertices);
|
||||||
|
|
||||||
|
context.AddExecutionMode(spvFunc, context.Config.OutputTopology switch
|
||||||
|
{
|
||||||
|
OutputTopology.PointList => ExecutionMode.OutputPoints,
|
||||||
|
OutputTopology.LineStrip => ExecutionMode.OutputLineStrip,
|
||||||
|
OutputTopology.TriangleStrip => ExecutionMode.OutputTriangleStrip,
|
||||||
|
_ => throw new InvalidOperationException($"Invalid output topology \"{context.Config.OutputTopology}\".")
|
||||||
|
});
|
||||||
|
|
||||||
|
context.AddExecutionMode(spvFunc, ExecutionMode.OutputVertices, (SpvLiteralInteger)context.Config.MaxOutputVertices);
|
||||||
|
}
|
||||||
|
else if (context.Config.Stage == ShaderStage.Fragment)
|
||||||
{
|
{
|
||||||
context.AddExecutionMode(spvFunc, context.Config.Options.TargetApi == TargetApi.Vulkan
|
context.AddExecutionMode(spvFunc, context.Config.Options.TargetApi == TargetApi.Vulkan
|
||||||
? ExecutionMode.OriginUpperLeft
|
? ExecutionMode.OriginUpperLeft
|
||||||
|
@ -228,7 +266,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
}
|
}
|
||||||
else if (dest.Type == OperandType.Attribute)
|
else if (dest.Type == OperandType.Attribute)
|
||||||
{
|
{
|
||||||
var elemPointer = context.GetAttributeElemPointer(dest, true, out var elemType);
|
var elemPointer = context.GetAttributeElemPointer(dest.Value, true, null, out var elemType);
|
||||||
context.Store(elemPointer, context.Get(elemType, assignment.Source));
|
context.Store(elemPointer, context.Get(elemType, assignment.Source));
|
||||||
}
|
}
|
||||||
else if (dest.Type == OperandType.Argument)
|
else if (dest.Type == OperandType.Argument)
|
||||||
|
|
|
@ -89,6 +89,18 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
{
|
{
|
||||||
Instruction inst = operation.Inst;
|
Instruction inst = operation.Inst;
|
||||||
|
|
||||||
|
if (inst == Instruction.LoadAttribute)
|
||||||
|
{
|
||||||
|
Operand src1 = operation.GetSource(0);
|
||||||
|
Operand src2 = operation.GetSource(1);
|
||||||
|
|
||||||
|
if (src1.Type == OperandType.Constant && src2.Type == OperandType.Constant)
|
||||||
|
{
|
||||||
|
int attrOffset = src1.Value + (src2.Value << 2);
|
||||||
|
context.Info.Inputs.Add(attrOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int sourcesCount = operation.SourcesCount;
|
int sourcesCount = operation.SourcesCount;
|
||||||
int outDestsCount = operation.DestsCount != 0 ? operation.DestsCount - 1 : 0;
|
int outDestsCount = operation.DestsCount != 0 ? operation.DestsCount - 1 : 0;
|
||||||
|
|
||||||
|
|
|
@ -279,7 +279,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
{
|
{
|
||||||
if (operand.Type == OperandType.Attribute)
|
if (operand.Type == OperandType.Attribute)
|
||||||
{
|
{
|
||||||
Info.Outputs.Add(operand.Value);
|
Info.Outputs.Add(operand.Value & AttributeConsts.Mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetOperand(operand);
|
return GetOperand(operand);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using Ryujinx.Common;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Shader.Translation
|
namespace Ryujinx.Graphics.Shader.Translation
|
||||||
{
|
{
|
||||||
|
@ -98,5 +97,17 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
return new AttributeInfo(value, 0, 0, AggregateType.Invalid);
|
return new AttributeInfo(value, 0, 0, AggregateType.Invalid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsArrayBuiltIn(int attr)
|
||||||
|
{
|
||||||
|
if (attr <= AttributeConsts.TessLevelInner1 ||
|
||||||
|
attr == AttributeConsts.TessCoordX ||
|
||||||
|
attr == AttributeConsts.TessCoordY)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (attr & AttributeConsts.SpecialMask) == 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,8 +183,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
if (Config.GpuAccessor.QueryTransformDepthMinusOneToOne())
|
if (Config.GpuAccessor.QueryTransformDepthMinusOneToOne())
|
||||||
{
|
{
|
||||||
Operand z = Attribute(AttributeConsts.PositionZ);
|
Operand z = Attribute(AttributeConsts.PositionZ | AttributeConsts.LoadOutputMask);
|
||||||
Operand w = Attribute(AttributeConsts.PositionW);
|
Operand w = Attribute(AttributeConsts.PositionW | AttributeConsts.LoadOutputMask);
|
||||||
Operand halfW = this.FPMultiply(w, ConstF(0.5f));
|
Operand halfW = this.FPMultiply(w, ConstF(0.5f));
|
||||||
|
|
||||||
this.Copy(Attribute(AttributeConsts.PositionZ), this.FPFusedMultiplyAdd(z, ConstF(0.5f), halfW));
|
this.Copy(Attribute(AttributeConsts.PositionZ), this.FPFusedMultiplyAdd(z, ConstF(0.5f), halfW));
|
||||||
|
|
Loading…
Reference in a new issue