Only enumerate cached textures that are modified when flushing. (#918)

* Only enumarate cached textures that are modified when flushing, rather than all of them.

* Remove locking.

* Add missing clear.

* Remove texture from modified list when data is disposed.

In case the game does not call either flush method at any point.

* Add ReferenceEqualityComparer from jD for the HashSet
This commit is contained in:
riperiperi 2020-02-06 21:49:26 +00:00 committed by GitHub
parent a906f2071c
commit 6db16b4110
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 13 deletions

View file

@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Ryujinx.Common
{
public class ReferenceEqualityComparer<T> : IEqualityComparer<T>
where T : class
{
public bool Equals(T x, T y)
{
return x == y;
}
public int GetHashCode([DisallowNull] T obj)
{
return obj.GetHashCode();
}
}
}

View file

@ -94,7 +94,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
srcTexture.HostTexture.CopyTo(dstTexture.HostTexture, srcRegion, dstRegion, linearFilter); srcTexture.HostTexture.CopyTo(dstTexture.HostTexture, srcRegion, dstRegion, linearFilter);
} }
dstTexture.Modified = true; dstTexture.SignalModified();
} }
} }
} }

View file

@ -286,7 +286,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
if (color != null) if (color != null)
{ {
color.Modified = true; color.SignalModified();
} }
} }
@ -306,7 +306,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
if (depthStencil != null) if (depthStencil != null)
{ {
depthStencil.Modified = true; depthStencil.SignalModified();
} }
} }

View file

@ -54,9 +54,14 @@ namespace Ryujinx.Graphics.Gpu.Image
public LinkedListNode<Texture> CacheNode { get; set; } public LinkedListNode<Texture> CacheNode { get; set; }
/// <summary> /// <summary>
/// Texture data modified by the GPU. /// Event to fire when texture data is modified by the GPU.
/// </summary> /// </summary>
public bool Modified { get; set; } public event Action<Texture> Modified;
/// <summary>
/// Event to fire when texture data is disposed.
/// </summary>
public event Action<Texture> Disposed;
/// <summary> /// <summary>
/// Start address of the texture in guest memory. /// Start address of the texture in guest memory.
@ -933,6 +938,14 @@ namespace Ryujinx.Graphics.Gpu.Image
_layers = info.GetLayers(); _layers = info.GetLayers();
} }
/// <summary>
/// Signals that the texture has been modified.
/// </summary>
public void SignalModified()
{
Modified?.Invoke(this);
}
/// <summary> /// <summary>
/// Replaces the host texture, while disposing of the old one if needed. /// Replaces the host texture, while disposing of the old one if needed.
/// </summary> /// </summary>
@ -1012,6 +1025,8 @@ namespace Ryujinx.Graphics.Gpu.Image
_arrayViewTexture?.Dispose(); _arrayViewTexture?.Dispose();
_arrayViewTexture = null; _arrayViewTexture = null;
Disposed?.Invoke(this);
} }
/// <summary> /// <summary>

View file

@ -5,6 +5,7 @@ using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Gpu.State; using Ryujinx.Graphics.Gpu.State;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
using System; using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Gpu.Image namespace Ryujinx.Graphics.Gpu.Image
{ {
@ -35,6 +36,8 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly AutoDeleteCache _cache; private readonly AutoDeleteCache _cache;
private readonly HashSet<Texture> _modified;
/// <summary> /// <summary>
/// Constructs a new instance of the texture manager. /// Constructs a new instance of the texture manager.
/// </summary> /// </summary>
@ -57,6 +60,8 @@ namespace Ryujinx.Graphics.Gpu.Image
_textureOverlaps = new Texture[OverlapsBufferInitialCapacity]; _textureOverlaps = new Texture[OverlapsBufferInitialCapacity];
_cache = new AutoDeleteCache(); _cache = new AutoDeleteCache();
_modified = new HashSet<Texture>(new ReferenceEqualityComparer<Texture>());
} }
/// <summary> /// <summary>
@ -579,6 +584,8 @@ namespace Ryujinx.Graphics.Gpu.Image
if (!isSamplerTexture) if (!isSamplerTexture)
{ {
_cache.Add(texture); _cache.Add(texture);
texture.Modified += CacheTextureModified;
texture.Disposed += CacheTextureDisposed;
} }
_textures.Add(texture); _textures.Add(texture);
@ -588,6 +595,24 @@ namespace Ryujinx.Graphics.Gpu.Image
return texture; return texture;
} }
/// <summary>
/// Signaled when a cache texture is modified, and adds it to a set to be enumerated when flushing textures.
/// </summary>
/// <param name="texture">The texture that was modified.</param>
private void CacheTextureModified(Texture texture)
{
_modified.Add(texture);
}
/// <summary>
/// Signaled when a cache texture is disposed, so it can be removed from the set of modified textures if present.
/// </summary>
/// <param name="texture">The texture that was diosposed.</param>
private void CacheTextureDisposed(Texture texture)
{
_modified.Remove(texture);
}
/// <summary> /// <summary>
/// Resizes the temporary buffer used for range list intersection results, if it has grown too much. /// Resizes the temporary buffer used for range list intersection results, if it has grown too much.
/// </summary> /// </summary>
@ -722,15 +747,14 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
public void Flush() public void Flush()
{ {
foreach (Texture texture in _cache) foreach (Texture texture in _modified)
{ {
if (texture.Info.IsLinear && texture.Modified) if (texture.Info.IsLinear)
{ {
texture.Flush(); texture.Flush();
texture.Modified = false;
} }
} }
_modified.Clear();
} }
/// <summary> /// <summary>
@ -740,15 +764,14 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="size">The range size</param> /// <param name="size">The range size</param>
public void Flush(ulong address, ulong size) public void Flush(ulong address, ulong size)
{ {
foreach (Texture texture in _cache) foreach (Texture texture in _modified)
{ {
if (texture.OverlapsWith(address, size) && texture.Modified) if (texture.OverlapsWith(address, size))
{ {
texture.Flush(); texture.Flush();
texture.Modified = false;
} }
} }
_modified.Clear();
} }
/// <summary> /// <summary>
@ -772,6 +795,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
foreach (Texture texture in _textures) foreach (Texture texture in _textures)
{ {
_modified.Remove(texture);
texture.Dispose(); texture.Dispose();
} }
} }