3c3bcd82fe
* Add a sampler pool cache and improve texture pool cache * Increase disposal timestamp delta more to be on the safe side * Nits * Use abstract class for PoolCache, remove factory callback
129 lines
No EOL
4.2 KiB
C#
129 lines
No EOL
4.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Ryujinx.Graphics.Gpu.Image
|
|
{
|
|
/// <summary>
|
|
/// Resource pool interface.
|
|
/// </summary>
|
|
/// <typeparam name="T">Resource pool type</typeparam>
|
|
interface IPool<T>
|
|
{
|
|
/// <summary>
|
|
/// Start address of the pool in memory.
|
|
/// </summary>
|
|
ulong Address { get; }
|
|
|
|
/// <summary>
|
|
/// Linked list node used on the texture pool cache.
|
|
/// </summary>
|
|
LinkedListNode<T> CacheNode { get; set; }
|
|
|
|
/// <summary>
|
|
/// Timestamp set on the last use of the pool by the cache.
|
|
/// </summary>
|
|
ulong CacheTimestamp { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Pool cache.
|
|
/// This can keep multiple pools, and return the current one as needed.
|
|
/// </summary>
|
|
abstract class PoolCache<T> : IDisposable where T : IPool<T>, IDisposable
|
|
{
|
|
private const int MaxCapacity = 2;
|
|
private const ulong MinDeltaForRemoval = 20000;
|
|
|
|
private readonly GpuContext _context;
|
|
private readonly LinkedList<T> _pools;
|
|
private ulong _currentTimestamp;
|
|
|
|
/// <summary>
|
|
/// Constructs a new instance of the pool.
|
|
/// </summary>
|
|
/// <param name="context">GPU context that the texture pool belongs to</param>
|
|
public PoolCache(GpuContext context)
|
|
{
|
|
_context = context;
|
|
_pools = new LinkedList<T>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Increments the internal timestamp of the cache that is used to decide when old resources will be deleted.
|
|
/// </summary>
|
|
public void Tick()
|
|
{
|
|
_currentTimestamp++;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds a cache texture pool, or creates a new one if not found.
|
|
/// </summary>
|
|
/// <param name="channel">GPU channel that the texture pool cache belongs to</param>
|
|
/// <param name="address">Start address of the texture pool</param>
|
|
/// <param name="maximumId">Maximum ID of the texture pool</param>
|
|
/// <returns>The found or newly created texture pool</returns>
|
|
public T FindOrCreate(GpuChannel channel, ulong address, int maximumId)
|
|
{
|
|
// Remove old entries from the cache, if possible.
|
|
while (_pools.Count > MaxCapacity && (_currentTimestamp - _pools.First.Value.CacheTimestamp) >= MinDeltaForRemoval)
|
|
{
|
|
T oldestPool = _pools.First.Value;
|
|
|
|
_pools.RemoveFirst();
|
|
oldestPool.Dispose();
|
|
oldestPool.CacheNode = null;
|
|
}
|
|
|
|
T pool;
|
|
|
|
// Try to find the pool on the cache.
|
|
for (LinkedListNode<T> node = _pools.First; node != null; node = node.Next)
|
|
{
|
|
pool = node.Value;
|
|
|
|
if (pool.Address == address)
|
|
{
|
|
if (pool.CacheNode != _pools.Last)
|
|
{
|
|
_pools.Remove(pool.CacheNode);
|
|
|
|
pool.CacheNode = _pools.AddLast(pool);
|
|
}
|
|
|
|
pool.CacheTimestamp = _currentTimestamp;
|
|
|
|
return pool;
|
|
}
|
|
}
|
|
|
|
// If not found, create a new one.
|
|
pool = CreatePool(_context, channel, address, maximumId);
|
|
|
|
pool.CacheNode = _pools.AddLast(pool);
|
|
pool.CacheTimestamp = _currentTimestamp;
|
|
|
|
return pool;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new instance of the pool.
|
|
/// </summary>
|
|
/// <param name="context">GPU context that the pool belongs to</param>
|
|
/// <param name="channel">GPU channel that the pool belongs to</param>
|
|
/// <param name="address">Address of the pool in guest memory</param>
|
|
/// <param name="maximumId">Maximum ID of the pool (equal to maximum minus one)</param>
|
|
protected abstract T CreatePool(GpuContext context, GpuChannel channel, ulong address, int maximumId);
|
|
|
|
public void Dispose()
|
|
{
|
|
foreach (T pool in _pools)
|
|
{
|
|
pool.Dispose();
|
|
pool.CacheNode = null;
|
|
}
|
|
|
|
_pools.Clear();
|
|
}
|
|
}
|
|
} |