From 85ffd760161c6995f0004e042178d2e9259b2af5 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Wed, 14 Nov 2018 20:22:02 -0200
Subject: [PATCH] Force cache to remove entries when memory usage exceeds a
 given threshold (#492)

---
 .../Gal/OpenGL/OGLCachedResource.cs           | 22 ++++++++++++++++---
 Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs |  4 +++-
 Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs  |  7 ++++--
 Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs     |  4 +++-
 4 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs
index efacb4d42..6e17872ba 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs
@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
     {
         public delegate void DeleteValue(T Value);
 
-        private const int MaxTimeDelta      = 5 * 60000;
+        private const int MinTimeDelta      = 5 * 60000;
         private const int MaxRemovalsPerRun = 10;
 
         private struct CacheBucket
@@ -41,8 +41,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
         private bool Locked;
 
-        public OGLCachedResource(DeleteValue DeleteValueCallback)
+        private long MaxSize;
+        private long TotalSize;
+
+        public OGLCachedResource(DeleteValue DeleteValueCallback, long MaxSize)
         {
+            this.MaxSize = MaxSize;
+
             if (DeleteValueCallback == null)
             {
                 throw new ArgumentNullException(nameof(DeleteValueCallback));
@@ -98,12 +103,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
                 SortedCache.Remove(Bucket.Node);
 
+                TotalSize -= Bucket.DataSize;
+
                 Cache[Key] = NewBucket;
             }
             else
             {
                 Cache.Add(Key, NewBucket);
             }
+
+            TotalSize += Size;
         }
 
         public bool TryGetValue(long Key, out T Value)
@@ -159,7 +168,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
                 long TimeDelta = Timestamp - Bucket.Timestamp;
 
-                if ((uint)TimeDelta <= (uint)MaxTimeDelta)
+                if (TimeDelta <= MinTimeDelta && !UnderMemoryPressure())
                 {
                     break;
                 }
@@ -169,7 +178,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
                 Cache.Remove(Node.Value);
 
                 DeleteValueCallback(Bucket.Value);
+
+                TotalSize -= Bucket.DataSize;
             }
         }
+
+        private bool UnderMemoryPressure()
+        {
+            return TotalSize >= MaxSize;
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs
index 4958b53b3..e04190e04 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs
@@ -5,11 +5,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 {
     class OGLConstBuffer : IGalConstBuffer
     {
+        private const long MaxConstBufferCacheSize = 64 * 1024 * 1024;
+
         private OGLCachedResource<OGLStreamBuffer> Cache;
 
         public OGLConstBuffer()
         {
-            Cache = new OGLCachedResource<OGLStreamBuffer>(DeleteBuffer);
+            Cache = new OGLCachedResource<OGLStreamBuffer>(DeleteBuffer, MaxConstBufferCacheSize);
         }
 
         public void LockCache()
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs
index cefbb2d2a..cd6292f7e 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs
@@ -5,6 +5,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 {
     class OGLRasterizer : IGalRasterizer
     {
+        private const long MaxVertexBufferCacheSize = 128 * 1024 * 1024;
+        private const long MaxIndexBufferCacheSize  = 64  * 1024 * 1024;
+
         private int[] VertexBuffers;
 
         private OGLCachedResource<int> VboCache;
@@ -24,8 +27,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
         {
             VertexBuffers = new int[32];
 
-            VboCache = new OGLCachedResource<int>(GL.DeleteBuffer);
-            IboCache = new OGLCachedResource<int>(GL.DeleteBuffer);
+            VboCache = new OGLCachedResource<int>(GL.DeleteBuffer, MaxVertexBufferCacheSize);
+            IboCache = new OGLCachedResource<int>(GL.DeleteBuffer, MaxIndexBufferCacheSize);
 
             IndexBuffer = new IbInfo();
         }
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
index 274b94ea8..6f843b9c3 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
@@ -6,13 +6,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 {
     class OGLTexture : IGalTexture
     {
+        private const long MaxTextureCacheSize = 768 * 1024 * 1024;
+
         private OGLCachedResource<ImageHandler> TextureCache;
 
         public EventHandler<int> TextureDeleted { get; set; }
 
         public OGLTexture()
         {
-            TextureCache = new OGLCachedResource<ImageHandler>(DeleteTexture);
+            TextureCache = new OGLCachedResource<ImageHandler>(DeleteTexture, MaxTextureCacheSize);
         }
 
         public void LockCache()