| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- using Ryujinx.Common;
- using System;
- using System.Collections.Generic;
- namespace Ryujinx.Graphics.Gal.OpenGL
- {
- class OGLCachedResource<T>
- {
- 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<long> Node { get; private set; }
- public long DataSize { get; private set; }
- public long Timestamp { get; private set; }
- public CacheBucket(T Value, long DataSize, LinkedListNode<long> Node)
- {
- this.Value = Value;
- this.DataSize = DataSize;
- this.Node = Node;
- Timestamp = PerformanceCounter.ElapsedMilliseconds;
- }
- }
- private Dictionary<long, CacheBucket> Cache;
- private LinkedList<long> SortedCache;
- private DeleteValue DeleteValueCallback;
- private Queue<T> DeletePending;
- private bool Locked;
- private long MaxSize;
- private long TotalSize;
- public OGLCachedResource(DeleteValue DeleteValueCallback, long MaxSize)
- {
- this.MaxSize = MaxSize;
- if (DeleteValueCallback == null)
- {
- throw new ArgumentNullException(nameof(DeleteValueCallback));
- }
- this.DeleteValueCallback = DeleteValueCallback;
- Cache = new Dictionary<long, CacheBucket>();
- SortedCache = new LinkedList<long>();
- DeletePending = new Queue<T>();
- }
- 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<long> 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<long> 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<long> 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;
- }
- }
- }
|