diff --git a/Ryujinx.Core/Gpu/NvGpu.cs b/Ryujinx.Core/Gpu/NvGpu.cs index 71df76ff31..0fca7b9923 100644 --- a/Ryujinx.Core/Gpu/NvGpu.cs +++ b/Ryujinx.Core/Gpu/NvGpu.cs @@ -3,7 +3,7 @@ using System.Threading; namespace Ryujinx.Core.Gpu { - public class NvGpu + class NvGpu { public IGalRenderer Renderer { get; private set; } diff --git a/Ryujinx.Core/Gpu/NvGpuBufferType.cs b/Ryujinx.Core/Gpu/NvGpuBufferType.cs new file mode 100644 index 0000000000..6c4e7d10be --- /dev/null +++ b/Ryujinx.Core/Gpu/NvGpuBufferType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Core.Gpu +{ + enum NvGpuBufferType + { + Index, + Vertex, + Texture + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Gpu/NvGpuEngine2d.cs b/Ryujinx.Core/Gpu/NvGpuEngine2d.cs index 88395b7ab5..c419355e86 100644 --- a/Ryujinx.Core/Gpu/NvGpuEngine2d.cs +++ b/Ryujinx.Core/Gpu/NvGpuEngine2d.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace Ryujinx.Core.Gpu { - public class NvGpuEngine2d : INvGpuEngine + class NvGpuEngine2d : INvGpuEngine { private enum CopyOperation { diff --git a/Ryujinx.Core/Gpu/NvGpuEngine3d.cs b/Ryujinx.Core/Gpu/NvGpuEngine3d.cs index fe3ba7468c..76d21f12c3 100644 --- a/Ryujinx.Core/Gpu/NvGpuEngine3d.cs +++ b/Ryujinx.Core/Gpu/NvGpuEngine3d.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; namespace Ryujinx.Core.Gpu { - public class NvGpuEngine3d : INvGpuEngine + class NvGpuEngine3d : INvGpuEngine { public int[] Registers { get; private set; } @@ -277,11 +277,11 @@ namespace Ryujinx.Core.Gpu { GalTexture NewTexture = TextureFactory.MakeTexture(Vmm, TicPosition); - if (Gpu.Renderer.TryGetCachedTexture(Tag, out GalTexture Texture)) - { - long Size = (uint)TextureHelper.GetTextureSize(NewTexture); + long Size = (uint)TextureHelper.GetTextureSize(NewTexture); - if (NewTexture.Equals(Texture) && !Vmm.IsRegionModified(Tag, Size)) + if (Gpu.Renderer.TryGetCachedTexture(Tag, Size, out GalTexture Texture)) + { + if (NewTexture.Equals(Texture) && !Vmm.IsRegionModified(Tag, Size, NvGpuBufferType.Texture)) { Gpu.Renderer.BindTexture(Tag, TexIndex); @@ -349,7 +349,9 @@ namespace Ryujinx.Core.Gpu { int IbSize = IndexCount * IndexSize; - if (!Gpu.Renderer.IsIboCached(IndexPosition) || Vmm.IsRegionModified(IndexPosition, (uint)IbSize)) + bool IboCached = Gpu.Renderer.IsIboCached(IndexPosition, (uint)IbSize); + + if (!IboCached || Vmm.IsRegionModified(IndexPosition, (uint)IbSize, NvGpuBufferType.Index)) { byte[] Data = Vmm.ReadBytes(IndexPosition, (uint)IbSize); @@ -418,7 +420,9 @@ namespace Ryujinx.Core.Gpu VbSize = VertexCount * Stride; } - if (!Gpu.Renderer.IsVboCached(VertexPosition) || Vmm.IsRegionModified(VertexPosition, VbSize)) + bool VboCached = Gpu.Renderer.IsVboCached(VertexPosition, VbSize); + + if (!VboCached || Vmm.IsRegionModified(VertexPosition, VbSize, NvGpuBufferType.Vertex)) { byte[] Data = Vmm.ReadBytes(VertexPosition, VbSize); diff --git a/Ryujinx.Core/Gpu/NvGpuFifo.cs b/Ryujinx.Core/Gpu/NvGpuFifo.cs index d0e6fc14a0..6a309b1822 100644 --- a/Ryujinx.Core/Gpu/NvGpuFifo.cs +++ b/Ryujinx.Core/Gpu/NvGpuFifo.cs @@ -2,7 +2,7 @@ using System.Collections.Concurrent; namespace Ryujinx.Core.Gpu { - public class NvGpuFifo + class NvGpuFifo { private const int MacrosCount = 0x80; private const int MacroIndexMask = MacrosCount - 1; diff --git a/Ryujinx.Core/Gpu/NvGpuPBEntry.cs b/Ryujinx.Core/Gpu/NvGpuPBEntry.cs index ebf35b9e42..d640656bd6 100644 --- a/Ryujinx.Core/Gpu/NvGpuPBEntry.cs +++ b/Ryujinx.Core/Gpu/NvGpuPBEntry.cs @@ -3,7 +3,7 @@ using System.Collections.ObjectModel; namespace Ryujinx.Core.Gpu { - public struct NvGpuPBEntry + struct NvGpuPBEntry { public int Method { get; private set; } diff --git a/Ryujinx.Core/Gpu/NvGpuPushBuffer.cs b/Ryujinx.Core/Gpu/NvGpuPushBuffer.cs index d55886559e..867bbe9875 100644 --- a/Ryujinx.Core/Gpu/NvGpuPushBuffer.cs +++ b/Ryujinx.Core/Gpu/NvGpuPushBuffer.cs @@ -3,7 +3,7 @@ using System.IO; namespace Ryujinx.Core.Gpu { - public static class NvGpuPushBuffer + static class NvGpuPushBuffer { private enum SubmissionMode { diff --git a/Ryujinx.Core/Gpu/NvGpuVmm.cs b/Ryujinx.Core/Gpu/NvGpuVmm.cs index 2a1b9864c3..9fa288d957 100644 --- a/Ryujinx.Core/Gpu/NvGpuVmm.cs +++ b/Ryujinx.Core/Gpu/NvGpuVmm.cs @@ -1,12 +1,10 @@ using ChocolArm64.Memory; using Ryujinx.Graphics.Gal; -using System; using System.Collections.Concurrent; -using System.Collections.Generic; namespace Ryujinx.Core.Gpu { - public class NvGpuVmm : IAMemory, IGalMemory + class NvGpuVmm : IAMemory, IGalMemory { public const long AddrSize = 1L << 40; @@ -39,50 +37,7 @@ namespace Ryujinx.Core.Gpu private ConcurrentDictionary Maps; - private class CachedPage - { - private List<(long Start, long End)> Regions; - - public CachedPage() - { - Regions = new List<(long, long)>(); - } - - public bool AddRange(long Start, long End) - { - for (int Index = 0; Index < Regions.Count; Index++) - { - (long RgStart, long RgEnd) = Regions[Index]; - - if (Start >= RgStart && End <= RgEnd) - { - return false; - } - - if (Start <= RgEnd && RgStart <= End) - { - long MinStart = Math.Min(RgStart, Start); - long MaxEnd = Math.Max(RgEnd, End); - - Regions[Index] = (MinStart, MaxEnd); - - return true; - } - } - - Regions.Add((Start, End)); - - return true; - } - - private static bool InRange(long Start, long End, long Value) - { - return (ulong)Value >= (ulong)Start && - (ulong)Value < (ulong)End; - } - } - - private Dictionary CachedPages; + private NvGpuVmmCache Cache; private const long PteUnmapped = -1; private const long PteReserved = -2; @@ -95,7 +50,7 @@ namespace Ryujinx.Core.Gpu Maps = new ConcurrentDictionary(); - CachedPages = new Dictionary(); + Cache = new NvGpuVmmCache(); PageTable = new long[PTLvl0Size][]; } @@ -319,62 +274,11 @@ namespace Ryujinx.Core.Gpu PageTable[L0][L1] = TgtAddr; } - public bool IsRegionModified(long Position, long Size) + public bool IsRegionModified(long Position, long Size, NvGpuBufferType BufferType) { - Position = GetPhysicalAddress(Position); + long PA = GetPhysicalAddress(Position); - long PageSize = Memory.GetHostPageSize(); - - long Mask = PageSize - 1; - - long EndPos = Position + Size; - - bool RegMod = false; - - while (Position < EndPos) - { - long Key = Position & ~Mask; - - long PgEndPos = (Position + PageSize) & ~Mask; - - if (PgEndPos > EndPos) - { - PgEndPos = EndPos; - } - - CachedPage Cp; - - if (Memory.IsRegionModified(Position, PgEndPos - Position)) - { - Cp = new CachedPage(); - - if (CachedPages.ContainsKey(Key)) - { - CachedPages[Key] = Cp; - } - else - { - CachedPages.Add(Key, Cp); - } - - RegMod = true; - } - else - { - if (!CachedPages.TryGetValue(Key, out Cp)) - { - Cp = new CachedPage(); - - CachedPages.Add(Key, Cp); - } - } - - RegMod |= Cp.AddRange(Position, PgEndPos); - - Position = PgEndPos; - } - - return RegMod; + return Cache.IsRegionModified(Memory, BufferType, Position, PA, Size); } public byte ReadByte(long Position) diff --git a/Ryujinx.Core/Gpu/NvGpuVmmCache.cs b/Ryujinx.Core/Gpu/NvGpuVmmCache.cs new file mode 100644 index 0000000000..753118e953 --- /dev/null +++ b/Ryujinx.Core/Gpu/NvGpuVmmCache.cs @@ -0,0 +1,209 @@ +using ChocolArm64.Memory; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.Gpu +{ + class NvGpuVmmCache + { + private const int MaxCpCount = 10000; + private const int MaxCpTimeDelta = 60000; + + private class CachedPage + { + private List<(long Start, long End)> Regions; + + public LinkedListNode Node { get; set; } + + public int Count => Regions.Count; + + public int Timestamp { get; private set; } + + public long PABase { get; private set; } + + public NvGpuBufferType BufferType { get; private set; } + + public CachedPage(long PABase, NvGpuBufferType BufferType) + { + this.PABase = PABase; + this.BufferType = BufferType; + + Regions = new List<(long, long)>(); + } + + public bool AddRange(long Start, long End) + { + for (int Index = 0; Index < Regions.Count; Index++) + { + (long RgStart, long RgEnd) = Regions[Index]; + + if (Start >= RgStart && End <= RgEnd) + { + return false; + } + + if (Start <= RgEnd && RgStart <= End) + { + long MinStart = Math.Min(RgStart, Start); + long MaxEnd = Math.Max(RgEnd, End); + + Regions[Index] = (MinStart, MaxEnd); + + Timestamp = Environment.TickCount; + + return true; + } + } + + Regions.Add((Start, End)); + + Timestamp = Environment.TickCount; + + return true; + } + } + + private Dictionary Cache; + + private LinkedList SortedCache; + + private int CpCount; + + public NvGpuVmmCache() + { + Cache = new Dictionary(); + + SortedCache = new LinkedList(); + } + + public bool IsRegionModified( + AMemory Memory, + NvGpuBufferType BufferType, + long VA, + long PA, + long Size) + { + ClearCachedPagesIfNeeded(); + + long PageSize = Memory.GetHostPageSize(); + + long Mask = PageSize - 1; + + long VAEnd = VA + Size; + long PAEnd = PA + Size; + + bool RegMod = false; + + while (VA < VAEnd) + { + long Key = VA & ~Mask; + long PABase = PA & ~Mask; + + long VAPgEnd = Math.Min((VA + PageSize) & ~Mask, VAEnd); + long PAPgEnd = Math.Min((PA + PageSize) & ~Mask, PAEnd); + + bool IsCached = Cache.TryGetValue(Key, out CachedPage Cp); + + bool PgReset = false; + + if (!IsCached) + { + Cp = new CachedPage(PABase, BufferType); + + Cache.Add(Key, Cp); + } + else + { + CpCount -= Cp.Count; + + SortedCache.Remove(Cp.Node); + + if (Cp.PABase != PABase || + Cp.BufferType != BufferType) + { + PgReset = true; + } + } + + PgReset |= Memory.IsRegionModified(PA, PAPgEnd - PA) && IsCached; + + if (PgReset) + { + Cp = new CachedPage(PABase, BufferType); + + Cache[Key] = Cp; + } + + Cp.Node = SortedCache.AddLast(Key); + + RegMod |= Cp.AddRange(VA, VAPgEnd); + + CpCount += Cp.Count; + + VA = VAPgEnd; + PA = PAPgEnd; + } + + return RegMod; + } + + private void ClearCachedPagesIfNeeded() + { + if (CpCount <= MaxCpCount) + { + return; + } + + int Timestamp = Environment.TickCount; + + int TimeDelta; + + do + { + if (!TryPopOldestCachedPageKey(Timestamp, out long Key)) + { + break; + } + + CachedPage Cp = Cache[Key]; + + Cache.Remove(Key); + + CpCount -= Cp.Count; + + TimeDelta = RingDelta(Cp.Timestamp, Timestamp); + } + while (CpCount > (MaxCpCount >> 1) || (uint)TimeDelta > (uint)MaxCpTimeDelta); + } + + private bool TryPopOldestCachedPageKey(int Timestamp, out long Key) + { + LinkedListNode Node = SortedCache.First; + + if (Node == null) + { + Key = 0; + + return false; + } + + SortedCache.Remove(Node); + + Key = Node.Value; + + return true; + } + + private int RingDelta(int Old, int New) + { + if ((uint)New < (uint)Old) + { + return New + (~Old + 1); + } + else + { + return New - Old; + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Gpu/Texture.cs b/Ryujinx.Core/Gpu/Texture.cs index 39a35059bc..022df83feb 100644 --- a/Ryujinx.Core/Gpu/Texture.cs +++ b/Ryujinx.Core/Gpu/Texture.cs @@ -2,7 +2,7 @@ using Ryujinx.Graphics.Gal; namespace Ryujinx.Core.Gpu { - public struct Texture + struct Texture { public long Position { get; private set; } diff --git a/Ryujinx.Core/Gpu/TextureReader.cs b/Ryujinx.Core/Gpu/TextureReader.cs index ae3b00007f..acd17c5dc0 100644 --- a/Ryujinx.Core/Gpu/TextureReader.cs +++ b/Ryujinx.Core/Gpu/TextureReader.cs @@ -4,7 +4,7 @@ using System; namespace Ryujinx.Core.Gpu { - public static class TextureReader + static class TextureReader { public static byte[] Read(IAMemory Memory, Texture Texture) { diff --git a/Ryujinx.Core/Gpu/TextureSwizzle.cs b/Ryujinx.Core/Gpu/TextureSwizzle.cs index 3214f45f81..fbca40e123 100644 --- a/Ryujinx.Core/Gpu/TextureSwizzle.cs +++ b/Ryujinx.Core/Gpu/TextureSwizzle.cs @@ -1,6 +1,6 @@ namespace Ryujinx.Core.Gpu { - public enum TextureSwizzle + enum TextureSwizzle { _1dBuffer = 0, PitchColorKey = 1, diff --git a/Ryujinx.Core/Gpu/TextureWriter.cs b/Ryujinx.Core/Gpu/TextureWriter.cs index 125bb8c4f5..686d0dce63 100644 --- a/Ryujinx.Core/Gpu/TextureWriter.cs +++ b/Ryujinx.Core/Gpu/TextureWriter.cs @@ -4,7 +4,7 @@ using System; namespace Ryujinx.Core.Gpu { - public static class TextureWriter + static class TextureWriter { public static void Write(IAMemory Memory, Texture Texture, byte[] Data) { diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs index 372b4e8885..b8f83469bd 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderer.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs @@ -49,9 +49,9 @@ namespace Ryujinx.Graphics.Gal //Rasterizer void ClearBuffers(int RtIndex, GalClearBufferFlags Flags); - bool IsVboCached(long Tag); + bool IsVboCached(long Tag, long DataSize); - bool IsIboCached(long Tag); + bool IsIboCached(long Tag, long DataSize); void CreateVbo(long Tag, byte[] Buffer); @@ -83,7 +83,7 @@ namespace Ryujinx.Graphics.Gal //Texture void SetTextureAndSampler(long Tag, byte[] Data, GalTexture Texture, GalTextureSampler Sampler); - bool TryGetCachedTexture(long Tag, out GalTexture Texture); + bool TryGetCachedTexture(long Tag, long DataSize, out GalTexture Texture); void BindTexture(long Tag, int Index); } diff --git a/Ryujinx.Graphics/Gal/OpenGL/DeleteValueCallback.cs b/Ryujinx.Graphics/Gal/OpenGL/DeleteValueCallback.cs new file mode 100644 index 0000000000..acd8d72f66 --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/DeleteValueCallback.cs @@ -0,0 +1,4 @@ +namespace Ryujinx.Graphics.Gal.OpenGL +{ + delegate void DeleteValue(T Value); +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs new file mode 100644 index 0000000000..06d76b8bdd --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + class OGLCachedResource + { + public delegate void DeleteValue(T Value); + + private const int MaxTimeDelta = 5 * 60000; + private const int MaxRemovalsPerRun = 10; + + private struct CacheBucket + { + public T Value { get; private set; } + + public LinkedListNode Node { get; private set; } + + public long DataSize { get; private set; } + + public int Timestamp { get; private set; } + + public CacheBucket(T Value, long DataSize, LinkedListNode Node) + { + this.Value = Value; + this.DataSize = DataSize; + this.Node = Node; + + Timestamp = Environment.TickCount; + } + } + + private Dictionary Cache; + + private LinkedList SortedCache; + + private DeleteValue DeleteValueCallback; + + public OGLCachedResource(DeleteValue DeleteValueCallback) + { + if (DeleteValueCallback == null) + { + throw new ArgumentNullException(nameof(DeleteValueCallback)); + } + + this.DeleteValueCallback = DeleteValueCallback; + + Cache = new Dictionary(); + + SortedCache = new LinkedList(); + } + + public void AddOrUpdate(long Key, T Value, long Size) + { + ClearCacheIfNeeded(); + + LinkedListNode Node = SortedCache.AddLast(Key); + + CacheBucket NewBucket = new CacheBucket(Value, Size, Node); + + if (Cache.TryGetValue(Key, out CacheBucket Bucket)) + { + DeleteValueCallback(Bucket.Value); + + SortedCache.Remove(Bucket.Node); + + Cache[Key] = NewBucket; + } + else + { + Cache.Add(Key, NewBucket); + } + } + + public bool TryGetValue(long Key, out T Value) + { + if (Cache.TryGetValue(Key, out CacheBucket Bucket)) + { + Value = Bucket.Value; + + return true; + } + + Value = default(T); + + return false; + } + + public bool TryGetSize(long Key, out long Size) + { + if (Cache.TryGetValue(Key, out CacheBucket Bucket)) + { + Size = Bucket.DataSize; + + return true; + } + + Size = 0; + + return false; + } + + private void ClearCacheIfNeeded() + { + int Timestamp = Environment.TickCount; + + int Count = 0; + + while (Count++ < MaxRemovalsPerRun) + { + LinkedListNode Node = SortedCache.First; + + if (Node == null) + { + break; + } + + CacheBucket Bucket = Cache[Node.Value]; + + int TimeDelta = RingDelta(Bucket.Timestamp, Timestamp); + + if ((uint)TimeDelta <= (uint)MaxTimeDelta) + { + break; + } + + SortedCache.Remove(Node); + + Cache.Remove(Node.Value); + + DeleteValueCallback(Bucket.Value); + } + } + + private int RingDelta(int Old, int New) + { + if ((uint)New < (uint)Old) + { + return New + (~Old + 1); + } + else + { + return New - Old; + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs index 1876666891..b63c8b358c 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs @@ -44,6 +44,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL { GalVertexAttribSize._11_11_10, VertexAttribPointerType.Int } //? }; + private int VaoHandle; + + private int[] VertexBuffers; + + private OGLCachedResource VboCache; + private OGLCachedResource IboCache; + private struct IbInfo { public int Count; @@ -51,21 +58,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL public DrawElementsType Type; } - private int VaoHandle; - - private int[] VertexBuffers; - - private Dictionary VboCache; - private Dictionary IboCache; - private IbInfo IndexBuffer; public OGLRasterizer() { VertexBuffers = new int[32]; - VboCache = new Dictionary(); - IboCache = new Dictionary(); + VboCache = new OGLCachedResource(GL.DeleteBuffer); + IboCache = new OGLCachedResource(GL.DeleteBuffer); IndexBuffer = new IbInfo(); } @@ -97,24 +97,21 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.Clear(Mask); } - public bool IsVboCached(long Tag) + public bool IsVboCached(long Tag, long DataSize) { - return VboCache.ContainsKey(Tag); + return VboCache.TryGetSize(Tag, out long Size) && Size == DataSize; } - public bool IsIboCached(long Tag) + public bool IsIboCached(long Tag, long DataSize) { - return IboCache.ContainsKey(Tag); + return IboCache.TryGetSize(Tag, out long Size) && Size == DataSize; } public void CreateVbo(long Tag, byte[] Buffer) { - if (!VboCache.TryGetValue(Tag, out int Handle)) - { - Handle = GL.GenBuffer(); + int Handle = GL.GenBuffer(); - VboCache.Add(Tag, Handle); - } + VboCache.AddOrUpdate(Tag, Handle, (uint)Buffer.Length); IntPtr Length = new IntPtr(Buffer.Length); @@ -125,12 +122,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL public void CreateIbo(long Tag, byte[] Buffer) { - if (!IboCache.TryGetValue(Tag, out int Handle)) - { - Handle = GL.GenBuffer(); + int Handle = GL.GenBuffer(); - IboCache.Add(Tag, Handle); - } + IboCache.AddOrUpdate(Tag, Handle, (uint)Buffer.Length); IntPtr Length = new IntPtr(Buffer.Length); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs index 816e274bac..540e473592 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -1,7 +1,6 @@ using OpenTK.Graphics.OpenGL; using Ryujinx.Graphics.Gal.Texture; using System; -using System.Collections.Generic; namespace Ryujinx.Graphics.Gal.OpenGL { @@ -20,29 +19,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - private Dictionary TextureCache; + private OGLCachedResource TextureCache; public OGLTexture() { - TextureCache = new Dictionary(); + TextureCache = new OGLCachedResource(DeleteTexture); + } + + private static void DeleteTexture(TCE CachedTexture) + { + GL.DeleteTexture(CachedTexture.Handle); } public void Create(long Tag, byte[] Data, GalTexture Texture) { - if (!TextureCache.TryGetValue(Tag, out TCE CachedTexture)) - { - int Handle = GL.GenTexture(); + int Handle = GL.GenTexture(); - CachedTexture = new TCE(Handle, Texture); + TextureCache.AddOrUpdate(Tag, new TCE(Handle, Texture), (uint)Data.Length); - TextureCache.Add(Tag, CachedTexture); - } - else - { - CachedTexture.Texture = Texture; - } - - GL.BindTexture(TextureTarget.Texture2D, CachedTexture.Handle); + GL.BindTexture(TextureTarget.Texture2D, Handle); const int Level = 0; //TODO: Support mipmap textures. const int Border = 0; @@ -151,13 +146,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL throw new ArgumentException(nameof(Format)); } - public bool TryGetCachedTexture(long Tag, out GalTexture Texture) + public bool TryGetCachedTexture(long Tag, long DataSize, out GalTexture Texture) { - if (TextureCache.TryGetValue(Tag, out TCE CachedTexture)) + if (TextureCache.TryGetSize(Tag, out long Size) && Size == DataSize) { - Texture = CachedTexture.Texture; + if (TextureCache.TryGetValue(Tag, out TCE CachedTexture)) + { + Texture = CachedTexture.Texture; - return true; + return true; + } } Texture = default(GalTexture); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs index c474abc702..4c4bd2caea 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs @@ -156,14 +156,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags)); } - public bool IsVboCached(long Tag) + public bool IsVboCached(long Tag, long DataSize) { - return Rasterizer.IsVboCached(Tag); + return Rasterizer.IsVboCached(Tag, DataSize); } - public bool IsIboCached(long Tag) + public bool IsIboCached(long Tag, long DataSize) { - return Rasterizer.IsIboCached(Tag); + return Rasterizer.IsIboCached(Tag, DataSize); } public void CreateVbo(long Tag, byte[] Buffer) @@ -271,9 +271,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL }); } - public bool TryGetCachedTexture(long Tag, out GalTexture Texture) + public bool TryGetCachedTexture(long Tag, long DataSize, out GalTexture Texture) { - return this.Texture.TryGetCachedTexture(Tag, out Texture); + return this.Texture.TryGetCachedTexture(Tag, DataSize, out Texture); } public void BindTexture(long Tag, int Index)