Remove cache entries on pool removal, disable for OpenGL

This commit is contained in:
Gabriel A 2024-04-07 22:26:54 -03:00
commit 859d4675e4
10 changed files with 80 additions and 19 deletions

View file

@ -36,6 +36,7 @@ namespace Ryujinx.Graphics.GAL
public readonly bool SupportsMismatchingViewFormat; public readonly bool SupportsMismatchingViewFormat;
public readonly bool SupportsCubemapView; public readonly bool SupportsCubemapView;
public readonly bool SupportsNonConstantTextureOffset; public readonly bool SupportsNonConstantTextureOffset;
public readonly bool SupportsSeparateSampler;
public readonly bool SupportsShaderBallot; public readonly bool SupportsShaderBallot;
public readonly bool SupportsShaderBarrierDivergence; public readonly bool SupportsShaderBarrierDivergence;
public readonly bool SupportsShaderFloat64; public readonly bool SupportsShaderFloat64;
@ -92,6 +93,7 @@ namespace Ryujinx.Graphics.GAL
bool supportsMismatchingViewFormat, bool supportsMismatchingViewFormat,
bool supportsCubemapView, bool supportsCubemapView,
bool supportsNonConstantTextureOffset, bool supportsNonConstantTextureOffset,
bool supportsSeparateSampler,
bool supportsShaderBallot, bool supportsShaderBallot,
bool supportsShaderBarrierDivergence, bool supportsShaderBarrierDivergence,
bool supportsShaderFloat64, bool supportsShaderFloat64,
@ -144,6 +146,7 @@ namespace Ryujinx.Graphics.GAL
SupportsMismatchingViewFormat = supportsMismatchingViewFormat; SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
SupportsCubemapView = supportsCubemapView; SupportsCubemapView = supportsCubemapView;
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset; SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
SupportsSeparateSampler = supportsSeparateSampler;
SupportsShaderBallot = supportsShaderBallot; SupportsShaderBallot = supportsShaderBallot;
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence; SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
SupportsShaderFloat64 = supportsShaderFloat64; SupportsShaderFloat64 = supportsShaderFloat64;

View file

@ -62,8 +62,9 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="channel">GPU channel that the texture pool cache belongs to</param> /// <param name="channel">GPU channel that the texture pool cache belongs to</param>
/// <param name="address">Start address of the texture pool</param> /// <param name="address">Start address of the texture pool</param>
/// <param name="maximumId">Maximum ID of the texture pool</param> /// <param name="maximumId">Maximum ID of the texture pool</param>
/// <param name="bindingsArrayCache">Cache of texture array bindings</param>
/// <returns>The found or newly created texture pool</returns> /// <returns>The found or newly created texture pool</returns>
public T FindOrCreate(GpuChannel channel, ulong address, int maximumId) public T FindOrCreate(GpuChannel channel, ulong address, int maximumId, TextureBindingsArrayCache bindingsArrayCache)
{ {
// Remove old entries from the cache, if possible. // Remove old entries from the cache, if possible.
while (_pools.Count > MaxCapacity && (_currentTimestamp - _pools.First.Value.CacheTimestamp) >= MinDeltaForRemoval) while (_pools.Count > MaxCapacity && (_currentTimestamp - _pools.First.Value.CacheTimestamp) >= MinDeltaForRemoval)
@ -73,6 +74,7 @@ namespace Ryujinx.Graphics.Gpu.Image
_pools.RemoveFirst(); _pools.RemoveFirst();
oldestPool.Dispose(); oldestPool.Dispose();
oldestPool.CacheNode = null; oldestPool.CacheNode = null;
bindingsArrayCache.RemoveAllWithPool(oldestPool);
} }
T pool; T pool;
@ -87,8 +89,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (pool.CacheNode != _pools.Last) if (pool.CacheNode != _pools.Last)
{ {
_pools.Remove(pool.CacheNode); _pools.Remove(pool.CacheNode);
_pools.AddLast(pool.CacheNode);
pool.CacheNode = _pools.AddLast(pool);
} }
pool.CacheTimestamp = _currentTimestamp; pool.CacheTimestamp = _currentTimestamp;

View file

