Declare and use gl_PerVertex block for VTG per-vertex built-ins (#5576)
* Declare and use gl_PerVertex block for VTG per-vertex built-ins * Shader cache version bump
This commit is contained in:
parent
0c445184c1
commit
17354d59d1
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 5529;
|
private const uint CodeGenVersion = 5576;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@ -348,12 +348,98 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (IoMap.IsPerVertexBuiltIn(ioDefinition.IoVariable))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
bool isOutput = ioDefinition.StorageKind.IsOutput();
|
bool isOutput = ioDefinition.StorageKind.IsOutput();
|
||||||
bool isPerPatch = ioDefinition.StorageKind.IsPerPatch();
|
bool isPerPatch = ioDefinition.StorageKind.IsPerPatch();
|
||||||
|
|
||||||
DeclareInputOrOutput(context, ioDefinition, isOutput, isPerPatch, iq, firstLocation);
|
DeclareInputOrOutput(context, ioDefinition, isOutput, isPerPatch, iq, firstLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeclarePerVertexBlock(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DeclarePerVertexBlock(CodeGenContext context)
|
||||||
|
{
|
||||||
|
if (context.Definitions.Stage.IsVtg())
|
||||||
|
{
|
||||||
|
if (context.Definitions.Stage != ShaderStage.Vertex)
|
||||||
|
{
|
||||||
|
var perVertexInputStructType = CreatePerVertexStructType(context);
|
||||||
|
int arraySize = context.Definitions.Stage == ShaderStage.Geometry ? context.InputVertices : 32;
|
||||||
|
var perVertexInputArrayType = context.TypeArray(perVertexInputStructType, context.Constant(context.TypeU32(), arraySize));
|
||||||
|
var perVertexInputPointerType = context.TypePointer(StorageClass.Input, perVertexInputArrayType);
|
||||||
|
var perVertexInputVariable = context.Variable(perVertexInputPointerType, StorageClass.Input);
|
||||||
|
|
||||||
|
context.Name(perVertexInputVariable, "gl_in");
|
||||||
|
|
||||||
|
context.AddGlobalVariable(perVertexInputVariable);
|
||||||
|
context.Inputs.Add(new IoDefinition(StorageKind.Input, IoVariable.Position), perVertexInputVariable);
|
||||||
|
}
|
||||||
|
|
||||||
|
var perVertexOutputStructType = CreatePerVertexStructType(context);
|
||||||
|
|
||||||
|
void DecorateTfo(IoVariable ioVariable, int fieldIndex)
|
||||||
|
{
|
||||||
|
if (context.Definitions.TryGetTransformFeedbackOutput(ioVariable, 0, 0, out var transformFeedbackOutput))
|
||||||
|
{
|
||||||
|
context.MemberDecorate(perVertexOutputStructType, fieldIndex, Decoration.XfbBuffer, (LiteralInteger)transformFeedbackOutput.Buffer);
|
||||||
|
context.MemberDecorate(perVertexOutputStructType, fieldIndex, Decoration.XfbStride, (LiteralInteger)transformFeedbackOutput.Stride);
|
||||||
|
context.MemberDecorate(perVertexOutputStructType, fieldIndex, Decoration.Offset, (LiteralInteger)transformFeedbackOutput.Offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DecorateTfo(IoVariable.Position, 0);
|
||||||
|
DecorateTfo(IoVariable.PointSize, 1);
|
||||||
|
DecorateTfo(IoVariable.ClipDistance, 2);
|
||||||
|
|
||||||
|
SpvInstruction perVertexOutputArrayType;
|
||||||
|
|
||||||
|
if (context.Definitions.Stage == ShaderStage.TessellationControl)
|
||||||
|
{
|
||||||
|
int arraySize = context.Definitions.ThreadsPerInputPrimitive;
|
||||||
|
perVertexOutputArrayType = context.TypeArray(perVertexOutputStructType, context.Constant(context.TypeU32(), arraySize));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
perVertexOutputArrayType = perVertexOutputStructType;
|
||||||
|
}
|
||||||
|
|
||||||
|
var perVertexOutputPointerType = context.TypePointer(StorageClass.Output, perVertexOutputArrayType);
|
||||||
|
var perVertexOutputVariable = context.Variable(perVertexOutputPointerType, StorageClass.Output);
|
||||||
|
|
||||||
|
context.AddGlobalVariable(perVertexOutputVariable);
|
||||||
|
context.Outputs.Add(new IoDefinition(StorageKind.Output, IoVariable.Position), perVertexOutputVariable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SpvInstruction CreatePerVertexStructType(CodeGenContext context)
|
||||||
|
{
|
||||||
|
var vec4FloatType = context.TypeVector(context.TypeFP32(), 4);
|
||||||
|
var floatType = context.TypeFP32();
|
||||||
|
var array8FloatType = context.TypeArray(context.TypeFP32(), context.Constant(context.TypeU32(), 8));
|
||||||
|
var array1FloatType = context.TypeArray(context.TypeFP32(), context.Constant(context.TypeU32(), 1));
|
||||||
|
|
||||||
|
var perVertexStructType = context.TypeStruct(true, vec4FloatType, floatType, array8FloatType, array1FloatType);
|
||||||
|
|
||||||
|
context.Name(perVertexStructType, "gl_PerVertex");
|
||||||
|
|
||||||
|
context.MemberName(perVertexStructType, 0, "gl_Position");
|
||||||
|
context.MemberName(perVertexStructType, 1, "gl_PointSize");
|
||||||
|
context.MemberName(perVertexStructType, 2, "gl_ClipDistance");
|
||||||
|
context.MemberName(perVertexStructType, 3, "gl_CullDistance");
|
||||||
|
|
||||||
|
context.Decorate(perVertexStructType, Decoration.Block);
|
||||||
|
|
||||||
|
context.MemberDecorate(perVertexStructType, 0, Decoration.BuiltIn, (LiteralInteger)BuiltIn.Position);
|
||||||
|
context.MemberDecorate(perVertexStructType, 1, Decoration.BuiltIn, (LiteralInteger)BuiltIn.PointSize);
|
||||||
|
context.MemberDecorate(perVertexStructType, 2, Decoration.BuiltIn, (LiteralInteger)BuiltIn.ClipDistance);
|
||||||
|
context.MemberDecorate(perVertexStructType, 3, Decoration.BuiltIn, (LiteralInteger)BuiltIn.CullDistance);
|
||||||
|
|
||||||
|
return perVertexStructType;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeclareInputOrOutput(
|
private static void DeclareInputOrOutput(
|
||||||
|
@ -1788,6 +1788,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
StorageClass storageClass;
|
StorageClass storageClass;
|
||||||
SpvInstruction baseObj;
|
SpvInstruction baseObj;
|
||||||
int srcIndex = 0;
|
int srcIndex = 0;
|
||||||
|
IoVariable? perVertexBuiltIn = null;
|
||||||
|
|
||||||
switch (storageKind)
|
switch (storageKind)
|
||||||
{
|
{
|
||||||
@ -1881,6 +1882,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
(_, varType) = IoMap.GetSpirvBuiltIn(ioVariable);
|
(_, varType) = IoMap.GetSpirvBuiltIn(ioVariable);
|
||||||
|
|
||||||
|
if (IoMap.IsPerVertexBuiltIn(ioVariable))
|
||||||
|
{
|
||||||
|
perVertexBuiltIn = ioVariable;
|
||||||
|
ioVariable = IoVariable.Position;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
varType &= AggregateType.ElementTypeMask;
|
varType &= AggregateType.ElementTypeMask;
|
||||||
@ -1902,6 +1909,31 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
bool isStoreOrAtomic = operation.Inst == Instruction.Store || operation.Inst.IsAtomic();
|
bool isStoreOrAtomic = operation.Inst == Instruction.Store || operation.Inst.IsAtomic();
|
||||||
int inputsCount = (isStoreOrAtomic ? operation.SourcesCount - 1 : operation.SourcesCount) - srcIndex;
|
int inputsCount = (isStoreOrAtomic ? operation.SourcesCount - 1 : operation.SourcesCount) - srcIndex;
|
||||||
|
|
||||||
|
if (perVertexBuiltIn.HasValue)
|
||||||
|
{
|
||||||
|
int fieldIndex = IoMap.GetPerVertexStructFieldIndex(perVertexBuiltIn.Value);
|
||||||
|
|
||||||
|
var indexes = new SpvInstruction[inputsCount + 1];
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
if (IoMap.IsPerVertexArrayBuiltIn(storageKind, context.Definitions.Stage))
|
||||||
|
{
|
||||||
|
indexes[index++] = context.Get(AggregateType.S32, operation.GetSource(srcIndex++));
|
||||||
|
indexes[index++] = context.Constant(context.TypeS32(), fieldIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
indexes[index++] = context.Constant(context.TypeS32(), fieldIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; index < inputsCount + 1; srcIndex++, index++)
|
||||||
|
{
|
||||||
|
indexes[index] = context.Get(AggregateType.S32, operation.GetSource(srcIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.AccessChain(context.TypePointer(storageClass, context.GetType(varType)), baseObj, indexes);
|
||||||
|
}
|
||||||
|
|
||||||
if (operation.Inst == Instruction.AtomicCompareAndSwap)
|
if (operation.Inst == Instruction.AtomicCompareAndSwap)
|
||||||
{
|
{
|
||||||
inputsCount--;
|
inputsCount--;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
using Ryujinx.Graphics.Shader.Translation;
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
|
using System;
|
||||||
using static Spv.Specification;
|
using static Spv.Specification;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
@ -80,5 +81,43 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsPerVertexBuiltIn(IoVariable ioVariable)
|
||||||
|
{
|
||||||
|
switch (ioVariable)
|
||||||
|
{
|
||||||
|
case IoVariable.Position:
|
||||||
|
case IoVariable.PointSize:
|
||||||
|
case IoVariable.ClipDistance:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsPerVertexArrayBuiltIn(StorageKind storageKind, ShaderStage stage)
|
||||||
|
{
|
||||||
|
if (storageKind == StorageKind.Output)
|
||||||
|
{
|
||||||
|
return stage == ShaderStage.TessellationControl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return stage == ShaderStage.TessellationControl ||
|
||||||
|
stage == ShaderStage.TessellationEvaluation ||
|
||||||
|
stage == ShaderStage.Geometry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetPerVertexStructFieldIndex(IoVariable ioVariable)
|
||||||
|
{
|
||||||
|
return ioVariable switch
|
||||||
|
{
|
||||||
|
IoVariable.Position => 0,
|
||||||
|
IoVariable.PointSize => 1,
|
||||||
|
IoVariable.ClipDistance => 2,
|
||||||
|
_ => throw new ArgumentException($"Invalid built-in variable {ioVariable}.")
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,5 +23,18 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
{
|
{
|
||||||
return stage == ShaderStage.Vertex || stage == ShaderStage.Fragment || stage == ShaderStage.Compute;
|
return stage == ShaderStage.Vertex || stage == ShaderStage.Fragment || stage == ShaderStage.Compute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the shader stage is vertex, tessellation or geometry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stage">Shader stage</param>
|
||||||
|
/// <returns>True if the shader stage is vertex, tessellation or geometry, false otherwise</returns>
|
||||||
|
public static bool IsVtg(this ShaderStage stage)
|
||||||
|
{
|
||||||
|
return stage == ShaderStage.Vertex ||
|
||||||
|
stage == ShaderStage.TessellationControl ||
|
||||||
|
stage == ShaderStage.TessellationEvaluation ||
|
||||||
|
stage == ShaderStage.Geometry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ namespace Spv.Generator
|
|||||||
|
|
||||||
// In the declaration block.
|
// In the declaration block.
|
||||||
private readonly Dictionary<TypeDeclarationKey, Instruction> _typeDeclarations;
|
private readonly Dictionary<TypeDeclarationKey, Instruction> _typeDeclarations;
|
||||||
|
private readonly List<Instruction> _typeDeclarationsList;
|
||||||
// In the declaration block.
|
// In the declaration block.
|
||||||
private readonly List<Instruction> _globals;
|
private readonly List<Instruction> _globals;
|
||||||
// In the declaration block.
|
// In the declaration block.
|
||||||
@ -54,6 +55,7 @@ namespace Spv.Generator
|
|||||||
_debug = new List<Instruction>();
|
_debug = new List<Instruction>();
|
||||||
_annotations = new List<Instruction>();
|
_annotations = new List<Instruction>();
|
||||||
_typeDeclarations = new Dictionary<TypeDeclarationKey, Instruction>();
|
_typeDeclarations = new Dictionary<TypeDeclarationKey, Instruction>();
|
||||||
|
_typeDeclarationsList = new List<Instruction>();
|
||||||
_constants = new Dictionary<ConstantKey, Instruction>();
|
_constants = new Dictionary<ConstantKey, Instruction>();
|
||||||
_globals = new List<Instruction>();
|
_globals = new List<Instruction>();
|
||||||
_functionsDeclarations = new List<Instruction>();
|
_functionsDeclarations = new List<Instruction>();
|
||||||
@ -126,7 +128,8 @@ namespace Spv.Generator
|
|||||||
|
|
||||||
instruction.SetId(GetNewId());
|
instruction.SetId(GetNewId());
|
||||||
|
|
||||||
_typeDeclarations.Add(key, instruction);
|
_typeDeclarations[key] = instruction;
|
||||||
|
_typeDeclarationsList.Add(instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddEntryPoint(ExecutionModel executionModel, Instruction function, string name, params Instruction[] interfaces)
|
public void AddEntryPoint(ExecutionModel executionModel, Instruction function, string name, params Instruction[] interfaces)
|
||||||
@ -330,7 +333,7 @@ namespace Spv.Generator
|
|||||||
|
|
||||||
// Ensure that everything is in the right order in the declarations section.
|
// Ensure that everything is in the right order in the declarations section.
|
||||||
List<Instruction> declarations = new();
|
List<Instruction> declarations = new();
|
||||||
declarations.AddRange(_typeDeclarations.Values);
|
declarations.AddRange(_typeDeclarationsList);
|
||||||
declarations.AddRange(_globals);
|
declarations.AddRange(_globals);
|
||||||
declarations.AddRange(_constants.Values);
|
declarations.AddRange(_constants.Values);
|
||||||
declarations.Sort((Instruction x, Instruction y) => x.Id.CompareTo(y.Id));
|
declarations.Sort((Instruction x, Instruction y) => x.Id.CompareTo(y.Id));
|
||||||
|
Loading…
Reference in New Issue
Block a user