diff options
Diffstat (limited to 'Ryujinx.Memory/WindowsShared/PlaceholderList.cs')
-rw-r--r-- | Ryujinx.Memory/WindowsShared/PlaceholderList.cs | 293 |
1 files changed, 0 insertions, 293 deletions
diff --git a/Ryujinx.Memory/WindowsShared/PlaceholderList.cs b/Ryujinx.Memory/WindowsShared/PlaceholderList.cs deleted file mode 100644 index 848e410e..00000000 --- a/Ryujinx.Memory/WindowsShared/PlaceholderList.cs +++ /dev/null @@ -1,293 +0,0 @@ -using Ryujinx.Memory.Range; -using System; -using System.Diagnostics; - -namespace Ryujinx.Memory.WindowsShared -{ - /// <summary> - /// A specialized list used for keeping track of Windows 10's memory placeholders. - /// This is used to make splitting a large placeholder into equally small - /// granular chunks much easier, while avoiding slowdown due to a large number of - /// placeholders by coalescing adjacent granular placeholders after they are unused. - /// </summary> - class PlaceholderList - { - private class PlaceholderBlock : IRange - { - public ulong Address { get; } - public ulong Size { get; private set; } - public ulong EndAddress { get; private set; } - public bool IsGranular { get; set; } - - public PlaceholderBlock(ulong id, ulong size, bool isGranular) - { - Address = id; - Size = size; - EndAddress = id + size; - IsGranular = isGranular; - } - - public bool OverlapsWith(ulong address, ulong size) - { - return Address < address + size && address < EndAddress; - } - - public void ExtendTo(ulong end, RangeList<PlaceholderBlock> list) - { - EndAddress = end; - Size = end - Address; - - list.UpdateEndAddress(this); - } - } - - private RangeList<PlaceholderBlock> _placeholders; - private PlaceholderBlock[] _foundBlocks = new PlaceholderBlock[32]; - - /// <summary> - /// Create a new list to manage placeholders. - /// Note that a size is measured in granular placeholders. - /// If the placeholder granularity is 65536 bytes, then a 65536 region will be covered by 1 placeholder granularity. - /// </summary> - /// <param name="size">Size measured in granular placeholders</param> - public PlaceholderList(ulong size) - { - _placeholders = new RangeList<PlaceholderBlock>(); - - _placeholders.Add(new PlaceholderBlock(0, size, false)); - } - - /// <summary> - /// Ensure that the given range of placeholders is granular. - /// </summary> - /// <param name="id">Start of the range, measured in granular placeholders</param> - /// <param name="size">Size of the range, measured in granular placeholders</param> - /// <param name="splitPlaceholderCallback">Callback function to run when splitting placeholders, calls with (start, middle)</param> - public void EnsurePlaceholders(ulong id, ulong size, Action<ulong, ulong> splitPlaceholderCallback) - { - // Search 1 before and after the placeholders, as we may need to expand/join granular regions surrounding the requested area. - - ulong endId = id + size; - ulong searchStartId = id == 0 ? 0 : (id - 1); - int blockCount = _placeholders.FindOverlapsNonOverlapping(searchStartId, (endId - searchStartId) + 1, ref _foundBlocks); - - PlaceholderBlock first = _foundBlocks[0]; - PlaceholderBlock last = _foundBlocks[blockCount - 1]; - bool overlapStart = first.EndAddress >= id && id != 0; - bool overlapEnd = last.Address <= endId; - - for (int i = 0; i < blockCount; i++) - { - // Go through all non-granular blocks in the range and create placeholders. - PlaceholderBlock block = _foundBlocks[i]; - - if (block.Address <= id && block.EndAddress >= endId && block.IsGranular) - { - return; // The region we're searching for is already granular. - } - - if (!block.IsGranular) - { - ulong placeholderStart = Math.Max(block.Address, id); - ulong placeholderEnd = Math.Min(block.EndAddress - 1, endId); - - if (placeholderStart != block.Address && placeholderStart != block.EndAddress) - { - splitPlaceholderCallback(block.Address, placeholderStart - block.Address); - } - - for (ulong j = placeholderStart; j < placeholderEnd; j++) - { - splitPlaceholderCallback(j, 1); - } - } - - if (!((block == first && overlapStart) || (block == last && overlapEnd))) - { - // Remove blocks that will be replaced - _placeholders.Remove(block); - } - } - - if (overlapEnd) - { - if (!(first == last && overlapStart)) - { - _placeholders.Remove(last); - } - - if (last.IsGranular) - { - endId = last.EndAddress; - } - else if (last.EndAddress != endId) - { - _placeholders.Add(new PlaceholderBlock(endId, last.EndAddress - endId, false)); - } - } - - if (overlapStart && first.IsGranular) - { - first.ExtendTo(endId, _placeholders); - } - else - { - if (overlapStart) - { - first.ExtendTo(id, _placeholders); - } - - _placeholders.Add(new PlaceholderBlock(id, endId - id, true)); - } - - ValidateList(); - } - - /// <summary> - /// Coalesces placeholders in a given region, as they are not being used. - /// This assumes that the region only contains placeholders - all views and allocations must have been replaced with placeholders. - /// </summary> - /// <param name="id">Start of the range, measured in granular placeholders</param> - /// <param name="size">Size of the range, measured in granular placeholders</param> - /// <param name="coalescePlaceholderCallback">Callback function to run when coalescing two placeholders, calls with (start, end)</param> - public void RemovePlaceholders(ulong id, ulong size, Action<ulong, ulong> coalescePlaceholderCallback) - { - ulong endId = id + size; - int blockCount = _placeholders.FindOverlapsNonOverlapping(id, size, ref _foundBlocks); - - PlaceholderBlock first = _foundBlocks[0]; - PlaceholderBlock last = _foundBlocks[blockCount - 1]; - - // All granular blocks must have non-granular blocks surrounding them, unless they start at 0. - // We must extend the non-granular blocks into the granular ones. This does mean that we need to search twice. - - if (first.IsGranular || last.IsGranular) - { - ulong surroundStart = Math.Max(0, (first.IsGranular && first.Address != 0) ? first.Address - 1 : id); - blockCount = _placeholders.FindOverlapsNonOverlapping( - surroundStart, - (last.IsGranular ? last.EndAddress + 1 : endId) - surroundStart, - ref _foundBlocks); - - first = _foundBlocks[0]; - last = _foundBlocks[blockCount - 1]; - } - - if (first == last) - { - return; // Already coalesced. - } - - PlaceholderBlock extendBlock = id == 0 ? null : first; - bool newBlock = false; - for (int i = extendBlock == null ? 0 : 1; i < blockCount; i++) - { - // Go through all granular blocks in the range and extend placeholders. - PlaceholderBlock block = _foundBlocks[i]; - - ulong blockEnd = block.EndAddress; - ulong extendFrom; - ulong extent = Math.Min(blockEnd, endId); - - if (block.Address < id && blockEnd > id) - { - block.ExtendTo(id, _placeholders); - extendBlock = null; - } - else - { - _placeholders.Remove(block); - } - - if (extendBlock == null) - { - extendFrom = id; - extendBlock = new PlaceholderBlock(id, extent - id, false); - _placeholders.Add(extendBlock); - - if (blockEnd > extent) - { - _placeholders.Add(new PlaceholderBlock(extent, blockEnd - extent, true)); - - // Skip the next non-granular block, and extend from that into the granular block afterwards. - // (assuming that one is still in the requested range) - - if (i + 1 < blockCount) - { - extendBlock = _foundBlocks[i + 1]; - } - - i++; - } - - newBlock = true; - } - else - { - extendFrom = extendBlock.Address; - extendBlock.ExtendTo(block.IsGranular ? extent : block.EndAddress, _placeholders); - } - - if (block.IsGranular) - { - ulong placeholderStart = Math.Max(block.Address, id); - ulong placeholderEnd = extent; - - if (newBlock) - { - placeholderStart++; - newBlock = false; - } - - for (ulong j = placeholderStart; j < placeholderEnd; j++) - { - coalescePlaceholderCallback(extendFrom, (j + 1) - extendFrom); - } - - if (extent < block.EndAddress) - { - _placeholders.Add(new PlaceholderBlock(placeholderEnd, block.EndAddress - placeholderEnd, true)); - ValidateList(); - return; - } - } - else - { - coalescePlaceholderCallback(extendFrom, block.EndAddress - extendFrom); - } - } - - ValidateList(); - } - - /// <summary> - /// Ensure that the placeholder list is valid. - /// A valid list should not have any gaps between the placeholders, - /// and there may be no placehonders with the same IsGranular value next to each other. - /// </summary> - [Conditional("DEBUG")] - private void ValidateList() - { - bool isGranular = false; - bool first = true; - ulong lastAddress = 0; - - foreach (var placeholder in _placeholders) - { - if (placeholder.Address != lastAddress) - { - throw new InvalidOperationException("Gap in placeholder list."); - } - - if (isGranular == placeholder.IsGranular && !first) - { - throw new InvalidOperationException("Placeholder list not alternating."); - } - - first = false; - isGranular = placeholder.IsGranular; - lastAddress = placeholder.EndAddress; - } - } - } -} |