Use a descriptor cache for faster pool invalidation. (#1977)

* Use a descriptor cache for faster pool invalidation.

* Speed up comparison by casting to Vector256

Now we never need to worry about this ever again
This commit is contained in:
riperiperi 2021-01-29 03:19:06 +00:00 committed by GitHub
parent 9eb0ab05c6
commit c30504e3b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 60 additions and 22 deletions

View File

@ -8,14 +8,16 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary> /// <summary>
/// Represents a pool of GPU resources, such as samplers or textures. /// Represents a pool of GPU resources, such as samplers or textures.
/// </summary> /// </summary>
/// <typeparam name="T">Type of the GPU resource</typeparam> /// <typeparam name="T1">Type of the GPU resource</typeparam>
abstract class Pool<T> : IDisposable /// <typeparam name="T2">Type of the descriptor</typeparam>
abstract class Pool<T1, T2> : IDisposable where T2 : unmanaged
{ {
protected const int DescriptorSize = 0x20; protected const int DescriptorSize = 0x20;
protected GpuContext Context; protected GpuContext Context;
protected T[] Items; protected T1[] Items;
protected T2[] DescriptorCache;
/// <summary> /// <summary>
/// The maximum ID value of resources on the pool (inclusive). /// The maximum ID value of resources on the pool (inclusive).
@ -47,7 +49,8 @@ namespace Ryujinx.Graphics.Gpu.Image
ulong size = (ulong)(uint)count * DescriptorSize; ulong size = (ulong)(uint)count * DescriptorSize;
Items = new T[count]; Items = new T1[count];
DescriptorCache = new T2[count];
Address = address; Address = address;
Size = size; Size = size;
@ -56,12 +59,23 @@ namespace Ryujinx.Graphics.Gpu.Image
_modifiedDelegate = RegionModified; _modifiedDelegate = RegionModified;
} }
/// <summary>
/// Gets the descriptor for a given ID.
/// </summary>
/// <param name="id">ID of the descriptor. This is effectively a zero-based index</param>
/// <returns>The descriptor</returns>
public T2 GetDescriptor(int id)
{
return Context.PhysicalMemory.Read<T2>(Address + (ulong)id * DescriptorSize);
}
/// <summary> /// <summary>
/// Gets the GPU resource with the given ID. /// Gets the GPU resource with the given ID.
/// </summary> /// </summary>
/// <param name="id">ID of the resource. This is effectively a zero-based index</param> /// <param name="id">ID of the resource. This is effectively a zero-based index</param>
/// <returns>The GPU resource with the given ID</returns> /// <returns>The GPU resource with the given ID</returns>
public abstract T Get(int id); public abstract T1 Get(int id);
/// <summary> /// <summary>
/// Synchronizes host memory with guest memory. /// Synchronizes host memory with guest memory.
@ -97,7 +111,7 @@ namespace Ryujinx.Graphics.Gpu.Image
protected abstract void InvalidateRangeImpl(ulong address, ulong size); protected abstract void InvalidateRangeImpl(ulong address, ulong size);
protected abstract void Delete(T item); protected abstract void Delete(T1 item);
/// <summary> /// <summary>
/// Performs the disposal of all resources stored on the pool. /// Performs the disposal of all resources stored on the pool.

View File

@ -1,4 +1,6 @@
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
namespace Ryujinx.Graphics.Gpu.Image namespace Ryujinx.Graphics.Gpu.Image
{ {
@ -244,5 +246,15 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
return ((Word2 >> 12) & 0xfff) * Frac8ToF32; return ((Word2 >> 12) & 0xfff) * Frac8ToF32;
} }
/// <summary>
/// Check if two descriptors are equal.
/// </summary>
/// <param name="other">The descriptor to compare against</param>
/// <returns>True if they are equal, false otherwise</returns>
public bool Equals(ref SamplerDescriptor other)
{
return Unsafe.As<SamplerDescriptor, Vector256<byte>>(ref this).Equals(Unsafe.As<SamplerDescriptor, Vector256<byte>>(ref other));
}
} }
} }

