mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-10-05 01:38:55 +02:00
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:
@@ -45,7 +45,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
private const int GranularLayerThreshold = 8;
|
||||
|
||||
private delegate void HandlesCallbackDelegate(int baseHandle, int regionCount, bool split = false);
|
||||
private delegate bool HandlesCallbackDelegate(int baseHandle, int regionCount, bool split = false, bool specialData = false);
|
||||
|
||||
private readonly HandlesCallbackDelegate _signalModifyingCallback;
|
||||
private readonly HandlesCallbackDelegate _discardDataCallback;
|
||||
private readonly HandlesCallbackDelegate _checkDirtyCallback;
|
||||
|
||||
/// <summary>
|
||||
/// The storage texture associated with this group.
|
||||
@@ -126,6 +130,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
_incompatibleOverlaps = incompatibleOverlaps;
|
||||
_flushIncompatibleOverlaps = TextureCompatibility.IsFormatHostIncompatible(storage.Info, context.Capabilities);
|
||||
|
||||
_signalModifyingCallback = SignalModifyingCallback;
|
||||
_discardDataCallback = DiscardDataCallback;
|
||||
_checkDirtyCallback = CheckDirtyCallback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -254,29 +262,33 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <param name="consume">True to consume the dirty flags and reprotect, false to leave them as is</param>
|
||||
/// <returns>True if a flag was dirty, false otherwise</returns>
|
||||
public bool CheckDirty(Texture texture, bool consume)
|
||||
{
|
||||
EvaluateRelevantHandles(texture, _checkDirtyCallback, out bool dirty, consume);
|
||||
|
||||
return dirty;
|
||||
}
|
||||
|
||||
bool CheckDirtyCallback(int baseHandle, int regionCount, bool split, bool consume)
|
||||
{
|
||||
bool dirty = false;
|
||||
|
||||
EvaluateRelevantHandles(texture, (baseHandle, regionCount, _) =>
|
||||
for (int i = 0; i < regionCount; i++)
|
||||
{
|
||||
for (int i = 0; i < regionCount; i++)
|
||||
TextureGroupHandle group = _handles[baseHandle + i];
|
||||
|
||||
foreach (RegionHandle handle in group.Handles)
|
||||
{
|
||||
TextureGroupHandle group = _handles[baseHandle + i];
|
||||
|
||||
foreach (RegionHandle handle in group.Handles)
|
||||
if (handle.Dirty)
|
||||
{
|
||||
if (handle.Dirty)
|
||||
if (consume)
|
||||
{
|
||||
if (consume)
|
||||
{
|
||||
handle.Reprotect();
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
handle.Reprotect();
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return dirty;
|
||||
}
|
||||
@@ -288,15 +300,19 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <param name="texture">The texture being discarded</param>
|
||||
public void DiscardData(Texture texture)
|
||||
{
|
||||
EvaluateRelevantHandles(texture, (baseHandle, regionCount, _) =>
|
||||
EvaluateRelevantHandles(texture, _discardDataCallback, out _);
|
||||
}
|
||||
|
||||
bool DiscardDataCallback(int baseHandle, int regionCount, bool split, bool bound)
|
||||
{
|
||||
for (int i = 0; i < regionCount; i++)
|
||||
{
|
||||
for (int i = 0; i < regionCount; i++)
|
||||
{
|
||||
TextureGroupHandle group = _handles[baseHandle + i];
|
||||
TextureGroupHandle group = _handles[baseHandle + i];
|
||||
|
||||
group.DiscardData();
|
||||
}
|
||||
});
|
||||
group.DiscardData();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -308,7 +324,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
FlushIncompatibleOverlapsIfNeeded();
|
||||
|
||||
EvaluateRelevantHandles(texture, (baseHandle, regionCount, split) =>
|
||||
EvaluateRelevantHandles(texture, (baseHandle, regionCount, split, _) =>
|
||||
{
|
||||
bool dirty = false;
|
||||
bool anyModified = false;
|
||||
@@ -384,7 +400,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
texture.SynchronizeFull();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -461,7 +479,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <param name="texture">The texture to synchronize dependents of</param>
|
||||
public void SynchronizeDependents(Texture texture)
|
||||
{
|
||||
EvaluateRelevantHandles(texture, (baseHandle, regionCount, _) =>
|
||||
EvaluateRelevantHandles(texture, (baseHandle, regionCount, _, _) =>
|
||||
{
|
||||
for (int i = 0; i < regionCount; i++)
|
||||
{
|
||||
@@ -469,7 +487,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
group.SynchronizeDependents();
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -551,7 +571,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
tracked = tracked || ShouldFlushTriggerTracking();
|
||||
bool flushed = false;
|
||||
|
||||
EvaluateRelevantHandles(texture, (baseHandle, regionCount, split) =>
|
||||
EvaluateRelevantHandles(texture, (baseHandle, regionCount, split, _) =>
|
||||
{
|
||||
int startSlice = 0;
|
||||
int endSlice = 0;
|
||||
@@ -605,7 +625,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
flushed = true;
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}, out _);
|
||||
|
||||
Storage.SignalModifiedDirty();
|
||||
|
||||
@@ -694,7 +716,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
ClearIncompatibleOverlaps(texture);
|
||||
|
||||
EvaluateRelevantHandles(texture, (baseHandle, regionCount, _) =>
|
||||
EvaluateRelevantHandles(texture, (baseHandle, regionCount, _, _) =>
|
||||
{
|
||||
for (int i = 0; i < regionCount; i++)
|
||||
{
|
||||
@@ -702,7 +724,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
group.SignalModified(_context);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -715,16 +739,20 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
ModifiedSequence = _context.GetModifiedSequence();
|
||||
|
||||
ClearIncompatibleOverlaps(texture);
|
||||
|
||||
EvaluateRelevantHandles(texture, (baseHandle, regionCount, _) =>
|
||||
|
||||
EvaluateRelevantHandles(texture, _signalModifyingCallback, out _, bound);
|
||||
}
|
||||
|
||||
bool SignalModifyingCallback(int baseHandle, int regionCount, bool split, bool bound)
|
||||
{
|
||||
for (int i = 0; i < regionCount; i++)
|
||||
{
|
||||
for (int i = 0; i < regionCount; i++)
|
||||
{
|
||||
TextureGroupHandle group = _handles[baseHandle + i];
|
||||
TextureGroupHandle group = _handles[baseHandle + i];
|
||||
|
||||
group.SignalModifying(bound, _context);
|
||||
}
|
||||
});
|
||||
group.SignalModifying(bound, _context);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -768,16 +796,16 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// A function to be called with the base index of the range of handles for the given texture, and the number of handles it covers.
|
||||
/// This can be called for multiple disjoint ranges, if required.
|
||||
/// </param>
|
||||
private void EvaluateRelevantHandles(Texture texture, HandlesCallbackDelegate callback)
|
||||
private void EvaluateRelevantHandles(Texture texture, HandlesCallbackDelegate callback, out bool result, bool specialData = false)
|
||||
{
|
||||
if (texture == Storage || !(_hasMipViews || _hasLayerViews))
|
||||
{
|
||||
callback(0, _handles.Length);
|
||||
result = callback(0, _handles.Length, specialData: specialData);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
EvaluateRelevantHandles(texture.FirstLayer, texture.FirstLevel, texture.Info.GetSlices(), texture.Info.Levels, callback);
|
||||
EvaluateRelevantHandles(texture.FirstLayer, texture.FirstLevel, texture.Info.GetSlices(), texture.Info.Levels, callback, out result, specialData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -792,11 +820,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// A function to be called with the base index of the range of handles for the given texture, and the number of handles it covers.
|
||||
/// This can be called for multiple disjoint ranges, if required.
|
||||
/// </param>
|
||||
private void EvaluateRelevantHandles(int firstLayer, int firstLevel, int slices, int levels, HandlesCallbackDelegate callback)
|
||||
private void EvaluateRelevantHandles(int firstLayer, int firstLevel, int slices, int levels, HandlesCallbackDelegate callback, out bool result, bool specialData = false)
|
||||
{
|
||||
int targetLayerHandles = _hasLayerViews ? slices : 1;
|
||||
int targetLevelHandles = _hasMipViews ? levels : 1;
|
||||
|
||||
result = false;
|
||||
|
||||
if (_isBuffer)
|
||||
{
|
||||
return;
|
||||
@@ -809,7 +839,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
// When there are no layer views, the mips are at a consistent offset.
|
||||
|
||||
callback(firstLevel, targetLevelHandles);
|
||||
result = callback(firstLevel, targetLevelHandles, specialData: specialData);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -823,7 +853,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
while (levels-- > 1)
|
||||
{
|
||||
callback(firstLayer + levelIndex, slices);
|
||||
result = callback(firstLayer + levelIndex, slices, specialData: specialData);
|
||||
|
||||
levelIndex += layerCount;
|
||||
layerCount = Math.Max(layerCount >> 1, 1);
|
||||
@@ -840,7 +870,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
totalSize += layerCount;
|
||||
}
|
||||
|
||||
callback(firstLayer + levelIndex, totalSize);
|
||||
result = callback(firstLayer + levelIndex, totalSize, specialData: specialData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -857,12 +887,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
for (int i = 0; i < slices; i++)
|
||||
{
|
||||
callback(firstLevel + (firstLayer + i) * levelHandles, targetLevelHandles, true);
|
||||
result = callback(firstLevel + (firstLayer + i) * levelHandles, targetLevelHandles, true, specialData: specialData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(firstLevel + firstLayer * levelHandles, targetLevelHandles + (targetLayerHandles - 1) * levelHandles);
|
||||
result = callback(firstLevel + firstLayer * levelHandles, targetLevelHandles + (targetLayerHandles - 1) * levelHandles, specialData: specialData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1441,8 +1471,16 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
var targetRange = new List<(int BaseHandle, int RegionCount)>();
|
||||
var otherRange = new List<(int BaseHandle, int RegionCount)>();
|
||||
|
||||
EvaluateRelevantHandles(firstLayer, firstLevel, other.Info.GetSlices(), other.Info.Levels, (baseHandle, regionCount, _) => targetRange.Add((baseHandle, regionCount)));
|
||||
otherGroup.EvaluateRelevantHandles(other, (baseHandle, regionCount, _) => otherRange.Add((baseHandle, regionCount)));
|
||||
EvaluateRelevantHandles(firstLayer, firstLevel, other.Info.GetSlices(), other.Info.Levels, (baseHandle, regionCount, _, _) =>
|
||||
{
|
||||
targetRange.Add((baseHandle, regionCount));
|
||||
return true;
|
||||
}, out _);
|
||||
otherGroup.EvaluateRelevantHandles(other, (baseHandle, regionCount, _, _) =>
|
||||
{
|
||||
otherRange.Add((baseHandle, regionCount));
|
||||
return true;
|
||||
}, out _);
|
||||
|
||||
int targetIndex = 0;
|
||||
int otherIndex = 0;
|
||||
|
||||
Reference in New Issue
Block a user