Use unique temporary variables for function call parameters on SPIR-V (#5757)
* Use unique temporary variables for function call parameters on SPIR-V * Shader cache version bump
This commit is contained in:
parent
f61b7818c3
commit
a0af6e4d07
7 changed files with 33 additions and 49 deletions
|
@ -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 = 5750;
|
private const uint CodeGenVersion = 5757;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
|
|
@ -44,7 +44,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
public StructuredFunction CurrentFunction { get; set; }
|
public StructuredFunction CurrentFunction { get; set; }
|
||||||
private readonly Dictionary<AstOperand, Instruction> _locals = new();
|
private readonly Dictionary<AstOperand, Instruction> _locals = new();
|
||||||
private readonly Dictionary<int, Instruction[]> _localForArgs = new();
|
|
||||||
private readonly Dictionary<int, Instruction> _funcArgs = new();
|
private readonly Dictionary<int, Instruction> _funcArgs = new();
|
||||||
private readonly Dictionary<int, (StructuredFunction, Instruction)> _functions = new();
|
private readonly Dictionary<int, (StructuredFunction, Instruction)> _functions = new();
|
||||||
|
|
||||||
|
@ -112,7 +111,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
IsMainFunction = isMainFunction;
|
IsMainFunction = isMainFunction;
|
||||||
MayHaveReturned = false;
|
MayHaveReturned = false;
|
||||||
_locals.Clear();
|
_locals.Clear();
|
||||||
_localForArgs.Clear();
|
|
||||||
_funcArgs.Clear();
|
_funcArgs.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,11 +167,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
_locals.Add(local, spvLocal);
|
_locals.Add(local, spvLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeclareLocalForArgs(int funcIndex, Instruction[] spvLocals)
|
|
||||||
{
|
|
||||||
_localForArgs.Add(funcIndex, spvLocals);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DeclareArgument(int argIndex, Instruction spvLocal)
|
public void DeclareArgument(int argIndex, Instruction spvLocal)
|
||||||
{
|
{
|
||||||
_funcArgs.Add(argIndex, spvLocal);
|
_funcArgs.Add(argIndex, spvLocal);
|
||||||
|
@ -278,11 +271,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
return _locals[local];
|
return _locals[local];
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instruction[] GetLocalForArgsPointers(int funcIndex)
|
|
||||||
{
|
|
||||||
return _localForArgs[funcIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instruction GetArgumentPointer(AstOperand funcArg)
|
public Instruction GetArgumentPointer(AstOperand funcArg)
|
||||||
{
|
{
|
||||||
return _funcArgs[funcArg.Value];
|
return _funcArgs[funcArg.Value];
|
||||||
|
|
|
@ -41,28 +41,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DeclareLocalForArgs(CodeGenContext context, List<StructuredFunction> functions)
|
|
||||||
{
|
|
||||||
for (int funcIndex = 0; funcIndex < functions.Count; funcIndex++)
|
|
||||||
{
|
|
||||||
StructuredFunction function = functions[funcIndex];
|
|
||||||
SpvInstruction[] locals = new SpvInstruction[function.InArguments.Length];
|
|
||||||
|
|
||||||
for (int i = 0; i < function.InArguments.Length; i++)
|
|
||||||
{
|
|
||||||
var type = function.GetArgumentType(i);
|
|
||||||
var localPointerType = context.TypePointer(StorageClass.Function, context.GetType(type));
|
|
||||||
var spvLocal = context.Variable(localPointerType, StorageClass.Function);
|
|
||||||
|
|
||||||
context.AddLocalVariable(spvLocal);
|
|
||||||
|
|
||||||
locals[i] = spvLocal;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.DeclareLocalForArgs(funcIndex, locals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DeclareAll(CodeGenContext context, StructuredProgramInfo info)
|
public static void DeclareAll(CodeGenContext context, StructuredProgramInfo info)
|
||||||
{
|
{
|
||||||
DeclareConstantBuffers(context, context.Properties.ConstantBuffers.Values);
|
DeclareConstantBuffers(context, context.Properties.ConstantBuffers.Values);
|
||||||
|
|
|
@ -311,7 +311,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
var (function, spvFunc) = context.GetFunction(funcId.Value);
|
var (function, spvFunc) = context.GetFunction(funcId.Value);
|
||||||
|
|
||||||
var args = new SpvInstruction[operation.SourcesCount - 1];
|
var args = new SpvInstruction[operation.SourcesCount - 1];
|
||||||
var spvLocals = context.GetLocalForArgsPointers(funcId.Value);
|
|
||||||
|
|
||||||
for (int i = 0; i < args.Length; i++)
|
for (int i = 0; i < args.Length; i++)
|
||||||
{
|
{
|
||||||
|
@ -324,12 +323,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var type = function.GetArgumentType(i);
|
var type = function.GetArgumentType(i);
|
||||||
var value = context.Get(type, operand);
|
|
||||||
var spvLocal = spvLocals[i];
|
|
||||||
|
|
||||||
context.Store(spvLocal, value);
|
args[i] = context.Get(type, operand);
|
||||||
|
|
||||||
args[i] = spvLocal;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
context.EnterBlock(function.MainBlock);
|
context.EnterBlock(function.MainBlock);
|
||||||
|
|
||||||
Declarations.DeclareLocals(context, function);
|
Declarations.DeclareLocals(context, function);
|
||||||
Declarations.DeclareLocalForArgs(context, info.Functions);
|
|
||||||
|
|
||||||
Generate(context, function.MainBlock);
|
Generate(context, function.MainBlock);
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
{
|
{
|
||||||
static class StructuredProgram
|
static class StructuredProgram
|
||||||
{
|
{
|
||||||
|
// TODO: Eventually it should be possible to specify the parameter types for the function instead of using S32 for everything.
|
||||||
|
private const AggregateType FuncParameterType = AggregateType.S32;
|
||||||
|
|
||||||
public static StructuredProgramInfo MakeStructuredProgram(
|
public static StructuredProgramInfo MakeStructuredProgram(
|
||||||
IReadOnlyList<Function> functions,
|
IReadOnlyList<Function> functions,
|
||||||
AttributeUsage attributeUsage,
|
AttributeUsage attributeUsage,
|
||||||
ShaderDefinitions definitions,
|
ShaderDefinitions definitions,
|
||||||
ResourceManager resourceManager,
|
ResourceManager resourceManager,
|
||||||
|
TargetLanguage targetLanguage,
|
||||||
bool debugMode)
|
bool debugMode)
|
||||||
{
|
{
|
||||||
StructuredProgramContext context = new(attributeUsage, definitions, resourceManager, debugMode);
|
StructuredProgramContext context = new(attributeUsage, definitions, resourceManager, debugMode);
|
||||||
|
@ -23,19 +27,19 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
|
|
||||||
BasicBlock[] blocks = function.Blocks;
|
BasicBlock[] blocks = function.Blocks;
|
||||||
|
|
||||||
AggregateType returnType = function.ReturnsValue ? AggregateType.S32 : AggregateType.Void;
|
AggregateType returnType = function.ReturnsValue ? FuncParameterType : AggregateType.Void;
|
||||||
|
|
||||||
AggregateType[] inArguments = new AggregateType[function.InArgumentsCount];
|
AggregateType[] inArguments = new AggregateType[function.InArgumentsCount];
|
||||||
AggregateType[] outArguments = new AggregateType[function.OutArgumentsCount];
|
AggregateType[] outArguments = new AggregateType[function.OutArgumentsCount];
|
||||||
|
|
||||||
for (int i = 0; i < inArguments.Length; i++)
|
for (int i = 0; i < inArguments.Length; i++)
|
||||||
{
|
{
|
||||||
inArguments[i] = AggregateType.S32;
|
inArguments[i] = FuncParameterType;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < outArguments.Length; i++)
|
for (int i = 0; i < outArguments.Length; i++)
|
||||||
{
|
{
|
||||||
outArguments[i] = AggregateType.S32;
|
outArguments[i] = FuncParameterType;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.EnterFunction(blocks.Length, function.Name, returnType, inArguments, outArguments);
|
context.EnterFunction(blocks.Length, function.Name, returnType, inArguments, outArguments);
|
||||||
|
@ -58,7 +62,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddOperation(context, operation);
|
AddOperation(context, operation, targetLanguage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +77,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
return context.Info;
|
return context.Info;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddOperation(StructuredProgramContext context, Operation operation)
|
private static void AddOperation(StructuredProgramContext context, Operation operation, TargetLanguage targetLanguage)
|
||||||
{
|
{
|
||||||
Instruction inst = operation.Inst;
|
Instruction inst = operation.Inst;
|
||||||
StorageKind storageKind = operation.StorageKind;
|
StorageKind storageKind = operation.StorageKind;
|
||||||
|
@ -114,10 +118,29 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
|
|
||||||
IAstNode[] sources = new IAstNode[sourcesCount + outDestsCount];
|
IAstNode[] sources = new IAstNode[sourcesCount + outDestsCount];
|
||||||
|
|
||||||
|
if (inst == Instruction.Call && targetLanguage == TargetLanguage.Spirv)
|
||||||
|
{
|
||||||
|
// SPIR-V requires that all function parameters are copied to a local variable before the call
|
||||||
|
// (or at least that's what the Khronos compiler does).
|
||||||
|
|
||||||
|
// First one is the function index.
|
||||||
|
sources[0] = context.GetOperandOrCbLoad(operation.GetSource(0));
|
||||||
|
|
||||||
|
// Remaining ones are parameters, copy them to a temp local variable.
|
||||||
|
for (int index = 1; index < operation.SourcesCount; index++)
|
||||||
|
{
|
||||||
|
AstOperand argTemp = context.NewTemp(FuncParameterType);
|
||||||
|
context.AddNode(new AstAssignment(argTemp, context.GetOperandOrCbLoad(operation.GetSource(index))));
|
||||||
|
sources[index] = argTemp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
for (int index = 0; index < operation.SourcesCount; index++)
|
for (int index = 0; index < operation.SourcesCount; index++)
|
||||||
{
|
{
|
||||||
sources[index] = context.GetOperandOrCbLoad(operation.GetSource(index));
|
sources[index] = context.GetOperandOrCbLoad(operation.GetSource(index));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int index = 0; index < outDestsCount; index++)
|
for (int index = 0; index < outDestsCount; index++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -329,6 +329,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
attributeUsage,
|
attributeUsage,
|
||||||
definitions,
|
definitions,
|
||||||
resourceManager,
|
resourceManager,
|
||||||
|
Options.TargetLanguage,
|
||||||
Options.Flags.HasFlag(TranslationFlags.DebugMode));
|
Options.Flags.HasFlag(TranslationFlags.DebugMode));
|
||||||
|
|
||||||
int geometryVerticesPerPrimitive = Definitions.OutputTopology switch
|
int geometryVerticesPerPrimitive = Definitions.OutputTopology switch
|
||||||
|
|
Reference in a new issue