diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs b/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs index 9e5c5e8404..6322743161 100644 --- a/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs +++ b/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs @@ -365,7 +365,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { lock (_lock) { - Items.Clear(); + Count = 0; } } } diff --git a/Ryujinx.Memory/Range/RangeList.cs b/Ryujinx.Memory/Range/RangeList.cs index fd26065632..d82a05c5ef 100644 --- a/Ryujinx.Memory/Range/RangeList.cs +++ b/Ryujinx.Memory/Range/RangeList.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace Ryujinx.Memory.Range { @@ -10,18 +11,40 @@ namespace Ryujinx.Memory.Range /// Type of the range. public class RangeList : IEnumerable where T : IRange { + private readonly struct RangeItem where TValue : IRange + { + public readonly ulong Address; + public readonly ulong EndAddress; + + public readonly TValue Value; + + public RangeItem(TValue value) + { + Value = value; + + Address = value.Address; + EndAddress = value.Address + value.Size; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool OverlapsWith(ulong address, ulong endAddress) + { + return Address < endAddress && address < EndAddress; + } + } + private const int ArrayGrowthSize = 32; + private const int BackingGrowthSize = 1024; - protected readonly List Items; - - public int Count => Items.Count; + private RangeItem[] _items; + public int Count { get; protected set; } /// /// Creates a new range list. /// public RangeList() { - Items = new List(); + _items = new RangeItem[BackingGrowthSize]; } /// @@ -37,7 +60,40 @@ namespace Ryujinx.Memory.Range index = ~index; } - Items.Insert(index, item); + Insert(index, new RangeItem(item)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Insert(int index, RangeItem item) + { + if (Count + 1 > _items.Length) + { + Array.Resize(ref _items, _items.Length + ArrayGrowthSize); + } + + if (index >= Count) + { + if (index == Count) + { + _items[Count++] = item; + } + } + else + { + Array.Copy(_items, index, _items, index + 1, Count - index); + + _items[index] = item; + Count++; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void RemoveAt(int index) + { + if (index < --Count) + { + Array.Copy(_items, index + 1, _items, index, Count - index); + } } /// @@ -51,21 +107,21 @@ namespace Ryujinx.Memory.Range if (index >= 0) { - while (index > 0 && Items[index - 1].Address == item.Address) + while (index > 0 && _items[index - 1].Address == item.Address) { index--; } - while (index < Items.Count) + while (index < Count) { - if (Items[index].Equals(item)) + if (_items[index].Value.Equals(item)) { - Items.RemoveAt(index); + RemoveAt(index); return true; } - if (Items[index].Address > item.Address) + if (_items[index].Address > item.Address) { break; } @@ -77,6 +133,40 @@ namespace Ryujinx.Memory.Range return false; } + /// + /// Updates an item's end address. + /// + /// The item to be updated + public void UpdateEndAddress(T item) + { + int index = BinarySearch(item.Address); + + if (index >= 0) + { + while (index > 0 && _items[index - 1].Address == item.Address) + { + index--; + } + + while (index < Count) + { + if (_items[index].Value.Equals(item)) + { + _items[index] = new RangeItem(item); + + return; + } + + if (_items[index].Address > item.Address) + { + break; + } + + index++; + } + } + } + /// /// Gets the first item on the list overlapping in memory with the specified item. /// @@ -103,14 +193,14 @@ namespace Ryujinx.Memory.Range /// The overlapping item, or the default value for the type if none found public T FindFirstOverlap(ulong address, ulong size) { - int index = BinarySearch(address, size); + int index = BinarySearch(address, address + size); if (index < 0) { return default(T); } - return Items[index]; + return _items[index].Value; } /// @@ -137,21 +227,23 @@ namespace Ryujinx.Memory.Range ulong endAddress = address + size; - foreach (T item in Items) + for (int i = 0; i < Count; i++) { + ref RangeItem item = ref _items[i]; + if (item.Address >= endAddress) { break; } - if (item.OverlapsWith(address, size)) + if (item.OverlapsWith(address, endAddress)) { if (outputIndex == output.Length) { Array.Resize(ref output, outputIndex + ArrayGrowthSize); } - output[outputIndex++] = item; + output[outputIndex++] = item.Value; } } @@ -192,11 +284,13 @@ namespace Ryujinx.Memory.Range // when none of the items on the list overlaps with each other. int outputIndex = 0; - int index = BinarySearch(address, size); + ulong endAddress = address + size; + + int index = BinarySearch(address, endAddress); if (index >= 0) { - while (index > 0 && Items[index - 1].OverlapsWith(address, size)) + while (index > 0 && _items[index - 1].OverlapsWith(address, endAddress)) { index--; } @@ -208,9 +302,9 @@ namespace Ryujinx.Memory.Range Array.Resize(ref output, outputIndex + ArrayGrowthSize); } - output[outputIndex++] = Items[index++]; + output[outputIndex++] = _items[index++].Value; } - while (index < Items.Count && Items[index].OverlapsWith(address, size)); + while (index < Count && _items[index].OverlapsWith(address, endAddress)); } return outputIndex; @@ -230,14 +324,14 @@ namespace Ryujinx.Memory.Range if (index >= 0) { - while (index > 0 && Items[index - 1].Address == address) + while (index > 0 && _items[index - 1].Address == address) { index--; } - while (index < Items.Count) + while (index < Count) { - T overlap = Items[index++]; + ref RangeItem overlap = ref _items[index++]; if (overlap.Address != address) { @@ -249,7 +343,7 @@ namespace Ryujinx.Memory.Range Array.Resize(ref output, outputIndex + ArrayGrowthSize); } - output[outputIndex++] = overlap; + output[outputIndex++] = overlap.Value; } } @@ -264,7 +358,7 @@ namespace Ryujinx.Memory.Range private int BinarySearch(ulong address) { int left = 0; - int right = Items.Count - 1; + int right = Count - 1; while (left <= right) { @@ -272,7 +366,7 @@ namespace Ryujinx.Memory.Range int middle = left + (range >> 1); - T item = Items[middle]; + ref RangeItem item = ref _items[middle]; if (item.Address == address) { @@ -296,12 +390,12 @@ namespace Ryujinx.Memory.Range /// Performs binary search for items overlapping a given memory range. /// /// Start address of the range - /// Size in bytes of the range + /// End address of the range /// List index of the item, or complement index of nearest item with lower value on the list - private int BinarySearch(ulong address, ulong size) + private int BinarySearch(ulong address, ulong endAddress) { int left = 0; - int right = Items.Count - 1; + int right = Count - 1; while (left <= right) { @@ -309,9 +403,9 @@ namespace Ryujinx.Memory.Range int middle = left + (range >> 1); - T item = Items[middle]; + ref RangeItem item = ref _items[middle]; - if (item.OverlapsWith(address, size)) + if (item.OverlapsWith(address, endAddress)) { return middle; } @@ -331,12 +425,18 @@ namespace Ryujinx.Memory.Range public IEnumerator GetEnumerator() { - return Items.GetEnumerator(); + for (int i = 0; i < Count; i++) + { + yield return _items[i].Value; + } } IEnumerator IEnumerable.GetEnumerator() { - return Items.GetEnumerator(); + for (int i = 0; i < Count; i++) + { + yield return _items[i].Value; + } } } } \ No newline at end of file diff --git a/Ryujinx.Memory/WindowsShared/EmulatedSharedMemoryWindows.cs b/Ryujinx.Memory/WindowsShared/EmulatedSharedMemoryWindows.cs index 46399504ef..1417f7d5ab 100644 --- a/Ryujinx.Memory/WindowsShared/EmulatedSharedMemoryWindows.cs +++ b/Ryujinx.Memory/WindowsShared/EmulatedSharedMemoryWindows.cs @@ -41,10 +41,12 @@ namespace Ryujinx.Memory.WindowsShared return Address < address + size && address < EndAddress; } - public void ExtendTo(ulong endAddress) + public void ExtendTo(ulong endAddress, RangeList list) { EndAddress = endAddress; Size = endAddress - Address; + + list.UpdateEndAddress(this); } public void AddBlocks(IEnumerable blocks) @@ -300,14 +302,14 @@ namespace Ryujinx.Memory.WindowsShared _mappings.Remove(endOverlap); - startOverlap.ExtendTo(endOverlap.EndAddress); + startOverlap.ExtendTo(endOverlap.EndAddress, _mappings); startOverlap.AddBlocks(blocks); startOverlap.AddBlocks(endOverlap.Blocks); } else if (startOverlap != null) { - startOverlap.ExtendTo(endAddress); + startOverlap.ExtendTo(endAddress, _mappings); startOverlap.AddBlocks(blocks); } @@ -317,7 +319,7 @@ namespace Ryujinx.Memory.WindowsShared if (endOverlap != null) { - mapping.ExtendTo(endOverlap.EndAddress); + mapping.ExtendTo(endOverlap.EndAddress, _mappings); mapping.AddBlocks(endOverlap.Blocks); @@ -381,6 +383,7 @@ namespace Ryujinx.Memory.WindowsShared if (mapping.EndAddress > endAddress) { var newMapping = (SharedMemoryMapping)mapping.Split(endAddress); + _mappings.UpdateEndAddress(mapping); _mappings.Add(newMapping); if ((endAddress & MappingMask) != 0) @@ -400,7 +403,9 @@ namespace Ryujinx.Memory.WindowsShared // If the first region starts before the decommit address, split it by modifying its end address. if (mapping.Address < address) { + var oldMapping = mapping; mapping = (SharedMemoryMapping)mapping.Split(address); + _mappings.UpdateEndAddress(oldMapping); if ((address & MappingMask) != 0) { diff --git a/Ryujinx.Memory/WindowsShared/PlaceholderList.cs b/Ryujinx.Memory/WindowsShared/PlaceholderList.cs index be8cef9c3e..848e410e8e 100644 --- a/Ryujinx.Memory/WindowsShared/PlaceholderList.cs +++ b/Ryujinx.Memory/WindowsShared/PlaceholderList.cs @@ -32,10 +32,12 @@ namespace Ryujinx.Memory.WindowsShared return Address < address + size && address < EndAddress; } - public void ExtendTo(ulong end) + public void ExtendTo(ulong end, RangeList list) { EndAddress = end; Size = end - Address; + + list.UpdateEndAddress(this); } } @@ -126,13 +128,13 @@ namespace Ryujinx.Memory.WindowsShared if (overlapStart && first.IsGranular) { - first.ExtendTo(endId); + first.ExtendTo(endId, _placeholders); } else { if (overlapStart) { - first.ExtendTo(id); + first.ExtendTo(id, _placeholders); } _placeholders.Add(new PlaceholderBlock(id, endId - id, true)); @@ -189,7 +191,7 @@ namespace Ryujinx.Memory.WindowsShared if (block.Address < id && blockEnd > id) { - block.ExtendTo(id); + block.ExtendTo(id, _placeholders); extendBlock = null; } else @@ -223,7 +225,7 @@ namespace Ryujinx.Memory.WindowsShared else { extendFrom = extendBlock.Address; - extendBlock.ExtendTo(block.IsGranular ? extent : block.EndAddress); + extendBlock.ExtendTo(block.IsGranular ? extent : block.EndAddress, _placeholders); } if (block.IsGranular)