Support bindless textures with separate constant buffers for texture and sampler (#2339)

This commit is contained in:
gdkchan 2021-06-08 19:42:25 -03:00 committed by GitHub
parent 8588586062
commit 02e2e561ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 22 deletions

View file

@ -12,6 +12,9 @@ namespace Ryujinx.Graphics.Gpu.Image
private const int HandleHigh = 16; private const int HandleHigh = 16;
private const int HandleMask = (1 << HandleHigh) - 1; private const int HandleMask = (1 << HandleHigh) - 1;
private const int SlotHigh = 16;
private const int SlotMask = (1 << SlotHigh) - 1;
private GpuContext _context; private GpuContext _context;
private bool _isCompute; private bool _isCompute;
@ -267,9 +270,21 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index]; 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 textureId = UnpackTextureId(packedId);
int samplerId; int samplerId;
@ -340,9 +355,21 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index]; 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); int textureId = UnpackTextureId(packedId);
Texture texture = pool.Get(textureId); Texture texture = pool.Get(textureId);
@ -402,7 +429,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>The texture descriptor for the specified texture</returns> /// <returns>The texture descriptor for the specified texture</returns>
public TextureDescriptor GetTextureDescriptor(GpuState state, int stageIndex, int handle, int cbufSlot) public TextureDescriptor GetTextureDescriptor(GpuState state, int stageIndex, int handle, int cbufSlot)
{ {
int packedId = ReadPackedId(stageIndex, handle, cbufSlot < 0 ? state.Get<int>(MethodOffset.TextureBufferIndex) : cbufSlot); int textureBufferIndex = cbufSlot < 0 ? state.Get<int>(MethodOffset.TextureBufferIndex) : cbufSlot & SlotMask;
int packedId = ReadPackedId(stageIndex, handle, textureBufferIndex, textureBufferIndex);
int textureId = UnpackTextureId(packedId); int textureId = UnpackTextureId(packedId);
var poolState = state.Get<PoolState>(MethodOffset.TexturePoolState); var poolState = state.Get<PoolState>(MethodOffset.TexturePoolState);
@ -421,23 +449,16 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="stageIndex">The number of the shader stage where the texture is bound</param> /// <param name="stageIndex">The number of the shader stage where the texture is bound</param>
/// <param name="wordOffset">A word offset of the handle on the buffer (the "fake" shader handle)</param> /// <param name="wordOffset">A word offset of the handle on the buffer (the "fake" shader handle)</param>
/// <param name="textureBufferIndex">Index of the constant buffer holding the texture handles</param> /// <param name="textureBufferIndex">Index of the constant buffer holding the texture handles</param>
/// <param name="samplerBufferIndex">Index of the constant buffer holding the sampler handles</param>
/// <returns>The packed texture and sampler ID (the real texture handle)</returns> /// <returns>The packed texture and sampler ID (the real texture handle)</returns>
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; var bufferManager = _context.Methods.BufferManager;
ulong textureBufferAddress = _isCompute
? bufferManager.GetComputeUniformBufferAddress(textureBufferIndex)
: bufferManager.GetGraphicsUniformBufferAddress(stageIndex, textureBufferIndex);
if (_isCompute) int handle = _context.PhysicalMemory.Read<int>(textureBufferAddress + (ulong)(wordOffset & HandleMask) * 4);
{
address = bufferManager.GetComputeUniformBufferAddress(textureBufferIndex);
}
else
{
address = bufferManager.GetGraphicsUniformBufferAddress(stageIndex, textureBufferIndex);
}
int handle = _context.PhysicalMemory.Read<int>(address + (ulong)(wordOffset & HandleMask) * 4);
// The "wordOffset" (which is really the immediate value used on texture instructions on the shader) // 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 // 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. // turn that into a regular texture access and produce those special handles with values on the higher 16 bits.
if (wordOffset >> HandleHigh != 0) if (wordOffset >> HandleHigh != 0)
{ {
handle |= _context.PhysicalMemory.Read<int>(address + (ulong)(wordOffset >> HandleHigh) * 4); ulong samplerBufferAddress = _isCompute
? bufferManager.GetComputeUniformBufferAddress(samplerBufferIndex)
: bufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex);
handle |= _context.PhysicalMemory.Read<int>(samplerBufferAddress + (ulong)((uint)wordOffset >> HandleHigh) * 4);
} }
return handle; return handle;

View file

@ -50,13 +50,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
Operand src0 = Utils.FindLastOperation(handleCombineOp.GetSource(0), block); Operand src0 = Utils.FindLastOperation(handleCombineOp.GetSource(0), block);
Operand src1 = Utils.FindLastOperation(handleCombineOp.GetSource(1), block); Operand src1 = Utils.FindLastOperation(handleCombineOp.GetSource(1), block);
if (src0.Type != OperandType.ConstantBuffer || if (src0.Type != OperandType.ConstantBuffer || src1.Type != OperandType.ConstantBuffer)
src1.Type != OperandType.ConstantBuffer || src0.GetCbufSlot() != src1.GetCbufSlot())
{ {
continue; 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) else if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore)
{ {