From 02e2e561ac136473d4d259d872dc5e211c6a3e67 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 8 Jun 2021 19:42:25 -0300 Subject: [PATCH] Support bindless textures with separate constant buffers for texture and sampler (#2339) --- .../Image/TextureBindingsManager.cs | 63 +++++++++++++------ .../Optimizations/BindlessElimination.cs | 9 ++- 2 files changed, 50 insertions(+), 22 deletions(-) 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) {