See merge request ryubing/ryujinx!132
This commit is contained in:
LotP
2025-08-30 20:30:17 -05:00
parent 6e47d8548c
commit 01a9b636af
7 changed files with 161 additions and 84 deletions

View File

@@ -82,15 +82,7 @@ namespace Ryujinx.Graphics.Device
{ {
uint alignedOffset = index * RegisterSize; uint alignedOffset = index * RegisterSize;
Func<int> readCallback = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_readCallbacks), (nint)index); return _readCallbacks[index]?.Invoke() ?? GetRefUnchecked<int>(alignedOffset);
if (readCallback != null)
{
return readCallback();
}
else
{
return GetRefUnchecked<int>(alignedOffset);
}
} }
return 0; return 0;
@@ -107,7 +99,7 @@ namespace Ryujinx.Graphics.Device
GetRefIntAlignedUncheck(index) = data; GetRefIntAlignedUncheck(index) = data;
Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_writeCallbacks), (nint)index)?.Invoke(data); _writeCallbacks[index]?.Invoke(data);
} }
} }
@@ -124,7 +116,7 @@ namespace Ryujinx.Graphics.Device
changed = storage != data; changed = storage != data;
storage = data; storage = data;
Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_writeCallbacks), (nint)index)?.Invoke(data); _writeCallbacks[index]?.Invoke(data);
} }
else else
{ {

View File

@@ -109,7 +109,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
if (index < BlockSize) if (index < BlockSize)
{ {
int groupIndex = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_registerToGroupMapping), (nint)index); int groupIndex = _registerToGroupMapping[index];
if (groupIndex != 0) if (groupIndex != 0)
{ {
groupIndex--; groupIndex--;

View File

@@ -120,11 +120,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
public void ExcludeModifiedRegions(ulong address, ulong size, Action<ulong, ulong> action) public void ExcludeModifiedRegions(ulong address, ulong size, Action<ulong, ulong> action)
{ {
// Slices a given region using the modified regions in the list. Calls the action for the new slices. // Slices a given region using the modified regions in the list. Calls the action for the new slices.
bool lockOwner = Lock.IsReadLockHeld;
if (!lockOwner)
{
Lock.EnterReadLock(); Lock.EnterReadLock();
}
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlaps(address, size); (RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlaps(address, size);
@@ -145,10 +141,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
current = current.Next; current = current.Next;
} }
if (!lockOwner)
{
Lock.ExitReadLock(); Lock.ExitReadLock();
}
if ((long)size > 0) if ((long)size > 0)
{ {
@@ -179,9 +172,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
return; return;
} }
BufferModifiedRange buffPost = null;
bool extendsPost = false;
bool extendsPre = false;
if (first == last) if (first == last)
{ {
@@ -196,14 +187,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (first.Address < address) if (first.Address < address)
{ {
first.Value.Size = address - first.Address; first.Value.Size = address - first.Address;
Update(first);
extendsPre = true;
if (first.EndAddress > endAddress) if (first.EndAddress > endAddress)
{ {
buffPost = new BufferModifiedRange(endAddress, first.EndAddress - endAddress, Add(new BufferModifiedRange(endAddress, first.EndAddress - endAddress,
first.Value.SyncNumber, first.Value.Parent); first.Value.SyncNumber, first.Value.Parent));
extendsPost = true;
} }
} }
else else
@@ -212,6 +201,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{ {
first.Value.Size = first.EndAddress - endAddress; first.Value.Size = first.EndAddress - endAddress;
first.Value.Address = endAddress; first.Value.Address = endAddress;
Update(first);
} }
else else
{ {
@@ -219,11 +209,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
} }
} }
if (extendsPre && extendsPost)
{
Add(buffPost);
}
Add(new BufferModifiedRange(address, size, syncNumber, this)); Add(new BufferModifiedRange(address, size, syncNumber, this));
Lock.ExitWriteLock(); Lock.ExitWriteLock();
@@ -231,6 +216,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
} }
BufferModifiedRange buffPre = null; BufferModifiedRange buffPre = null;
BufferModifiedRange buffPost = null;
bool extendsPost = false;
bool extendsPre = false;
if (first.Address < address) if (first.Address < address)
{ {
@@ -329,7 +317,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
public bool HasRange(ulong address, ulong size) public bool HasRange(ulong address, ulong size)
{ {
Lock.EnterReadLock(); Lock.EnterReadLock();
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> _) = FindOverlaps(address, size); RangeItem<BufferModifiedRange> first = FindOverlapFast(address, size);
bool result = first is not null; bool result = first is not null;
Lock.ExitReadLock(); Lock.ExitReadLock();
return result; return result;
@@ -386,9 +374,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
ulong clampAddress = Math.Max(address, overlap.Address); ulong clampAddress = Math.Max(address, overlap.Address);
ulong clampEnd = Math.Min(endAddress, overlap.EndAddress); ulong clampEnd = Math.Min(endAddress, overlap.EndAddress);
Lock.EnterWriteLock();
ClearPart(overlap, clampAddress, clampEnd); ClearPart(overlap, clampAddress, clampEnd);
Lock.ExitWriteLock();
RangeActionWithMigration(clampAddress, clampEnd - clampAddress, waitSync, _flushAction); RangeActionWithMigration(clampAddress, clampEnd - clampAddress, waitSync, _flushAction);
} }
@@ -418,40 +404,33 @@ namespace Ryujinx.Graphics.Gpu.Memory
ulong endAddress = address + size; ulong endAddress = address + size;
ulong currentSync = _context.SyncNumber; ulong currentSync = _context.SyncNumber;
int rangeCount = 0;
List<RangeItem<BufferModifiedRange>> overlaps = []; List<RangeItem<BufferModifiedRange>> overlaps = [];
// Range list must be consistent for this operation // Range list must be consistent for this operation
Lock.EnterReadLock();
if (_migrationTarget != null) if (_migrationTarget != null)
{
rangeCount = -1;
}
else
{
// We use the non-span method here because the array is partially modified by the code, which would invalidate a span.
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlaps(address, size);
RangeItem<BufferModifiedRange> current = first;
while (last != null && current != last.Next)
{
rangeCount++;
overlaps.Add(current);
current = current.Next;
}
}
Lock.ExitReadLock();
if (rangeCount == -1)
{ {
_migrationTarget!.WaitForAndFlushRanges(address, size); _migrationTarget!.WaitForAndFlushRanges(address, size);
return; return;
} }
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> first, RangeItem<BufferModifiedRange> last) = FindOverlaps(address, size);
RangeItem<BufferModifiedRange> current = first;
while (last != null && current != last.Next)
{
overlaps.Add(current);
current = current.Next;
}
int rangeCount = overlaps.Count;
if (rangeCount == 0) if (rangeCount == 0)
{ {
Lock.ExitWriteLock();
return; return;
} }
@@ -474,6 +453,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (highestDiff == long.MinValue) if (highestDiff == long.MinValue)
{ {
Lock.ExitWriteLock();
return; return;
} }
@@ -481,6 +462,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
_context.Renderer.WaitSync(currentSync + (ulong)highestDiff); _context.Renderer.WaitSync(currentSync + (ulong)highestDiff);
RemoveRangesAndFlush(overlaps.ToArray(), rangeCount, highestDiff, currentSync, address, endAddress); RemoveRangesAndFlush(overlaps.ToArray(), rangeCount, highestDiff, currentSync, address, endAddress);
Lock.ExitWriteLock();
} }
/// <summary> /// <summary>
@@ -607,22 +590,17 @@ namespace Ryujinx.Graphics.Gpu.Memory
return; return;
} }
BufferModifiedRange buffPost = null;
bool extendsPost = false;
bool extendsPre = false;
if (first == last) if (first == last)
{ {
if (first.Address < address) if (first.Address < address)
{ {
first.Value.Size = address - first.Address; first.Value.Size = address - first.Address;
extendsPre = true; Update(first);
if (first.EndAddress > endAddress) if (first.EndAddress > endAddress)
{ {
buffPost = new BufferModifiedRange(endAddress, first.EndAddress - endAddress, Add(new BufferModifiedRange(endAddress, first.EndAddress - endAddress,
first.Value.SyncNumber, first.Value.Parent); first.Value.SyncNumber, first.Value.Parent));
extendsPost = true;
} }
} }
else else
@@ -631,6 +609,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{ {
first.Value.Size = first.EndAddress - endAddress; first.Value.Size = first.EndAddress - endAddress;
first.Value.Address = endAddress; first.Value.Address = endAddress;
Update(first);
} }
else else
{ {
@@ -638,16 +617,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
} }
} }
if (extendsPre && extendsPost)
{
Add(buffPost);
}
Lock.ExitWriteLock(); Lock.ExitWriteLock();
return; return;
} }
BufferModifiedRange buffPre = null; BufferModifiedRange buffPre = null;
BufferModifiedRange buffPost = null;
bool extendsPost = false;
bool extendsPre = false;
if (first.Address < address) if (first.Address < address)
{ {

View File

@@ -87,6 +87,43 @@ namespace Ryujinx.Memory.Range
return false; return false;
} }
/// <summary>
/// Updates an item's end address on the list. Address must be the same.
/// </summary>
/// <param name="item">The RangeItem to be updated</param>
/// <returns>True if the item was located and updated, false otherwise</returns>
protected override bool Update(RangeItem<T> item)
{
int index = BinarySearch(item.Address);
RangeItem<T> rangeItem = new(item.Value) { Previous = item.Previous, Next = item.Next };
if (index > 0)
{
Items[index - 1].Next = rangeItem;
}
if (index < Count - 1)
{
Items[index + 1].Previous = rangeItem;
}
foreach (ulong addr in item.QuickAccessAddresses)
{
_quickAccess.Remove(addr);
_fastQuickAccess.Remove(addr);
}
Items[index] = rangeItem;
if (item.Address != rangeItem.Address)
_quickAccess.Remove(item.Address);
_quickAccess[rangeItem.Address] = rangeItem;
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Insert(int index, RangeItem<T> item) private void Insert(int index, RangeItem<T> item)
{ {
@@ -193,10 +230,9 @@ namespace Ryujinx.Memory.Range
return; return;
} }
int startIndex = BinarySearch(startItem.Address); (int startIndex, int endIndex) = BinarySearchEdges(startItem.Address, endItem.EndAddress);
int endIndex = BinarySearch(endItem.Address);
for (int i = startIndex; i <= endIndex; i++) for (int i = startIndex; i < endIndex; i++)
{ {
_quickAccess.Remove(Items[i].Address); _quickAccess.Remove(Items[i].Address);
foreach (ulong addr in Items[i].QuickAccessAddresses) foreach (ulong addr in Items[i].QuickAccessAddresses)
@@ -206,23 +242,23 @@ namespace Ryujinx.Memory.Range
} }
} }
if (endIndex < Count - 1) if (endIndex < Count)
{ {
Items[endIndex + 1].Previous = startIndex > 0 ? Items[startIndex - 1] : null; Items[endIndex].Previous = startIndex > 0 ? Items[startIndex - 1] : null;
} }
if (startIndex > 0) if (startIndex > 0)
{ {
Items[startIndex - 1].Next = endIndex < Count - 1 ? Items[endIndex + 1] : null; Items[startIndex - 1].Next = endIndex < Count ? Items[endIndex] : null;
} }
if (endIndex < Count - 1) if (endIndex < Count)
{ {
Array.Copy(Items, endIndex + 1, Items, startIndex, Count - endIndex - 1); Array.Copy(Items, endIndex, Items, startIndex, Count - endIndex);
} }
Count -= endIndex - startIndex + 1; Count -= endIndex - startIndex;
} }
/// <summary> /// <summary>

