GPU: Keep rendered textures without any pool references alive (#4662)
* GPU: Keep sampled textures without any pool references alive Occasionally games are very wasteful and clear/write to a texture without ever sampling it. As rendered textures in NVN games seem to all have overlapping memory ranges, the texture will eventually get overwritten. Normally, this would trigger a removal from the auto delete cache, but a pool entry would keep the texture alive. However, with these textures that are never used, they will get deleted immediately and recreated on the next frame. This change makes it so the ShortTextureCache can keep textures that have naver had a pool reference alive for a few frames, so they're not constantly being created and deleted. This improves performance in Zelda BOTW a little. * Cleanup
This commit is contained in:
parent
e18d258fa0
commit
2c94ac455e
3 changed files with 75 additions and 5 deletions
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Image
|
namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
@ -9,6 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class ShortTextureCacheEntry
|
class ShortTextureCacheEntry
|
||||||
{
|
{
|
||||||
|
public bool IsAutoDelete;
|
||||||
public readonly TextureDescriptor Descriptor;
|
public readonly TextureDescriptor Descriptor;
|
||||||
public readonly int InvalidatedSequence;
|
public readonly int InvalidatedSequence;
|
||||||
public readonly Texture Texture;
|
public readonly Texture Texture;
|
||||||
|
@ -24,6 +24,17 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
InvalidatedSequence = texture.InvalidatedSequence;
|
InvalidatedSequence = texture.InvalidatedSequence;
|
||||||
Texture = texture;
|
Texture = texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new entry on the short duration texture cache from the auto delete cache.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="texture">The texture</param>
|
||||||
|
public ShortTextureCacheEntry(Texture texture)
|
||||||
|
{
|
||||||
|
IsAutoDelete = true;
|
||||||
|
InvalidatedSequence = texture.InvalidatedSequence;
|
||||||
|
Texture = texture;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -199,7 +210,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
texture.DecrementReferenceCount();
|
texture.DecrementReferenceCount();
|
||||||
|
|
||||||
_shortCacheLookup.Remove(texture.ShortCacheEntry.Descriptor);
|
if (!texture.ShortCacheEntry.IsAutoDelete)
|
||||||
|
{
|
||||||
|
_shortCacheLookup.Remove(texture.ShortCacheEntry.Descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
texture.ShortCacheEntry = null;
|
texture.ShortCacheEntry = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,6 +237,25 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
texture.IncrementReferenceCount();
|
texture.IncrementReferenceCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a texture to the short duration cache without a descriptor. This typically keeps it alive for two ticks.
|
||||||
|
/// On expiry, it will be removed from the AutoDeleteCache.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="texture">Texture to add to the short cache</param>
|
||||||
|
public void AddShortCache(Texture texture)
|
||||||
|
{
|
||||||
|
if (texture.ShortCacheEntry != null)
|
||||||
|
{
|
||||||
|
var entry = new ShortTextureCacheEntry(texture);
|
||||||
|
|
||||||
|
_shortCacheBuilder.Add(entry);
|
||||||
|
|
||||||
|
texture.ShortCacheEntry = entry;
|
||||||
|
|
||||||
|
texture.IncrementReferenceCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete textures from the short duration cache.
|
/// Delete textures from the short duration cache.
|
||||||
/// Moves the builder set to be deleted on next process.
|
/// Moves the builder set to be deleted on next process.
|
||||||
|
@ -234,7 +268,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
entry.Texture.DecrementReferenceCount();
|
entry.Texture.DecrementReferenceCount();
|
||||||
|
|
||||||
_shortCacheLookup.Remove(entry.Descriptor);
|
if (entry.IsAutoDelete)
|
||||||
|
{
|
||||||
|
Remove(entry.Texture, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_shortCacheLookup.Remove(entry.Descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
entry.Texture.ShortCacheEntry = null;
|
entry.Texture.ShortCacheEntry = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ShortTextureCacheEntry ShortCacheEntry { get; set; }
|
public ShortTextureCacheEntry ShortCacheEntry { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this texture has ever been referenced by a pool.
|
||||||
|
/// </summary>
|
||||||
|
public bool HadPoolOwner { get; private set; }
|
||||||
|
|
||||||
/// Physical memory ranges where the texture data is located.
|
/// Physical memory ranges where the texture data is located.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MultiRange Range { get; private set; }
|
public MultiRange Range { get; private set; }
|
||||||
|
@ -1506,10 +1511,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <param name="gpuVa">GPU VA of the pool reference</param>
|
/// <param name="gpuVa">GPU VA of the pool reference</param>
|
||||||
public void IncrementReferenceCount(TexturePool pool, int id, ulong gpuVa)
|
public void IncrementReferenceCount(TexturePool pool, int id, ulong gpuVa)
|
||||||
{
|
{
|
||||||
|
HadPoolOwner = true;
|
||||||
|
|
||||||
lock (_poolOwners)
|
lock (_poolOwners)
|
||||||
{
|
{
|
||||||
_poolOwners.Add(new TexturePoolOwner { Pool = pool, ID = id, GpuAddress = gpuVa });
|
_poolOwners.Add(new TexturePoolOwner { Pool = pool, ID = id, GpuAddress = gpuVa });
|
||||||
}
|
}
|
||||||
|
|
||||||
_referenceCount++;
|
_referenceCount++;
|
||||||
|
|
||||||
if (ShortCacheEntry != null)
|
if (ShortCacheEntry != null)
|
||||||
|
@ -1594,7 +1602,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
_poolOwners.Clear();
|
_poolOwners.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShortCacheEntry != null && _context.IsGpuThread())
|
if (ShortCacheEntry != null && !ShortCacheEntry.IsAutoDelete && _context.IsGpuThread())
|
||||||
{
|
{
|
||||||
// If this is called from another thread (unmapped), the short cache will
|
// If this is called from another thread (unmapped), the short cache will
|
||||||
// have to remove this texture on a future tick.
|
// have to remove this texture on a future tick.
|
||||||
|
|
|
@ -848,7 +848,17 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
if (overlapInCache)
|
if (overlapInCache)
|
||||||
{
|
{
|
||||||
_cache.Remove(overlap, flush);
|
if (flush || overlap.HadPoolOwner || overlap.IsView)
|
||||||
|
{
|
||||||
|
_cache.Remove(overlap, flush);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This texture has only ever been referenced in the AutoDeleteCache.
|
||||||
|
// Keep this texture alive with the short duration cache, as it may be used often but not sampled.
|
||||||
|
|
||||||
|
_cache.AddShortCache(overlap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeOverlap = modified;
|
removeOverlap = modified;
|
||||||
|
@ -1198,6 +1208,16 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
_cache.AddShortCache(texture, ref descriptor);
|
_cache.AddShortCache(texture, ref descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a texture to the short duration cache without a descriptor. This typically keeps it alive for two ticks.
|
||||||
|
/// On expiry, it will be removed from the AutoDeleteCache.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="texture">Texture to add to the short cache</param>
|
||||||
|
public void AddShortCache(Texture texture)
|
||||||
|
{
|
||||||
|
_cache.AddShortCache(texture);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes a texture from the short duration cache.
|
/// Removes a texture from the short duration cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Reference in a new issue