Add support for large sampler arrays on Vulkan (#6489)

* Add support for large sampler arrays on Vulkan

* Shader cache version bump

* Format whitespace

* Move DescriptorSetManager to PipelineLayoutCacheEntry to allow different pool sizes per layout

* Handle array textures with different types on the same buffer

* Somewhat better caching system

* Avoid useless buffer data modification checks

* Move redundant bindings update checking to the backend

* Fix an issue where texture arrays would get the same bindings across stages on Vulkan

* Backport some fixes from part 2

* Fix typo

* PR feedback

* Format whitespace

* Add some missing XML docs
This commit is contained in:
gdkchan
2024-04-07 18:25:55 -03:00
committed by GitHub
parent 808803d97a
commit 3e6e0e4afa
83 changed files with 3263 additions and 955 deletions

View File

@@ -339,24 +339,17 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
private static void DeclareSamplers(CodeGenContext context, IEnumerable<TextureDefinition> definitions)
{
int arraySize = 0;
foreach (var definition in definitions)
{
string indexExpr = string.Empty;
string arrayDecl = string.Empty;
if (definition.Type.HasFlag(SamplerType.Indexed))
if (definition.ArrayLength > 1)
{
if (arraySize == 0)
{
arraySize = ResourceManager.SamplerArraySize;
}
else if (--arraySize != 0)
{
continue;
}
indexExpr = $"[{NumberFormatter.FormatInt(arraySize)}]";
arrayDecl = $"[{NumberFormatter.FormatInt(definition.ArrayLength)}]";
}
else if (definition.ArrayLength == 0)
{
arrayDecl = "[]";
}
string samplerTypeName = definition.Type.ToGlslSamplerType();
@@ -368,30 +361,23 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
layout = $", set = {definition.Set}";
}
context.AppendLine($"layout (binding = {definition.Binding}{layout}) uniform {samplerTypeName} {definition.Name}{indexExpr};");
context.AppendLine($"layout (binding = {definition.Binding}{layout}) uniform {samplerTypeName} {definition.Name}{arrayDecl};");
}
}
private static void DeclareImages(CodeGenContext context, IEnumerable<TextureDefinition> definitions)
{
int arraySize = 0;
foreach (var definition in definitions)
{
string indexExpr = string.Empty;
string arrayDecl = string.Empty;
if (definition.Type.HasFlag(SamplerType.Indexed))
if (definition.ArrayLength > 1)
{
if (arraySize == 0)
{
arraySize = ResourceManager.SamplerArraySize;
}
else if (--arraySize != 0)
{
continue;
}
indexExpr = $"[{NumberFormatter.FormatInt(arraySize)}]";
arrayDecl = $"[{NumberFormatter.FormatInt(definition.ArrayLength)}]";
}
else if (definition.ArrayLength == 0)
{
arrayDecl = "[]";
}
string imageTypeName = definition.Type.ToGlslImageType(definition.Format.GetComponentType());
@@ -413,7 +399,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
layout = $", set = {definition.Set}{layout}";
}
context.AppendLine($"layout (binding = {definition.Binding}{layout}) uniform {imageTypeName} {definition.Name}{indexExpr};");
context.AppendLine($"layout (binding = {definition.Binding}{layout}) uniform {imageTypeName} {definition.Name}{arrayDecl};");
}
}

View File

@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
AggregateType type = GetSrcVarType(operation.Inst, 0);
string srcExpr = GetSoureExpr(context, src, type);
string srcExpr = GetSourceExpr(context, src, type);
string zero;
if (type == AggregateType.FP64)
@@ -80,7 +80,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
for (int argIndex = operation.SourcesCount - arity + 2; argIndex < operation.SourcesCount; argIndex++)
{
builder.Append($", {GetSoureExpr(context, operation.GetSource(argIndex), dstType)}");
builder.Append($", {GetSourceExpr(context, operation.GetSource(argIndex), dstType)}");
}
}
else
@@ -94,7 +94,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
AggregateType dstType = GetSrcVarType(inst, argIndex);
builder.Append(GetSoureExpr(context, operation.GetSource(argIndex), dstType));
builder.Append(GetSourceExpr(context, operation.GetSource(argIndex), dstType));
}
}
@@ -107,7 +107,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
// Return may optionally have a return value (and in this case it is unary).
if (inst == Instruction.Return && operation.SourcesCount != 0)
{
return $"{op} {GetSoureExpr(context, operation.GetSource(0), context.CurrentFunction.ReturnType)}";
return $"{op} {GetSourceExpr(context, operation.GetSource(0), context.CurrentFunction.ReturnType)}";
}
int arity = (int)(info.Type & InstType.ArityMask);
@@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
IAstNode src = operation.GetSource(index);
string srcExpr = GetSoureExpr(context, src, GetSrcVarType(inst, index));
string srcExpr = GetSourceExpr(context, src, GetSrcVarType(inst, index));
bool isLhs = arity == 2 && index == 0;

