Add support for shader constant buffer slot indexing (#1608)

* Add support for shader constant buffer slot indexing

* Fix typo
This commit is contained in:
gdkchan 2020-10-12 21:40:50 -03:00 committed by GitHub
parent 14fd9aa640
commit b066cfc1a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 207 additions and 66 deletions

View file

@ -12,6 +12,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
public ShaderConfig Config { get; }
public bool CbIndexable { get; }
public List<BufferDescriptor> CBufferDescriptors { get; }
public List<BufferDescriptor> SBufferDescriptors { get; }
public List<TextureDescriptor> TextureDescriptors { get; }
@ -25,9 +27,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
private string _indentation;
public CodeGenContext(ShaderConfig config)
public CodeGenContext(ShaderConfig config, bool cbIndexable)
{
Config = config;
CbIndexable = cbIndexable;
CBufferDescriptors = new List<BufferDescriptor>();
SBufferDescriptors = new List<BufferDescriptor>();
@ -85,9 +88,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
int cBufSlot = bindless ? operand.CbufSlot : 0;
int cBufOffset = bindless ? operand.CbufOffset : 0;
return TextureDescriptors.FindIndex(descriptor =>
descriptor.Type == texOp.Type &&
descriptor.HandleIndex == texOp.Handle &&
return TextureDescriptors.FindIndex(descriptor =>
descriptor.Type == texOp.Type &&
descriptor.HandleIndex == texOp.Handle &&
descriptor.CbufSlot == cBufSlot &&
descriptor.CbufOffset == cBufOffset);
}

View file

@ -213,51 +213,57 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
private static void DeclareUniforms(CodeGenContext context, StructuredProgramInfo info)
{
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
string ubSize = "[" + NumberFormatter.FormatInt(Constants.ConstantBufferSize / 16) + "]";
if (info.UsesCbIndexing)
{
string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
ubName += "_" + DefaultNames.UniformNamePrefix + cbufSlot;
ubName += "_" + DefaultNames.UniformNamePrefix;
context.CBufferDescriptors.Add(new BufferDescriptor(ubName, cbufSlot));
string blockName = $"{ubName}_{DefaultNames.BlockSuffix}";
context.AppendLine("layout (std140) uniform " + ubName);
int maxSlot = 0;
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
{
context.CBufferDescriptors.Add(new BufferDescriptor($"{blockName}[{cbufSlot}]", cbufSlot));
if (maxSlot < cbufSlot)
{
maxSlot = cbufSlot;
}
}
context.AppendLine("layout (std140) uniform " + blockName);
context.EnterScope();
string ubSize = "[" + NumberFormatter.FormatInt(Constants.ConstantBufferSize / 16) + "]";
context.AppendLine("vec4 " + DefaultNames.DataName + ubSize + ";");
context.AppendLine("vec4 " + OperandManager.GetUbName(context.Config.Stage, cbufSlot) + ubSize + ";");
string arraySize = NumberFormatter.FormatInt(maxSlot + 1);
context.LeaveScope(";");
context.LeaveScope($" {ubName}[{arraySize}];");
}
}
private static bool DeclareRenderScale(CodeGenContext context)
{
if ((context.Config.UsedFeatures & (FeatureFlags.FragCoordXY | FeatureFlags.IntegerSampling)) != 0)
else
{
string stage = OperandManager.GetShaderStagePrefix(context.Config.Stage);
int scaleElements = context.TextureDescriptors.Count;
if (context.Config.Stage == ShaderStage.Fragment)
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
{
scaleElements++; // Also includes render target scale, for gl_FragCoord.
string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
ubName += "_" + DefaultNames.UniformNamePrefix + cbufSlot;
context.CBufferDescriptors.Add(new BufferDescriptor(ubName, cbufSlot));
context.AppendLine("layout (std140) uniform " + ubName);
context.EnterScope();
context.AppendLine("vec4 " + OperandManager.GetUbName(context.Config.Stage, cbufSlot, false) + ubSize + ";");
context.LeaveScope(";");
}
context.AppendLine($"uniform float {stage}_renderScale[{scaleElements}];");
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling))
{
context.AppendLine();
AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
}
return true;
}
return false;
}
private static void DeclareStorages(CodeGenContext context, StructuredProgramInfo info)
@ -500,6 +506,33 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
}
}
private static bool DeclareRenderScale(CodeGenContext context)
{
if ((context.Config.UsedFeatures & (FeatureFlags.FragCoordXY | FeatureFlags.IntegerSampling)) != 0)
{
string stage = OperandManager.GetShaderStagePrefix(context.Config.Stage);
int scaleElements = context.TextureDescriptors.Count;
if (context.Config.Stage == ShaderStage.Fragment)
{
scaleElements++; // Also includes render target scale, for gl_FragCoord.
}
context.AppendLine($"uniform float {stage}_renderScale[{scaleElements}];");
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling))
{
context.AppendLine();
AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
}
return true;
}
return false;
}
private static void AppendHelperFunction(CodeGenContext context, string filename)
{
string code = EmbeddedResources.ReadAllText(filename);

View file

@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
public static GlslProgram Generate(StructuredProgramInfo info, ShaderConfig config)
{
CodeGenContext context = new CodeGenContext(config);
CodeGenContext context = new CodeGenContext(config, info.UsesCbIndexing);
Declarations.Declare(context, info);

View file

@ -19,7 +19,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
}
else if (node is AstOperand operand)
{
return context.OperandManager.GetExpression(operand, context.Config);
return context.OperandManager.GetExpression(operand, context.Config, context.CbIndexable);
}
throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\".");

