initial commit

This commit is contained in:
LotP1 2025-06-01 07:30:35 +02:00
parent d688fed7d2
commit be8f4897a2
10 changed files with 935 additions and 407 deletions

View file

@ -2,7 +2,6 @@ using Ryujinx.Graphics.GAL;
using Ryujinx.Memory.Range;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace Ryujinx.Graphics.Gpu.Memory
@ -42,7 +41,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
private readonly RangeList<Buffer> _buffers;
private readonly MultiRangeList<MultiRangeBuffer> _multiRangeBuffers;
private Buffer[] _bufferOverlaps;
private RangeItem<Buffer>[] _bufferOverlaps;
private readonly Dictionary<ulong, BufferCacheEntry> _dirtyCache;
private readonly Dictionary<ulong, BufferCacheEntry> _modifiedCache;
@ -64,7 +63,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
_buffers = [];
_multiRangeBuffers = [];
_bufferOverlaps = new Buffer[OverlapsBufferInitialCapacity];
_bufferOverlaps = new RangeItem<Buffer>[OverlapsBufferInitialCapacity];
_dirtyCache = new Dictionary<ulong, BufferCacheEntry>();
@ -79,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="e">Event arguments</param>
public void MemoryUnmappedHandler(object sender, UnmapEventArgs e)
{
Buffer[] overlaps = new Buffer[10];
RangeItem<Buffer>[] overlaps = new RangeItem<Buffer>[10];
int overlapCount;
MultiRange range = ((MemoryManager)sender).GetPhysicalRegions(e.Address, e.Size);
@ -90,12 +89,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
lock (_buffers)
{
overlapCount = _buffers.FindOverlaps(subRange.Address, subRange.Size, ref overlaps);
overlapCount = _buffers.FindOverlaps(subRange.Address, subRange.Size, ref overlaps).Count;
}
for (int i = 0; i < overlapCount; i++)
{
overlaps[i].Unmapped(subRange.Address, subRange.Size);
overlaps[i].Value.Unmapped(subRange.Address, subRange.Size);
}
}
}
@ -495,10 +494,11 @@ 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[] overlaps = _bufferOverlaps;
int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
_buffers.Lock.EnterWriteLock();
RangeItem<Buffer>[] overlaps = _bufferOverlaps;
OverlapResult result = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
if (overlapsCount != 0)
if (result.Count != 0)
{
// The buffer already exists. We can just return the existing buffer
// if the buffer we need is fully contained inside the overlapping buffer.
@ -507,7 +507,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
// old buffer(s) to the new buffer.
ulong endAddress = address + size;
Buffer overlap0 = overlaps[0];
RangeItem<Buffer> overlap0 = overlaps[0];
if (overlap0.Address > address || overlap0.EndAddress < endAddress)
{
@ -522,39 +522,36 @@ 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 (overlapsCount == 1 &&
if (result.Count == 1 &&
address >= overlap0.Address &&
endAddress - overlap0.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 = overlap0.Size;
ulong existingSize = overlap0.Value.Size;
ulong growthSize = (existingSize + Math.Min(existingSize >> 1, MaxDynamicGrowthSize)) & ~BufferAlignmentMask;
size = Math.Max(size, growthSize);
endAddress = address + size;
overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
result = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
}
_buffers.RemoveRange(result);
address = Math.Min(address, overlaps[0].Address);
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
for (int index = 0; index < overlapsCount; index++)
for (int index = 0; index < result.Count; index++)
{
Buffer buffer = overlaps[index];
RangeItem<Buffer> buffer = overlaps[index];
anySparseCompatible |= buffer.SparseCompatible;
address = Math.Min(address, buffer.Address);
endAddress = Math.Max(endAddress, buffer.EndAddress);
lock (_buffers)
{
_buffers.Remove(buffer);
}
anySparseCompatible |= buffer.Value.SparseCompatible;
}
ulong newSize = endAddress - address;
CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlaps, overlapsCount);
CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlaps, result.Count);
}
}
else
@ -562,11 +559,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
// No overlap, just create a new buffer.
Buffer buffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible: false);
lock (_buffers)
{
_buffers.Add(buffer);
}
_buffers.Add(buffer);
}
_buffers.Lock.ExitWriteLock();
ShrinkOverlapsBufferIfNeeded();
}
@ -582,22 +578,23 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="alignment">Alignment of the start address of the buffer</param>
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage, ulong alignment)
{
Buffer[] overlaps = _bufferOverlaps;
int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
_buffers.Lock.EnterWriteLock();
RangeItem<Buffer>[] overlaps = _bufferOverlaps;
OverlapResult result = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
bool sparseAligned = alignment >= SparseBufferAlignmentSize;
if (overlapsCount != 0)
if (result.Count != 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;
Buffer overlap0 = overlaps[0];
RangeItem<Buffer> overlap0 = overlaps[0];
if (overlap0.Address > address ||
overlap0.EndAddress < endAddress ||
(overlap0.Address & (alignment - 1)) != 0 ||
(!overlap0.SparseCompatible && sparseAligned))
(!overlap0.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
@ -605,35 +602,24 @@ namespace Ryujinx.Graphics.Gpu.Memory
// and ensure we cover all overlaps.
int oldOverlapsCount;
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
do
{
for (int index = 0; index < overlapsCount; index++)
{
Buffer buffer = overlaps[index];
address = Math.Min(address, buffer.Address);
endAddress = Math.Max(endAddress, buffer.EndAddress);
}
address = Math.Min(address, overlaps[0].Address);
address &= ~(alignment - 1);
oldOverlapsCount = overlapsCount;
overlapsCount = _buffers.FindOverlapsNonOverlapping(address, endAddress - address, ref overlaps);
oldOverlapsCount = result.Count;
result = _buffers.FindOverlapsNonOverlapping(address, endAddress - address, ref overlaps);
}
while (oldOverlapsCount != overlapsCount);
while (oldOverlapsCount != result.Count);
lock (_buffers)
{
for (int index = 0; index < overlapsCount; index++)
{
_buffers.Remove(overlaps[index]);
}
}
_buffers.RemoveRange(result);
ulong newSize = endAddress - address;
CreateBufferAligned(address, newSize, stage, sparseAligned, overlaps, overlapsCount);
CreateBufferAligned(address, newSize, stage, sparseAligned, overlaps, result.Count);
}
}
else
@ -641,11 +627,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
// No overlap, just create a new buffer.
Buffer buffer = new(_context, _physicalMemory, address, size, stage, sparseAligned);
lock (_buffers)
{
_buffers.Add(buffer);
}
_buffers.Add(buffer);
}
_buffers.Lock.ExitWriteLock();
ShrinkOverlapsBufferIfNeeded();
}
@ -661,18 +645,15 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="sparseCompatible">Indicates if the buffer can be used in a sparse buffer mapping</param>
/// <param name="overlaps">Buffers overlapping the range</param>
/// <param name="overlapsCount">Total of overlaps</param>
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage, bool sparseCompatible, Buffer[] overlaps, int overlapsCount)
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage, bool sparseCompatible, RangeItem<Buffer>[] overlaps, int overlapsCount)
{
Buffer newBuffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible, overlaps.Take(overlapsCount));
Buffer newBuffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible, overlaps);
lock (_buffers)
{
_buffers.Add(newBuffer);
}
_buffers.Add(newBuffer);
for (int index = 0; index < overlapsCount; index++)
{
Buffer buffer = overlaps[index];
Buffer buffer = overlaps[index].Value;
int dstOffset = (int)(buffer.Address - newBuffer.Address);