mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-10-04 06:28:58 +02:00
Memory Changes 3.2
Fixes a few crashes: - fixes a crash related to waking threads (priorities were wrong). - fixes a crash from reusing the SetRenderTargets texture array (left-over data causing issues). - fixes a mistake and an oversight in the buffer system. - buffers were getting updated wrong causing bad data to be stored or some times cut. - modified ranges would extend past their old buffers, crashing on syncs. Old buffers are now skipped as the new buffers already sync instead. Introduces pooling in a few more places to increase memory efficiency. simplified RangeList item logic. - removed RangeItem by making all the range objects use the I(NonOverlapping)Range interface. - BufferCache class no longer locks its RangeList, as the list is only ever accessed synchronously. Small change to how keyboard snapshots are stored. Increase ThreadedRenderer SpanPool size to fit slightly more data (4MB -> 8MB).
This commit is contained in:
@@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// Buffer, used to store vertex and index data, uniform and storage buffers, and others.
|
||||
/// </summary>
|
||||
class Buffer : INonOverlappingRange, ISyncActionHandler, IDisposable
|
||||
class Buffer : INonOverlappingRange<Buffer>, ISyncActionHandler, IDisposable
|
||||
{
|
||||
private const ulong GranularBufferThreshold = 4096;
|
||||
|
||||
@@ -41,6 +41,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// End address of the buffer in guest memory.
|
||||
/// </summary>
|
||||
public ulong EndAddress => Address + Size;
|
||||
|
||||
public Buffer Next { get; set; }
|
||||
public Buffer Previous { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Increments when the buffer is (partially) unmapped or disposed.
|
||||
@@ -87,6 +90,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
private readonly bool _useGranular;
|
||||
private bool _syncActionRegistered;
|
||||
private bool _bufferInherited;
|
||||
|
||||
private int _referenceCount = 1;
|
||||
|
||||
@@ -113,7 +117,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
ulong size,
|
||||
BufferStage stage,
|
||||
bool sparseCompatible,
|
||||
RangeItem<Buffer>[] baseBuffers)
|
||||
Buffer[] baseBuffers)
|
||||
{
|
||||
_context = context;
|
||||
_physicalMemory = physicalMemory;
|
||||
@@ -134,15 +138,15 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
if (baseBuffers.Length != 0)
|
||||
{
|
||||
baseHandles = new List<IRegionHandle>();
|
||||
foreach (RangeItem<Buffer> item in baseBuffers)
|
||||
foreach (Buffer item in baseBuffers)
|
||||
{
|
||||
if (item.Value._useGranular)
|
||||
if (item._useGranular)
|
||||
{
|
||||
baseHandles.AddRange((item.Value._memoryTrackingGranular.GetHandles()));
|
||||
baseHandles.AddRange((item._memoryTrackingGranular.GetHandles()));
|
||||
}
|
||||
else
|
||||
{
|
||||
baseHandles.Add(item.Value._memoryTracking);
|
||||
baseHandles.Add(item._memoryTracking);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,14 +251,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// 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>
|
||||
/// <param name="endAddress">End address of the range</param>
|
||||
/// <returns>True if the range overlaps, false otherwise</returns>
|
||||
public bool OverlapsWith(ulong address, ulong size)
|
||||
public bool OverlapsWith(ulong address, ulong endAddress)
|
||||
{
|
||||
return Address < address + size && address < EndAddress;
|
||||
return Address < endAddress && address < EndAddress;
|
||||
}
|
||||
|
||||
public INonOverlappingRange Split(ulong splitAddress)
|
||||
public INonOverlappingRange<Buffer> Split(ulong splitAddress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -426,10 +430,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
_syncActionRegistered = false;
|
||||
|
||||
if (_bufferInherited)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_useGranular)
|
||||
{
|
||||
|
||||
|
||||
_modifiedRanges?.GetRanges(Address, Size, _syncRangeAction);
|
||||
}
|
||||
else
|
||||
@@ -453,6 +460,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="from">The buffer to inherit from</param>
|
||||
public void InheritModifiedRanges(Buffer from)
|
||||
{
|
||||
from._bufferInherited = true;
|
||||
|
||||
if (from._modifiedRanges is { HasRanges: true })
|
||||
{
|
||||
if (from._syncActionRegistered && !_syncActionRegistered)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Memory.Range;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
@@ -56,7 +55,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, RangeItem<Buffer>[] baseBuffers)
|
||||
public BufferBackingState(GpuContext context, Buffer parent, BufferStage stage, Buffer[] baseBuffers)
|
||||
{
|
||||
_size = (int)parent.Size;
|
||||
_systemMemoryType = context.Capabilities.MemoryType;
|
||||
@@ -102,9 +101,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (baseBuffers.Length != 0)
|
||||
{
|
||||
foreach (RangeItem<Buffer> item in baseBuffers)
|
||||
foreach (Buffer item in baseBuffers)
|
||||
{
|
||||
CombineState(item.Value.BackingState);
|
||||
CombineState(item.BackingState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,16 +79,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
for (int index = 0; index < range.Count; index++)
|
||||
{
|
||||
MemoryRange subRange = range.GetSubRange(index);
|
||||
|
||||
_buffers.Lock.EnterReadLock();
|
||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(subRange.Address, subRange.Size);
|
||||
|
||||
ReadOnlySpan<Buffer> overlaps = _buffers.FindOverlapsAsSpan(subRange.Address, subRange.Size);
|
||||
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
overlaps[i].Value.Unmapped(subRange.Address, subRange.Size);
|
||||
overlaps[i].Unmapped(subRange.Address, subRange.Size);
|
||||
}
|
||||
|
||||
_buffers.Lock.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,7 +325,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
ulong alignedEndAddress = (endAddress + alignmentMask) & ~alignmentMask;
|
||||
ulong alignedSize = alignedEndAddress - alignedAddress;
|
||||
|
||||
Buffer buffer = _buffers.FindOverlap(alignedAddress, alignedSize).Value;
|
||||
Buffer buffer = _buffers.FindOverlap(alignedAddress, alignedSize);
|
||||
BufferRange bufferRange = buffer.GetRange(alignedAddress, alignedSize, false);
|
||||
|
||||
alignedSubRanges[i] = new MemoryRange(alignedAddress, alignedSize);
|
||||
@@ -395,7 +392,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (subRange.Address != MemoryManager.PteUnmapped)
|
||||
{
|
||||
Buffer buffer = _buffers.FindOverlap(subRange.Address, subRange.Size).Value;
|
||||
Buffer buffer = _buffers.FindOverlap(subRange.Address, subRange.Size);
|
||||
|
||||
virtualBuffer.AddPhysicalDependency(buffer, subRange.Address, dstOffset, subRange.Size);
|
||||
physicalBuffers.Add(buffer);
|
||||
@@ -487,10 +484,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="stage">The type of usage that created the buffer</param>
|
||||
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage)
|
||||
{
|
||||
Buffer newBuffer = null;
|
||||
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
||||
ReadOnlySpan<Buffer> overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
||||
|
||||
if (overlaps.Length != 0)
|
||||
{
|
||||
@@ -521,7 +515,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
// 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 = overlaps[0].Value.Size;
|
||||
ulong existingSize = overlaps[0].Size;
|
||||
ulong growthSize = (existingSize + Math.Min(existingSize >> 1, MaxDynamicGrowthSize)) & ~BufferAlignmentMask;
|
||||
|
||||
size = Math.Max(size, growthSize);
|
||||
@@ -535,39 +529,22 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
anySparseCompatible |= overlaps[i].Value.SparseCompatible;
|
||||
anySparseCompatible |= overlaps[i].SparseCompatible;
|
||||
}
|
||||
|
||||
RangeItem<Buffer>[] overlapsArray = overlaps.ToArray();
|
||||
Buffer[] overlapsArray = overlaps.ToArray();
|
||||
|
||||
_buffers.RemoveRange(overlaps[0], overlaps[^1]);
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
ulong newSize = endAddress - address;
|
||||
|
||||
newBuffer = CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlapsArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
_buffers.Add(CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlapsArray));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
// No overlap, just create a new buffer.
|
||||
newBuffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible: false, []);
|
||||
}
|
||||
|
||||
if (newBuffer is not null)
|
||||
{
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
|
||||
_buffers.Add(newBuffer);
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
_buffers.Add(new(_context, _physicalMemory, address, size, stage, sparseCompatible: false, []));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,10 +560,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage, ulong alignment)
|
||||
{
|
||||
bool sparseAligned = alignment >= SparseBufferAlignmentSize;
|
||||
Buffer newBuffer = null;
|
||||
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
||||
ReadOnlySpan<Buffer> overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
||||
|
||||
if (overlaps.Length != 0)
|
||||
{
|
||||
@@ -598,7 +573,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
if (overlaps[0].Address > address ||
|
||||
overlaps[0].EndAddress < endAddress ||
|
||||
(overlaps[0].Address & (alignment - 1)) != 0 ||
|
||||
(!overlaps[0].Value.SparseCompatible && sparseAligned))
|
||||
(!overlaps[0].SparseCompatible && sparseAligned))
|
||||
{
|
||||
// We need to make sure the new buffer is properly aligned.
|
||||
// However, after the range is aligned, it is possible that it
|
||||
@@ -622,35 +597,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
ulong newSize = endAddress - address;
|
||||
|
||||
RangeItem<Buffer>[] overlapsArray = overlaps.ToArray();
|
||||
Buffer[] overlapsArray = overlaps.ToArray();
|
||||
|
||||
_buffers.RemoveRange(overlaps[0], overlaps[^1]);
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
newBuffer = CreateBufferAligned(address, newSize, stage, sparseAligned, overlapsArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
_buffers.Add(CreateBufferAligned(address, newSize, stage, sparseAligned, overlapsArray));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
// No overlap, just create a new buffer.
|
||||
newBuffer = new(_context, _physicalMemory, address, size, stage, sparseAligned, []);
|
||||
}
|
||||
|
||||
if (newBuffer is not null)
|
||||
{
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
|
||||
_buffers.Add(newBuffer);
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
}
|
||||
_buffers.Add(new(_context, _physicalMemory, address, size, stage, sparseAligned, []));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -663,13 +621,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, RangeItem<Buffer>[] overlaps)
|
||||
private Buffer CreateBufferAligned(ulong address, ulong size, BufferStage stage, bool sparseCompatible, Buffer[] overlaps)
|
||||
{
|
||||
Buffer newBuffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible, overlaps);
|
||||
|
||||
for (int index = 0; index < overlaps.Length; index++)
|
||||
{
|
||||
Buffer buffer = overlaps[index].Value;
|
||||
Buffer buffer = overlaps[index];
|
||||
|
||||
int dstOffset = (int)(buffer.Address - newBuffer.Address);
|
||||
|
||||
@@ -897,7 +855,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
MemoryRange subRange = range.GetSubRange(i);
|
||||
|
||||
Buffer subBuffer = _buffers.FindOverlap(subRange.Address, subRange.Size).Value;
|
||||
Buffer subBuffer = _buffers.FindOverlap(subRange.Address, subRange.Size);
|
||||
|
||||
subBuffer.SynchronizeMemory(subRange.Address, subRange.Size);
|
||||
|
||||
@@ -945,7 +903,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
buffer = _buffers.FindOverlap(address, size).Value;
|
||||
buffer = _buffers.FindOverlap(address, size);
|
||||
|
||||
buffer.CopyFromDependantVirtualBuffers();
|
||||
buffer.SynchronizeMemory(address, size);
|
||||
@@ -957,7 +915,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = _buffers.FindOverlapFast(address, 1).Value;
|
||||
buffer = _buffers.FindOverlapFast(address, 1);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
@@ -995,7 +953,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
Buffer buffer = _buffers.FindOverlap(address, size).Value;
|
||||
Buffer buffer = _buffers.FindOverlap(address, size);
|
||||
|
||||
if (copyBackVirtual)
|
||||
{
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
using Ryujinx.Memory.Range;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
/// <summary>
|
||||
/// A range within a buffer that has been modified by the GPU.
|
||||
/// </summary>
|
||||
class BufferModifiedRange : INonOverlappingRange
|
||||
class BufferModifiedRange : INonOverlappingRange<BufferModifiedRange>
|
||||
{
|
||||
/// <summary>
|
||||
/// Start address of the range in guest memory.
|
||||
@@ -24,6 +23,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// End address of the range in guest memory.
|
||||
/// </summary>
|
||||
public ulong EndAddress => Address + Size;
|
||||
|
||||
public BufferModifiedRange Next { get; set; }
|
||||
public BufferModifiedRange Previous { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The GPU sync number at the time of the last modification.
|
||||
@@ -54,14 +56,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// Checks if a given range overlaps with the modified range.
|
||||
/// </summary>
|
||||
/// <param name="address">Start address of the range</param>
|
||||
/// <param name="size">Size in bytes of the range</param>
|
||||
/// <param name="endAddress">End address of the range</param>
|
||||
/// <returns>True if the range overlaps, false otherwise</returns>
|
||||
public bool OverlapsWith(ulong address, ulong size)
|
||||
public bool OverlapsWith(ulong address, ulong endAddress)
|
||||
{
|
||||
return Address < address + size && address < EndAddress;
|
||||
return Address < endAddress && address < EndAddress;
|
||||
}
|
||||
|
||||
public INonOverlappingRange Split(ulong splitAddress)
|
||||
public INonOverlappingRange<BufferModifiedRange> Split(ulong splitAddress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -119,11 +121,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();
|
||||
|
||||
Span<RangeItem<BufferModifiedRange>> overlaps = FindOverlapsAsSpan(address, size);
|
||||
ReadOnlySpan<BufferModifiedRange> overlaps = FindOverlapsAsSpan(address, size);
|
||||
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
|
||||
if (overlap.Address > address)
|
||||
{
|
||||
@@ -157,7 +159,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
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);
|
||||
(BufferModifiedRange first, BufferModifiedRange last) = FindOverlapsAsNodes(address, size);
|
||||
|
||||
if (first is null)
|
||||
{
|
||||
@@ -170,34 +172,39 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
if (first.Address == address && first.EndAddress == endAddress)
|
||||
{
|
||||
first.Value.SyncNumber = syncNumber;
|
||||
first.Value.Parent = this;
|
||||
first.SyncNumber = syncNumber;
|
||||
first.Parent = this;
|
||||
Lock.ExitWriteLock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (first.Address < address)
|
||||
{
|
||||
first.Value.Size = address - first.Address;
|
||||
Update(first);
|
||||
|
||||
if (first.EndAddress > endAddress)
|
||||
{
|
||||
Add(new BufferModifiedRange(endAddress, first.EndAddress - endAddress,
|
||||
first.Value.SyncNumber, first.Value.Parent));
|
||||
first.SyncNumber, first.Parent));
|
||||
}
|
||||
|
||||
first.Size = address - first.Address;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first.EndAddress > endAddress)
|
||||
{
|
||||
first.Value.Size = first.EndAddress - endAddress;
|
||||
first.Value.Address = endAddress;
|
||||
Update(first);
|
||||
first.Size = first.EndAddress - endAddress;
|
||||
first.Address = endAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove(first.Value);
|
||||
first.Address = address;
|
||||
first.Size = size;
|
||||
first.SyncNumber = syncNumber;
|
||||
first.Parent = this;
|
||||
|
||||
Lock.ExitWriteLock();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,38 +214,39 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
return;
|
||||
}
|
||||
|
||||
BufferModifiedRange buffPre = null;
|
||||
BufferModifiedRange buffPost = null;
|
||||
bool extendsPost = false;
|
||||
bool extendsPre = false;
|
||||
|
||||
if (first.Address < address)
|
||||
{
|
||||
buffPre = new BufferModifiedRange(first.Address, address - first.Address,
|
||||
first.Value.SyncNumber, first.Value.Parent);
|
||||
extendsPre = true;
|
||||
first.Size = address - first.Address;
|
||||
first = first.Next;
|
||||
}
|
||||
|
||||
if (last.EndAddress > endAddress)
|
||||
{
|
||||
buffPost = new BufferModifiedRange(endAddress, last.EndAddress - endAddress,
|
||||
last.Value.SyncNumber, last.Value.Parent);
|
||||
extendsPost = true;
|
||||
last.Size = last.EndAddress - endAddress;
|
||||
last.Address = endAddress;
|
||||
last = last.Previous;
|
||||
}
|
||||
|
||||
RemoveRange(first, last);
|
||||
|
||||
if (extendsPre)
|
||||
if (first.Address < last.Address)
|
||||
{
|
||||
Add(buffPre);
|
||||
RemoveRange(first.Next, last);
|
||||
first.Address = address;
|
||||
first.Size = size;
|
||||
first.SyncNumber = syncNumber;
|
||||
first.Parent = this;
|
||||
}
|
||||
|
||||
if (extendsPost)
|
||||
else if (first.Address == last.Address)
|
||||
{
|
||||
Add(buffPost);
|
||||
first.Address = address;
|
||||
first.Size = size;
|
||||
first.SyncNumber = syncNumber;
|
||||
first.Parent = this;
|
||||
}
|
||||
|
||||
Add(new BufferModifiedRange(address, size, syncNumber, this));
|
||||
else
|
||||
{
|
||||
Add(new BufferModifiedRange(address, size, syncNumber, this));
|
||||
}
|
||||
|
||||
Lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
@@ -252,11 +260,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
public void GetRangesAtSync(ulong address, ulong size, ulong syncNumber, Action<ulong, ulong> rangeAction)
|
||||
{
|
||||
Lock.EnterReadLock();
|
||||
Span<RangeItem<BufferModifiedRange>> overlaps = FindOverlapsAsSpan(address, size);
|
||||
ReadOnlySpan<BufferModifiedRange> overlaps = FindOverlapsAsSpan(address, size);
|
||||
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
|
||||
if (overlap.SyncNumber == syncNumber)
|
||||
{
|
||||
@@ -277,18 +285,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
// We use the non-span method here because keeping the lock will cause a deadlock.
|
||||
Lock.EnterReadLock();
|
||||
RangeItem<BufferModifiedRange>[] overlaps = FindOverlapsAsArray(address, size, out int length);
|
||||
BufferModifiedRange[] overlaps = FindOverlapsAsArray(address, size, out int length);
|
||||
Lock.ExitReadLock();
|
||||
|
||||
if (length != 0)
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
rangeAction(overlap.Address, overlap.Size);
|
||||
}
|
||||
|
||||
ArrayPool<RangeItem<BufferModifiedRange>>.Shared.Return(overlaps);
|
||||
ArrayPool<BufferModifiedRange>.Shared.Return(overlaps);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,7 +309,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
public bool HasRange(ulong address, ulong size)
|
||||
{
|
||||
Lock.EnterReadLock();
|
||||
RangeItem<BufferModifiedRange> first = FindOverlapFast(address, size);
|
||||
BufferModifiedRange first = FindOverlapFast(address, size);
|
||||
bool result = first is not null;
|
||||
Lock.ExitReadLock();
|
||||
return result;
|
||||
@@ -336,7 +344,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="address">The start address of the flush range</param>
|
||||
/// <param name="endAddress">The end address of the flush range</param>
|
||||
private void RemoveRangesAndFlush(
|
||||
RangeItem<BufferModifiedRange>[] overlaps,
|
||||
BufferModifiedRange[] overlaps,
|
||||
int rangeCount,
|
||||
long highestDiff,
|
||||
ulong currentSync,
|
||||
@@ -349,7 +357,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
for (int i = 0; i < rangeCount; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
|
||||
long diff = (long)(overlap.SyncNumber - currentSync);
|
||||
|
||||
@@ -358,7 +366,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
ulong clampAddress = Math.Max(address, overlap.Address);
|
||||
ulong clampEnd = Math.Min(endAddress, overlap.EndAddress);
|
||||
|
||||
ClearPart(overlap, clampAddress, clampEnd);
|
||||
if (i == 0 || i == rangeCount - 1)
|
||||
{
|
||||
ClearPart(overlap, clampAddress, clampEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove(overlap);
|
||||
}
|
||||
|
||||
RangeActionWithMigration(clampAddress, clampEnd - clampAddress, waitSync, _flushAction);
|
||||
}
|
||||
@@ -398,7 +413,7 @@ 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>[] overlaps = FindOverlapsAsArray(address, size, out int rangeCount);
|
||||
BufferModifiedRange[] overlaps = FindOverlapsAsArray(address, size, out int rangeCount);
|
||||
|
||||
if (rangeCount == 0)
|
||||
{
|
||||
@@ -414,7 +429,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
for (int i = 0; i < rangeCount; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps![i].Value;
|
||||
BufferModifiedRange overlap = overlaps![i];
|
||||
|
||||
long diff = (long)(overlap.SyncNumber - currentSync);
|
||||
|
||||
@@ -436,7 +451,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
RemoveRangesAndFlush(overlaps, rangeCount, highestDiff, currentSync, address, endAddress);
|
||||
|
||||
ArrayPool<RangeItem<BufferModifiedRange>>.Shared.Return(overlaps!);
|
||||
ArrayPool<BufferModifiedRange>.Shared.Return(overlaps!);
|
||||
|
||||
Lock.ExitWriteLock();
|
||||
}
|
||||
@@ -452,7 +467,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
public void InheritRanges(BufferModifiedRangeList ranges, Action<ulong, ulong> registerRangeAction)
|
||||
{
|
||||
ranges.Lock.EnterReadLock();
|
||||
BufferModifiedRange[] inheritRanges = ranges.ToArray();
|
||||
int rangesCount = ranges.Count;
|
||||
BufferModifiedRange[] inheritRanges = ArrayPool<BufferModifiedRange>.Shared.Rent(ranges.Count);
|
||||
ranges.Items.AsSpan(0, ranges.Count).CopyTo(inheritRanges);
|
||||
ranges.Lock.ExitReadLock();
|
||||
|
||||
// Copy over the migration from the previous range list
|
||||
@@ -478,22 +495,26 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
ranges._migrationTarget = this;
|
||||
|
||||
Lock.EnterWriteLock();
|
||||
|
||||
foreach (BufferModifiedRange range in inheritRanges)
|
||||
|
||||
for (int i = 0; i < rangesCount; i++)
|
||||
{
|
||||
BufferModifiedRange range = inheritRanges[i];
|
||||
Add(range);
|
||||
}
|
||||
|
||||
Lock.ExitWriteLock();
|
||||
|
||||
ulong currentSync = _context.SyncNumber;
|
||||
foreach (BufferModifiedRange range in inheritRanges)
|
||||
for (int i = 0; i < rangesCount; i++)
|
||||
{
|
||||
BufferModifiedRange range = inheritRanges[i];
|
||||
if (range.SyncNumber != currentSync)
|
||||
{
|
||||
registerRangeAction(range.Address, range.Size);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayPool<BufferModifiedRange>.Shared.Return(inheritRanges);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -534,18 +555,25 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
private void ClearPart(BufferModifiedRange overlap, ulong address, ulong endAddress)
|
||||
{
|
||||
Remove(overlap);
|
||||
|
||||
// If the overlap extends outside of the clear range, make sure those parts still exist.
|
||||
|
||||
if (overlap.Address < address)
|
||||
{
|
||||
Add(new BufferModifiedRange(overlap.Address, address - overlap.Address, overlap.SyncNumber, overlap.Parent));
|
||||
if (overlap.EndAddress > endAddress)
|
||||
{
|
||||
Add(new BufferModifiedRange(endAddress, overlap.EndAddress - endAddress, overlap.SyncNumber, overlap.Parent));
|
||||
}
|
||||
|
||||
overlap.Size = address - overlap.Address;
|
||||
}
|
||||
|
||||
if (overlap.EndAddress > endAddress)
|
||||
else if (overlap.EndAddress > endAddress)
|
||||
{
|
||||
Add(new BufferModifiedRange(endAddress, overlap.EndAddress - endAddress, overlap.SyncNumber, overlap.Parent));
|
||||
overlap.Size = overlap.EndAddress - endAddress;
|
||||
overlap.Address = endAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove(overlap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,7 +586,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
ulong endAddress = address + size;
|
||||
Lock.EnterWriteLock();
|
||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlapsAsNodes(address, size);
|
||||
(BufferModifiedRange first, BufferModifiedRange last) = FindOverlapsAsNodes(address, size);
|
||||
|
||||
if (first is null)
|
||||
{
|
||||
@@ -570,26 +598,24 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
if (first.Address < address)
|
||||
{
|
||||
first.Value.Size = address - first.Address;
|
||||
Update(first);
|
||||
first.Size = address - first.Address;
|
||||
|
||||
if (first.EndAddress > endAddress)
|
||||
{
|
||||
Add(new BufferModifiedRange(endAddress, first.EndAddress - endAddress,
|
||||
first.Value.SyncNumber, first.Value.Parent));
|
||||
first.SyncNumber, first.Parent));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first.EndAddress > endAddress)
|
||||
{
|
||||
first.Value.Size = first.EndAddress - endAddress;
|
||||
first.Value.Address = endAddress;
|
||||
Update(first);
|
||||
first.Size = first.EndAddress - endAddress;
|
||||
first.Address = endAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove(first.Value);
|
||||
Remove(first);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,14 +631,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
if (first.Address < address)
|
||||
{
|
||||
buffPre = new BufferModifiedRange(first.Address, address - first.Address,
|
||||
first.Value.SyncNumber, first.Value.Parent);
|
||||
first.SyncNumber, first.Parent);
|
||||
extendsPre = true;
|
||||
}
|
||||
|
||||
if (last.EndAddress > endAddress)
|
||||
{
|
||||
buffPost = new BufferModifiedRange(endAddress, last.EndAddress - endAddress,
|
||||
last.Value.SyncNumber, last.Value.Parent);
|
||||
last.SyncNumber, last.Parent);
|
||||
extendsPost = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// Represents a GPU virtual memory range.
|
||||
/// </summary>
|
||||
private class VirtualRange : INonOverlappingRange
|
||||
private class VirtualRange : INonOverlappingRange<VirtualRange>
|
||||
{
|
||||
/// <summary>
|
||||
/// GPU virtual address where the range starts.
|
||||
@@ -32,6 +32,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// </summary>
|
||||
public ulong EndAddress => Address + Size;
|
||||
|
||||
public VirtualRange Next { get; set; }
|
||||
public VirtualRange Previous { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Physical regions where the GPU virtual region is mapped.
|
||||
/// </summary>
|
||||
@@ -54,14 +57,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// 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>
|
||||
/// <param name="endAddress">End address of the range</param>
|
||||
/// <returns>True if the range overlaps, false otherwise</returns>
|
||||
public bool OverlapsWith(ulong address, ulong size)
|
||||
public bool OverlapsWith(ulong address, ulong endAddress)
|
||||
{
|
||||
return Address < address + size && address < EndAddress;
|
||||
return Address < endAddress && address < EndAddress;
|
||||
}
|
||||
|
||||
public INonOverlappingRange Split(ulong splitAddress)
|
||||
public INonOverlappingRange<VirtualRange> Split(ulong splitAddress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -122,7 +125,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
ulong originalVa = gpuVa;
|
||||
|
||||
_virtualRanges.Lock.EnterWriteLock();
|
||||
(RangeItem<VirtualRange> first, RangeItem<VirtualRange> last) = _virtualRanges.FindOverlapsAsNodes(gpuVa, size);
|
||||
(VirtualRange first, VirtualRange last) = _virtualRanges.FindOverlapsAsNodes(gpuVa, size);
|
||||
|
||||
if (first is not null)
|
||||
{
|
||||
@@ -147,8 +150,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
}
|
||||
else
|
||||
{
|
||||
found = first.Value.Range.Count == 1 || IsSparseAligned(first.Value.Range);
|
||||
range = first.Value.Range.Slice(gpuVa - first.Address, size);
|
||||
found = first.Range.Count == 1 || IsSparseAligned(first.Range);
|
||||
range = first.Range.Slice(gpuVa - first.Address, size);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user