@ -21,7 +21,6 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly GpuContext _context; private readonly GpuContext _context;
private readonly GpuChannel _channel; private readonly GpuChannel _channel;
private readonly bool _isCompute;
/// <summary> /// <summary>
/// Array cache entry key. /// Array cache entry key.
@ -69,6 +68,16 @@ namespace Ryujinx.Graphics.Gpu.Image
_samplerPool = samplerPool; _samplerPool = samplerPool;
} }
/// <summary>
/// Checks if the pool matches the cached pool.
/// </summary>
/// <param name="texturePool">Texture or sampler pool instance</param>
/// <returns>True if the pool matches, false otherwise</returns>
public bool MatchesPool<T>(IPool<T> pool)
{
return _texturePool == pool || _samplerPool == pool;
}
/// <summary> /// <summary>
/// Checks if the texture and sampler pools matches the cached pools. /// Checks if the texture and sampler pools matches the cached pools.
/// </summary> /// </summary>
@ -531,12 +540,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
/// <param name="context">GPU context</param> /// <param name="context">GPU context</param>
/// <param name="channel">GPU channel</param> /// <param name="channel">GPU channel</param>
/// <param name="isCompute">Whether the bindings will be used for compute or graphics pipelines</param> public TextureBindingsArrayCache(GpuContext context, GpuChannel channel)
public TextureBindingsArrayCache(GpuContext context, GpuChannel channel, bool isCompute)
{ {
_context = context; _context = context;
_channel = channel; _channel = channel;
_isCompute = isCompute;
_cacheFromBuffer = new Dictionary<CacheEntryFromBufferKey, CacheEntryFromBuffer>(); _cacheFromBuffer = new Dictionary<CacheEntryFromBufferKey, CacheEntryFromBuffer>();
_cacheFromPool = new Dictionary<CacheEntryFromPoolKey, CacheEntry>(); _cacheFromPool = new Dictionary<CacheEntryFromPoolKey, CacheEntry>();
_lruCache = new LinkedList<CacheEntryFromBuffer>(); _lruCache = new LinkedList<CacheEntryFromBuffer>();
@ -757,9 +764,10 @@ namespace Ryujinx.Graphics.Gpu.Image
(textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex); (textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex);
bool separateSamplerBuffer = textureBufferIndex != samplerBufferIndex; bool separateSamplerBuffer = textureBufferIndex != samplerBufferIndex;
bool isCompute = stage == ShaderStage.Compute;
ref BufferBounds textureBufferBounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, textureBufferIndex); ref BufferBounds textureBufferBounds = ref _channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, textureBufferIndex);
ref BufferBounds samplerBufferBounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, samplerBufferIndex); ref BufferBounds samplerBufferBounds = ref _channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, samplerBufferIndex);
CacheEntryFromBuffer entry = GetOrAddEntry( CacheEntryFromBuffer entry = GetOrAddEntry(
texturePool, texturePool,
@ -1064,6 +1072,31 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
} }
/// <summary>
/// Removes all cached texture arrays matching the specified texture pool.
/// </summary>
/// <param name="pool">Texture pool</param>
public void RemoveAllWithPool<T>(IPool<T> pool)
{
List<CacheEntryFromPoolKey> keysToRemove = null;
foreach (CacheEntryFromPoolKey key in _cacheFromPool.Keys)
{
if (key.MatchesPool(pool))
{
(keysToRemove ??= new()).Add(key);
}
}
if (keysToRemove != null)
{
foreach (CacheEntryFromPoolKey key in keysToRemove)
{
_cacheFromPool.Remove(key);
}
}
}
/// <summary> /// <summary>
/// Checks if a handle indicates the binding should have all its textures sourced directly from a pool. /// Checks if a handle indicates the binding should have all its textures sourced directly from a pool.
/// </summary> /// </summary>

View file

