From 5afd521c5a75da956448df76e415528316ee8a8d Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sat, 2 Jul 2022 15:03:35 -0300 Subject: [PATCH] Bindless elimination for constant sampler handle (#3424) * Bindless elimination for constant sampler handle * Shader cache version bump * Update TextureHandle.ReadPackedId for new bindless elimination --- .../Image/TextureBindingsManager.cs | 20 ++++-- .../Shader/DiskCache/DiskCacheHostStorage.cs | 2 +- Ryujinx.Graphics.Shader/IGpuAccessor.cs | 2 +- Ryujinx.Graphics.Shader/TextureHandle.cs | 17 ++++- .../Optimizations/BindlessElimination.cs | 62 ++++++++++++++----- 5 files changed, 78 insertions(+), 25 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs index 18f5a74a..fcd23441 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs @@ -792,13 +792,23 @@ 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 (handleType != TextureHandleType.CombinedSampler) { - ulong samplerBufferAddress = _isCompute - ? _channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex) - : _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex); + int samplerHandle; - int samplerHandle = _channel.MemoryManager.Physical.Read(samplerBufferAddress + (uint)samplerWordOffset * 4); + if (handleType != TextureHandleType.SeparateConstantSamplerHandle) + { + ulong samplerBufferAddress = _isCompute + ? _channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex) + : _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex); - if (handleType == TextureHandleType.SeparateSamplerId) + samplerHandle = _channel.MemoryManager.Physical.Read(samplerBufferAddress + (uint)samplerWordOffset * 4); + } + else + { + samplerHandle = samplerWordOffset; + } + + if (handleType == TextureHandleType.SeparateSamplerId || + handleType == TextureHandleType.SeparateConstantSamplerHandle) { samplerHandle <<= 20; } diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs index 5d99957f..59801001 100644 --- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs +++ b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs @@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMinor = 1; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; - private const uint CodeGenVersion = 1; + private const uint CodeGenVersion = 3424; private const string SharedTocFileName = "shared.toc"; private const string SharedDataFileName = "shared.data"; diff --git a/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/Ryujinx.Graphics.Shader/IGpuAccessor.cs index 180fc187..42f210a5 100644 --- a/Ryujinx.Graphics.Shader/IGpuAccessor.cs +++ b/Ryujinx.Graphics.Shader/IGpuAccessor.cs @@ -237,7 +237,7 @@ namespace Ryujinx.Graphics.Shader /// True if the coordinates are normalized, false otherwise bool QueryTextureCoordNormalized(int handle, int cbufSlot = -1) { - return false; + return true; } /// diff --git a/Ryujinx.Graphics.Shader/TextureHandle.cs b/Ryujinx.Graphics.Shader/TextureHandle.cs index d468188b..a2842bb8 100644 --- a/Ryujinx.Graphics.Shader/TextureHandle.cs +++ b/Ryujinx.Graphics.Shader/TextureHandle.cs @@ -7,7 +7,8 @@ namespace Ryujinx.Graphics.Shader { CombinedSampler = 0, // Must be 0. SeparateSamplerHandle = 1, - SeparateSamplerId = 2 + SeparateSamplerId = 2, + SeparateConstantSamplerHandle = 3 } public static class TextureHandle @@ -97,9 +98,19 @@ namespace Ryujinx.Graphics.Shader // turn that into a regular texture access and produce those special handles with values on the higher 16 bits. if (handleType != TextureHandleType.CombinedSampler) { - int samplerHandle = cachedSamplerBuffer[samplerWordOffset]; + int samplerHandle; - if (handleType == TextureHandleType.SeparateSamplerId) + if (handleType != TextureHandleType.SeparateConstantSamplerHandle) + { + samplerHandle = cachedSamplerBuffer[samplerWordOffset]; + } + else + { + samplerHandle = samplerWordOffset; + } + + if (handleType == TextureHandleType.SeparateSamplerId || + handleType == TextureHandleType.SeparateConstantSamplerHandle) { samplerHandle <<= 20; } diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs index 1b303caf..73d89761 100644 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs +++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs @@ -51,16 +51,32 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations Operand src0 = Utils.FindLastOperation(handleCombineOp.GetSource(0), block); Operand src1 = Utils.FindLastOperation(handleCombineOp.GetSource(1), block); + // For cases where we have a constant, ensure that the constant is always + // the second operand. + // Since this is a commutative operation, both are fine, + // and having a "canonical" representation simplifies some checks below. + if (src0.Type == OperandType.Constant && src1.Type != OperandType.Constant) + { + Operand temp = src1; + src1 = src0; + src0 = temp; + } + TextureHandleType handleType = TextureHandleType.SeparateSamplerHandle; - // Try to match masked pattern: - // - samplerHandle = samplerHandle & 0xFFF00000; - // - textureHandle = textureHandle & 0xFFFFF; - // - combinedHandle = samplerHandle | textureHandle; - // where samplerHandle and textureHandle comes from a constant buffer, and shifted pattern: - // - samplerHandle = samplerId << 20; - // - combinedHandle = samplerHandle | textureHandle; - // where samplerId and textureHandle comes from a constant buffer. + // Try to match the following patterns: + // Masked pattern: + // - samplerHandle = samplerHandle & 0xFFF00000; + // - textureHandle = textureHandle & 0xFFFFF; + // - combinedHandle = samplerHandle | textureHandle; + // Where samplerHandle and textureHandle comes from a constant buffer. + // Shifted pattern: + // - samplerHandle = samplerId << 20; + // - combinedHandle = samplerHandle | textureHandle; + // Where samplerId and textureHandle comes from a constant buffer. + // Constant pattern: + // - combinedHandle = samplerHandleConstant | textureHandle; + // Where samplerHandleConstant is a constant value, and textureHandle comes from a constant buffer. if (src0.AsgOp is Operation src0AsgOp) { if (src1.AsgOp is Operation src1AsgOp && @@ -104,18 +120,34 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations handleType = TextureHandleType.SeparateSamplerId; } } + else if (src1.Type == OperandType.Constant && (src1.Value & 0xfffff) == 0) + { + handleType = TextureHandleType.SeparateConstantSamplerHandle; + } - if (src0.Type != OperandType.ConstantBuffer || src1.Type != OperandType.ConstantBuffer) + if (src0.Type != OperandType.ConstantBuffer) { continue; } - SetHandle( - config, - texOp, - TextureHandle.PackOffsets(src0.GetCbufOffset(), src1.GetCbufOffset(), handleType), - TextureHandle.PackSlots(src0.GetCbufSlot(), src1.GetCbufSlot()), - rewriteSamplerType); + if (handleType == TextureHandleType.SeparateConstantSamplerHandle) + { + SetHandle( + config, + texOp, + TextureHandle.PackOffsets(src0.GetCbufOffset(), ((src1.Value >> 20) & 0xfff), handleType), + TextureHandle.PackSlots(src0.GetCbufSlot(), 0), + rewriteSamplerType); + } + else if (src1.Type == OperandType.ConstantBuffer) + { + SetHandle( + config, + texOp, + TextureHandle.PackOffsets(src0.GetCbufOffset(), src1.GetCbufOffset(), handleType), + TextureHandle.PackSlots(src0.GetCbufSlot(), src1.GetCbufSlot()), + rewriteSamplerType); + } } else if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore ||