diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index d86d12032..79effedfa 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -12,6 +12,9 @@ namespace Ryujinx.Graphics.Gpu.Image
private const int HandleHigh = 16;
private const int HandleMask = (1 << HandleHigh) - 1;
+ private const int SlotHigh = 16;
+ private const int SlotMask = (1 << SlotHigh) - 1;
+
private GpuContext _context;
private bool _isCompute;
@@ -267,9 +270,21 @@ namespace Ryujinx.Graphics.Gpu.Image
{
TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index];
- int textureBufferIndex = bindingInfo.CbufSlot < 0 ? _textureBufferIndex : bindingInfo.CbufSlot;
+ int textureBufferIndex;
+ int samplerBufferIndex;
- int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex);
+ if (bindingInfo.CbufSlot < 0)
+ {
+ textureBufferIndex = _textureBufferIndex;
+ samplerBufferIndex = textureBufferIndex;
+ }
+ else
+ {
+ textureBufferIndex = bindingInfo.CbufSlot & SlotMask;
+ samplerBufferIndex = ((bindingInfo.CbufSlot >> SlotHigh) != 0) ? (bindingInfo.CbufSlot >> SlotHigh) - 1 : textureBufferIndex;
+ }
+
+ int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex, samplerBufferIndex);
int textureId = UnpackTextureId(packedId);
int samplerId;
@@ -340,9 +355,21 @@ namespace Ryujinx.Graphics.Gpu.Image
{
TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index];
- int textureBufferIndex = bindingInfo.CbufSlot < 0 ? _textureBufferIndex : bindingInfo.CbufSlot;
+ int textureBufferIndex;
+ int samplerBufferIndex;
- int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex);
+ if (bindingInfo.CbufSlot < 0)
+ {
+ textureBufferIndex = _textureBufferIndex;
+ samplerBufferIndex = textureBufferIndex;
+ }
+ else
+ {
+ textureBufferIndex = bindingInfo.CbufSlot & SlotMask;
+ samplerBufferIndex = ((bindingInfo.CbufSlot >> SlotHigh) != 0) ? (bindingInfo.CbufSlot >> SlotHigh) - 1 : textureBufferIndex;
+ }
+
+ int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex, samplerBufferIndex);
int textureId = UnpackTextureId(packedId);
Texture texture = pool.Get(textureId);
@@ -402,7 +429,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// The texture descriptor for the specified texture
public TextureDescriptor GetTextureDescriptor(GpuState state, int stageIndex, int handle, int cbufSlot)
{
- int packedId = ReadPackedId(stageIndex, handle, cbufSlot < 0 ? state.Get(MethodOffset.TextureBufferIndex) : cbufSlot);
+ int textureBufferIndex = cbufSlot < 0 ? state.Get(MethodOffset.TextureBufferIndex) : cbufSlot & SlotMask;
+ int packedId = ReadPackedId(stageIndex, handle, textureBufferIndex, textureBufferIndex);
int textureId = UnpackTextureId(packedId);
var poolState = state.Get(MethodOffset.TexturePoolState);
@@ -421,23 +449,16 @@ namespace Ryujinx.Graphics.Gpu.Image
/// The number of the shader stage where the texture is bound
/// A word offset of the handle on the buffer (the "fake" shader handle)
/// Index of the constant buffer holding the texture handles
+ /// Index of the constant buffer holding the sampler handles
/// The packed texture and sampler ID (the real texture handle)
- private int ReadPackedId(int stageIndex, int wordOffset, int textureBufferIndex)
+ private int ReadPackedId(int stageIndex, int wordOffset, int textureBufferIndex, int samplerBufferIndex)
{
- ulong address;
-
var bufferManager = _context.Methods.BufferManager;
+ ulong textureBufferAddress = _isCompute
+ ? bufferManager.GetComputeUniformBufferAddress(textureBufferIndex)
+ : bufferManager.GetGraphicsUniformBufferAddress(stageIndex, textureBufferIndex);
- if (_isCompute)
- {
- address = bufferManager.GetComputeUniformBufferAddress(textureBufferIndex);
- }
- else
- {
- address = bufferManager.GetGraphicsUniformBufferAddress(stageIndex, textureBufferIndex);
- }
-
- int handle = _context.PhysicalMemory.Read(address + (ulong)(wordOffset & HandleMask) * 4);
+ int handle = _context.PhysicalMemory.Read(textureBufferAddress + (ulong)(wordOffset & HandleMask) * 4);
// The "wordOffset" (which is really the immediate value used on texture instructions on the shader)
// is a 13-bit value. However, in order to also support separate samplers and textures (which uses
@@ -447,7 +468,11 @@ namespace Ryujinx.Graphics.Gpu.Image
// turn that into a regular texture access and produce those special handles with values on the higher 16 bits.
if (wordOffset >> HandleHigh != 0)
{
- handle |= _context.PhysicalMemory.Read(address + (ulong)(wordOffset >> HandleHigh) * 4);
+ ulong samplerBufferAddress = _isCompute
+ ? bufferManager.GetComputeUniformBufferAddress(samplerBufferIndex)
+ : bufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex);
+
+ handle |= _context.PhysicalMemory.Read(samplerBufferAddress + (ulong)((uint)wordOffset >> HandleHigh) * 4);
}
return handle;
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
index 3a523adc2..6156a6f4a 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
@@ -50,13 +50,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
Operand src0 = Utils.FindLastOperation(handleCombineOp.GetSource(0), block);
Operand src1 = Utils.FindLastOperation(handleCombineOp.GetSource(1), block);
- if (src0.Type != OperandType.ConstantBuffer ||
- src1.Type != OperandType.ConstantBuffer || src0.GetCbufSlot() != src1.GetCbufSlot())
+ if (src0.Type != OperandType.ConstantBuffer || src1.Type != OperandType.ConstantBuffer)
{
continue;
}
- SetHandle(config, texOp, src0.GetCbufOffset() | (src1.GetCbufOffset() << 16), src0.GetCbufSlot());
+ SetHandle(
+ config,
+ texOp,
+ src0.GetCbufOffset() | (src1.GetCbufOffset() << 16),
+ src0.GetCbufSlot() | ((src1.GetCbufSlot() + 1) << 16));
}
else if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore)
{