diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2024-02-22 11:03:07 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-22 11:03:07 -0300 |
| commit | 167f50bbcd5b2378a038e540877be4d9b71a12f6 (patch) | |
| tree | b425e6529ade9eb52dca3f9ff92ea767a78224b4 /src/Ryujinx.Graphics.Gpu/Memory/VirtualBufferCache.cs | |
| parent | ba91f5d401bf5f9fc39aaa30feac2600e82f9c42 (diff) | |
Implement virtual buffer dependencies (#6190)
* Implement virtual buffer copies
* Introduce TranslateAndCreateMultiBuffersPhysicalOnly, use it for copy and clear
* Rename VirtualBufferCache to VirtualRangeCache
* Fix potential issue where virtual range could exist in the cache, without a physical buffer
* Fix bug that could cause copy with negative size on CopyToDependantVirtualBuffer
* Remove virtual copy back for SyncAction
* GetData XML docs
* Make field readonly
* Fix virtual buffer modification tracking
* Remove CopyFromDependantVirtualBuffers from ExternalFlush
* Move things around a little to avoid perf impact
- Inline null check for CopyFromDependantVirtualBuffers
- Remove extra method call for SynchronizeMemoryWithVirtualCopyBack, prefer calling CopyFromDependantVirtualBuffers separately
* Fix up XML doc
---------
Co-authored-by: riperiperi <rhy3756547@hotmail.com>
Diffstat (limited to 'src/Ryujinx.Graphics.Gpu/Memory/VirtualBufferCache.cs')
| -rw-r--r-- | src/Ryujinx.Graphics.Gpu/Memory/VirtualBufferCache.cs | 238 |
1 files changed, 0 insertions, 238 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Memory/VirtualBufferCache.cs b/src/Ryujinx.Graphics.Gpu/Memory/VirtualBufferCache.cs deleted file mode 100644 index 858c5e3b..00000000 --- a/src/Ryujinx.Graphics.Gpu/Memory/VirtualBufferCache.cs +++ /dev/null @@ -1,238 +0,0 @@ -using Ryujinx.Memory.Range; -using System; -using System.Collections.Concurrent; -using System.Threading; - -namespace Ryujinx.Graphics.Gpu.Memory -{ - /// <summary> - /// Virtual buffer cache. - /// </summary> - class VirtualBufferCache - { - private readonly MemoryManager _memoryManager; - - /// <summary> - /// Represents a GPU virtual memory range. - /// </summary> - private readonly struct VirtualRange : IRange - { - /// <summary> - /// GPU virtual address where the range starts. - /// </summary> - public ulong Address { get; } - - /// <summary> - /// Size of the range in bytes. - /// </summary> - public ulong Size { get; } - - /// <summary> - /// GPU virtual address where the range ends. - /// </summary> - public ulong EndAddress => Address + Size; - - /// <summary> - /// Physical regions where the GPU virtual region is mapped. - /// </summary> - public MultiRange Range { get; } - - /// <summary> - /// Creates a new virtual memory range. - /// </summary> - /// <param name="address">GPU virtual address where the range starts</param> - /// <param name="size">Size of the range in bytes</param> - /// <param name="range">Physical regions where the GPU virtual region is mapped</param> - public VirtualRange(ulong address, ulong size, MultiRange range) - { - Address = address; - Size = size; - Range = range; - } - - /// <summary> - /// Checks if a given range overlaps with the buffer. - /// </summary> - /// <param name="address">Start address of the range</param> - /// <param name="size">Size in bytes of the range</param> - /// <returns>True if the range overlaps, false otherwise</returns> - public bool OverlapsWith(ulong address, ulong size) - { - return Address < address + size && address < EndAddress; - } - } - - private readonly RangeList<VirtualRange> _virtualRanges; - private VirtualRange[] _virtualRangeOverlaps; - private readonly ConcurrentQueue<VirtualRange> _deferredUnmaps; - private int _hasDeferredUnmaps; - - /// <summary> - /// Creates a new instance of the virtual buffer cache. - /// </summary> - /// <param name="memoryManager">Memory manager that the virtual buffer cache belongs to</param> - public VirtualBufferCache(MemoryManager memoryManager) - { - _memoryManager = memoryManager; - _virtualRanges = new RangeList<VirtualRange>(); - _virtualRangeOverlaps = new VirtualRange[BufferCache.OverlapsBufferInitialCapacity]; - _deferredUnmaps = new ConcurrentQueue<VirtualRange>(); - } - - /// <summary> - /// Handles removal of buffers written to a memory region being unmapped. - /// </summary> - /// <param name="sender">Sender object</param> - /// <param name="e">Event arguments</param> - public void MemoryUnmappedHandler(object sender, UnmapEventArgs e) - { - void EnqueueUnmap() - { - _deferredUnmaps.Enqueue(new VirtualRange(e.Address, e.Size, default)); - - Interlocked.Exchange(ref _hasDeferredUnmaps, 1); - } - - e.AddRemapAction(EnqueueUnmap); - } - - /// <summary> - /// Tries to get a existing, cached physical range for the specified virtual region. - /// If no cached range is found, a new one is created and added. - /// </summary> - /// <param name="gpuVa">GPU virtual address to get the physical range from</param> - /// <param name="size">Size in bytes of the region</param> - /// <param name="supportsSparse">Indicates host support for sparse buffer mapping of non-contiguous ranges</param> - /// <param name="range">Physical range for the specified GPU virtual region</param> - /// <returns>True if the range already existed, false if a new one was created and added</returns> - public bool TryGetOrAddRange(ulong gpuVa, ulong size, bool supportsSparse, out MultiRange range) - { - VirtualRange[] overlaps = _virtualRangeOverlaps; - int overlapsCount; - - if (Interlocked.Exchange(ref _hasDeferredUnmaps, 0) != 0) - { - while (_deferredUnmaps.TryDequeue(out VirtualRange unmappedRange)) - { - overlapsCount = _virtualRanges.FindOverlapsNonOverlapping(unmappedRange.Address, unmappedRange.Size, ref overlaps); - - for (int index = 0; index < overlapsCount; index++) - { - _virtualRanges.Remove(overlaps[index]); - } - } - } - - bool found = false; - - ulong originalVa = gpuVa; - - overlapsCount = _virtualRanges.FindOverlapsNonOverlapping(gpuVa, size, ref overlaps); - - if (overlapsCount != 0) - { - // The virtual range already exists. We just need to check if our range fits inside - // the existing one, and if not, we must extend the existing one. - - ulong endAddress = gpuVa + size; - VirtualRange overlap0 = overlaps[0]; - - if (overlap0.Address > gpuVa || overlap0.EndAddress < endAddress) - { - for (int index = 0; index < overlapsCount; index++) - { - VirtualRange virtualRange = overlaps[index]; - - gpuVa = Math.Min(gpuVa, virtualRange.Address); - endAddress = Math.Max(endAddress, virtualRange.EndAddress); - - _virtualRanges.Remove(virtualRange); - } - - ulong newSize = endAddress - gpuVa; - MultiRange newRange = _memoryManager.GetPhysicalRegions(gpuVa, newSize); - - _virtualRanges.Add(new(gpuVa, newSize, newRange)); - - range = newRange.Slice(originalVa - gpuVa, size); - } - else - { - found = true; - range = overlap0.Range.Slice(gpuVa - overlap0.Address, size); - } - } - else - { - // No overlap, just create a new virtual range. - range = _memoryManager.GetPhysicalRegions(gpuVa, size); - - VirtualRange virtualRange = new(gpuVa, size, range); - - _virtualRanges.Add(virtualRange); - } - - ShrinkOverlapsBufferIfNeeded(); - - // If the the range is not properly aligned for sparse mapping, - // or if the host does not support sparse mapping, let's just - // force it to a single range. - // This might cause issues in some applications that uses sparse - // mappings. - if (!IsSparseAligned(range) || !supportsSparse) - { - range = new MultiRange(range.GetSubRange(0).Address, size); - } - - return found; - } - - /// <summary> - /// Checks if the physical memory ranges are valid for sparse mapping, - /// which requires all sub-ranges to be 64KB aligned. - /// </summary> - /// <param name="range">Range to check</param> - /// <returns>True if the range is valid for sparse mapping, false otherwise</returns> - private static bool IsSparseAligned(MultiRange range) - { - if (range.Count == 1) - { - return (range.GetSubRange(0).Address & (BufferCache.SparseBufferAlignmentSize - 1)) == 0; - } - - for (int i = 0; i < range.Count; i++) - { - MemoryRange subRange = range.GetSubRange(i); - - // Check if address is aligned. The address of the first sub-range can - // be misaligned as it is at the start. - if (i > 0 && - subRange.Address != MemoryManager.PteUnmapped && - (subRange.Address & (BufferCache.SparseBufferAlignmentSize - 1)) != 0) - { - return false; - } - - // Check if the size is aligned. The size of the last sub-range can - // be misaligned as it is at the end. - if (i < range.Count - 1 && (subRange.Size & (BufferCache.SparseBufferAlignmentSize - 1)) != 0) - { - return false; - } - } - - return true; - } - - /// <summary> - /// Resizes the temporary buffer used for range list intersection results, if it has grown too much. - /// </summary> - private void ShrinkOverlapsBufferIfNeeded() - { - if (_virtualRangeOverlaps.Length > BufferCache.OverlapsBufferMaxCapacity) - { - Array.Resize(ref _virtualRangeOverlaps, BufferCache.OverlapsBufferMaxCapacity); - } - } - } -} |