View File

@@ -81,12 +81,73 @@ namespace Ryujinx.Memory.Range
{ {
if (Items[index].Value.Equals(item)) if (Items[index].Value.Equals(item))
{ {
RangeItem<T> rangeItem = new(item) { Previous = Items[index].Previous, Next = Items[index].Next };
if (index > 0)
{
Items[index - 1].Next = rangeItem;
}
if (index < Count - 1)
{
Items[index + 1].Previous = rangeItem;
}
foreach (ulong address in Items[index].QuickAccessAddresses) foreach (ulong address in Items[index].QuickAccessAddresses)
{ {
_quickAccess.Remove(address); _quickAccess.Remove(address);
} }
Items[index] = new RangeItem<T>(item); Items[index] = rangeItem;
return true;
}
if (Items[index].Address > item.Address)
{
break;
}
index++;
}
}
return false;
}
/// <summary>
/// Updates an item's end address on the list. Address must be the same.
/// </summary>
/// <param name="item">The RangeItem to be updated</param>
/// <returns>True if the item was located and updated, false otherwise</returns>
protected override bool Update(RangeItem<T> item)
{
int index = BinarySearch(item.Address);
if (index >= 0)
{
while (index < Count)
{
if (Items[index].Equals(item))
{
RangeItem<T> rangeItem = new(item.Value) { Previous = item.Previous, Next = item.Next };
if (index > 0)
{
Items[index - 1].Next = rangeItem;
}
if (index < Count - 1)
{
Items[index + 1].Previous = rangeItem;
}
foreach (ulong address in item.QuickAccessAddresses)
{
_quickAccess.Remove(address);
}
Items[index] = rangeItem;
return true; return true;
} }

View File

@@ -30,7 +30,7 @@ namespace Ryujinx.Memory.Range
return u1 == u2; return u1 == u2;
} }
public int GetHashCode(ulong value) => (int)(value >> 5); public int GetHashCode(ulong value) => (int)(value << 5);
public static readonly AddressEqualityComparer Comparer = new(); public static readonly AddressEqualityComparer Comparer = new();
} }
@@ -63,6 +63,13 @@ namespace Ryujinx.Memory.Range
/// <returns>True if the item was located and updated, false otherwise</returns> /// <returns>True if the item was located and updated, false otherwise</returns>
protected abstract bool Update(T item); protected abstract bool Update(T item);
/// <summary>
/// Updates an item's end address on the list. Address must be the same.
/// </summary>
/// <param name="item">The RangeItem to be updated</param>
/// <returns>True if the item was located and updated, false otherwise</returns>
protected abstract bool Update(RangeItem<T> item);
public abstract bool Remove(T item); public abstract bool Remove(T item);
public abstract void RemoveRange(RangeItem<T> startItem, RangeItem<T> endItem); public abstract void RemoveRange(RangeItem<T> startItem, RangeItem<T> endItem);

View File

@@ -182,11 +182,15 @@ namespace Ryujinx.Memory.Tracking
{ {
if (region.Guest) if (region.Guest)
{ {
_guestVirtualRegions.Lock.EnterWriteLock();
_guestVirtualRegions.Remove(region); _guestVirtualRegions.Remove(region);
_guestVirtualRegions.Lock.ExitWriteLock();
} }
else else
{ {
_virtualRegions.Lock.EnterWriteLock();
_virtualRegions.Remove(region); _virtualRegions.Remove(region);
_virtualRegions.Lock.ExitWriteLock();
} }
} }