aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-06-08 21:15:56 -0300
committerGitHub <noreply@github.com>2018-06-08 21:15:56 -0300
commit231fae1a4c97d7588655e9775f37c1dc9bd55fb0 (patch)
tree1c0e7b298ec33d5bf5b6a5693dd69a8c7e0bd23b /Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs
parent6fe51f970501fe732276c17ed0dacb564b92a73d (diff)
Texture/Vertex/Index data cache (#132)
* Initial implementation of the texture cache * Cache vertex and index data aswell, some cleanup * Improve handling of the cache by storing cached ranges on a list for each page * Delete old data from the caches automatically, ensure that the cache is cleaned when the mapping/size changes, and some general cleanup
Diffstat (limited to 'Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs')
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs147
1 files changed, 147 insertions, 0 deletions
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs
new file mode 100644
index 00000000..06d76b8b
--- /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<T>
+ {
+ 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<long> Node { get; private set; }
+
+ public long DataSize { get; private set; }
+
+ public int Timestamp { get; private set; }
+
+ public CacheBucket(T Value, long DataSize, LinkedListNode<long> Node)
+ {
+ this.Value = Value;
+ this.DataSize = DataSize;
+ this.Node = Node;
+
+ Timestamp = Environment.TickCount;
+ }
+ }
+
+ private Dictionary<long, CacheBucket> Cache;
+
+ private LinkedList<long> SortedCache;
+
+ private DeleteValue DeleteValueCallback;
+
+ public OGLCachedResource(DeleteValue DeleteValueCallback)
+ {
+ if (DeleteValueCallback == null)
+ {
+ throw new ArgumentNullException(nameof(DeleteValueCallback));
+ }
+
+ this.DeleteValueCallback = DeleteValueCallback;
+
+ Cache = new Dictionary<long, CacheBucket>();
+
+ SortedCache = new LinkedList<long>();
+ }
+
+ public void AddOrUpdate(long Key, T Value, long Size)
+ {
+ ClearCacheIfNeeded();
+
+ LinkedListNode<long> 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<long> 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