View File

@@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
AggregateType dstType = GetSrcVarType(operation.Inst, 0);
string arg = GetSoureExpr(context, operation.GetSource(0), dstType);
string arg = GetSourceExpr(context, operation.GetSource(0), dstType);
char component = "xyzw"[operation.Index];
if (context.HostCapabilities.SupportsShaderBallot)

View File

@@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
for (int i = 0; i < args.Length; i++)
{
args[i] = GetSoureExpr(context, operation.GetSource(i + 1), function.GetArgumentType(i));
args[i] = GetSourceExpr(context, operation.GetSource(i + 1), function.GetArgumentType(i));
}
return $"{function.Name}({string.Join(", ", args)})";

View File

@@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
return _infoTable[(int)(inst & Instruction.Mask)];
}
public static string GetSoureExpr(CodeGenContext context, IAstNode node, AggregateType dstType)
public static string GetSourceExpr(CodeGenContext context, IAstNode node, AggregateType dstType)
{
return ReinterpretCast(context, node, OperandManager.GetNodeDestType(context, node), dstType);
}

View File

@@ -14,35 +14,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
// TODO: Bindless texture support. For now we just return 0/do nothing.
if (isBindless)
{
switch (texOp.Inst)
{
case Instruction.ImageStore:
return "// imageStore(bindless)";
case Instruction.ImageLoad:
AggregateType componentType = texOp.Format.GetComponentType();
NumberFormatter.TryFormat(0, componentType, out string imageConst);
AggregateType outputType = texOp.GetVectorType(componentType);
if ((outputType & AggregateType.ElementCountMask) != 0)
{
return $"{Declarations.GetVarTypeName(context, outputType, precise: false)}({imageConst})";
}
return imageConst;
default:
return NumberFormatter.FormatInt(0);
}
}
bool isArray = (texOp.Type & SamplerType.Array) != 0;
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
var texCallBuilder = new StringBuilder();
@@ -70,21 +42,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
texCallBuilder.Append(texOp.Inst == Instruction.ImageLoad ? "imageLoad" : "imageStore");
}
int srcIndex = isBindless ? 1 : 0;
int srcIndex = 0;
string Src(AggregateType type)
{
return GetSoureExpr(context, texOp.GetSource(srcIndex++), type);
return GetSourceExpr(context, texOp.GetSource(srcIndex++), type);
}
string indexExpr = null;
if (isIndexed)
{
indexExpr = Src(AggregateType.S32);
}
string imageName = GetImageName(context.Properties, texOp, indexExpr);
string imageName = GetImageName(context, texOp, ref srcIndex);
texCallBuilder.Append('(');
texCallBuilder.Append(imageName);
@@ -198,27 +163,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
AstTextureOperation texOp = (AstTextureOperation)operation;
int coordsCount = texOp.Type.GetDimensions();
int coordsIndex = 0;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return NumberFormatter.FormatFloat(0);
}
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
string indexExpr = null;
if (isIndexed)
{
indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32);
}
string samplerName = GetSamplerName(context.Properties, texOp, indexExpr);
int coordsIndex = isBindless || isIndexed ? 1 : 0;
string samplerName = GetSamplerName(context, texOp, ref coordsIndex);
string coordsExpr;
@@ -228,14 +175,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
for (int index = 0; index < coordsCount; index++)
{
elems[index] = GetSoureExpr(context, texOp.GetSource(coordsIndex + index), AggregateType.FP32);
elems[index] = GetSourceExpr(context, texOp.GetSource(coordsIndex + index), AggregateType.FP32);
}
coordsExpr = "vec" + coordsCount + "(" + string.Join(", ", elems) + ")";
}
else
{
coordsExpr = GetSoureExpr(context, texOp.GetSource(coordsIndex), AggregateType.FP32);
coordsExpr = GetSourceExpr(context, texOp.GetSource(coordsIndex), AggregateType.FP32);
}
return $"textureQueryLod({samplerName}, {coordsExpr}){GetMask(texOp.Index)}";
@@ -250,7 +197,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
bool isGather = (texOp.Flags & TextureFlags.Gather) != 0;
bool hasDerivatives = (texOp.Flags & TextureFlags.Derivatives) != 0;
bool intCoords = (texOp.Flags & TextureFlags.IntCoords) != 0;
@@ -260,12 +206,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0;
bool isArray = (texOp.Type & SamplerType.Array) != 0;
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0;
bool isShadow = (texOp.Type & SamplerType.Shadow) != 0;
bool colorIsVector = isGather || !isShadow;
SamplerType type = texOp.Type & SamplerType.Mask;
bool is2D = type == SamplerType.Texture2D;
@@ -286,24 +229,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
hasLodLevel = false;
}
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
string scalarValue = NumberFormatter.FormatFloat(0);
if (colorIsVector)
{
AggregateType outputType = texOp.GetVectorType(AggregateType.FP32);
if ((outputType & AggregateType.ElementCountMask) != 0)
{
return $"{Declarations.GetVarTypeName(context, outputType, precise: false)}({scalarValue})";
}
}
return scalarValue;
}
string texCall = intCoords ? "texelFetch" : "texture";
if (isGather)
@@ -328,21 +253,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
texCall += "Offsets";
}
int srcIndex = isBindless ? 1 : 0;
int srcIndex = 0;
string Src(AggregateType type)
{
return GetSoureExpr(context, texOp.GetSource(srcIndex++), type);
return GetSourceExpr(context, texOp.GetSource(srcIndex++), type);
}
string indexExpr = null;
if (isIndexed)
{
indexExpr = Src(AggregateType.S32);
}
string samplerName = GetSamplerName(context.Properties, texOp, indexExpr);
string samplerName = GetSamplerName(context, texOp, ref srcIndex);
texCall += "(" + samplerName;
@@ -512,6 +430,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Append(Src(AggregateType.S32));
}
bool colorIsVector = isGather || !isShadow;
texCall += ")" + (colorIsVector ? GetMaskMultiDest(texOp.Index) : "");
return texCall;
@@ -521,24 +441,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
int srcIndex = 0;
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return NumberFormatter.FormatInt(0);
}
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
string indexExpr = null;
if (isIndexed)
{
indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32);
}
string samplerName = GetSamplerName(context.Properties, texOp, indexExpr);
string samplerName = GetSamplerName(context, texOp, ref srcIndex);
return $"textureSamples({samplerName})";
}
@@ -547,24 +452,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
int srcIndex = 0;
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return NumberFormatter.FormatInt(0);
}
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
string indexExpr = null;
if (isIndexed)
{
indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32);
}
string samplerName = GetSamplerName(context.Properties, texOp, indexExpr);
string samplerName = GetSamplerName(context, texOp, ref srcIndex);
if (texOp.Index == 3)
{
@@ -578,9 +468,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
if (hasLod)
{
int lodSrcIndex = isBindless || isIndexed ? 1 : 0;
IAstNode lod = operation.GetSource(lodSrcIndex);
string lodExpr = GetSoureExpr(context, lod, GetSrcVarType(operation.Inst, lodSrcIndex));
IAstNode lod = operation.GetSource(srcIndex);
string lodExpr = GetSourceExpr(context, lod, GetSrcVarType(operation.Inst, srcIndex));
texCall = $"textureSize({samplerName}, {lodExpr}){GetMask(texOp.Index)}";
}
@@ -697,12 +586,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
if (storageKind == StorageKind.Input)
{
string expr = GetSoureExpr(context, operation.GetSource(srcIndex++), AggregateType.S32);
string expr = GetSourceExpr(context, operation.GetSource(srcIndex++), AggregateType.S32);
varName = $"gl_in[{expr}].{varName}";
}
else if (storageKind == StorageKind.Output)
{
string expr = GetSoureExpr(context, operation.GetSource(srcIndex++), AggregateType.S32);
string expr = GetSourceExpr(context, operation.GetSource(srcIndex++), AggregateType.S32);
varName = $"gl_out[{expr}].{varName}";
}
}
@@ -735,38 +624,40 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
}
else
{
varName += $"[{GetSoureExpr(context, src, AggregateType.S32)}]";
varName += $"[{GetSourceExpr(context, src, AggregateType.S32)}]";
}
}
if (isStore)
{
varType &= AggregateType.ElementTypeMask;
varName = $"{varName} = {GetSoureExpr(context, operation.GetSource(srcIndex), varType)}";
varName = $"{varName} = {GetSourceExpr(context, operation.GetSource(srcIndex), varType)}";
}
return varName;
}
private static string GetSamplerName(ShaderProperties resourceDefinitions, AstTextureOperation texOp, string indexExpr)
private static string GetSamplerName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex)
{
string name = resourceDefinitions.Textures[texOp.Binding].Name;
TextureDefinition definition = context.Properties.Textures[texOp.Binding];
string name = definition.Name;
if (texOp.Type.HasFlag(SamplerType.Indexed))
if (definition.ArrayLength != 1)
{
name = $"{name}[{indexExpr}]";
name = $"{name}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]";
}
return name;
}
private static string GetImageName(ShaderProperties resourceDefinitions, AstTextureOperation texOp, string indexExpr)
private static string GetImageName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex)
{
string name = resourceDefinitions.Images[texOp.Binding].Name;
TextureDefinition definition = context.Properties.Images[texOp.Binding];
string name = definition.Name;
if (texOp.Type.HasFlag(SamplerType.Indexed))
if (definition.ArrayLength != 1)
{
name = $"{name}[{indexExpr}]";
name = $"{name}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]";
}
return name;

View File

@@ -13,8 +13,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
IAstNode src0 = operation.GetSource(0);
IAstNode src1 = operation.GetSource(1);
string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0));
string src1Expr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 1));
string src0Expr = GetSourceExpr(context, src0, GetSrcVarType(operation.Inst, 0));
string src1Expr = GetSourceExpr(context, src1, GetSrcVarType(operation.Inst, 1));
return $"packDouble2x32(uvec2({src0Expr}, {src1Expr}))";
}
@@ -24,8 +24,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
IAstNode src0 = operation.GetSource(0);
IAstNode src1 = operation.GetSource(1);
string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0));
string src1Expr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 1));
string src0Expr = GetSourceExpr(context, src0, GetSrcVarType(operation.Inst, 0));
string src1Expr = GetSourceExpr(context, src1, GetSrcVarType(operation.Inst, 1));
return $"packHalf2x16(vec2({src0Expr}, {src1Expr}))";
}
@@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
IAstNode src = operation.GetSource(0);
string srcExpr = GetSoureExpr(context, src, GetSrcVarType(operation.Inst, 0));
string srcExpr = GetSourceExpr(context, src, GetSrcVarType(operation.Inst, 0));
return $"unpackDouble2x32({srcExpr}){GetMask(operation.Index)}";
}
@@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
IAstNode src = operation.GetSource(0);
string srcExpr = GetSoureExpr(context, src, GetSrcVarType(operation.Inst, 0));
string srcExpr = GetSourceExpr(context, src, GetSrcVarType(operation.Inst, 0));
return $"unpackHalf2x16({srcExpr}){GetMask(operation.Index)}";
}

