From 0129250c2e169c7386f7e2868cc055f8ec55c005 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Wed, 19 May 2021 19:05:43 +0100 Subject: [PATCH] Pass CbufSlot when getting info from the texture descriptor (#2291) * Pass CbufSlot when getting info from the texture descriptor Fixes some issues with bindless textures, when CbufSlot is not equal to the current TextureBufferIndex. Specifically fixes a random chance of full screen colour flickering in Super Mario Party. * Apply suggestions from code review Oops Co-authored-by: gdkchan Co-authored-by: gdkchan --- .../Image/TextureBindingsManager.cs | 5 +++-- Ryujinx.Graphics.Gpu/Image/TextureManager.cs | 12 +++++++----- .../Shader/Cache/CacheHelper.cs | 2 +- .../Shader/CachedGpuAccessor.cs | 3 ++- Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs | 7 ++++--- .../TextureDescriptorCapableGpuAccessor.cs | 17 ++++++++++------- Ryujinx.Graphics.Shader/IGpuAccessor.cs | 6 +++--- .../Optimizations/BindlessElimination.cs | 2 +- Ryujinx.Graphics.Shader/Translation/Rewriter.cs | 4 ++-- .../Translation/ShaderConfig.cs | 4 ++-- 10 files changed, 35 insertions(+), 27 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs index 7fea7ebe0..ae610a766 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs @@ -398,10 +398,11 @@ namespace Ryujinx.Graphics.Gpu.Image /// The current GPU state /// The stage number where the texture is bound /// The texture handle + /// The texture handle's constant buffer slot /// The texture descriptor for the specified texture - public TextureDescriptor GetTextureDescriptor(GpuState state, int stageIndex, int handle) + public TextureDescriptor GetTextureDescriptor(GpuState state, int stageIndex, int handle, int cbufSlot) { - int packedId = ReadPackedId(stageIndex, handle, state.Get(MethodOffset.TextureBufferIndex)); + int packedId = ReadPackedId(stageIndex, handle, cbufSlot < 0 ? state.Get(MethodOffset.TextureBufferIndex) : cbufSlot); int textureId = UnpackTextureId(packedId); var poolState = state.Get(MethodOffset.TexturePoolState); diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs index 17bb553f3..e08e55eea 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs @@ -340,10 +340,11 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Current GPU state /// Shader "fake" handle of the texture + /// Shader constant buffer slot of the texture /// The texture descriptor - public TextureDescriptor GetComputeTextureDescriptor(GpuState state, int handle) + public TextureDescriptor GetComputeTextureDescriptor(GpuState state, int handle, int cbufSlot) { - return _cpBindingsManager.GetTextureDescriptor(state, 0, handle); + return _cpBindingsManager.GetTextureDescriptor(state, 0, handle, cbufSlot); } /// @@ -352,10 +353,11 @@ namespace Ryujinx.Graphics.Gpu.Image /// Current GPU state /// Index of the shader stage where the texture is bound /// Shader "fake" handle of the texture + /// Shader constant buffer slot of the texture /// The texture descriptor - public TextureDescriptor GetGraphicsTextureDescriptor(GpuState state, int stageIndex, int handle) + public TextureDescriptor GetGraphicsTextureDescriptor(GpuState state, int stageIndex, int handle, int cbufSlot) { - return _gpBindingsManager.GetTextureDescriptor(state, stageIndex, handle); + return _gpBindingsManager.GetTextureDescriptor(state, stageIndex, handle, cbufSlot); } /// @@ -1297,4 +1299,4 @@ namespace Ryujinx.Graphics.Gpu.Image } } } -} \ No newline at end of file +} diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/CacheHelper.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/CacheHelper.cs index 1ec4ab74c..f6caddef1 100644 --- a/Ryujinx.Graphics.Gpu/Shader/Cache/CacheHelper.cs +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/CacheHelper.cs @@ -417,7 +417,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache { foreach (int textureHandle in context.TextureHandlesForCache) { - GuestTextureDescriptor textureDescriptor = ((Image.TextureDescriptor)gpuAccessor.GetTextureDescriptor(textureHandle)).ToCache(); + GuestTextureDescriptor textureDescriptor = ((Image.TextureDescriptor)gpuAccessor.GetTextureDescriptor(textureHandle, -1)).ToCache(); textureDescriptor.Handle = (uint)textureHandle; diff --git a/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs index f714d97bd..a7bd4edb9 100644 --- a/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs @@ -140,8 +140,9 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Gets the texture descriptor for a given texture on the pool. /// /// Index of the texture (this is the word offset of the handle in the constant buffer) + /// Constant buffer slot for the texture handle /// Texture descriptor - public override Image.ITextureDescriptor GetTextureDescriptor(int handle) + public override Image.ITextureDescriptor GetTextureDescriptor(int handle, int cbufSlot) { if (!_textureDescriptors.TryGetValue(handle, out GuestTextureDescriptor textureDescriptor)) { diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs index c0ad481ea..f5373bd6f 100644 --- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs @@ -184,16 +184,17 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Gets the texture descriptor for a given texture on the pool. /// /// Index of the texture (this is the word offset of the handle in the constant buffer) + /// Constant buffer slot for the texture handle /// Texture descriptor - public override Image.ITextureDescriptor GetTextureDescriptor(int handle) + public override Image.ITextureDescriptor GetTextureDescriptor(int handle, int cbufSlot) { if (_compute) { - return _context.Methods.TextureManager.GetComputeTextureDescriptor(_state, handle); + return _context.Methods.TextureManager.GetComputeTextureDescriptor(_state, handle, cbufSlot); } else { - return _context.Methods.TextureManager.GetGraphicsTextureDescriptor(_state, _stageIndex, handle); + return _context.Methods.TextureManager.GetGraphicsTextureDescriptor(_state, _stageIndex, handle, cbufSlot); } } diff --git a/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs index dc0e392bc..904a0fd45 100644 --- a/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Shader { public abstract T MemoryRead(ulong address) where T : unmanaged; - public abstract ITextureDescriptor GetTextureDescriptor(int handle); + public abstract ITextureDescriptor GetTextureDescriptor(int handle, int cbufSlot); /// /// Queries texture format information, for shaders using image load or store. @@ -18,10 +18,11 @@ namespace Ryujinx.Graphics.Gpu.Shader /// If the format of the texture is a compressed, depth or unsupported format, then a default value is returned. /// /// Texture handle + /// Constant buffer slot for the texture handle /// Color format of the non-compressed texture - public TextureFormat QueryTextureFormat(int handle) + public TextureFormat QueryTextureFormat(int handle, int cbufSlot = -1) { - var descriptor = GetTextureDescriptor(handle); + var descriptor = GetTextureDescriptor(handle, cbufSlot); if (!FormatTable.TryGetTextureFormat(descriptor.UnpackFormat(), descriptor.UnpackSrgb(), out FormatInfo formatInfo)) { @@ -78,20 +79,22 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Queries texture target information. /// /// Texture handle + /// Constant buffer slot for the texture handle /// True if the texture is a buffer texture, false otherwise - public bool QueryIsTextureBuffer(int handle) + public bool QueryIsTextureBuffer(int handle, int cbufSlot = -1) { - return GetTextureDescriptor(handle).UnpackTextureTarget() == TextureTarget.TextureBuffer; + return GetTextureDescriptor(handle, cbufSlot).UnpackTextureTarget() == TextureTarget.TextureBuffer; } /// /// Queries texture target information. /// /// Texture handle + /// Constant buffer slot for the texture handle /// True if the texture is a rectangle texture, false otherwise - public bool QueryIsTextureRectangle(int handle) + public bool QueryIsTextureRectangle(int handle, int cbufSlot = -1) { - var descriptor = GetTextureDescriptor(handle); + var descriptor = GetTextureDescriptor(handle, cbufSlot); TextureTarget target = descriptor.UnpackTextureTarget(); diff --git a/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/Ryujinx.Graphics.Shader/IGpuAccessor.cs index fe034c57c..1e05cdcd6 100644 --- a/Ryujinx.Graphics.Shader/IGpuAccessor.cs +++ b/Ryujinx.Graphics.Shader/IGpuAccessor.cs @@ -44,12 +44,12 @@ return 0xffff; } - bool QueryIsTextureBuffer(int handle) + bool QueryIsTextureBuffer(int handle, int cbufSlot = -1) { return false; } - bool QueryIsTextureRectangle(int handle) + bool QueryIsTextureRectangle(int handle, int cbufSlot = -1) { return false; } @@ -74,7 +74,7 @@ return true; } - TextureFormat QueryTextureFormat(int handle) + TextureFormat QueryTextureFormat(int handle, int cbufSlot = -1) { return TextureFormat.R8G8B8A8Unorm; } diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs index f462cedbc..f91a00eba 100644 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs +++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs @@ -65,7 +65,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations if (src0.Type == OperandType.ConstantBuffer) { texOp.SetHandle(src0.GetCbufOffset(), src0.GetCbufSlot()); - texOp.Format = config.GetTextureFormat(texOp.Handle); + texOp.Format = config.GetTextureFormat(texOp.Handle, texOp.CbufSlot); } } } diff --git a/Ryujinx.Graphics.Shader/Translation/Rewriter.cs b/Ryujinx.Graphics.Shader/Translation/Rewriter.cs index a928f9357..5427c013a 100644 --- a/Ryujinx.Graphics.Shader/Translation/Rewriter.cs +++ b/Ryujinx.Graphics.Shader/Translation/Rewriter.cs @@ -142,7 +142,7 @@ namespace Ryujinx.Graphics.Shader.Translation bool hasInvalidOffset = (hasOffset || hasOffsets) && !config.GpuAccessor.QuerySupportsNonConstantTextureOffset(); - bool isRect = config.GpuAccessor.QueryIsTextureRectangle(texOp.Handle); + bool isRect = config.GpuAccessor.QueryIsTextureRectangle(texOp.Handle, texOp.CbufSlot); if (!(hasInvalidOffset || isRect)) { @@ -433,7 +433,7 @@ namespace Ryujinx.Graphics.Shader.Translation { TextureOperation texOp = (TextureOperation)node.Value; - TextureFormat format = config.GpuAccessor.QueryTextureFormat(texOp.Handle); + TextureFormat format = config.GpuAccessor.QueryTextureFormat(texOp.Handle, texOp.CbufSlot); int maxPositive = format switch { diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs index c71a83984..077ce70d9 100644 --- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs +++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs @@ -91,7 +91,7 @@ namespace Ryujinx.Graphics.Shader.Translation return count + 1; } - public TextureFormat GetTextureFormat(int handle) + public TextureFormat GetTextureFormat(int handle, int cbufSlot = -1) { // When the formatted load extension is supported, we don't need to // specify a format, we can just declare it without a format and the GPU will handle it. @@ -100,7 +100,7 @@ namespace Ryujinx.Graphics.Shader.Translation return TextureFormat.Unknown; } - var format = GpuAccessor.QueryTextureFormat(handle); + var format = GpuAccessor.QueryTextureFormat(handle, cbufSlot); if (format == TextureFormat.Unknown) {