diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Shader')
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; |
