mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-08-01 02:30:08 -06:00
Add support for bindless textures from shader input (vertex buffer) on Vulkan (#6577)
* Add support for bindless textures from shader input (vertex buffer) * Shader cache version bump * Format whitespace * Remove cache entries on pool removal, disable for OpenGL * PR feedback
This commit is contained in:
@ -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())
|
||||
|
Reference in New Issue
Block a user