using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.OpenGL.Image;
using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.OpenGL
{
class DisposedTexture
{
public TextureCreateInfo Info;
public TextureView View;
public int RemainingFrames;
}
///
/// A structure for pooling resources that can be reused without recreation, such as textures.
///
class ResourcePool : IDisposable
{
private const int DisposedLiveFrames = 2;
private readonly object _lock = new();
private readonly Dictionary> _textures = new();
///
/// Add a texture that is not being used anymore to the resource pool to be used later.
/// Both the texture's view and storage should be completely unused.
///
/// The texture's view
public void AddTexture(TextureView view)
{
lock (_lock)
{
if (!_textures.TryGetValue(view.Info, out List list))
{
list = new List();
_textures.Add(view.Info, list);
}
list.Add(new DisposedTexture()
{
Info = view.Info,
View = view,
RemainingFrames = DisposedLiveFrames,
});
}
}
///
/// Attempt to obtain a texture from the resource cache with the desired parameters.
///
/// The creation info for the desired texture
/// A TextureView with the description specified, or null if one was not found.
public TextureView GetTextureOrNull(TextureCreateInfo info)
{
lock (_lock)
{
if (!_textures.TryGetValue(info, out List list))
{
return null;
}
foreach (DisposedTexture texture in list)
{
list.Remove(texture);
return texture.View;
}
return null;
}
}
///
/// Update the pool, removing any resources that have expired.
///
public void Tick()
{
lock (_lock)
{
foreach (List list in _textures.Values)
{
for (int i = 0; i < list.Count; i++)
{
DisposedTexture tex = list[i];
if (--tex.RemainingFrames < 0)
{
tex.View.Dispose();
list.RemoveAt(i--);
}
}
}
}
}
///
/// Disposes the resource pool.
///
public void Dispose()
{
lock (_lock)
{
foreach (List list in _textures.Values)
{
foreach (DisposedTexture texture in list)
{
texture.View.Dispose();
}
}
_textures.Clear();
}
}
}
}