diff --git a/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs b/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
index 75b8e2200c..e3e8d5ba7a 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 ea64f46c14..a6fa96526f 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 fd2a74766e..0ec41a8f33 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.
///