@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly TexturePoolCache _texturePoolCache; private readonly TexturePoolCache _texturePoolCache;
private readonly SamplerPoolCache _samplerPoolCache; private readonly SamplerPoolCache _samplerPoolCache;
private readonly TextureBindingsArrayCache _arrayBindingsCache; private readonly TextureBindingsArrayCache _bindingsArrayCache;
private TexturePool _cachedTexturePool; private TexturePool _cachedTexturePool;
private SamplerPool _cachedSamplerPool; private SamplerPool _cachedSamplerPool;
@ -72,12 +72,14 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
/// <param name="context">The GPU context that the texture bindings manager belongs to</param> /// <param name="context">The GPU context that the texture bindings manager belongs to</param>
/// <param name="channel">The GPU channel that the texture bindings manager belongs to</param> /// <param name="channel">The GPU channel that the texture bindings manager belongs to</param>
/// <param name="bindingsArrayCache">Cache of texture array bindings</param>
/// <param name="texturePoolCache">Texture pools cache used to get texture pools from</param> /// <param name="texturePoolCache">Texture pools cache used to get texture pools from</param>
/// <param name="samplerPoolCache">Sampler pools cache used to get sampler pools from</param> /// <param name="samplerPoolCache">Sampler pools cache used to get sampler pools from</param>
/// <param name="isCompute">True if the bindings manager is used for the compute engine</param> /// <param name="isCompute">True if the bindings manager is used for the compute engine</param>
public TextureBindingsManager( public TextureBindingsManager(
GpuContext context, GpuContext context,
GpuChannel channel, GpuChannel channel,
TextureBindingsArrayCache bindingsArrayCache,
TexturePoolCache texturePoolCache, TexturePoolCache texturePoolCache,
SamplerPoolCache samplerPoolCache, SamplerPoolCache samplerPoolCache,
bool isCompute) bool isCompute)
@ -89,7 +91,7 @@ namespace Ryujinx.Graphics.Gpu.Image
_isCompute = isCompute; _isCompute = isCompute;
_arrayBindingsCache = new TextureBindingsArrayCache(context, channel, isCompute); _bindingsArrayCache = bindingsArrayCache;
int stages = isCompute ? 1 : Constants.ShaderStages; int stages = isCompute ? 1 : Constants.ShaderStages;
@ -456,7 +458,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (bindingInfo.ArrayLength > 1) if (bindingInfo.ArrayLength > 1)
{ {
_arrayBindingsCache.UpdateTextureArray(texturePool, samplerPool, stage, stageIndex, _textureBufferIndex, _samplerIndex, bindingInfo); _bindingsArrayCache.UpdateTextureArray(texturePool, samplerPool, stage, stageIndex, _textureBufferIndex, _samplerIndex, bindingInfo);
continue; continue;
} }
@ -594,7 +596,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (bindingInfo.ArrayLength > 1) if (bindingInfo.ArrayLength > 1)
{ {
_arrayBindingsCache.UpdateImageArray(pool, stage, stageIndex, _textureBufferIndex, bindingInfo); _bindingsArrayCache.UpdateImageArray(pool, stage, stageIndex, _textureBufferIndex, bindingInfo);
continue; continue;
} }
@ -732,7 +734,7 @@ namespace Ryujinx.Graphics.Gpu.Image
ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa);
TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId); TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId, _bindingsArrayCache);
TextureDescriptor descriptor; TextureDescriptor descriptor;
@ -828,7 +830,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (poolAddress != MemoryManager.PteUnmapped) if (poolAddress != MemoryManager.PteUnmapped)
{ {
texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, _texturePoolMaximumId); texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, _texturePoolMaximumId, _bindingsArrayCache);
_texturePool = texturePool; _texturePool = texturePool;
} }
} }
@ -839,7 +841,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (poolAddress != MemoryManager.PteUnmapped) if (poolAddress != MemoryManager.PteUnmapped)
{ {
samplerPool = _samplerPoolCache.FindOrCreate(_channel, poolAddress, _samplerPoolMaximumId); samplerPool = _samplerPoolCache.FindOrCreate(_channel, poolAddress, _samplerPoolMaximumId, _bindingsArrayCache);
_samplerPool = samplerPool; _samplerPool = samplerPool;
} }
} }

View file

