diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs index d7fe2bb1d7..85a5d686b6 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureBindingsArrayCache.cs @@ -176,6 +176,7 @@ namespace Ryujinx.Graphics.Gpu.Image private int[] _cachedSamplerBuffer; private int _lastBinding; + private int _lastSequenceNumber; /// /// Creates a new array cache entry. @@ -192,6 +193,9 @@ namespace Ryujinx.Graphics.Gpu.Image _texturePool = texturePool; _samplerPool = samplerPool; + + _lastBinding = -1; + _lastSequenceNumber = -1; } /// @@ -218,6 +222,23 @@ namespace Ryujinx.Graphics.Gpu.Image ImageArray = array; } + /// + /// Synchronizes memory for all textures in the array. + /// + /// Indicates if the texture may be modified by the access + public void SynchronizeMemory(bool isStore) + { + foreach (Texture texture in Textures.Keys) + { + texture.SynchronizeMemory(); + + if (isStore) + { + texture.SignalModified(); + } + } + } + /// /// Clears all cached texture instances. /// @@ -336,6 +357,23 @@ namespace Ryujinx.Graphics.Gpu.Image return false; } + /// + /// Checks if the sequence number matches the one used on the last call to this method. + /// + /// Current sequence number + /// True if the sequence numbers match, false otherwise + public bool MatchesSequenceNumber(int currentSequenceNumber) + { + if (_lastSequenceNumber == currentSequenceNumber) + { + return true; + } + + _lastSequenceNumber = currentSequenceNumber; + + return false; + } + /// /// Checks if the buffer data matches the cached data. /// @@ -455,9 +493,6 @@ namespace Ryujinx.Graphics.Gpu.Image SamplerIndex samplerIndex, TextureBindingInfo bindingInfo) { - ReadOnlySpan cachedTextureBuffer; - ReadOnlySpan cachedSamplerBuffer; - (textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex); bool separateSamplerBuffer = textureBufferIndex != samplerBufferIndex; @@ -465,19 +500,6 @@ namespace Ryujinx.Graphics.Gpu.Image ref BufferBounds textureBufferBounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, textureBufferIndex); ref BufferBounds samplerBufferBounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, samplerBufferIndex); - cachedTextureBuffer = MemoryMarshal.Cast(_channel.MemoryManager.Physical.GetSpan(textureBufferBounds.Range)); - - if (separateSamplerBuffer) - { - cachedSamplerBuffer = MemoryMarshal.Cast(_channel.MemoryManager.Physical.GetSpan(samplerBufferBounds.Range)); - } - else - { - cachedSamplerBuffer = cachedTextureBuffer; - } - - (_, int samplerWordOffset, _) = TextureHandle.UnpackOffsets(bindingInfo.Handle); - CacheEntry entry = GetOrAddEntry( texturePool, samplerPool, @@ -486,30 +508,63 @@ namespace Ryujinx.Graphics.Gpu.Image ref textureBufferBounds, out bool isNewEnry); - bool isStore = bindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore); bool poolsModified = entry.PoolsModified(); + bool isStore = bindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore); - if (!poolsModified && - !isNewEnry && - entry.MatchesBufferData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer, samplerWordOffset) && - entry.ValidateTextures()) + ReadOnlySpan cachedTextureBuffer; + ReadOnlySpan cachedSamplerBuffer; + + if (!poolsModified && !isNewEnry && entry.ValidateTextures()) { - foreach (Texture texture in entry.Textures.Keys) + if (entry.MatchesSequenceNumber(_context.SequenceNumber)) { - texture.SynchronizeMemory(); + entry.SynchronizeMemory(isStore); - if (isStore) + if (entry.BindingChanged(this, bindingInfo.Binding)) { - texture.SignalModified(); + _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray); } + + return; } - if (entry.BindingChanged(this, bindingInfo.Binding)) + cachedTextureBuffer = MemoryMarshal.Cast(_channel.MemoryManager.Physical.GetSpan(textureBufferBounds.Range)); + + if (separateSamplerBuffer) { - _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray); + cachedSamplerBuffer = MemoryMarshal.Cast(_channel.MemoryManager.Physical.GetSpan(samplerBufferBounds.Range)); + } + else + { + cachedSamplerBuffer = cachedTextureBuffer; } - return; + (_, int samplerWordOffset, _) = TextureHandle.UnpackOffsets(bindingInfo.Handle); + + if (entry.MatchesBufferData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer, samplerWordOffset)) + { + entry.SynchronizeMemory(isStore); + + if (entry.BindingChanged(this, bindingInfo.Binding)) + { + _context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray); + } + + return; + } + } + else + { + cachedTextureBuffer = MemoryMarshal.Cast(_channel.MemoryManager.Physical.GetSpan(textureBufferBounds.Range)); + + if (separateSamplerBuffer) + { + cachedSamplerBuffer = MemoryMarshal.Cast(_channel.MemoryManager.Physical.GetSpan(samplerBufferBounds.Range)); + } + else + { + cachedSamplerBuffer = cachedTextureBuffer; + } } if (!isNewEnry)