diff --git a/Ryujinx.Graphics.Gpu/GpuChannel.cs b/Ryujinx.Graphics.Gpu/GpuChannel.cs
index b9d91f93e3..f3bdd57632 100644
--- a/Ryujinx.Graphics.Gpu/GpuChannel.cs
+++ b/Ryujinx.Graphics.Gpu/GpuChannel.cs
@@ -59,9 +59,24 @@ namespace Ryujinx.Graphics.Gpu
{
oldMemoryManager.Physical.BufferCache.NotifyBuffersModified -= BufferManager.Rebind;
oldMemoryManager.Physical.DecrementReferenceCount();
+ oldMemoryManager.MemoryUnmapped -= MemoryUnmappedHandler;
}
memoryManager.Physical.BufferCache.NotifyBuffersModified += BufferManager.Rebind;
+ memoryManager.MemoryUnmapped += MemoryUnmappedHandler;
+
+ // Since the memory manager changed, make sure we will get pools from addresses of the new memory manager.
+ TextureManager.ReloadPools();
+ }
+
+ ///
+ /// Memory mappings change event handler.
+ ///
+ /// Memory manager where the mappings changed
+ /// Information about the region that is being changed
+ private void MemoryUnmappedHandler(object sender, UnmapEventArgs e)
+ {
+ TextureManager.ReloadPools();
}
///
diff --git a/Ryujinx.Graphics.Gpu/Image/PoolCache.cs b/Ryujinx.Graphics.Gpu/Image/PoolCache.cs
new file mode 100644
index 0000000000..e1493f3888
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Image/PoolCache.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Gpu.Image
+{
+ ///
+ /// Resource pool interface.
+ ///
+ /// Resource pool type
+ interface IPool
+ {
+ ///
+ /// Start address of the pool in memory.
+ ///
+ ulong Address { get; }
+
+ ///
+ /// Linked list node used on the texture pool cache.
+ ///
+ LinkedListNode CacheNode { get; set; }
+
+ ///
+ /// Timestamp set on the last use of the pool by the cache.
+ ///
+ ulong CacheTimestamp { get; set; }
+ }
+
+ ///
+ /// Pool cache.
+ /// This can keep multiple pools, and return the current one as needed.
+ ///
+ abstract class PoolCache : IDisposable where T : IPool, IDisposable
+ {
+ private const int MaxCapacity = 2;
+ private const ulong MinDeltaForRemoval = 20000;
+
+ private readonly GpuContext _context;
+ private readonly LinkedList _pools;
+ private ulong _currentTimestamp;
+
+ ///
+ /// Constructs a new instance of the pool.
+ ///
+ /// GPU context that the texture pool belongs to
+ public PoolCache(GpuContext context)
+ {
+ _context = context;
+ _pools = new LinkedList();
+ }
+
+ ///
+ /// Increments the internal timestamp of the cache that is used to decide when old resources will be deleted.
+ ///
+ public void Tick()
+ {
+ _currentTimestamp++;
+ }
+
+ ///
+ /// Finds a cache texture pool, or creates a new one if not found.
+ ///
+ /// GPU channel that the texture pool cache belongs to
+ /// Start address of the texture pool
+ /// Maximum ID of the texture pool
+ /// The found or newly created texture pool
+ 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 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;
+ }
+
+ ///
+ /// Creates a new instance of the pool.
+ ///
+ /// GPU context that the pool belongs to
+ /// GPU channel that the pool belongs to
+ /// Address of the pool in guest memory
+ /// Maximum ID of the pool (equal to maximum minus one)
+ 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();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
index e95800ada8..eb7222f9c1 100644
--- a/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/SamplerPool.cs
@@ -1,16 +1,27 @@
using Ryujinx.Graphics.Gpu.Memory;
+using System.Collections.Generic;
namespace Ryujinx.Graphics.Gpu.Image
{
///
/// Sampler pool.
///
- class SamplerPool : Pool
+ class SamplerPool : Pool, IPool
{
private float _forcedAnisotropy;
///
- /// Constructs a new instance of the sampler pool.
+ /// Linked list node used on the sampler pool cache.
+ ///
+ public LinkedListNode CacheNode { get; set; }
+
+ ///
+ /// Timestamp used by the sampler pool cache, updated on every use of this sampler pool.
+ ///
+ public ulong CacheTimestamp { get; set; }
+
+ ///
+ /// Creates a new instance of the sampler pool.
///
/// GPU context that the sampler pool belongs to
/// Physical memory where the sampler descriptors are mapped
diff --git a/Ryujinx.Graphics.Gpu/Image/SamplerPoolCache.cs b/Ryujinx.Graphics.Gpu/Image/SamplerPoolCache.cs
new file mode 100644
index 0000000000..3b3350fb5c
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Image/SamplerPoolCache.cs
@@ -0,0 +1,30 @@
+namespace Ryujinx.Graphics.Gpu.Image
+{
+ ///
+ /// Sampler pool cache.
+ /// This can keep multiple sampler pools, and return the current one as needed.
+ /// It is useful for applications that uses multiple sampler pools.
+ ///
+ class SamplerPoolCache : PoolCache
+ {
+ ///
+ /// Constructs a new instance of the texture pool.
+ ///
+ /// GPU context that the texture pool belongs to
+ public SamplerPoolCache(GpuContext context) : base(context)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the sampler pool.
+ ///
+ /// GPU context that the sampler pool belongs to
+ /// GPU channel that the texture pool belongs to
+ /// Address of the sampler pool in guest memory
+ /// Maximum sampler ID of the sampler pool (equal to maximum samplers minus one)
+ protected override SamplerPool CreatePool(GpuContext context, GpuChannel channel, ulong address, int maximumId)
+ {
+ return new SamplerPool(context, channel.MemoryManager.Physical, address, maximumId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index fcd2344143..067a1f9fee 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Image
///
/// Texture bindings manager.
///
- class TextureBindingsManager : IDisposable
+ class TextureBindingsManager
{
private const int InitialTextureStateSize = 32;
private const int InitialImageStateSize = 8;
@@ -22,15 +22,17 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly bool _isCompute;
- private SamplerPool _samplerPool;
-
+ private ulong _texturePoolGpuVa;
+ private int _texturePoolMaximumId;
+ private TexturePool _texturePool;
+ private ulong _samplerPoolGpuVa;
+ private int _samplerPoolMaximumId;
private SamplerIndex _samplerIndex;
-
- private ulong _texturePoolAddress;
- private int _texturePoolMaximumId;
+ private SamplerPool _samplerPool;
private readonly GpuChannel _channel;
private readonly TexturePoolCache _texturePoolCache;
+ private readonly SamplerPoolCache _samplerPoolCache;
private TexturePool _cachedTexturePool;
private SamplerPool _cachedSamplerPool;
@@ -72,16 +74,25 @@ namespace Ryujinx.Graphics.Gpu.Image
///
/// The GPU context that the texture bindings manager belongs to
/// The GPU channel that the texture bindings manager belongs to
- /// Texture pools cache used to get texture pools from
+ /// Texture pools cache used to get texture pools from
+ /// Sampler pools cache used to get sampler pools from
/// Array where the scales for the currently bound textures are stored
/// True if the bindings manager is used for the compute engine
- public TextureBindingsManager(GpuContext context, GpuChannel channel, TexturePoolCache poolCache, float[] scales, bool isCompute)
+ public TextureBindingsManager(
+ GpuContext context,
+ GpuChannel channel,
+ TexturePoolCache texturePoolCache,
+ SamplerPoolCache samplerPoolCache,
+ float[] scales,
+ bool isCompute)
{
- _context = context;
- _channel = channel;
- _texturePoolCache = poolCache;
- _scales = scales;
- _isCompute = isCompute;
+ _context = context;
+ _channel = channel;
+ _texturePoolCache = texturePoolCache;
+ _samplerPoolCache = samplerPoolCache;
+
+ _scales = scales;
+ _isCompute = isCompute;
int stages = isCompute ? 1 : Constants.ShaderStages;
@@ -173,25 +184,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Type of the sampler pool indexing used for bound samplers
public void SetSamplerPool(ulong gpuVa, int maximumId, SamplerIndex samplerIndex)
{
- if (gpuVa != 0)
- {
- ulong address = _channel.MemoryManager.Translate(gpuVa);
-
- if (_samplerPool != null && _samplerPool.Address == address && _samplerPool.MaximumId >= maximumId)
- {
- return;
- }
-
- _samplerPool?.Dispose();
- _samplerPool = new SamplerPool(_context, _channel.MemoryManager.Physical, address, maximumId);
- }
- else
- {
- _samplerPool?.Dispose();
- _samplerPool = null;
- }
-
+ _samplerPoolGpuVa = gpuVa;
+ _samplerPoolMaximumId = maximumId;
_samplerIndex = samplerIndex;
+ _samplerPool = null;
}
///
@@ -201,18 +197,9 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Maximum ID of the pool (total count minus one)
public void SetTexturePool(ulong gpuVa, int maximumId)
{
- if (gpuVa != 0)
- {
- ulong address = _channel.MemoryManager.Translate(gpuVa);
-
- _texturePoolAddress = address;
- _texturePoolMaximumId = maximumId;
- }
- else
- {
- _texturePoolAddress = 0;
- _texturePoolMaximumId = 0;
- }
+ _texturePoolGpuVa = gpuVa;
+ _texturePoolMaximumId = maximumId;
+ _texturePool = null;
}
///
@@ -222,13 +209,9 @@ namespace Ryujinx.Graphics.Gpu.Image
/// ID of the sampler
public (Texture, Sampler) GetTextureAndSampler(int textureId, int samplerId)
{
- ulong texturePoolAddress = _texturePoolAddress;
+ (TexturePool texturePool, SamplerPool samplerPool) = GetPools();
- TexturePool texturePool = texturePoolAddress != 0
- ? _texturePoolCache.FindOrCreate(_channel, texturePoolAddress, _texturePoolMaximumId)
- : null;
-
- return (texturePool.Get(textureId), _samplerPool.Get(samplerId));
+ return (texturePool.Get(textureId), samplerPool.Get(samplerId));
}
///
@@ -340,13 +323,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// True if all bound textures match the current shader specialiation state, false otherwise
public bool CommitBindings(ShaderSpecializationState specState)
{
- ulong texturePoolAddress = _texturePoolAddress;
-
- TexturePool texturePool = texturePoolAddress != 0
- ? _texturePoolCache.FindOrCreate(_channel, texturePoolAddress, _texturePoolMaximumId)
- : null;
-
- SamplerPool samplerPool = _samplerPool;
+ (TexturePool texturePool, SamplerPool samplerPool) = GetPools();
// Check if the texture pool has been modified since bindings were last committed.
// If it wasn't, then it's possible to avoid looking up textures again when the handle remains the same.
@@ -381,7 +358,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (_isCompute)
{
- specStateMatches &= CommitTextureBindings(texturePool, ShaderStage.Compute, 0, poolModified, specState);
+ specStateMatches &= CommitTextureBindings(texturePool, samplerPool, ShaderStage.Compute, 0, poolModified, specState);
specStateMatches &= CommitImageBindings(texturePool, ShaderStage.Compute, 0, poolModified, specState);
}
else
@@ -390,7 +367,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
int stageIndex = (int)stage - 1;
- specStateMatches &= CommitTextureBindings(texturePool, stage, stageIndex, poolModified, specState);
+ specStateMatches &= CommitTextureBindings(texturePool, samplerPool, stage, stageIndex, poolModified, specState);
specStateMatches &= CommitImageBindings(texturePool, stage, stageIndex, poolModified, specState);
}
}
@@ -447,13 +424,20 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Ensures that the texture bindings are visible to the host GPU.
/// Note: this actually performs the binding using the host graphics API.
///
- /// The current texture pool
+ /// The current texture pool
+ /// The current sampler pool
/// The shader stage using the textures to be bound
/// The stage number of the specified shader stageTrue if either the texture or sampler pool was modified, false otherwise
/// Specialization state for the bound shader
/// True if all bound textures match the current shader specialiation state, false otherwise
- private bool CommitTextureBindings(TexturePool pool, ShaderStage stage, int stageIndex, bool poolModified, ShaderSpecializationState specState)
+ private bool CommitTextureBindings(
+ TexturePool texturePool,
+ SamplerPool samplerPool,
+ ShaderStage stage,
+ int stageIndex,
+ bool poolModified,
+ ShaderSpecializationState specState)
{
int textureCount = _textureBindingsCount[stageIndex];
if (textureCount == 0)
@@ -461,9 +445,7 @@ namespace Ryujinx.Graphics.Gpu.Image
return true;
}
- var samplerPool = _samplerPool;
-
- if (pool == null)
+ if (texturePool == null)
{
Logger.Error?.Print(LogClass.Gpu, $"Shader stage \"{stage}\" uses textures, but texture pool was not set.");
return true;
@@ -528,7 +510,7 @@ namespace Ryujinx.Graphics.Gpu.Image
state.TextureHandle = textureId;
state.SamplerHandle = samplerId;
- ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, out Texture texture);
+ ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, out Texture texture);
specStateMatches &= specState.MatchesTexture(stage, index, descriptor);
@@ -819,6 +801,54 @@ namespace Ryujinx.Graphics.Gpu.Image
return handle;
}
+ ///
+ /// Gets the texture and sampler pool for the GPU virtual address that are currently set.
+ ///
+ /// The texture and sampler pools
+ private (TexturePool, SamplerPool) GetPools()
+ {
+ MemoryManager memoryManager = _channel.MemoryManager;
+
+ TexturePool texturePool = _texturePool;
+ SamplerPool samplerPool = _samplerPool;
+
+ if (texturePool == null)
+ {
+ ulong poolAddress = memoryManager.Translate(_texturePoolGpuVa);
+
+ if (poolAddress != MemoryManager.PteUnmapped)
+ {
+ texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, _texturePoolMaximumId);
+ _texturePool = texturePool;
+ }
+ }
+
+ if (samplerPool == null)
+ {
+ ulong poolAddress = memoryManager.Translate(_samplerPoolGpuVa);
+
+ if (poolAddress != MemoryManager.PteUnmapped)
+ {
+ samplerPool = _samplerPoolCache.FindOrCreate(_channel, poolAddress, _samplerPoolMaximumId);
+ _samplerPool = samplerPool;
+ }
+ }
+
+ return (texturePool, samplerPool);
+ }
+
+ ///
+ /// Forces the texture and sampler pools to be re-loaded from the cache on next use.
+ ///
+ ///
+ /// This should be called if the memory mappings change, to ensure the correct pools are being used.
+ ///
+ public void ReloadPools()
+ {
+ _samplerPool = null;
+ _texturePool = null;
+ }
+
///
/// Force all bound textures and images to be rebound the next time CommitBindings is called.
///
@@ -827,13 +857,5 @@ namespace Ryujinx.Graphics.Gpu.Image
Array.Clear(_textureState);
Array.Clear(_imageState);
}
-
- ///
- /// Disposes all textures and samplers in the cache.
- ///
- public void Dispose()
- {
- _samplerPool?.Dispose();
- }
}
}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
index 628c31596a..fe0175a6a6 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
@@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly TextureBindingsManager _cpBindingsManager;
private readonly TextureBindingsManager _gpBindingsManager;
private readonly TexturePoolCache _texturePoolCache;
+ private readonly SamplerPoolCache _samplerPoolCache;
private readonly Texture[] _rtColors;
private readonly ITexture[] _rtHostColors;
@@ -41,13 +42,15 @@ namespace Ryujinx.Graphics.Gpu.Image
_channel = channel;
TexturePoolCache texturePoolCache = new TexturePoolCache(context);
+ SamplerPoolCache samplerPoolCache = new SamplerPoolCache(context);
float[] scales = new float[64];
new Span(scales).Fill(1f);
- _cpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, scales, isCompute: true);
- _gpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, scales, isCompute: false);
+ _cpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, samplerPoolCache, scales, isCompute: true);
+ _gpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, samplerPoolCache, scales, isCompute: false);
_texturePoolCache = texturePoolCache;
+ _samplerPoolCache = samplerPoolCache;
_rtColors = new Texture[Constants.TotalRenderTargets];
_rtHostColors = new ITexture[Constants.TotalRenderTargets];
@@ -368,6 +371,10 @@ namespace Ryujinx.Graphics.Gpu.Image
// we must rebind everything.
// Since compute work happens less often, we always do that
// before and after the compute dispatch.
+
+ _texturePoolCache.Tick();
+ _samplerPoolCache.Tick();
+
_cpBindingsManager.Rebind();
bool result = _cpBindingsManager.CommitBindings(specState);
_gpBindingsManager.Rebind();
@@ -382,6 +389,9 @@ namespace Ryujinx.Graphics.Gpu.Image
/// True if all bound textures match the current shader specialization state, false otherwise
public bool CommitGraphicsBindings(ShaderSpecializationState specState)
{
+ _texturePoolCache.Tick();
+ _samplerPoolCache.Tick();
+
bool result = _gpBindingsManager.CommitBindings(specState);
UpdateRenderTargets();
@@ -501,6 +511,15 @@ namespace Ryujinx.Graphics.Gpu.Image
_context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, _rtHostDs);
}
+ ///
+ /// Forces the texture and sampler pools to be re-loaded from the cache on next use.
+ ///
+ public void ReloadPools()
+ {
+ _cpBindingsManager.ReloadPools();
+ _gpBindingsManager.ReloadPools();
+ }
+
///
/// Forces all textures, samplers, images and render targets to be rebound the next time
/// CommitGraphicsBindings is called.
@@ -523,8 +542,8 @@ namespace Ryujinx.Graphics.Gpu.Image
///
public void Dispose()
{
- _cpBindingsManager.Dispose();
- _gpBindingsManager.Dispose();
+ // Textures are owned by the texture cache, so we shouldn't dispose the texture pool cache.
+ _samplerPoolCache.Dispose();
for (int i = 0; i < _rtColors.Length; i++)
{
diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
index 75974c43b0..4d2544e270 100644
--- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
@@ -10,19 +10,24 @@ namespace Ryujinx.Graphics.Gpu.Image
///
/// Texture pool.
///
- class TexturePool : Pool
+ class TexturePool : Pool, IPool
{
private readonly GpuChannel _channel;
private readonly ConcurrentQueue _dereferenceQueue = new ConcurrentQueue();
private TextureDescriptor _defaultDescriptor;
///
- /// Intrusive linked list node used on the texture pool cache.
+ /// Linked list node used on the texture pool cache.
///
public LinkedListNode CacheNode { get; set; }
///
- /// Constructs a new instance of the texture pool.
+ /// Timestamp used by the texture pool cache, updated on every use of this texture pool.
+ ///
+ public ulong CacheTimestamp { get; set; }
+
+ ///
+ /// Creates a new instance of the texture pool.
///
/// GPU context that the texture pool belongs to
/// GPU channel that the texture pool belongs to
diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs b/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs
index 99c5a88b48..0017f4cc5a 100644
--- a/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TexturePoolCache.cs
@@ -1,6 +1,3 @@
-using System;
-using System.Collections.Generic;
-
namespace Ryujinx.Graphics.Gpu.Image
{
///
@@ -8,69 +5,26 @@ namespace Ryujinx.Graphics.Gpu.Image
/// This can keep multiple texture pools, and return the current one as needed.
/// It is useful for applications that uses multiple texture pools.
///
- class TexturePoolCache
+ class TexturePoolCache : PoolCache
{
- private const int MaxCapacity = 4;
-
- private readonly GpuContext _context;
- private readonly LinkedList _pools;
-
///
/// Constructs a new instance of the texture pool.
///
/// GPU context that the texture pool belongs to
- public TexturePoolCache(GpuContext context)
+ public TexturePoolCache(GpuContext context) : base(context)
{
- _context = context;
- _pools = new LinkedList();
}
///
- /// Finds a cache texture pool, or creates a new one if not found.
+ /// Creates a new instance of the texture pool.
///
- /// GPU channel that the texture pool cache belongs to
- /// Start address of the texture pool
- /// Maximum ID of the texture pool
- /// The found or newly created texture pool
- public TexturePool FindOrCreate(GpuChannel channel, ulong address, int maximumId)
+ /// GPU context that the texture pool belongs to
+ /// GPU channel that the texture pool belongs to
+ /// Address of the texture pool in guest memory
+ /// Maximum texture ID of the texture pool (equal to maximum textures minus one)
+ protected override TexturePool CreatePool(GpuContext context, GpuChannel channel, ulong address, int maximumId)
{
- TexturePool pool;
-
- // First we try to find the pool.
- for (LinkedListNode 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);
- }
-
- return pool;
- }
- }
-
- // If not found, create a new one.
- pool = new TexturePool(_context, channel, address, maximumId);
-
- pool.CacheNode = _pools.AddLast(pool);
-
- if (_pools.Count > MaxCapacity)
- {
- TexturePool oldestPool = _pools.First.Value;
-
- _pools.RemoveFirst();
-
- oldestPool.Dispose();
-
- oldestPool.CacheNode = null;
- }
-
- return pool;
+ return new TexturePool(context, channel, address, maximumId);
}
}
}
\ No newline at end of file