View file

@ -125,7 +125,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
offsetExpr = Enclose(offsetExpr, src2, Instruction.ShiftRightS32, isLhs: true);
return OperandManager.GetConstantBufferName(src1, offsetExpr, context.Config.Stage);
if (src1 is AstOperand oper && oper.Type == OperandType.Constant)
{
return OperandManager.GetConstantBufferName(oper.Value, offsetExpr, context.Config.Stage, context.CbIndexable);
}
else
{
string slotExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
return OperandManager.GetConstantBufferName(slotExpr, offsetExpr, context.Config.Stage);
}
}
public static string LoadLocal(CodeGenContext context, AstOperation operation)

View file

@ -92,7 +92,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return name;
}
public string GetExpression(AstOperand operand, ShaderConfig config)
public string GetExpression(AstOperand operand, ShaderConfig config, bool cbIndexable)
{
switch (operand.Type)
{
@ -103,7 +103,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return NumberFormatter.FormatInt(operand.Value);
case OperandType.ConstantBuffer:
return GetConstantBufferName(operand.CbufSlot, operand.CbufOffset, config.Stage);
return GetConstantBufferName(operand.CbufSlot, operand.CbufOffset, config.Stage, cbIndexable);
case OperandType.LocalVariable:
return _locals[operand];
@ -115,13 +115,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
throw new ArgumentException($"Invalid operand type \"{operand.Type}\".");
}
public static string GetConstantBufferName(int slot, int offset, ShaderStage stage)
public static string GetConstantBufferName(int slot, int offset, ShaderStage stage, bool cbIndexable)
{
string ubName = GetUbName(stage, slot);
ubName += "[" + (offset >> 2) + "]";
return ubName + "." + GetSwizzleMask(offset & 3);
return $"{GetUbName(stage, slot, cbIndexable)}[{offset >> 2}].{GetSwizzleMask(offset & 3)}";
}
private static string GetVec4Indexed(string vectorName, string indexExpr)
@ -134,18 +130,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return $"({result})";
}
public static string GetConstantBufferName(IAstNode slot, string offsetExpr, ShaderStage stage)
public static string GetConstantBufferName(int slot, string offsetExpr, ShaderStage stage, bool cbIndexable)
{
// Non-constant slots are not supported.
// It is expected that upstream stages are never going to generate non-constant
// slot access.
AstOperand operand = (AstOperand)slot;
return GetVec4Indexed(GetUbName(stage, slot, cbIndexable) + $"[{offsetExpr} >> 2]", offsetExpr + " & 3");
}
string ubName = GetUbName(stage, operand.Value);
string index0 = "[" + offsetExpr + " >> 2]";
return GetVec4Indexed(ubName + index0, offsetExpr + " & 3");
public static string GetConstantBufferName(string slotExpr, string offsetExpr, ShaderStage stage)
{
return GetVec4Indexed(GetUbName(stage, slotExpr) + $"[{offsetExpr} >> 2]", offsetExpr + " & 3");
}
public static string GetOutAttributeName(AstOperand attr, ShaderConfig config)
@ -228,13 +220,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return isOutAttr ? "// bad_attr0x" + value.ToString("X") : "0.0";
}
public static string GetUbName(ShaderStage stage, int slot)
public static string GetUbName(ShaderStage stage, int slot, bool cbIndexable)
{
string ubName = GetShaderStagePrefix(stage);
if (cbIndexable)
{
return GetUbName(stage, NumberFormatter.FormatInt(slot, VariableType.S32));
}
ubName += "_" + DefaultNames.UniformNamePrefix + slot;
return $"{GetShaderStagePrefix(stage)}_{DefaultNames.UniformNamePrefix}{slot}_{DefaultNames.UniformNameSuffix}";
}
return ubName + "_" + DefaultNames.UniformNameSuffix;
private static string GetUbName(ShaderStage stage, string slotExpr)
{
return $"{GetShaderStagePrefix(stage)}_{DefaultNames.UniformNamePrefix}[{slotExpr}].{DefaultNames.DataName}";
}
public static string GetSamplerName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)