diff options
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Memory')
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/Buffer.cs | 74 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/BufferManager.cs | 2 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/IRange.cs | 13 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs | 4 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs | 41 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/RangeList.cs | 343 |
6 files changed, 80 insertions, 397 deletions
diff --git a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs index 2394f90d..3cc96432 100644 --- a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs +++ b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs @@ -1,4 +1,6 @@ +using Ryujinx.Cpu.Tracking; using Ryujinx.Graphics.GAL; +using Ryujinx.Memory.Range; using System; namespace Ryujinx.Graphics.Gpu.Memory @@ -8,6 +10,8 @@ namespace Ryujinx.Graphics.Gpu.Memory /// </summary> class Buffer : IRange, IDisposable { + private static ulong GranularBufferThreshold = 4096; + private readonly GpuContext _context; /// <summary> @@ -30,9 +34,11 @@ namespace Ryujinx.Graphics.Gpu.Memory /// </summary> public ulong EndAddress => Address + Size; - private readonly (ulong, ulong)[] _modifiedRanges; + private CpuSmartMultiRegionHandle _memoryTrackingGranular; + private CpuRegionHandle _memoryTracking; + private int _sequenceNumber; - private readonly int[] _sequenceNumbers; + private bool _useGranular; /// <summary> /// Creates a new instance of the buffer. @@ -48,9 +54,16 @@ namespace Ryujinx.Graphics.Gpu.Memory Handle = context.Renderer.CreateBuffer((int)size); - _modifiedRanges = new (ulong, ulong)[size / PhysicalMemory.PageSize]; + _useGranular = size > GranularBufferThreshold; - _sequenceNumbers = new int[size / MemoryManager.PageSize]; + if (_useGranular) + { + _memoryTrackingGranular = context.PhysicalMemory.BeginSmartGranularTracking(address, size); + } + else + { + _memoryTracking = context.PhysicalMemory.BeginTracking(address, size); + } } /// <summary> @@ -91,41 +104,35 @@ namespace Ryujinx.Graphics.Gpu.Memory /// <param name="size">Size in bytes of the range to synchronize</param> public void SynchronizeMemory(ulong address, ulong size) { - int currentSequenceNumber = _context.SequenceNumber; - - bool needsSync = false; - - ulong buffOffset = address - Address; - - ulong buffEndOffset = (buffOffset + size + MemoryManager.PageMask) & ~MemoryManager.PageMask; - - int startIndex = (int)(buffOffset / MemoryManager.PageSize); - int endIndex = (int)(buffEndOffset / MemoryManager.PageSize); - - for (int index = startIndex; index < endIndex; index++) + if (_useGranular) { - if (_sequenceNumbers[index] != currentSequenceNumber) + _memoryTrackingGranular.QueryModified(address, size, (ulong mAddress, ulong mSize) => { - _sequenceNumbers[index] = currentSequenceNumber; + if (mAddress < Address) + { + mAddress = Address; + } - needsSync = true; - } - } + ulong maxSize = Address + Size - mAddress; - if (!needsSync) - { - return; - } + if (mSize > maxSize) + { + mSize = maxSize; + } - int count = _context.PhysicalMemory.QueryModified(address, size, ResourceName.Buffer, _modifiedRanges); + int offset = (int)(mAddress - Address); - for (int index = 0; index < count; index++) + _context.Renderer.SetBufferData(Handle, offset, _context.PhysicalMemory.GetSpan(mAddress, (int)mSize)); + }, _context.SequenceNumber); + } + else { - (ulong mAddress, ulong mSize) = _modifiedRanges[index]; - - int offset = (int)(mAddress - Address); - - _context.Renderer.SetBufferData(Handle, offset, _context.PhysicalMemory.GetSpan(mAddress, (int)mSize)); + if (_memoryTracking.Dirty && _context.SequenceNumber != _sequenceNumber) + { + _memoryTracking.Reprotect(); + _context.Renderer.SetBufferData(Handle, 0, _context.PhysicalMemory.GetSpan(Address, (int)Size)); + _sequenceNumber = _context.SequenceNumber; + } } } @@ -161,6 +168,9 @@ namespace Ryujinx.Graphics.Gpu.Memory public void Dispose() { _context.Renderer.DeleteBuffer(Handle); + + _memoryTrackingGranular?.Dispose(); + _memoryTracking?.Dispose(); } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs index 41067a11..ee1be74b 100644 --- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs +++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs @@ -2,6 +2,7 @@ using Ryujinx.Common; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu.State; using Ryujinx.Graphics.Shader; +using Ryujinx.Memory.Range; using System; namespace Ryujinx.Graphics.Gpu.Memory @@ -407,6 +408,7 @@ namespace Ryujinx.Graphics.Gpu.Memory } Buffer newBuffer = new Buffer(_context, address, endAddress - address); + newBuffer.SynchronizeMemory(address, endAddress - address); _buffers.Add(newBuffer); diff --git a/Ryujinx.Graphics.Gpu/Memory/IRange.cs b/Ryujinx.Graphics.Gpu/Memory/IRange.cs deleted file mode 100644 index 9d5eee0b..00000000 --- a/Ryujinx.Graphics.Gpu/Memory/IRange.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.Graphics.Gpu.Memory -{ - /// <summary> - /// Range of memory. - /// </summary> - interface IRange - { - ulong Address { get; } - ulong Size { get; } - - bool OverlapsWith(ulong address, ulong size); - } -}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs index 59b6d1e5..517dacef 100644 --- a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs +++ b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs @@ -125,6 +125,8 @@ namespace Ryujinx.Graphics.Gpu.Memory { lock (_pageTable) { + MemoryUnmapped?.Invoke(this, new UnmapEventArgs(va, size)); + for (ulong offset = 0; offset < size; offset += PageSize) { SetPte(va + offset, pa + offset); @@ -201,6 +203,8 @@ namespace Ryujinx.Graphics.Gpu.Memory { lock (_pageTable) { + MemoryUnmapped?.Invoke(this, new UnmapEventArgs(va, size)); + for (ulong offset = 0; offset < size; offset += PageSize) { if (IsPageInUse(va + offset)) diff --git a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs index ed325369..3ebf2fd7 100644 --- a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs +++ b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs @@ -1,4 +1,5 @@ using Ryujinx.Cpu; +using Ryujinx.Cpu.Tracking; using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -29,10 +30,11 @@ namespace Ryujinx.Graphics.Gpu.Memory /// </summary> /// <param name="address">Start address of the range</param> /// <param name="size">Size in bytes to be range</param> + /// <param name="tracked">True if read tracking is triggered on the span</param> /// <returns>A read only span of the data at the specified memory location</returns> - public ReadOnlySpan<byte> GetSpan(ulong address, int size) + public ReadOnlySpan<byte> GetSpan(ulong address, int size, bool tracked = false) { - return _cpuMemory.GetSpan(address, size); + return _cpuMemory.GetSpan(address, size, tracked); } /// <summary> @@ -78,17 +80,38 @@ namespace Ryujinx.Graphics.Gpu.Memory } /// <summary> - /// Checks if a specified virtual memory region has been modified by the CPU since the last call. + /// Obtains a memory tracking handle for the given virtual region. This should be disposed when finished with. /// </summary> /// <param name="address">CPU virtual address of the region</param> /// <param name="size">Size of the region</param> - /// <param name="name">Resource name</param> - /// <param name="modifiedRanges">Optional array where the modified ranges should be written</param> - /// <returns>The number of modified ranges</returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int QueryModified(ulong address, ulong size, ResourceName name, (ulong, ulong)[] modifiedRanges = null) + /// <returns>The memory tracking handle</returns> + public CpuRegionHandle BeginTracking(ulong address, ulong size) { - return _cpuMemory.QueryModified(address, size, (int)name, modifiedRanges); + return _cpuMemory.BeginTracking(address, size); + } + + /// <summary> + /// Obtains a memory tracking handle for the given virtual region, with a specified granularity. This should be disposed when finished with. + /// </summary> + /// <param name="address">CPU virtual address of the region</param> + /// <param name="size">Size of the region</param> + /// <param name="granularity">Desired granularity of write tracking</param> + /// <returns>The memory tracking handle</returns> + public CpuMultiRegionHandle BeginGranularTracking(ulong address, ulong size, ulong granularity = 4096) + { + return _cpuMemory.BeginGranularTracking(address, size, granularity); + } + + /// <summary> + /// Obtains a smart memory tracking handle for the given virtual region, with a specified granularity. This should be disposed when finished with. + /// </summary> + /// <param name="address">CPU virtual address of the region</param> + /// <param name="size">Size of the region</param> + /// <param name="granularity">Desired granularity of write tracking</param> + /// <returns>The memory tracking handle</returns> + public CpuSmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity = 4096) + { + return _cpuMemory.BeginSmartGranularTracking(address, size, granularity); } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Memory/RangeList.cs b/Ryujinx.Graphics.Gpu/Memory/RangeList.cs deleted file mode 100644 index 6af440c0..00000000 --- a/Ryujinx.Graphics.Gpu/Memory/RangeList.cs +++ /dev/null @@ -1,343 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Gpu.Memory -{ - /// <summary> - /// List of GPU resources with data on guest memory. - /// </summary> - /// <typeparam name="T">Type of the GPU resource</typeparam> - class RangeList<T> : IEnumerable<T> where T : IRange - { - private const int ArrayGrowthSize = 32; - - private readonly List<T> _items; - - /// <summary> - /// Creates a new GPU resources list. - /// </summary> - public RangeList() - { - _items = new List<T>(); - } - - /// <summary> - /// Adds a new item to the list. - /// </summary> - /// <param name="item">The item to be added</param> - public void Add(T item) - { - int index = BinarySearch(item.Address); - - if (index < 0) - { - index = ~index; - } - - _items.Insert(index, item); - } - - /// <summary> - /// Removes an item from the list. - /// </summary> - /// <param name="item">The item to be removed</param> - /// <returns>True if the item was removed, or false if it was not found</returns> - public bool Remove(T item) - { - int index = BinarySearch(item.Address); - - if (index >= 0) - { - while (index > 0 && _items[index - 1].Address == item.Address) - { - index--; - } - - while (index < _items.Count) - { - if (_items[index].Equals(item)) - { - _items.RemoveAt(index); - - return true; - } - - if (_items[index].Address > item.Address) - { - break; - } - - index++; - } - } - - return false; - } - - /// <summary> - /// Gets the first item on the list overlapping in memory with the specified item. - /// </summary> - /// <remarks> - /// Despite the name, this has no ordering guarantees of the returned item. - /// It only ensures that the item returned overlaps the specified item. - /// </remarks> - /// <param name="item">Item to check for overlaps</param> - /// <returns>The overlapping item, or the default value for the type if none found</returns> - public T FindFirstOverlap(T item) - { - return FindFirstOverlap(item.Address, item.Size); - } - - /// <summary> - /// Gets the first item on the list overlapping the specified memory range. - /// </summary> - /// <remarks> - /// Despite the name, this has no ordering guarantees of the returned item. - /// It only ensures that the item returned overlaps the specified memory range. - /// </remarks> - /// <param name="address">Start address of the range</param> - /// <param name="size">Size in bytes of the range</param> - /// <returns>The overlapping item, or the default value for the type if none found</returns> - public T FindFirstOverlap(ulong address, ulong size) - { - int index = BinarySearch(address, size); - - if (index < 0) - { - return default(T); - } - - return _items[index]; - } - - /// <summary> - /// Gets all items overlapping with the specified item in memory. - /// </summary> - /// <param name="item">Item to check for overlaps</param> - /// <param name="output">Output array where matches will be written. It is automatically resized to fit the results</param> - /// <returns>The number of overlapping items found</returns> - public int FindOverlaps(T item, ref T[] output) - { - return FindOverlaps(item.Address, item.Size, ref output); - } - - /// <summary> - /// Gets all items on the list overlapping the specified memory range. - /// </summary> - /// <param name="address">Start address of the range</param> - /// <param name="size">Size in bytes of the range</param> - /// <param name="output">Output array where matches will be written. It is automatically resized to fit the results</param> - /// <returns>The number of overlapping items found</returns> - public int FindOverlaps(ulong address, ulong size, ref T[] output) - { - int outputIndex = 0; - - ulong endAddress = address + size; - - lock (_items) - { - foreach (T item in _items) - { - if (item.Address >= endAddress) - { - break; - } - - if (item.OverlapsWith(address, size)) - { - if (outputIndex == output.Length) - { - Array.Resize(ref output, outputIndex + ArrayGrowthSize); - } - - output[outputIndex++] = item; - } - } - } - - return outputIndex; - } - - /// <summary> - /// Gets all items overlapping with the specified item in memory. - /// </summary> - /// <remarks> - /// This method only returns correct results if none of the items on the list overlaps with - /// each other. If that is not the case, this method should not be used. - /// This method is faster than the regular method to find all overlaps. - /// </remarks> - /// <param name="item">Item to check for overlaps</param> - /// <param name="output">Output array where matches will be written. It is automatically resized to fit the results</param> - /// <returns>The number of overlapping items found</returns> - public int FindOverlapsNonOverlapping(T item, ref T[] output) - { - return FindOverlapsNonOverlapping(item.Address, item.Size, ref output); - } - - /// <summary> - /// Gets all items on the list overlapping the specified memory range. - /// </summary> - /// <remarks> - /// This method only returns correct results if none of the items on the list overlaps with - /// each other. If that is not the case, this method should not be used. - /// This method is faster than the regular method to find all overlaps. - /// </remarks> - /// <param name="address">Start address of the range</param> - /// <param name="size">Size in bytes of the range</param> - /// <param name="output">Output array where matches will be written. It is automatically resized to fit the results</param> - /// <returns>The number of overlapping items found</returns> - public int FindOverlapsNonOverlapping(ulong address, ulong size, ref T[] output) - { - // This is a bit faster than FindOverlaps, but only works - // when none of the items on the list overlaps with each other. - int outputIndex = 0; - - int index = BinarySearch(address, size); - - if (index >= 0) - { - while (index > 0 && _items[index - 1].OverlapsWith(address, size)) - { - index--; - } - - do - { - if (outputIndex == output.Length) - { - Array.Resize(ref output, outputIndex + ArrayGrowthSize); - } - - output[outputIndex++] = _items[index++]; - } - while (index < _items.Count && _items[index].OverlapsWith(address, size)); - } - - return outputIndex; - } - - /// <summary> - /// Gets all items on the list with the specified memory address. - /// </summary> - /// <param name="address">Address to find</param> - /// <param name="output">Output array where matches will be written. It is automatically resized to fit the results</param> - /// <returns>The number of matches found</returns> - public int FindOverlaps(ulong address, ref T[] output) - { - int index = BinarySearch(address); - - int outputIndex = 0; - - if (index >= 0) - { - while (index > 0 && _items[index - 1].Address == address) - { - index--; - } - - while (index < _items.Count) - { - T overlap = _items[index++]; - - if (overlap.Address != address) - { - break; - } - - if (outputIndex == output.Length) - { - Array.Resize(ref output, outputIndex + ArrayGrowthSize); - } - - output[outputIndex++] = overlap; - } - } - - return outputIndex; - } - - /// <summary> - /// Performs binary search on the internal list of items. - /// </summary> - /// <param name="address">Address to find</param> - /// <returns>List index of the item, or complement index of nearest item with lower value on the list</returns> - private int BinarySearch(ulong address) - { - int left = 0; - int right = _items.Count - 1; - - while (left <= right) - { - int range = right - left; - - int middle = left + (range >> 1); - - T item = _items[middle]; - - if (item.Address == address) - { - return middle; - } - - if (address < item.Address) - { - right = middle - 1; - } - else - { - left = middle + 1; - } - } - - return ~left; - } - - /// <summary> - /// Performs binary search for items overlapping a given memory range. - /// </summary> - /// <param name="address">Start address of the range</param> - /// <param name="size">Size in bytes of the range</param> - /// <returns>List index of the item, or complement index of nearest item with lower value on the list</returns> - private int BinarySearch(ulong address, ulong size) - { - int left = 0; - int right = _items.Count - 1; - - while (left <= right) - { - int range = right - left; - - int middle = left + (range >> 1); - - T item = _items[middle]; - - if (item.OverlapsWith(address, size)) - { - return middle; - } - - if (address < item.Address) - { - right = middle - 1; - } - else - { - left = middle + 1; - } - } - - return ~left; - } - - public IEnumerator<T> GetEnumerator() - { - return _items.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _items.GetEnumerator(); - } - } -}
\ No newline at end of file |
