diff --git a/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs b/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs index 75b8e2200..e3e8d5ba7 100644 --- a/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs +++ b/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs @@ -110,9 +110,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory ulong dstGpuVa = ((ulong)state.OffsetOutUpperValue << 32) | state.OffsetOut; - // Trigger read tracking, to flush any managed resources in the destination region. - _channel.MemoryManager.GetSpan(dstGpuVa, _size, true); - _dstGpuVa = dstGpuVa; _dstX = state.SetDstOriginBytesXV; _dstY = state.SetDstOriginSamplesYV; @@ -174,7 +171,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory if (_isLinear && _lineCount == 1) { - memoryManager.Write(_dstGpuVa, data); + memoryManager.Physical.CacheResourceWrite(memoryManager, _dstGpuVa, data); } else { @@ -227,11 +224,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory memoryManager.Write(dstAddress, data[srcOffset]); } } + + _context.AdvanceSequence(); } _finished = true; - - _context.AdvanceSequence(); } } } diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs index ea64f46c1..a6fa96526 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs @@ -99,6 +99,18 @@ namespace Ryujinx.Graphics.Gpu.Image return TextureScaleMode.Blacklisted; } + /// + /// Determines if any texture exists within the target memory range. + /// + /// The GPU memory manager + /// GPU virtual address to search for textures + /// The size of the range + /// True if any texture exists in the range, false otherwise + public bool IsTextureInRange(MemoryManager memoryManager, ulong gpuVa, ulong size) + { + return _textures.FindOverlaps(memoryManager.GetPhysicalRegions(gpuVa, size), ref _textureOverlaps) != 0; + } + /// /// Determines if a given texture is "safe" for upscaling from its info. /// Note that this is different from being compatible - this elilinates targets that would have detrimental effects when scaled. diff --git a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs index fd2a74766..0ec41a8f3 100644 --- a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs +++ b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs @@ -80,6 +80,28 @@ namespace Ryujinx.Graphics.Gpu.Memory } } + /// + /// Write data to memory that is destined for a resource in a cache. + /// This avoids triggering write tracking when possible, which can avoid flushes and incrementing sequence number. + /// + /// The GPU memory manager + /// GPU virtual address to write the data into + /// The data to be written + public void CacheResourceWrite(MemoryManager memoryManager, ulong gpuVa, ReadOnlySpan data) + { + if (TextureCache.IsTextureInRange(memoryManager, gpuVa, (ulong)data.Length)) + { + // No fast path yet - copy the data back and trigger write tracking. + memoryManager.Write(gpuVa, data); + _context.AdvanceSequence(); + } + else + { + BufferCache.ForceDirty(memoryManager, gpuVa, (ulong)data.Length); + memoryManager.WriteUntracked(gpuVa, data); + } + } + /// /// Gets a span of data from the application process. ///