View File

@ -3,7 +3,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary> /// <summary>
/// Sampler pool. /// Sampler pool.
/// </summary> /// </summary>
class SamplerPool : Pool<Sampler> class SamplerPool : Pool<Sampler, SamplerDescriptor>
{ {
private int _sequenceNumber; private int _sequenceNumber;
@ -38,11 +38,13 @@ namespace Ryujinx.Graphics.Gpu.Image
if (sampler == null) if (sampler == null)
{ {
SamplerDescriptor descriptor = Context.PhysicalMemory.Read<SamplerDescriptor>(Address + (ulong)id * DescriptorSize); SamplerDescriptor descriptor = GetDescriptor(id);
sampler = new Sampler(Context, descriptor); sampler = new Sampler(Context, descriptor);
Items[id] = sampler; Items[id] = sampler;
DescriptorCache[id] = descriptor;
} }
return sampler; return sampler;
@ -65,6 +67,14 @@ namespace Ryujinx.Graphics.Gpu.Image
if (sampler != null) if (sampler != null)
{ {
SamplerDescriptor descriptor = GetDescriptor(id);
// If the descriptors are the same, the sampler is still valid.
if (descriptor.Equals(ref DescriptorCache[id]))
{
continue;
}
sampler.Dispose(); sampler.Dispose();
Items[id] = null; Items[id] = null;

View File

@ -1,4 +1,6 @@
using Ryujinx.Graphics.Gpu.Shader.Cache.Definition; using Ryujinx.Graphics.Gpu.Shader.Cache.Definition;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
namespace Ryujinx.Graphics.Gpu.Image namespace Ryujinx.Graphics.Gpu.Image
{ {
@ -248,5 +250,15 @@ namespace Ryujinx.Graphics.Gpu.Image
return result; return result;
} }
/// <summary>
/// Check if two descriptors are equal.
/// </summary>
/// <param name="other">The descriptor to compare against</param>
/// <returns>True if they are equal, false otherwise</returns>
public bool Equals(ref TextureDescriptor other)
{
return Unsafe.As<TextureDescriptor, Vector256<byte>>(ref this).Equals(Unsafe.As<TextureDescriptor, Vector256<byte>>(ref other));
}
} }
} }

View File

@ -1,6 +1,5 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -10,7 +9,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary> /// <summary>
/// Texture pool. /// Texture pool.
/// </summary> /// </summary>
class TexturePool : Pool<Texture> class TexturePool : Pool<Texture, TextureDescriptor>
{ {
private int _sequenceNumber; private int _sequenceNumber;
@ -65,6 +64,8 @@ namespace Ryujinx.Graphics.Gpu.Image
texture.IncrementReferenceCount(); texture.IncrementReferenceCount();
Items[id] = texture; Items[id] = texture;
DescriptorCache[id] = descriptor;
} }
else else
{ {
@ -91,16 +92,6 @@ namespace Ryujinx.Graphics.Gpu.Image
return texture; return texture;
} }
/// <summary>
/// Gets the texture descriptor from a given texture ID.
/// </summary>
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
/// <returns>The texture descriptor</returns>
public TextureDescriptor GetDescriptor(int id)
{
return Context.PhysicalMemory.Read<TextureDescriptor>(Address + (ulong)id * DescriptorSize);
}
/// <summary> /// <summary>
/// Implementation of the texture pool range invalidation. /// Implementation of the texture pool range invalidation.
/// </summary> /// </summary>
@ -122,8 +113,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// If the descriptors are the same, the texture is the same, // If the descriptors are the same, the texture is the same,
// we don't need to remove as it was not modified. Just continue. // we don't need to remove as it was not modified. Just continue.
if (texture.Info.GpuAddress == descriptor.UnpackAddress() && if (descriptor.Equals(ref DescriptorCache[id]))
texture.IsExactMatch(GetInfo(descriptor, out _), TextureSearchFlags.Strict) != TextureMatchQuality.NoMatch)
{ {
continue; continue;
} }