aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Shader
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Shader')
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs3
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs19
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs54
-rw-r--r--src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs86
-rw-r--r--src/Ryujinx.Graphics.Shader/IGpuAccessor.cs35
-rw-r--r--src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs5
-rw-r--r--src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs9
-rw-r--r--src/Ryujinx.Graphics.Shader/SamplerType.cs26
-rw-r--r--src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs5
-rw-r--r--src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs2
-rw-r--r--src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs18
-rw-r--r--src/Ryujinx.Graphics.Shader/TextureDescriptor.cs4
-rw-r--r--src/Ryujinx.Graphics.Shader/TextureHandle.cs1
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs86
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs2
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs32
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs6
17 files changed, 306 insertions, 87 deletions
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index 763487da..eb6c689b 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -6,7 +6,6 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
-using System.Numerics;
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
@@ -352,7 +351,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
arrayDecl = "[]";
}
- string samplerTypeName = definition.Type.ToGlslSamplerType();
+ string samplerTypeName = definition.Separate ? definition.Type.ToGlslTextureType() : definition.Type.ToGlslSamplerType();
string layout = string.Empty;
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
index b4773b81..f0e57b53 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
@@ -639,14 +639,27 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
private static string GetSamplerName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex)
{
- TextureDefinition definition = context.Properties.Textures[texOp.Binding];
- string name = definition.Name;
+ TextureDefinition textureDefinition = context.Properties.Textures[texOp.Binding];
+ string name = textureDefinition.Name;
- if (definition.ArrayLength != 1)
+ if (textureDefinition.ArrayLength != 1)
{
name = $"{name}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]";
}
+ if (texOp.IsSeparate)
+ {
+ TextureDefinition samplerDefinition = context.Properties.Textures[texOp.SamplerBinding];
+ string samplerName = samplerDefinition.Name;
+
+ if (samplerDefinition.ArrayLength != 1)
+ {
+ samplerName = $"{samplerName}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]";
+ }
+
+ name = $"{texOp.Type.ToGlslSamplerType()}({name}, {samplerName})";
+ }
+
return name;
}
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
index 9633c522..37df4df8 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
@@ -160,37 +160,49 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
{
int setIndex = context.TargetApi == TargetApi.Vulkan ? sampler.Set : 0;
- var dim = (sampler.Type & SamplerType.Mask) switch
+ SpvInstruction imageType;
+ SpvInstruction sampledImageType;
+
+ if (sampler.Type != SamplerType.None)
{
- SamplerType.Texture1D => Dim.Dim1D,
- SamplerType.Texture2D => Dim.Dim2D,
- SamplerType.Texture3D => Dim.Dim3D,
- SamplerType.TextureCube => Dim.Cube,
- SamplerType.TextureBuffer => Dim.Buffer,
- _ => throw new InvalidOperationException($"Invalid sampler type \"{sampler.Type & SamplerType.Mask}\"."),
- };
+ var dim = (sampler.Type & SamplerType.Mask) switch
+ {
+ SamplerType.Texture1D => Dim.Dim1D,
+ SamplerType.Texture2D => Dim.Dim2D,
+ SamplerType.Texture3D => Dim.Dim3D,
+ SamplerType.TextureCube => Dim.Cube,
+ SamplerType.TextureBuffer => Dim.Buffer,
+ _ => throw new InvalidOperationException($"Invalid sampler type \"{sampler.Type & SamplerType.Mask}\"."),
+ };
+
+ imageType = context.TypeImage(
+ context.TypeFP32(),
+ dim,
+ sampler.Type.HasFlag(SamplerType.Shadow),
+ sampler.Type.HasFlag(SamplerType.Array),
+ sampler.Type.HasFlag(SamplerType.Multisample),
+ 1,
+ ImageFormat.Unknown);
+
+ sampledImageType = context.TypeSampledImage(imageType);
+ }
+ else
+ {
+ imageType = sampledImageType = context.TypeSampler();
+ }
- var imageType = context.TypeImage(
- context.TypeFP32(),
- dim,
- sampler.Type.HasFlag(SamplerType.Shadow),
- sampler.Type.HasFlag(SamplerType.Array),
- sampler.Type.HasFlag(SamplerType.Multisample),
- 1,
- ImageFormat.Unknown);
-
- var sampledImageType = context.TypeSampledImage(imageType);
- var sampledImagePointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageType);
+ var sampledOrSeparateImageType = sampler.Separate ? imageType : sampledImageType;
+ var sampledImagePointerType = context.TypePointer(StorageClass.UniformConstant, sampledOrSeparateImageType);
var sampledImageArrayPointerType = sampledImagePointerType;
if (sampler.ArrayLength == 0)
{
- var sampledImageArrayType = context.TypeRuntimeArray(sampledImageType);
+ var sampledImageArrayType = context.TypeRuntimeArray(sampledOrSeparateImageType);
sampledImageArrayPointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageArrayType);
}
else if (sampler.ArrayLength != 1)
{
- var sampledImageArrayType = context.TypeArray(sampledImageType, context.Constant(context.TypeU32(), sampler.ArrayLength));
+ var sampledImageArrayType = context.TypeArray(sampledOrSeparateImageType, context.Constant(context.TypeU32(), sampler.ArrayLength));
sampledImageArrayPointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageArrayType);
}
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
index 409e466c..34f8532a 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
@@ -838,16 +838,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
}
SamplerDeclaration declaration = context.Samplers[texOp.Binding];
- SpvInstruction image = declaration.Image;
-
- if (declaration.IsIndexed)
- {
- SpvInstruction textureIndex = Src(AggregateType.S32);
-
- image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex);
- }
-
- image = context.Load(declaration.SampledImageType, image);
+ SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
int pCount = texOp.Type.GetDimensions();
@@ -1171,16 +1162,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
}
SamplerDeclaration declaration = context.Samplers[texOp.Binding];
- SpvInstruction image = declaration.Image;
-
- if (declaration.IsIndexed)
- {
- SpvInstruction textureIndex = Src(AggregateType.S32);
-
- image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex);
- }
-
- image = context.Load(declaration.SampledImageType, image);
+ SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
int coordsCount = texOp.Type.GetDimensions();
@@ -1449,17 +1431,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
{
AstTextureOperation texOp = (AstTextureOperation)operation;
- SamplerDeclaration declaration = context.Samplers[texOp.Binding];
- SpvInstruction image = declaration.Image;
-
- if (declaration.IsIndexed)
- {
- SpvInstruction textureIndex = context.GetS32(texOp.GetSource(0));
+ int srcIndex = 0;
- image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex);
- }
+ SamplerDeclaration declaration = context.Samplers[texOp.Binding];
+ SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
- image = context.Load(declaration.SampledImageType, image);
image = context.Image(declaration.ImageType, image);
SpvInstruction result = context.ImageQuerySamples(context.TypeS32(), image);
@@ -1471,17 +1447,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
{
AstTextureOperation texOp = (AstTextureOperation)operation;
- SamplerDeclaration declaration = context.Samplers[texOp.Binding];
- SpvInstruction image = declaration.Image;
-
- if (declaration.IsIndexed)
- {
- SpvInstruction textureIndex = context.GetS32(texOp.GetSource(0));
+ int srcIndex = 0;
- image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex);
- }
+ SamplerDeclaration declaration = context.Samplers[texOp.Binding];
+ SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
- image = context.Load(declaration.SampledImageType, image);
image = context.Image(declaration.ImageType, image);
if (texOp.Index == 3)
@@ -1506,8 +1476,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
if (hasLod)
{
- int lodSrcIndex = declaration.IsIndexed ? 1 : 0;
- var lod = context.GetS32(operation.GetSource(lodSrcIndex));
+ var lod = context.GetS32(operation.GetSource(srcIndex));
result = context.ImageQuerySizeLod(resultType, image, lod);
}
else
@@ -1905,6 +1874,43 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
}
}
+ private static SpvInstruction GenerateSampledImageLoad(CodeGenContext context, AstTextureOperation texOp, SamplerDeclaration declaration, ref int srcIndex)
+ {
+ SpvInstruction image = declaration.Image;
+
+ if (declaration.IsIndexed)
+ {
+ SpvInstruction textureIndex = context.Get(AggregateType.S32, texOp.GetSource(srcIndex++));
+
+ image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex);
+ }
+
+ if (texOp.IsSeparate)
+ {
+ image = context.Load(declaration.ImageType, image);
+
+ SamplerDeclaration samplerDeclaration = context.Samplers[texOp.SamplerBinding];
+
+ SpvInstruction sampler = samplerDeclaration.Image;
+
+ if (samplerDeclaration.IsIndexed)
+ {
+ SpvInstruction samplerIndex = context.Get(AggregateType.S32, texOp.GetSource(srcIndex++));
+
+ sampler = context.AccessChain(samplerDeclaration.SampledImagePointerType, sampler, samplerIndex);
+ }
+
+ sampler = context.Load(samplerDeclaration.ImageType, sampler);
+ image = context.SampledImage(declaration.SampledImageType, image, sampler);
+ }
+ else
+ {
+ image = context.Load(declaration.SampledImageType, image);
+ }
+
+ return image;
+ }
+
private static OperationResult GenerateUnary(
CodeGenContext context,
AstOperation operation,
diff --git a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs
index 99366ad6..b1a9f9f8 100644
--- a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs
+++ b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs
@@ -27,13 +27,6 @@ namespace Ryujinx.Graphics.Shader
ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize);
/// <summary>
- /// Gets the size in bytes of a bound constant buffer for the current shader stage.
- /// </summary>
- /// <param name="slot">The number of the constant buffer to get the size from</param>
- /// <returns>Size in bytes</returns>
- int QueryTextureArrayLengthFromBuffer(int slot);
-
- /// <summary>
/// Queries the binding number of a constant buffer.
/// </summary>
/// <param name="index">Constant buffer index</param>
@@ -299,6 +292,15 @@ namespace Ryujinx.Graphics.Shader
}
/// <summary>
+ /// Queries host API support for separate textures and samplers.
+ /// </summary>
+ /// <returns>True if the API supports samplers and textures to be combined on the shader, false otherwise</returns>
+ bool QueryHostSupportsSeparateSampler()
+ {
+ return true;
+ }
+
+ /// <summary>
/// Queries host GPU shader ballot support.
/// </summary>
/// <returns>True if the GPU and driver supports shader ballot, false otherwise</returns>
@@ -389,6 +391,12 @@ namespace Ryujinx.Graphics.Shader
}
/// <summary>
+ /// Gets the maximum number of samplers that the bound texture pool may have.
+ /// </summary>
+ /// <returns>Maximum amount of samplers that the pool may have</returns>
+ int QuerySamplerArrayLengthFromPool();
+
+ /// <summary>
/// Queries sampler type information.
/// </summary>
/// <param name="handle">Texture handle</param>
@@ -400,6 +408,19 @@ namespace Ryujinx.Graphics.Shader
}
/// <summary>
+ /// Gets the size in bytes of a bound constant buffer for the current shader stage.
+ /// </summary>
+ /// <param name="slot">The number of the constant buffer to get the size from</param>
+ /// <returns>Size in bytes</returns>
+ int QueryTextureArrayLengthFromBuffer(int slot);
+
+ /// <summary>
+ /// Gets the maximum number of textures that the bound texture pool may have.
+ /// </summary>
+ /// <returns>Maximum amount of textures that the pool may have</returns>
+ int QueryTextureArrayLengthFromPool();
+
+ /// <summary>
/// Queries texture coordinate normalization information.
/// </summary>
/// <param name="handle">Texture handle</param>
diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs
index 0c1b2a3f..713e8a4f 100644
--- a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs
+++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs
@@ -216,6 +216,11 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
newSources[index] = source;
+ if (source != null && source.Type == OperandType.LocalVariable)
+ {
+ source.UseOps.Add(this);
+ }
+
_sources = newSources;
}
diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
index 1b82e294..74ec5ca6 100644
--- a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
+++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs
@@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
public TextureFlags Flags { get; private set; }
public int Binding { get; private set; }
+ public int SamplerBinding { get; private set; }
public TextureOperation(
Instruction inst,
@@ -24,6 +25,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
Format = format;
Flags = flags;
Binding = binding;
+ SamplerBinding = -1;
}
public void TurnIntoArray(int binding)
@@ -32,6 +34,13 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
Binding = binding;
}
+ public void TurnIntoArray(int textureBinding, int samplerBinding)
+ {
+ TurnIntoArray(textureBinding);
+
+ SamplerBinding = samplerBinding;
+ }
+
public void SetBinding(int binding)
{
if ((Flags & TextureFlags.Bindless) != 0)
diff --git a/src/Ryujinx.Graphics.Shader/SamplerType.cs b/src/Ryujinx.Graphics.Shader/SamplerType.cs
index 66c748bf..a693495f 100644
--- a/src/Ryujinx.Graphics.Shader/SamplerType.cs
+++ b/src/Ryujinx.Graphics.Shader/SamplerType.cs
@@ -69,6 +69,7 @@ namespace Ryujinx.Graphics.Shader
{
string typeName = (type & SamplerType.Mask) switch
{
+ SamplerType.None => "sampler",
SamplerType.Texture1D => "sampler1D",
SamplerType.TextureBuffer => "samplerBuffer",
SamplerType.Texture2D => "sampler2D",
@@ -95,6 +96,31 @@ namespace Ryujinx.Graphics.Shader
return typeName;
}
+ public static string ToGlslTextureType(this SamplerType type)
+ {
+ string typeName = (type & SamplerType.Mask) switch
+ {
+ SamplerType.Texture1D => "texture1D",
+ SamplerType.TextureBuffer => "textureBuffer",
+ SamplerType.Texture2D => "texture2D",
+ SamplerType.Texture3D => "texture3D",
+ SamplerType.TextureCube => "textureCube",
+ _ => throw new ArgumentException($"Invalid texture type \"{type}\"."),
+ };
+
+ if ((type & SamplerType.Multisample) != 0)
+ {
+ typeName += "MS";
+ }
+
+ if ((type & SamplerType.Array) != 0)
+ {
+ typeName += "Array";
+ }
+
+ return typeName;
+ }
+
public static string ToGlslImageType(this SamplerType type, AggregateType componentType)
{
string typeName = (type & SamplerType.Mask) switch
diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
index 3970df1e..4068c412 100644
--- a/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
+++ b/src/Ryujinx.Graphics.Shader/StructuredIr/AstTextureOperation.cs
@@ -9,6 +9,9 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
public TextureFlags Flags { get; }
public int Binding { get; }
+ public int SamplerBinding { get; }
+
+ public bool IsSeparate => SamplerBinding >= 0;
public AstTextureOperation(
Instruction inst,
@@ -16,6 +19,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
TextureFormat format,
TextureFlags flags,
int binding,
+ int samplerBinding,
int index,
params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length)
{
@@ -23,6 +27,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Format = format;
Flags = flags;
Binding = binding;
+ SamplerBinding = samplerBinding;
}
}
}
diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
index 2e2df754..c4ebaee7 100644
--- a/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
+++ b/src/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs
@@ -169,7 +169,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
AstTextureOperation GetAstTextureOperation(TextureOperation texOp)
{
- return new AstTextureOperation(inst, texOp.Type, texOp.Format, texOp.Flags, texOp.Binding, texOp.Index, sources);
+ return new AstTextureOperation(inst, texOp.Type, texOp.Format, texOp.Flags, texOp.Binding, texOp.SamplerBinding, texOp.Index, sources);
}
int componentsCount = BitOperations.PopCount((uint)operation.Index);
diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs
index bdd3a2ed..1021dff0 100644
--- a/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs
+++ b/src/Ryujinx.Graphics.Shader/StructuredIr/TextureDefinition.cs
@@ -5,25 +5,39 @@ namespace Ryujinx.Graphics.Shader
public int Set { get; }
public int Binding { get; }
public int ArrayLength { get; }
+ public bool Separate { get; }
public string Name { get; }
public SamplerType Type { get; }
public TextureFormat Format { get; }
public TextureUsageFlags Flags { get; }
- public TextureDefinition(int set, int binding, int arrayLength, string name, SamplerType type, TextureFormat format, TextureUsageFlags flags)
+ public TextureDefinition(
+ int set,
+ int binding,
+ int arrayLength,
+ bool separate,
+ string name,
+ SamplerType type,
+ TextureFormat format,
+ TextureUsageFlags flags)
{
Set = set;
Binding = binding;
ArrayLength = arrayLength;
+ Separate = separate;
Name = name;
Type = type;
Format = format;
Flags = flags;
}
+ public TextureDefinition(int set, int binding, string name, SamplerType type) : this(set, binding, 1, false, name, type, TextureFormat.Unknown, TextureUsageFlags.None)
+ {
+ }
+
public TextureDefinition SetFlag(TextureUsageFlags flag)
{
- return new TextureDefinition(Set, Binding, ArrayLength, Name, Type, Format, Flags | flag);
+ return new TextureDefinition(Set, Binding, ArrayLength, Separate, Name, Type, Format, Flags | flag);
}
}
}
diff --git a/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs b/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs
index 38834da7..d287a1aa 100644
--- a/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs
+++ b/src/Ryujinx.Graphics.Shader/TextureDescriptor.cs
@@ -13,6 +13,8 @@ namespace Ryujinx.Graphics.Shader
public readonly int HandleIndex;
public readonly int ArrayLength;
+ public readonly bool Separate;
+
public readonly TextureUsageFlags Flags;
public TextureDescriptor(
@@ -22,6 +24,7 @@ namespace Ryujinx.Graphics.Shader
int cbufSlot,
int handleIndex,
int arrayLength,
+ bool separate,
TextureUsageFlags flags)
{
Binding = binding;
@@ -30,6 +33,7 @@ namespace Ryujinx.Graphics.Shader
CbufSlot = cbufSlot;
HandleIndex = handleIndex;
ArrayLength = arrayLength;
+ Separate = separate;
Flags = flags;
}
}
diff --git a/src/Ryujinx.Graphics.Shader/TextureHandle.cs b/src/Ryujinx.Graphics.Shader/TextureHandle.cs
index 7df9c8e4..3aaceac4 100644
--- a/src/Ryujinx.Graphics.Shader/TextureHandle.cs
+++ b/src/Ryujinx.Graphics.Shader/TextureHandle.cs
@@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Shader
SeparateSamplerHandle = 1,
SeparateSamplerId = 2,
SeparateConstantSamplerHandle = 3,
+ Direct = 4,
}
public static class TextureHandle
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
index ad955278..22321543 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
@@ -1,6 +1,7 @@
using Ryujinx.Graphics.Shader.Instructions;
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr;
+using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Shader.Translation.Optimizations
@@ -31,7 +32,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
continue;
}
- if (!TryConvertBindless(block, resourceManager, gpuAccessor, texOp))
+ if (!TryConvertBindless(block, resourceManager, gpuAccessor, texOp) &&
+ !GenerateBindlessAccess(block, resourceManager, gpuAccessor, texOp, node))
{
// If we can't do bindless elimination, remove the texture operation.
// Set any destination variables to zero.
@@ -46,6 +48,88 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
}
}
+ private static bool GenerateBindlessAccess(
+ BasicBlock block,
+ ResourceManager resourceManager,
+ IGpuAccessor gpuAccessor,
+ TextureOperation texOp,
+ LinkedListNode<INode> node)
+ {
+ if (!gpuAccessor.QueryHostSupportsSeparateSampler())
+ {
+ // We depend on combining samplers and textures in the shader being supported for this.
+
+ return false;
+ }
+
+ Operand nvHandle = texOp.GetSource(0);
+
+ if (nvHandle.AsgOp is not Operation handleOp ||
+ handleOp.Inst != Instruction.Load ||
+ handleOp.StorageKind != StorageKind.Input)
+ {
+ // Right now, we only allow bindless access when the handle comes from a shader input.
+ // This is an artificial limitation to prevent it from being used in cases where it
+ // would have a large performance impact of loading all textures in the pool.
+ // It might be removed in the future, if we can mitigate the performance impact.
+
+ return false;
+ }
+
+ Operand textureHandle = OperandHelper.Local();
+ Operand samplerHandle = OperandHelper.Local();
+ Operand textureIndex = OperandHelper.Local();
+
+ block.Operations.AddBefore(node, new Operation(Instruction.BitwiseAnd, textureHandle, nvHandle, OperandHelper.Const(0xfffff)));
+ block.Operations.AddBefore(node, new Operation(Instruction.ShiftRightU32, samplerHandle, nvHandle, OperandHelper.Const(20)));
+
+ int texturePoolLength = Math.Max(BindlessToArray.MinimumArrayLength, gpuAccessor.QueryTextureArrayLengthFromPool());
+
+ block.Operations.AddBefore(node, new Operation(Instruction.MinimumU32, textureIndex, textureHandle, OperandHelper.Const(texturePoolLength - 1)));
+
+ texOp.SetSource(0, textureIndex);
+
+ bool hasSampler = !texOp.Inst.IsImage();
+
+ int textureBinding = resourceManager.GetTextureOrImageBinding(
+ texOp.Inst,
+ texOp.Type,
+ texOp.Format,
+ texOp.Flags & ~TextureFlags.Bindless,
+ 0,
+ TextureHandle.PackOffsets(0, 0, TextureHandleType.Direct),
+ texturePoolLength,
+ hasSampler);
+
+ if (hasSampler)
+ {
+ Operand samplerIndex = OperandHelper.Local();
+
+ int samplerPoolLength = Math.Max(BindlessToArray.MinimumArrayLength, gpuAccessor.QuerySamplerArrayLengthFromPool());
+
+ block.Operations.AddBefore(node, new Operation(Instruction.MinimumU32, samplerIndex, samplerHandle, OperandHelper.Const(samplerPoolLength - 1)));
+
+ texOp.InsertSource(1, samplerIndex);
+
+ int samplerBinding = resourceManager.GetTextureOrImageBinding(
+ texOp.Inst,
+ SamplerType.None,
+ texOp.Format,
+ TextureFlags.None,
+ 0,
+ TextureHandle.PackOffsets(0, 0, TextureHandleType.Direct),
+ samplerPoolLength);
+
+ texOp.TurnIntoArray(textureBinding, samplerBinding);
+ }
+ else
+ {
+ texOp.TurnIntoArray(textureBinding);
+ }
+
+ return true;
+ }
+
private static bool TryConvertBindless(BasicBlock block, ResourceManager resourceManager, IGpuAccessor gpuAccessor, TextureOperation texOp)
{
if (texOp.Inst == Instruction.TextureSample || texOp.Inst.IsTextureQuery())
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs
index 7543d1c2..f2be7975 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToArray.cs
@@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
private const int HardcodedArrayLengthOgl = 4;
// 1 and 0 elements are not considered arrays anymore.
- private const int MinimumArrayLength = 2;
+ public const int MinimumArrayLength = 2;
public static void RunPassOgl(BasicBlock block, ResourceManager resourceManager)
{
diff --git a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
index e9fe0b1e..890501c9 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
@@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Shader.Translation
private readonly HashSet<int> _usedConstantBufferBindings;
- private readonly record struct TextureInfo(int CbufSlot, int Handle, int ArrayLength, SamplerType Type, TextureFormat Format);
+ private readonly record struct TextureInfo(int CbufSlot, int Handle, int ArrayLength, bool Separate, SamplerType Type, TextureFormat Format);
private struct TextureMeta
{
@@ -225,7 +225,8 @@ namespace Ryujinx.Graphics.Shader.Translation
TextureFlags flags,
int cbufSlot,
int handle,
- int arrayLength = 1)
+ int arrayLength = 1,
+ bool separate = false)
{
inst &= Instruction.Mask;
bool isImage = inst.IsImage();
@@ -239,7 +240,18 @@ namespace Ryujinx.Graphics.Shader.Translation
format = TextureFormat.Unknown;
}
- int binding = GetTextureOrImageBinding(cbufSlot, handle, arrayLength, type, format, isImage, intCoords, isWrite, accurateType, coherent);
+ int binding = GetTextureOrImageBinding(
+ cbufSlot,
+ handle,
+ arrayLength,
+ type,
+ format,
+ isImage,
+ intCoords,
+ isWrite,
+ accurateType,
+ coherent,
+ separate);
_gpuAccessor.RegisterTexture(handle, cbufSlot);
@@ -256,9 +268,10 @@ namespace Ryujinx.Graphics.Shader.Translation
bool intCoords,
bool write,
bool accurateType,
- bool coherent)
+ bool coherent,
+ bool separate)
{
- var dimensions = type.GetDimensions();
+ var dimensions = type == SamplerType.None ? 0 : type.GetDimensions();
var dict = isImage ? _usedImages : _usedTextures;
var usageFlags = TextureUsageFlags.None;
@@ -290,7 +303,7 @@ namespace Ryujinx.Graphics.Shader.Translation
// For array textures, we also want to use type as key,
// since we may have texture handles stores in the same buffer, but for textures with different types.
var keyType = arrayLength > 1 ? type : SamplerType.None;
- var info = new TextureInfo(cbufSlot, handle, arrayLength, keyType, format);
+ var info = new TextureInfo(cbufSlot, handle, arrayLength, separate, keyType, format);
var meta = new TextureMeta()
{
AccurateType = accurateType,
@@ -332,6 +345,10 @@ namespace Ryujinx.Graphics.Shader.Translation
? $"{prefix}_tcb_{handle:X}_{format.ToGlslFormat()}"
: $"{prefix}_cb{cbufSlot}_{handle:X}_{format.ToGlslFormat()}";
}
+ else if (type == SamplerType.None)
+ {
+ nameSuffix = cbufSlot < 0 ? $"s_tcb_{handle:X}" : $"s_cb{cbufSlot}_{handle:X}";
+ }
else
{
nameSuffix = cbufSlot < 0 ? $"{prefix}_tcb_{handle:X}" : $"{prefix}_cb{cbufSlot}_{handle:X}";
@@ -341,6 +358,7 @@ namespace Ryujinx.Graphics.Shader.Translation
isImage ? 3 : 2,
binding,
arrayLength,
+ separate,
$"{_stagePrefix}_{nameSuffix}",
meta.Type,
info.Format,
@@ -495,6 +513,7 @@ namespace Ryujinx.Graphics.Shader.Translation
info.CbufSlot,
info.Handle,
info.ArrayLength,
+ info.Separate,
meta.UsageFlags));
}
@@ -514,6 +533,7 @@ namespace Ryujinx.Graphics.Shader.Translation
info.CbufSlot,
info.Handle,
info.ArrayLength,
+ info.Separate,
meta.UsageFlags));
}
}
diff --git a/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs b/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
index 581f4372..10653558 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
@@ -413,7 +413,7 @@ namespace Ryujinx.Graphics.Shader.Translation
if (Stage == ShaderStage.Vertex)
{
int ibBinding = resourceManager.Reservations.IndexBufferTextureBinding;
- TextureDefinition indexBuffer = new(2, ibBinding, 1, "ib_data", SamplerType.TextureBuffer, TextureFormat.Unknown, TextureUsageFlags.None);
+ TextureDefinition indexBuffer = new(2, ibBinding, "ib_data", SamplerType.TextureBuffer);
resourceManager.Properties.AddOrUpdateTexture(indexBuffer);
int inputMap = _program.AttributeUsage.UsedInputAttributes;
@@ -422,7 +422,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
int location = BitOperations.TrailingZeroCount(inputMap);
int binding = resourceManager.Reservations.GetVertexBufferTextureBinding(location);
- TextureDefinition vaBuffer = new(2, binding, 1, $"vb_data{location}", SamplerType.TextureBuffer, TextureFormat.Unknown, TextureUsageFlags.None);
+ TextureDefinition vaBuffer = new(2, binding, $"vb_data{location}", SamplerType.TextureBuffer);
resourceManager.Properties.AddOrUpdateTexture(vaBuffer);
inputMap &= ~(1 << location);
@@ -431,7 +431,7 @@ namespace Ryujinx.Graphics.Shader.Translation
else if (Stage == ShaderStage.Geometry)
{
int trbBinding = resourceManager.Reservations.TopologyRemapBufferTextureBinding;
- TextureDefinition remapBuffer = new(2, trbBinding, 1, "trb_data", SamplerType.TextureBuffer, TextureFormat.Unknown, TextureUsageFlags.None);
+ TextureDefinition remapBuffer = new(2, trbBinding, "trb_data", SamplerType.TextureBuffer);
resourceManager.Properties.AddOrUpdateTexture(remapBuffer);
int geometryVbOutputSbBinding = resourceManager.Reservations.GeometryVertexOutputStorageBufferBinding;