diff --git a/src/Ryujinx.Graphics.Device/DeviceState.cs b/src/Ryujinx.Graphics.Device/DeviceState.cs index 11d8e3ac2..f0b9da894 100644 --- a/src/Ryujinx.Graphics.Device/DeviceState.cs +++ b/src/Ryujinx.Graphics.Device/DeviceState.cs @@ -81,16 +81,8 @@ namespace Ryujinx.Graphics.Device if (index < Size) { uint alignedOffset = index * RegisterSize; - - Func readCallback = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_readCallbacks), (nint)index); - if (readCallback != null) - { - return readCallback(); - } - else - { - return GetRefUnchecked(alignedOffset); - } + + return _readCallbacks[index]?.Invoke() ?? GetRefUnchecked(alignedOffset); } return 0; @@ -107,7 +99,7 @@ namespace Ryujinx.Graphics.Device 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; storage = data; - Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_writeCallbacks), (nint)index)?.Invoke(data); + _writeCallbacks[index]?.Invoke(data); } else { diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs index 9383d3a3f..3e77eb8ac 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs @@ -109,7 +109,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed if (index < BlockSize) { - int groupIndex = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_registerToGroupMapping), (nint)index); + int groupIndex = _registerToGroupMapping[index]; if (groupIndex != 0) { groupIndex--; diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs index dc8f4e45f..1c7adf2fc 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs @@ -120,11 +120,7 @@ namespace Ryujinx.Graphics.Gpu.Memory public void ExcludeModifiedRegions(ulong address, ulong size, Action action) { // 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 first, RangeItem last) = FindOverlaps(address, size); @@ -145,10 +141,7 @@ namespace Ryujinx.Graphics.Gpu.Memory current = current.Next; } - if (!lockOwner) - { - Lock.ExitReadLock(); - } + Lock.ExitReadLock(); if ((long)size > 0) { @@ -179,9 +172,7 @@ namespace Ryujinx.Graphics.Gpu.Memory return; } - BufferModifiedRange buffPost = null; - bool extendsPost = false; - bool extendsPre = false; + if (first == last) { @@ -196,14 +187,12 @@ namespace Ryujinx.Graphics.Gpu.Memory if (first.Address < address) { first.Value.Size = address - first.Address; - - extendsPre = true; + Update(first); if (first.EndAddress > endAddress) { - buffPost = new BufferModifiedRange(endAddress, first.EndAddress - endAddress, - first.Value.SyncNumber, first.Value.Parent); - extendsPost = true; + Add(new BufferModifiedRange(endAddress, first.EndAddress - endAddress, + first.Value.SyncNumber, first.Value.Parent)); } } else @@ -212,6 +201,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { first.Value.Size = first.EndAddress - endAddress; first.Value.Address = endAddress; + Update(first); } else { @@ -219,11 +209,6 @@ namespace Ryujinx.Graphics.Gpu.Memory } } - if (extendsPre && extendsPost) - { - Add(buffPost); - } - Add(new BufferModifiedRange(address, size, syncNumber, this)); Lock.ExitWriteLock(); @@ -231,6 +216,9 @@ namespace Ryujinx.Graphics.Gpu.Memory } BufferModifiedRange buffPre = null; + BufferModifiedRange buffPost = null; + bool extendsPost = false; + bool extendsPre = false; if (first.Address < address) { @@ -329,7 +317,7 @@ namespace Ryujinx.Graphics.Gpu.Memory public bool HasRange(ulong address, ulong size) { Lock.EnterReadLock(); - (RangeItem first, RangeItem _) = FindOverlaps(address, size); + RangeItem first = FindOverlapFast(address, size); bool result = first is not null; Lock.ExitReadLock(); return result; @@ -386,9 +374,7 @@ namespace Ryujinx.Graphics.Gpu.Memory ulong clampAddress = Math.Max(address, overlap.Address); ulong clampEnd = Math.Min(endAddress, overlap.EndAddress); - Lock.EnterWriteLock(); ClearPart(overlap, clampAddress, clampEnd); - Lock.ExitWriteLock(); RangeActionWithMigration(clampAddress, clampEnd - clampAddress, waitSync, _flushAction); } @@ -418,40 +404,33 @@ namespace Ryujinx.Graphics.Gpu.Memory ulong endAddress = address + size; ulong currentSync = _context.SyncNumber; - int rangeCount = 0; - List> overlaps = []; // Range list must be consistent for this operation - Lock.EnterReadLock(); 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 first, RangeItem last) = FindOverlaps(address, size); - - RangeItem current = first; - while (last != null && current != last.Next) - { - rangeCount++; - overlaps.Add(current); - current = current.Next; - } - } - Lock.ExitReadLock(); - - if (rangeCount == -1) { _migrationTarget!.WaitForAndFlushRanges(address, size); 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 first, RangeItem last) = FindOverlaps(address, size); + + RangeItem current = first; + while (last != null && current != last.Next) + { + overlaps.Add(current); + current = current.Next; + } + + int rangeCount = overlaps.Count; if (rangeCount == 0) { + Lock.ExitWriteLock(); + return; } @@ -474,6 +453,8 @@ namespace Ryujinx.Graphics.Gpu.Memory if (highestDiff == long.MinValue) { + Lock.ExitWriteLock(); + return; } @@ -481,6 +462,8 @@ namespace Ryujinx.Graphics.Gpu.Memory _context.Renderer.WaitSync(currentSync + (ulong)highestDiff); RemoveRangesAndFlush(overlaps.ToArray(), rangeCount, highestDiff, currentSync, address, endAddress); + + Lock.ExitWriteLock(); } /// @@ -607,22 +590,17 @@ namespace Ryujinx.Graphics.Gpu.Memory return; } - BufferModifiedRange buffPost = null; - bool extendsPost = false; - bool extendsPre = false; - if (first == last) { if (first.Address < address) { first.Value.Size = address - first.Address; - extendsPre = true; + Update(first); if (first.EndAddress > endAddress) { - buffPost = new BufferModifiedRange(endAddress, first.EndAddress - endAddress, - first.Value.SyncNumber, first.Value.Parent); - extendsPost = true; + Add(new BufferModifiedRange(endAddress, first.EndAddress - endAddress, + first.Value.SyncNumber, first.Value.Parent)); } } else @@ -631,6 +609,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { first.Value.Size = first.EndAddress - endAddress; first.Value.Address = endAddress; + Update(first); } else { @@ -638,16 +617,14 @@ namespace Ryujinx.Graphics.Gpu.Memory } } - if (extendsPre && extendsPost) - { - Add(buffPost); - } - Lock.ExitWriteLock(); return; } BufferModifiedRange buffPre = null; + BufferModifiedRange buffPost = null; + bool extendsPost = false; + bool extendsPre = false; if (first.Address < address) { diff --git a/src/Ryujinx.Memory/Range/NonOverlappingRangeList.cs b/src/Ryujinx.Memory/Range/NonOverlappingRangeList.cs index 64329147e..76513c9ef 100644 --- a/src/Ryujinx.Memory/Range/NonOverlappingRangeList.cs +++ b/src/Ryujinx.Memory/Range/NonOverlappingRangeList.cs @@ -87,6 +87,43 @@ namespace Ryujinx.Memory.Range return false; } + /// + /// Updates an item's end address on the list. Address must be the same. + /// + /// The RangeItem to be updated + /// True if the item was located and updated, false otherwise + protected override bool Update(RangeItem item) + { + int index = BinarySearch(item.Address); + + RangeItem 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)] private void Insert(int index, RangeItem item) { @@ -193,10 +230,9 @@ namespace Ryujinx.Memory.Range return; } - int startIndex = BinarySearch(startItem.Address); - int endIndex = BinarySearch(endItem.Address); + (int startIndex, int endIndex) = BinarySearchEdges(startItem.Address, endItem.EndAddress); - for (int i = startIndex; i <= endIndex; i++) + for (int i = startIndex; i < endIndex; i++) { _quickAccess.Remove(Items[i].Address); 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) { - 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; } /// diff --git a/src/Ryujinx.Memory/Range/RangeList.cs b/src/Ryujinx.Memory/Range/RangeList.cs index 379fc648c..be0e34653 100644 --- a/src/Ryujinx.Memory/Range/RangeList.cs +++ b/src/Ryujinx.Memory/Range/RangeList.cs @@ -81,12 +81,73 @@ namespace Ryujinx.Memory.Range { if (Items[index].Value.Equals(item)) { + RangeItem 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) { _quickAccess.Remove(address); } - Items[index] = new RangeItem(item); + Items[index] = rangeItem; + + return true; + } + + if (Items[index].Address > item.Address) + { + break; + } + + index++; + } + } + + return false; + } + + /// + /// Updates an item's end address on the list. Address must be the same. + /// + /// The RangeItem to be updated + /// True if the item was located and updated, false otherwise + protected override bool Update(RangeItem item) + { + int index = BinarySearch(item.Address); + + if (index >= 0) + { + while (index < Count) + { + if (Items[index].Equals(item)) + { + RangeItem 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; } diff --git a/src/Ryujinx.Memory/Range/RangeListBase.cs b/src/Ryujinx.Memory/Range/RangeListBase.cs index 7dccd2d38..a1a48b087 100644 --- a/src/Ryujinx.Memory/Range/RangeListBase.cs +++ b/src/Ryujinx.Memory/Range/RangeListBase.cs @@ -30,7 +30,7 @@ namespace Ryujinx.Memory.Range 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(); } @@ -63,6 +63,13 @@ namespace Ryujinx.Memory.Range /// True if the item was located and updated, false otherwise protected abstract bool Update(T item); + /// + /// Updates an item's end address on the list. Address must be the same. + /// + /// The RangeItem to be updated + /// True if the item was located and updated, false otherwise + protected abstract bool Update(RangeItem item); + public abstract bool Remove(T item); public abstract void RemoveRange(RangeItem startItem, RangeItem endItem); diff --git a/src/Ryujinx.Memory/Tracking/MemoryTracking.cs b/src/Ryujinx.Memory/Tracking/MemoryTracking.cs index 8f7ef0be2..feee36ead 100644 --- a/src/Ryujinx.Memory/Tracking/MemoryTracking.cs +++ b/src/Ryujinx.Memory/Tracking/MemoryTracking.cs @@ -182,11 +182,15 @@ namespace Ryujinx.Memory.Tracking { if (region.Guest) { + _guestVirtualRegions.Lock.EnterWriteLock(); _guestVirtualRegions.Remove(region); + _guestVirtualRegions.Lock.ExitWriteLock(); } else { + _virtualRegions.Lock.EnterWriteLock(); _virtualRegions.Remove(region); + _virtualRegions.Lock.ExitWriteLock(); } }