Memory changes 3

General memory improvements to decrease GC pressure and frequency.

Pool big arrays and objects that are created and deleted often.

Skip data copies when they aren't needed.

Inline flag checks to skip unneeded allocations.

From my testing the performance is about the same, but the GC frequency is much lower and collection is faster causing less and smaller spikes.
This commit is contained in:
LotP
2025-10-30 23:25:51 -05:00
committed by KeatonTheBot
parent 2c50fbcc1f
commit e3ee28605d
42 changed files with 703 additions and 331 deletions
+21 -9
View File
@@ -93,6 +93,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
private ulong _dirtyStart = ulong.MaxValue;
private ulong _dirtyEnd = ulong.MaxValue;
private readonly Action<ulong, ulong> _syncPreRangeAction;
private readonly Action<ulong, ulong> _syncRangeAction;
/// <summary>
/// Creates a new instance of the buffer.
/// </summary>
@@ -177,6 +180,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
_modifiedDelegate = RegionModified;
_virtualDependenciesLock = new ReaderWriterLockSlim();
_syncPreRangeAction = SyncPreRangeAction;
_syncRangeAction = SyncRangeAction;
}
/// <summary>
@@ -401,13 +407,15 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (_preFlush.ShouldCopy)
{
_modifiedRanges?.GetRangesAtSync(Address, Size, _context.SyncNumber, (address, size) =>
{
_preFlush.CopyModified(address, size);
});
_modifiedRanges?.GetRangesAtSync(Address, Size, _context.SyncNumber, _syncPreRangeAction);
}
}
}
void SyncPreRangeAction(ulong address, ulong size)
{
_preFlush.CopyModified(address, size);
}
/// <summary>
/// Action to be performed when a syncpoint is reached after modification.
@@ -420,11 +428,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (_useGranular)
{
_modifiedRanges?.GetRanges(Address, Size, (address, size) =>
{
_memoryTrackingGranular.RegisterAction(address, size, _externalFlushDelegate);
SynchronizeMemory(address, size);
});
_modifiedRanges?.GetRanges(Address, Size, _syncRangeAction);
}
else
{
@@ -434,6 +440,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
return true;
}
void SyncRangeAction(ulong address, ulong size)
{
_memoryTrackingGranular.RegisterAction(address, size, _externalFlushDelegate);
SynchronizeMemory(address, size);
}
/// <summary>
/// Inherit modified and dirty ranges from another buffer.
@@ -1,5 +1,6 @@
using Ryujinx.Memory.Range;
using System;
using System.Buffers;
using System.Linq;
namespace Ryujinx.Graphics.Gpu.Memory
@@ -276,13 +277,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
// We use the non-span method here because keeping the lock will cause a deadlock.
Lock.EnterReadLock();
RangeItem<BufferModifiedRange>[] overlaps = FindOverlapsAsArray(address, size);
RangeItem<BufferModifiedRange>[] overlaps = FindOverlapsAsArray(address, size, out int length);
Lock.ExitReadLock();
for (int i = 0; i < overlaps.Length; i++)
if (length != 0)
{
BufferModifiedRange overlap = overlaps[i].Value;
rangeAction(overlap.Address, overlap.Size);
for (int i = 0; i < length; i++)
{
BufferModifiedRange overlap = overlaps[i].Value;
rangeAction(overlap.Address, overlap.Size);
}
ArrayPool<RangeItem<BufferModifiedRange>>.Shared.Return(overlaps);
}
}
@@ -392,9 +398,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
Lock.EnterWriteLock();
// We use the non-span method here because the array is partially modified by the code, which would invalidate a span.
RangeItem<BufferModifiedRange>[] overlaps = FindOverlapsAsArray(address, size);
int rangeCount = overlaps.Length;
RangeItem<BufferModifiedRange>[] overlaps = FindOverlapsAsArray(address, size, out int rangeCount);
if (rangeCount == 0)
{
@@ -410,7 +414,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
for (int i = 0; i < rangeCount; i++)
{
BufferModifiedRange overlap = overlaps[i].Value;
BufferModifiedRange overlap = overlaps![i].Value;
long diff = (long)(overlap.SyncNumber - currentSync);
@@ -430,7 +434,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
// Wait for the syncpoint.
_context.Renderer.WaitSync(currentSync + (ulong)highestDiff);
RemoveRangesAndFlush(overlaps.ToArray(), rangeCount, highestDiff, currentSync, address, endAddress);
RemoveRangesAndFlush(overlaps, rangeCount, highestDiff, currentSync, address, endAddress);
ArrayPool<RangeItem<BufferModifiedRange>>.Shared.Return(overlaps!);
Lock.ExitWriteLock();
}