View File

@@ -9,8 +9,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
public static string Shuffle(CodeGenContext context, AstOperation operation)
{
string value = GetSoureExpr(context, operation.GetSource(0), AggregateType.FP32);
string index = GetSoureExpr(context, operation.GetSource(1), AggregateType.U32);
string value = GetSourceExpr(context, operation.GetSource(0), AggregateType.FP32);
string index = GetSourceExpr(context, operation.GetSource(1), AggregateType.U32);
if (context.HostCapabilities.SupportsShaderBallot)
{

View File

@@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
IAstNode vector = operation.GetSource(0);
IAstNode index = operation.GetSource(1);
string vectorExpr = GetSoureExpr(context, vector, OperandManager.GetNodeDestType(context, vector));
string vectorExpr = GetSourceExpr(context, vector, OperandManager.GetNodeDestType(context, vector));
if (index is AstOperand indexOperand && indexOperand.Type == OperandType.Constant)
{
@@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
}
else
{
string indexExpr = GetSoureExpr(context, index, GetSrcVarType(operation.Inst, 1));
string indexExpr = GetSourceExpr(context, index, GetSrcVarType(operation.Inst, 1));
return $"{vectorExpr}[{indexExpr}]";
}

View File

@@ -146,9 +146,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
}
else if (operation is AstTextureOperation texOp)
{
if (texOp.Inst == Instruction.ImageLoad ||
texOp.Inst == Instruction.ImageStore ||
texOp.Inst == Instruction.ImageAtomic)
if (texOp.Inst.IsImage())
{
return texOp.GetVectorType(texOp.Format.GetComponentType());
}