@ -15,6 +15,7 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly TextureBindingsManager _cpBindingsManager; private readonly TextureBindingsManager _cpBindingsManager;
private readonly TextureBindingsManager _gpBindingsManager; private readonly TextureBindingsManager _gpBindingsManager;
private readonly TextureBindingsArrayCache _bindingsArrayCache;
private readonly TexturePoolCache _texturePoolCache; private readonly TexturePoolCache _texturePoolCache;
private readonly SamplerPoolCache _samplerPoolCache; private readonly SamplerPoolCache _samplerPoolCache;
@ -46,8 +47,9 @@ namespace Ryujinx.Graphics.Gpu.Image
TexturePoolCache texturePoolCache = new(context); TexturePoolCache texturePoolCache = new(context);
SamplerPoolCache samplerPoolCache = new(context); SamplerPoolCache samplerPoolCache = new(context);
_cpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, samplerPoolCache, isCompute: true); _bindingsArrayCache = new TextureBindingsArrayCache(context, channel);
_gpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, samplerPoolCache, isCompute: false); _cpBindingsManager = new TextureBindingsManager(context, channel, _bindingsArrayCache, texturePoolCache, samplerPoolCache, isCompute: true);
_gpBindingsManager = new TextureBindingsManager(context, channel, _bindingsArrayCache, texturePoolCache, samplerPoolCache, isCompute: false);
_texturePoolCache = texturePoolCache; _texturePoolCache = texturePoolCache;
_samplerPoolCache = samplerPoolCache; _samplerPoolCache = samplerPoolCache;
@ -384,7 +386,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa);
TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId); TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId, _bindingsArrayCache);
return texturePool; return texturePool;
} }

View file

@ -213,6 +213,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
public bool QueryHostSupportsScaledVertexFormats() => _context.Capabilities.SupportsScaledVertexFormats; public bool QueryHostSupportsScaledVertexFormats() => _context.Capabilities.SupportsScaledVertexFormats;
public bool QueryHostSupportsSeparateSampler() => _context.Capabilities.SupportsSeparateSampler;
public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot; public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot;
public bool QueryHostSupportsShaderBarrierDivergence() => _context.Capabilities.SupportsShaderBarrierDivergence; public bool QueryHostSupportsShaderBarrierDivergence() => _context.Capabilities.SupportsShaderBarrierDivergence;

View file

@ -176,6 +176,7 @@ namespace Ryujinx.Graphics.OpenGL
supportsCubemapView: true, supportsCubemapView: true,
supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset, supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
supportsScaledVertexFormats: true, supportsScaledVertexFormats: true,
supportsSeparateSampler: false,
supportsShaderBallot: HwCapabilities.SupportsShaderBallot, supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
supportsShaderBarrierDivergence: !(intelWindows || intelUnix), supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
supportsShaderFloat64: true, supportsShaderFloat64: true,

View file

@ -291,6 +291,15 @@ namespace Ryujinx.Graphics.Shader
return true; return true;
} }
/// <summary>
/// Queries host API support for separate textures and samplers.
/// </summary>
/// <returns>True if the API supports samplers and textures to be combined on the shader, false otherwise</returns>
bool QueryHostSupportsSeparateSampler()
{
return true;
}
/// <summary> /// <summary>
/// Queries host GPU shader ballot support. /// Queries host GPU shader ballot support.
/// </summary> /// </summary>

View file

@ -55,6 +55,13 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
TextureOperation texOp, TextureOperation texOp,
LinkedListNode<INode> node) LinkedListNode<INode> node)
{ {
if (!gpuAccessor.QueryHostSupportsSeparateSampler())
{
// We depend on combining samplers and textures in the shader being supported for this.
return false;
}
Operand nvHandle = texOp.GetSource(0); Operand nvHandle = texOp.GetSource(0);
if (nvHandle.AsgOp is not Operation handleOp || if (nvHandle.AsgOp is not Operation handleOp ||

View file

@ -706,6 +706,7 @@ namespace Ryujinx.Graphics.Vulkan
supportsCubemapView: !IsAmdGcn, supportsCubemapView: !IsAmdGcn,
supportsNonConstantTextureOffset: false, supportsNonConstantTextureOffset: false,
supportsScaledVertexFormats: FormatCapabilities.SupportsScaledVertexFormats(), supportsScaledVertexFormats: FormatCapabilities.SupportsScaledVertexFormats(),
supportsSeparateSampler: true,
supportsShaderBallot: false, supportsShaderBallot: false,
supportsShaderBarrierDivergence: Vendor != Vendor.Intel, supportsShaderBarrierDivergence: Vendor != Vendor.Intel,
supportsShaderFloat64: Capabilities.SupportsShaderFloat64, supportsShaderFloat64: Capabilities.SupportsShaderFloat64,