From 1f554c1093dde6a4d3ed80fae2675abfb6c12fac Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 3 Mar 2019 19:45:25 -0600 Subject: Do naming refactoring on Ryujinx.Graphics (#611) * Renaming part 1 * Renaming part 2 * Renaming part 3 * Renaming part 4 * Renaming part 5 * Renaming part 6 * Renaming part 7 * Renaming part 8 * Renaming part 9 * Renaming part 10 * General cleanup * Thought I got all of these * Apply #595 * Additional renaming * Tweaks from feedback * Rename files --- Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs | 191 +++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs (limited to 'Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs') diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs b/Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs new file mode 100644 index 00000000..91f0a7e1 --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs @@ -0,0 +1,191 @@ +using Ryujinx.Common; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + class OglCachedResource + { + public delegate void DeleteValue(T value); + + private const int MinTimeDelta = 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 long Timestamp { get; private set; } + + public CacheBucket(T value, long dataSize, LinkedListNode node) + { + Value = value; + DataSize = dataSize; + Node = node; + + Timestamp = PerformanceCounter.ElapsedMilliseconds; + } + } + + private Dictionary _cache; + + private LinkedList _sortedCache; + + private DeleteValue _deleteValueCallback; + + private Queue _deletePending; + + private bool _locked; + + private long _maxSize; + private long _totalSize; + + public OglCachedResource(DeleteValue deleteValueCallback, long maxSize) + { + _maxSize = maxSize; + + if (deleteValueCallback == null) + { + throw new ArgumentNullException(nameof(deleteValueCallback)); + } + + _deleteValueCallback = deleteValueCallback; + + _cache = new Dictionary(); + + _sortedCache = new LinkedList(); + + _deletePending = new Queue(); + } + + public void Lock() + { + _locked = true; + } + + public void Unlock() + { + _locked = false; + + while (_deletePending.TryDequeue(out T value)) + { + _deleteValueCallback(value); + } + + ClearCacheIfNeeded(); + } + + public void AddOrUpdate(long key, T value, long size) + { + if (!_locked) + { + ClearCacheIfNeeded(); + } + + LinkedListNode node = _sortedCache.AddLast(key); + + CacheBucket newBucket = new CacheBucket(value, size, node); + + if (_cache.TryGetValue(key, out CacheBucket bucket)) + { + if (_locked) + { + _deletePending.Enqueue(bucket.Value); + } + else + { + _deleteValueCallback(bucket.Value); + } + + _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) + { + if (_cache.TryGetValue(key, out CacheBucket bucket)) + { + value = bucket.Value; + + _sortedCache.Remove(bucket.Node); + + LinkedListNode node = _sortedCache.AddLast(key); + + _cache[key] = new CacheBucket(value, bucket.DataSize, node); + + 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() + { + long timestamp = PerformanceCounter.ElapsedMilliseconds; + + int count = 0; + + while (count++ < MaxRemovalsPerRun) + { + LinkedListNode node = _sortedCache.First; + + if (node == null) + { + break; + } + + CacheBucket bucket = _cache[node.Value]; + + long timeDelta = timestamp - bucket.Timestamp; + + if (timeDelta <= MinTimeDelta && !UnderMemoryPressure()) + { + break; + } + + _sortedCache.Remove(node); + + _cache.Remove(node.Value); + + _deleteValueCallback(bucket.Value); + + _totalSize -= bucket.DataSize; + } + } + + private bool UnderMemoryPressure() + { + return _totalSize >= _maxSize; + } + } +} \ No newline at end of file -- cgit v1.2.3