mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-05-01 19:12:54 +00:00
Memory changes 2.2 (ryubing/ryujinx!143)
See merge request ryubing/ryujinx!143
This commit is contained in:
@@ -110,7 +110,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
ulong size,
|
||||
BufferStage stage,
|
||||
bool sparseCompatible,
|
||||
List<Buffer> baseBuffers)
|
||||
RangeItem<Buffer>[] baseBuffers)
|
||||
{
|
||||
_context = context;
|
||||
_physicalMemory = physicalMemory;
|
||||
@@ -128,18 +128,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
List<IRegionHandle> baseHandles = null;
|
||||
|
||||
if (baseBuffers.Count != 0)
|
||||
if (baseBuffers.Length != 0)
|
||||
{
|
||||
baseHandles = new List<IRegionHandle>();
|
||||
foreach (Buffer buffer in baseBuffers)
|
||||
foreach (RangeItem<Buffer> item in baseBuffers)
|
||||
{
|
||||
if (buffer._useGranular)
|
||||
if (item.Value._useGranular)
|
||||
{
|
||||
baseHandles.AddRange((buffer._memoryTrackingGranular.GetHandles()));
|
||||
baseHandles.AddRange((item.Value._memoryTrackingGranular.GetHandles()));
|
||||
}
|
||||
else
|
||||
{
|
||||
baseHandles.Add(buffer._memoryTracking);
|
||||
baseHandles.Add(item.Value._memoryTracking);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Memory.Range;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -56,7 +57,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="parent">Parent buffer</param>
|
||||
/// <param name="stage">Initial buffer stage</param>
|
||||
/// <param name="baseBuffers">Buffers to inherit state from</param>
|
||||
public BufferBackingState(GpuContext context, Buffer parent, BufferStage stage, List<Buffer> baseBuffers)
|
||||
public BufferBackingState(GpuContext context, Buffer parent, BufferStage stage, RangeItem<Buffer>[] baseBuffers)
|
||||
{
|
||||
_size = (int)parent.Size;
|
||||
_systemMemoryType = context.Capabilities.MemoryType;
|
||||
@@ -72,7 +73,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
BufferStage storageFlags = stage & BufferStage.StorageMask;
|
||||
|
||||
if (parent.Size > DeviceLocalSizeThreshold && baseBuffers.Count == 0)
|
||||
if (parent.Size > DeviceLocalSizeThreshold && baseBuffers.Length == 0)
|
||||
{
|
||||
_desiredType = BufferBackingType.DeviceMemory;
|
||||
}
|
||||
@@ -100,11 +101,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
// TODO: Might be nice to force atomic access to be device local for any stage.
|
||||
}
|
||||
|
||||
if (baseBuffers.Count != 0)
|
||||
if (baseBuffers.Length != 0)
|
||||
{
|
||||
foreach (Buffer buffer in baseBuffers)
|
||||
foreach (RangeItem<Buffer> item in baseBuffers)
|
||||
{
|
||||
CombineState(buffer.BackingState);
|
||||
CombineState(item.Value.BackingState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,13 +81,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
MemoryRange subRange = range.GetSubRange(index);
|
||||
|
||||
_buffers.Lock.EnterReadLock();
|
||||
(RangeItem<Buffer> first, RangeItem<Buffer> last) = _buffers.FindOverlaps(subRange.Address, subRange.Size);
|
||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(subRange.Address, subRange.Size);
|
||||
|
||||
RangeItem<Buffer> current = first;
|
||||
while (last != null && current != last.Next)
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
current.Value.Unmapped(subRange.Address, subRange.Size);
|
||||
current = current.Next;
|
||||
overlaps[i].Value.Unmapped(subRange.Address, subRange.Size);
|
||||
}
|
||||
|
||||
_buffers.Lock.ExitReadLock();
|
||||
@@ -490,9 +488,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage)
|
||||
{
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
(RangeItem<Buffer> first, RangeItem<Buffer> last) = _buffers.FindOverlaps(address, size);
|
||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
||||
|
||||
if (first is not null)
|
||||
if (overlaps.Length > 0)
|
||||
{
|
||||
// The buffer already exists. We can just return the existing buffer
|
||||
// if the buffer we need is fully contained inside the overlapping buffer.
|
||||
@@ -502,7 +500,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
ulong endAddress = address + size;
|
||||
|
||||
if (first.Address > address || first.EndAddress < endAddress)
|
||||
if (overlaps[0].Address > address || overlaps[0].EndAddress < endAddress)
|
||||
{
|
||||
bool anySparseCompatible = false;
|
||||
|
||||
@@ -515,39 +513,40 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
// sequential memory.
|
||||
// Allowing for 2 pages (rather than just one) is necessary to catch cases where the
|
||||
// range crosses a page, and after alignment, ends having a size of 2 pages.
|
||||
if (first == last &&
|
||||
address >= first.Address &&
|
||||
endAddress - first.EndAddress <= BufferAlignmentSize * 2)
|
||||
if (overlaps.Length == 1 &&
|
||||
address >= overlaps[0].Address &&
|
||||
endAddress - overlaps[0].EndAddress <= BufferAlignmentSize * 2)
|
||||
{
|
||||
// Try to grow the buffer by 1.5x of its current size.
|
||||
// This improves performance in the cases where the buffer is resized often by small amounts.
|
||||
ulong existingSize = first.Value.Size;
|
||||
ulong existingSize = overlaps[0].Value.Size;
|
||||
ulong growthSize = (existingSize + Math.Min(existingSize >> 1, MaxDynamicGrowthSize)) & ~BufferAlignmentMask;
|
||||
|
||||
size = Math.Max(size, growthSize);
|
||||
endAddress = address + size;
|
||||
|
||||
(first, last) = _buffers.FindOverlaps(address, size);
|
||||
overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
||||
}
|
||||
|
||||
address = Math.Min(address, first.Address);
|
||||
endAddress = Math.Max(endAddress, last.EndAddress);
|
||||
address = Math.Min(address, overlaps[0].Address);
|
||||
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
|
||||
|
||||
List<Buffer> overlaps = [];
|
||||
RangeItem<Buffer>[] overlapsArray = overlaps.ToArray();
|
||||
|
||||
RangeItem<Buffer> current = first;
|
||||
while (current != last.Next)
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
anySparseCompatible |= current.Value.SparseCompatible;
|
||||
overlaps.Add(current.Value);
|
||||
_buffers.Remove(current.Value);
|
||||
|
||||
current = current.Next;
|
||||
anySparseCompatible |= overlaps[i].Value.SparseCompatible;
|
||||
}
|
||||
|
||||
_buffers.RemoveRange(overlaps[0], overlaps[^1]);
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
ulong newSize = endAddress - address;
|
||||
|
||||
Buffer newBuffer = CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlaps);
|
||||
Buffer newBuffer = CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlapsArray);
|
||||
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
|
||||
_buffers.Add(newBuffer);
|
||||
}
|
||||
@@ -577,19 +576,19 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
bool sparseAligned = alignment >= SparseBufferAlignmentSize;
|
||||
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
(RangeItem<Buffer> first, RangeItem<Buffer> last) = _buffers.FindOverlaps(address, size);
|
||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
||||
|
||||
if (first is not null)
|
||||
if (overlaps.Length > 0)
|
||||
{
|
||||
// If the buffer already exists, make sure if covers the entire range,
|
||||
// and make sure it is properly aligned, otherwise sparse mapping may fail.
|
||||
|
||||
ulong endAddress = address + size;
|
||||
|
||||
if (first.Address > address ||
|
||||
first.EndAddress < endAddress ||
|
||||
(first.Address & (alignment - 1)) != 0 ||
|
||||
(!first.Value.SparseCompatible && sparseAligned))
|
||||
if (overlaps[0].Address > address ||
|
||||
overlaps[0].EndAddress < endAddress ||
|
||||
(overlaps[0].Address & (alignment - 1)) != 0 ||
|
||||
(!overlaps[0].Value.SparseCompatible && sparseAligned))
|
||||
{
|
||||
// We need to make sure the new buffer is properly aligned.
|
||||
// However, after the range is aligned, it is possible that it
|
||||
@@ -597,33 +596,30 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
// and ensure we cover all overlaps.
|
||||
|
||||
RangeItem<Buffer> oldFirst;
|
||||
endAddress = Math.Max(endAddress, last.EndAddress);
|
||||
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
|
||||
|
||||
do
|
||||
{
|
||||
address = Math.Min(address, first.Address);
|
||||
address = Math.Min(address, overlaps[0].Address);
|
||||
|
||||
address &= ~(alignment - 1);
|
||||
|
||||
oldFirst = first;
|
||||
(first, last) = _buffers.FindOverlaps(address, endAddress - address);
|
||||
oldFirst = overlaps[0];
|
||||
overlaps = _buffers.FindOverlapsAsSpan(address, endAddress - address);
|
||||
}
|
||||
while (oldFirst != first);
|
||||
while (oldFirst != overlaps[0]);
|
||||
|
||||
ulong newSize = endAddress - address;
|
||||
|
||||
List<Buffer> overlaps = [];
|
||||
RangeItem<Buffer>[] overlapsArray = overlaps.ToArray();
|
||||
|
||||
RangeItem<Buffer> current = first;
|
||||
while (current != last.Next)
|
||||
{
|
||||
overlaps.Add(current.Value);
|
||||
_buffers.Remove(current.Value);
|
||||
|
||||
current = current.Next;
|
||||
}
|
||||
_buffers.RemoveRange(overlaps[0], overlaps[^1]);
|
||||
|
||||
Buffer newBuffer = CreateBufferAligned(address, newSize, stage, sparseAligned, overlaps);
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
Buffer newBuffer = CreateBufferAligned(address, newSize, stage, sparseAligned, overlapsArray);
|
||||
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
|
||||
_buffers.Add(newBuffer);
|
||||
}
|
||||
@@ -635,6 +631,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
_buffers.Add(buffer);
|
||||
}
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
@@ -648,13 +645,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="stage">The type of usage that created the buffer</param>
|
||||
/// <param name="sparseCompatible">Indicates if the buffer can be used in a sparse buffer mapping</param>
|
||||
/// <param name="overlaps">Buffers overlapping the range</param>
|
||||
private Buffer CreateBufferAligned(ulong address, ulong size, BufferStage stage, bool sparseCompatible, List<Buffer> overlaps)
|
||||
private Buffer CreateBufferAligned(ulong address, ulong size, BufferStage stage, bool sparseCompatible, RangeItem<Buffer>[] overlaps)
|
||||
{
|
||||
Buffer newBuffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible, overlaps);
|
||||
|
||||
for (int index = 0; index < overlaps.Count; index++)
|
||||
for (int index = 0; index < overlaps.Length; index++)
|
||||
{
|
||||
Buffer buffer = overlaps[index];
|
||||
Buffer buffer = overlaps[index].Value;
|
||||
|
||||
int dstOffset = (int)(buffer.Address - newBuffer.Address);
|
||||
|
||||
@@ -930,7 +927,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
buffer = _buffers.FindOverlapFast(address, size).Value;
|
||||
buffer = _buffers.FindOverlap(address, size).Value;
|
||||
|
||||
buffer.CopyFromDependantVirtualBuffers();
|
||||
buffer.SynchronizeMemory(address, size);
|
||||
|
||||
@@ -80,8 +80,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
private BufferMigration _source;
|
||||
private BufferModifiedRangeList _migrationTarget;
|
||||
|
||||
private List<RangeItem<BufferModifiedRange>> _overlaps;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the modified range list has any entries or not.
|
||||
@@ -108,7 +106,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
_context = context;
|
||||
_parent = parent;
|
||||
_flushAction = flushAction;
|
||||
_overlaps = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -122,12 +119,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
// Slices a given region using the modified regions in the list. Calls the action for the new slices.
|
||||
Lock.EnterReadLock();
|
||||
|
||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlaps(address, size);
|
||||
Span<RangeItem<BufferModifiedRange>> overlaps = FindOverlapsAsSpan(address, size);
|
||||
|
||||
RangeItem<BufferModifiedRange> current = first;
|
||||
while (last != null && current != last.Next)
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = current.Value;
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
|
||||
if (overlap.Address > address)
|
||||
{
|
||||
@@ -138,7 +134,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
// Remaining region is after this overlap.
|
||||
size -= overlap.EndAddress - address;
|
||||
address = overlap.EndAddress;
|
||||
current = current.Next;
|
||||
}
|
||||
|
||||
Lock.ExitReadLock();
|
||||
@@ -158,12 +153,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="size">Size of the modified region in bytes</param>
|
||||
public void SignalModified(ulong address, ulong size)
|
||||
{
|
||||
// We may overlap with some existing modified regions. They must be cut into by the new entry.
|
||||
Lock.EnterWriteLock();
|
||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlaps(address, size);
|
||||
|
||||
ulong endAddress = address + size;
|
||||
ulong syncNumber = _context.SyncNumber;
|
||||
// We may overlap with some existing modified regions. They must be cut into by the new entry.
|
||||
Lock.EnterWriteLock();
|
||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlapsAsNodes(address, size);
|
||||
|
||||
if (first is null)
|
||||
{
|
||||
@@ -172,8 +166,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (first == last)
|
||||
{
|
||||
if (first.Address == address && first.EndAddress == endAddress)
|
||||
@@ -260,19 +252,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
public void GetRangesAtSync(ulong address, ulong size, ulong syncNumber, Action<ulong, ulong> rangeAction)
|
||||
{
|
||||
Lock.EnterReadLock();
|
||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlaps(address, size);
|
||||
Span<RangeItem<BufferModifiedRange>> overlaps = FindOverlapsAsSpan(address, size);
|
||||
|
||||
RangeItem<BufferModifiedRange> current = first;
|
||||
while (last != null && current != last.Next)
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = current.Value;
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
|
||||
if (overlap.SyncNumber == syncNumber)
|
||||
{
|
||||
rangeAction(overlap.Address, overlap.Size);
|
||||
}
|
||||
|
||||
current = current.Next;
|
||||
}
|
||||
|
||||
Lock.ExitReadLock();
|
||||
@@ -288,22 +277,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
// We use the non-span method here because keeping the lock will cause a deadlock.
|
||||
Lock.EnterReadLock();
|
||||
|
||||
_overlaps.Clear();
|
||||
|
||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlaps(address, size);
|
||||
|
||||
RangeItem<BufferModifiedRange> current = first;
|
||||
while (last != null && current != last.Next)
|
||||
{
|
||||
_overlaps.Add(current);
|
||||
current = current.Next;
|
||||
}
|
||||
RangeItem<BufferModifiedRange>[] overlaps = FindOverlapsAsArray(address, size);
|
||||
Lock.ExitReadLock();
|
||||
|
||||
for (int i = 0; i < _overlaps.Count; i++)
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = _overlaps[i].Value;
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
rangeAction(overlap.Address, overlap.Size);
|
||||
}
|
||||
}
|
||||
@@ -404,8 +383,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
ulong endAddress = address + size;
|
||||
ulong currentSync = _context.SyncNumber;
|
||||
|
||||
List<RangeItem<BufferModifiedRange>> overlaps = [];
|
||||
|
||||
// Range list must be consistent for this operation
|
||||
if (_migrationTarget != null)
|
||||
{
|
||||
@@ -416,16 +393,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
Lock.EnterWriteLock();
|
||||
// We use the non-span method here because the array is partially modified by the code, which would invalidate a span.
|
||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlaps(address, size);
|
||||
|
||||
RangeItem<BufferModifiedRange> current = first;
|
||||
while (last != null && current != last.Next)
|
||||
{
|
||||
overlaps.Add(current);
|
||||
current = current.Next;
|
||||
}
|
||||
RangeItem<BufferModifiedRange>[] overlaps = FindOverlapsAsArray(address, size);
|
||||
|
||||
int rangeCount = overlaps.Count;
|
||||
int rangeCount = overlaps.Length;
|
||||
|
||||
if (rangeCount == 0)
|
||||
{
|
||||
@@ -582,7 +552,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
ulong endAddress = address + size;
|
||||
Lock.EnterWriteLock();
|
||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlaps(address, size);
|
||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlapsAsNodes(address, size);
|
||||
|
||||
if (first is null)
|
||||
{
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
ulong originalVa = gpuVa;
|
||||
|
||||
_virtualRanges.Lock.EnterWriteLock();
|
||||
(RangeItem<VirtualRange> first, RangeItem<VirtualRange> last) = _virtualRanges.FindOverlaps(gpuVa, size);
|
||||
(RangeItem<VirtualRange> first, RangeItem<VirtualRange> last) = _virtualRanges.FindOverlapsAsNodes(gpuVa, size);
|
||||
|
||||
if (first is not null)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user