From 383c0390370aa52243abfd1189d23b080cbfbb14 Mon Sep 17 00:00:00 2001 From: Mary Date: Tue, 17 Nov 2020 22:20:17 +0100 Subject: [PATCH] shader cache: Fix invalid virtual address clean up (#1717) * shader cache: Fix invalid virtual address clean up This fix an issue causing the virtual address of texture descriptors to not be cleaned up when caching and instead cleaning texture format and swizzle. This should fix duplicate high duplication in the cache for certain games and possible texture corruption issues. **THIS WILL INVALIDATE ALL SHADER CACHE LEVELS CONSIDERING THE NATURE OF THE ISSUE** * shader cache: Address gdk's comment --- .../Image/ITextureDescriptor.cs | 10 ++++++ .../Image/TextureDescriptor.cs | 12 +++---- Ryujinx.Graphics.Gpu/Image/TextureTarget.cs | 2 +- .../Shader/Cache/CacheManager.cs | 2 +- .../Definition/GuestTextureDescriptor.cs | 34 ++++++++++++++++--- .../Shader/CachedGpuAccessor.cs | 10 +++--- Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs | 2 +- Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | 6 ++-- .../TextureDescriptorCapableGpuAccessor.cs | 2 +- 9 files changed, 58 insertions(+), 22 deletions(-) create mode 100644 Ryujinx.Graphics.Gpu/Image/ITextureDescriptor.cs diff --git a/Ryujinx.Graphics.Gpu/Image/ITextureDescriptor.cs b/Ryujinx.Graphics.Gpu/Image/ITextureDescriptor.cs new file mode 100644 index 00000000..378de44b --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Image/ITextureDescriptor.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Graphics.Gpu.Image +{ + interface ITextureDescriptor + { + public uint UnpackFormat(); + public TextureTarget UnpackTextureTarget(); + public bool UnpackSrgb(); + public bool UnpackTextureCoordNormalized(); + } +} diff --git a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs index 74fb9887..76d97bf8 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs @@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Maxwell texture descriptor, as stored on the GPU texture pool memory region. /// - struct TextureDescriptor + struct TextureDescriptor : ITextureDescriptor { #pragma warning disable CS0649 public uint Word0; @@ -239,12 +239,12 @@ namespace Ryujinx.Graphics.Gpu.Image GuestTextureDescriptor result = new GuestTextureDescriptor { Handle = uint.MaxValue, - Descriptor = this - }; + Format = UnpackFormat(), + Target = UnpackTextureTarget(), + IsSrgb = UnpackSrgb(), + IsTextureCoordNormalized = UnpackTextureCoordNormalized(), - // Clear the virtual address - result.Descriptor.Word0 = 0; - result.Descriptor.Word2 &= 0xFFFF0000; + }; return result; } diff --git a/Ryujinx.Graphics.Gpu/Image/TextureTarget.cs b/Ryujinx.Graphics.Gpu/Image/TextureTarget.cs index 301fc87b..1db758fc 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureTarget.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureTarget.cs @@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// /// Texture target. /// - enum TextureTarget + enum TextureTarget : byte { Texture1D, Texture2D, diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/CacheManager.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/CacheManager.cs index d241eb01..0c4eba2a 100644 --- a/Ryujinx.Graphics.Gpu/Shader/Cache/CacheManager.cs +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/CacheManager.cs @@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache /// /// Version of the guest cache shader (to increment when guest cache structure change). /// - private const ulong GuestCacheVersion = 1; + private const ulong GuestCacheVersion = 1717; /// /// Create a new cache manager instance diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestTextureDescriptor.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestTextureDescriptor.cs index 7c73ef7b..9491496d 100644 --- a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestTextureDescriptor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestTextureDescriptor.cs @@ -4,12 +4,38 @@ using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition { /// - /// Mostly identical to TextureDescriptor from but we don't store the address of the texture and store its handle instead. + /// Contains part of TextureDescriptor from used for shader codegen. /// - [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 1)] - struct GuestTextureDescriptor + [StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 1)] + struct GuestTextureDescriptor : ITextureDescriptor { public uint Handle; - internal TextureDescriptor Descriptor; + public uint Format; + public TextureTarget Target; + [MarshalAs(UnmanagedType.I1)] + public bool IsSrgb; + [MarshalAs(UnmanagedType.I1)] + public bool IsTextureCoordNormalized; + public byte Reserved; + + public uint UnpackFormat() + { + return Format; + } + + public bool UnpackSrgb() + { + return IsSrgb; + } + + public bool UnpackTextureCoordNormalized() + { + return IsTextureCoordNormalized; + } + + public TextureTarget UnpackTextureTarget() + { + return Target; + } } } diff --git a/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs index 5f1458fa..02136982 100644 --- a/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Gpu.Shader private readonly GpuContext _context; private readonly ReadOnlyMemory _data; private readonly GuestGpuAccessorHeader _header; - private readonly Dictionary _textureDescriptors; + private readonly Dictionary _textureDescriptors; /// /// Creates a new instance of the cached GPU state accessor for shader translation. @@ -26,11 +26,11 @@ namespace Ryujinx.Graphics.Gpu.Shader _context = context; _data = data; _header = header; - _textureDescriptors = new Dictionary(); + _textureDescriptors = new Dictionary(); foreach (KeyValuePair guestTextureDescriptor in guestTextureDescriptors) { - _textureDescriptors.Add(guestTextureDescriptor.Key, guestTextureDescriptor.Value.Descriptor); + _textureDescriptors.Add(guestTextureDescriptor.Key, guestTextureDescriptor.Value); } } @@ -141,9 +141,9 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Index of the texture (this is the word offset of the handle in the constant buffer) /// Texture descriptor - public override Image.TextureDescriptor GetTextureDescriptor(int handle) + public override Image.ITextureDescriptor GetTextureDescriptor(int handle) { - if (!_textureDescriptors.TryGetValue(handle, out Image.TextureDescriptor textureDescriptor)) + if (!_textureDescriptors.TryGetValue(handle, out GuestTextureDescriptor textureDescriptor)) { throw new ArgumentException(); } diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs index b3f1b3a8..2783714b 100644 --- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs @@ -185,7 +185,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Index of the texture (this is the word offset of the handle in the constant buffer) /// Texture descriptor - public override Image.TextureDescriptor GetTextureDescriptor(int handle) + public override Image.ITextureDescriptor GetTextureDescriptor(int handle) { if (_compute) { diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index ac5aedbe..b469aab5 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -35,9 +35,9 @@ namespace Ryujinx.Graphics.Gpu.Shader private Dictionary _cpProgramsDiskCache; /// - /// Version of the codegen (to be incremented when codegen changes). + /// Version of the codegen (to be changed when codegen or guest format change). /// - private const ulong ShaderCodeGenVersion = 1; + private const ulong ShaderCodeGenVersion = 1717; /// /// Creates a new instance of the shader cache. @@ -888,7 +888,7 @@ namespace Ryujinx.Graphics.Gpu.Shader foreach (int textureHandle in textureHandlesInUse) { - GuestTextureDescriptor textureDescriptor = gpuAccessor.GetTextureDescriptor(textureHandle).ToCache(); + GuestTextureDescriptor textureDescriptor = ((Image.TextureDescriptor)gpuAccessor.GetTextureDescriptor(textureHandle)).ToCache(); textureDescriptor.Handle = (uint)textureHandle; diff --git a/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs index 7901fe59..dc0e392b 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 Image.TextureDescriptor GetTextureDescriptor(int handle); + public abstract ITextureDescriptor GetTextureDescriptor(int handle); /// /// Queries texture format information, for shaders using image load or store.