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:
parent
9eb0ab05c6
commit
c30504e3b3
5 changed files with 60 additions and 22 deletions
|
@ -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.
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue