aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Memory
diff options
context:
space:
mode:
authorTSR Berry <20988865+TSRBerry@users.noreply.github.com>2023-04-08 01:22:00 +0200
committerMary <thog@protonmail.com>2023-04-27 23:51:14 +0200
commitcee712105850ac3385cd0091a923438167433f9f (patch)
tree4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /Ryujinx.Graphics.Gpu/Memory
parentcd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff)
Move solution and projects to src
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Memory')
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/Buffer.cs544
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs38
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferCache.cs507
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferCacheEntry.cs43
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferManager.cs754
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferMigration.cs125
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs514
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs75
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/CounterCache.cs191
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/GpuRegionHandle.cs102
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/IndexBuffer.cs15
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs713
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/MultiRangeWritableBlock.cs58
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs413
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/PteKind.cs268
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/ResourceKind.cs13
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/UnmapEventArgs.cs14
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/VertexBuffer.cs13
18 files changed, 0 insertions, 4400 deletions
diff --git a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs b/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
deleted file mode 100644
index f267dfda..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
+++ /dev/null
@@ -1,544 +0,0 @@
-using Ryujinx.Cpu.Tracking;
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Memory.Range;
-using Ryujinx.Memory.Tracking;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// Buffer, used to store vertex and index data, uniform and storage buffers, and others.
- /// </summary>
- class Buffer : IRange, IDisposable
- {
- private const ulong GranularBufferThreshold = 4096;
-
- private readonly GpuContext _context;
- private readonly PhysicalMemory _physicalMemory;
-
- /// <summary>
- /// Host buffer handle.
- /// </summary>
- public BufferHandle Handle { get; }
-
- /// <summary>
- /// Start address of the buffer in guest memory.
- /// </summary>
- public ulong Address { get; }
-
- /// <summary>
- /// Size of the buffer in bytes.
- /// </summary>
- public ulong Size { get; }
-
- /// <summary>
- /// End address of the buffer in guest memory.
- /// </summary>
- public ulong EndAddress => Address + Size;
-
- /// <summary>
- /// Increments when the buffer is (partially) unmapped or disposed.
- /// </summary>
- public int UnmappedSequence { get; private set; }
-
- /// <summary>
- /// Ranges of the buffer that have been modified on the GPU.
- /// Ranges defined here cannot be updated from CPU until a CPU waiting sync point is reached.
- /// Then, write tracking will signal, wait for GPU sync (generated at the syncpoint) and flush these regions.
- /// </summary>
- /// <remarks>
- /// This is null until at least one modification occurs.
- /// </remarks>
- private BufferModifiedRangeList _modifiedRanges = null;
-
- private readonly CpuMultiRegionHandle _memoryTrackingGranular;
- private readonly CpuRegionHandle _memoryTracking;
-
- private readonly RegionSignal _externalFlushDelegate;
- private readonly Action<ulong, ulong> _loadDelegate;
- private readonly Action<ulong, ulong> _modifiedDelegate;
-
- private int _sequenceNumber;
-
- private bool _useGranular;
- private bool _syncActionRegistered;
-
- private int _referenceCount = 1;
-
- /// <summary>
- /// Creates a new instance of the buffer.
- /// </summary>
- /// <param name="context">GPU context that the buffer belongs to</param>
- /// <param name="physicalMemory">Physical memory where the buffer is mapped</param>
- /// <param name="address">Start address of the buffer</param>
- /// <param name="size">Size of the buffer in bytes</param>
- /// <param name="baseBuffers">Buffers which this buffer contains, and will inherit tracking handles from</param>
- public Buffer(GpuContext context, PhysicalMemory physicalMemory, ulong address, ulong size, IEnumerable<Buffer> baseBuffers = null)
- {
- _context = context;
- _physicalMemory = physicalMemory;
- Address = address;
- Size = size;
-
- Handle = context.Renderer.CreateBuffer((int)size, baseBuffers?.MaxBy(x => x.Size).Handle ?? BufferHandle.Null);
-
- _useGranular = size > GranularBufferThreshold;
-
- IEnumerable<IRegionHandle> baseHandles = null;
-
- if (baseBuffers != null)
- {
- baseHandles = baseBuffers.SelectMany(buffer =>
- {
- if (buffer._useGranular)
- {
- return buffer._memoryTrackingGranular.GetHandles();
- }
- else
- {
- return Enumerable.Repeat(buffer._memoryTracking.GetHandle(), 1);
- }
- });
- }
-
- if (_useGranular)
- {
- _memoryTrackingGranular = physicalMemory.BeginGranularTracking(address, size, ResourceKind.Buffer, baseHandles);
-
- _memoryTrackingGranular.RegisterPreciseAction(address, size, PreciseAction);
- }
- else
- {
- _memoryTracking = physicalMemory.BeginTracking(address, size, ResourceKind.Buffer);
-
- if (baseHandles != null)
- {
- _memoryTracking.Reprotect(false);
-
- foreach (IRegionHandle handle in baseHandles)
- {
- if (handle.Dirty)
- {
- _memoryTracking.Reprotect(true);
- }
-
- handle.Dispose();
- }
- }
-
- _memoryTracking.RegisterPreciseAction(PreciseAction);
- }
-
- _externalFlushDelegate = new RegionSignal(ExternalFlush);
- _loadDelegate = new Action<ulong, ulong>(LoadRegion);
- _modifiedDelegate = new Action<ulong, ulong>(RegionModified);
- }
-
- /// <summary>
- /// Gets a sub-range from the buffer, from a start address till the end of the buffer.
- /// </summary>
- /// <remarks>
- /// This can be used to bind and use sub-ranges of the buffer on the host API.
- /// </remarks>
- /// <param name="address">Start address of the sub-range, must be greater than or equal to the buffer address</param>
- /// <returns>The buffer sub-range</returns>
- public BufferRange GetRange(ulong address)
- {
- ulong offset = address - Address;
-
- return new BufferRange(Handle, (int)offset, (int)(Size - offset));
- }
-
- /// <summary>
- /// Gets a sub-range from the buffer.
- /// </summary>
- /// <remarks>
- /// This can be used to bind and use sub-ranges of the buffer on the host API.
- /// </remarks>
- /// <param name="address">Start address of the sub-range, must be greater than or equal to the buffer address</param>
- /// <param name="size">Size in bytes of the sub-range, must be less than or equal to the buffer size</param>
- /// <returns>The buffer sub-range</returns>
- public BufferRange GetRange(ulong address, ulong size)
- {
- int offset = (int)(address - Address);
-
- return new BufferRange(Handle, offset, (int)size);
- }
-
- /// <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;
- }
-
- /// <summary>
- /// Checks if a given range is fully contained in 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 is contained, false otherwise</returns>
- public bool FullyContains(ulong address, ulong size)
- {
- return address >= Address && address + size <= EndAddress;
- }
-
- /// <summary>
- /// Performs guest to host memory synchronization of the buffer data.
- /// </summary>
- /// <remarks>
- /// This causes the buffer data to be overwritten if a write was detected from the CPU,
- /// since the last call to this method.
- /// </remarks>
- /// <param name="address">Start address of the range to synchronize</param>
- /// <param name="size">Size in bytes of the range to synchronize</param>
- public void SynchronizeMemory(ulong address, ulong size)
- {
- if (_useGranular)
- {
- _memoryTrackingGranular.QueryModified(address, size, _modifiedDelegate, _context.SequenceNumber);
- }
- else
- {
- if (_context.SequenceNumber != _sequenceNumber && _memoryTracking.DirtyOrVolatile())
- {
- _memoryTracking.Reprotect();
-
- if (_modifiedRanges != null)
- {
- _modifiedRanges.ExcludeModifiedRegions(Address, Size, _loadDelegate);
- }
- else
- {
- _context.Renderer.SetBufferData(Handle, 0, _physicalMemory.GetSpan(Address, (int)Size));
- }
-
- _sequenceNumber = _context.SequenceNumber;
- }
- }
- }
-
- /// <summary>
- /// Ensure that the modified range list exists.
- /// </summary>
- private void EnsureRangeList()
- {
- if (_modifiedRanges == null)
- {
- _modifiedRanges = new BufferModifiedRangeList(_context, this, Flush);
- }
- }
-
- /// <summary>
- /// Signal that the given region of the buffer has been modified.
- /// </summary>
- /// <param name="address">The start address of the modified region</param>
- /// <param name="size">The size of the modified region</param>
- public void SignalModified(ulong address, ulong size)
- {
- EnsureRangeList();
-
- _modifiedRanges.SignalModified(address, size);
-
- if (!_syncActionRegistered)
- {
- _context.RegisterSyncAction(SyncAction);
- _syncActionRegistered = true;
- }
- }
-
- /// <summary>
- /// Indicate that mofifications in a given region of this buffer have been overwritten.
- /// </summary>
- /// <param name="address">The start address of the region</param>
- /// <param name="size">The size of the region</param>
- public void ClearModified(ulong address, ulong size)
- {
- _modifiedRanges?.Clear(address, size);
- }
-
- /// <summary>
- /// Action to be performed when a syncpoint is reached after modification.
- /// This will register read/write tracking to flush the buffer from GPU when its memory is used.
- /// </summary>
- private void SyncAction()
- {
- _syncActionRegistered = false;
-
- if (_useGranular)
- {
- _modifiedRanges?.GetRanges(Address, Size, (address, size) =>
- {
- _memoryTrackingGranular.RegisterAction(address, size, _externalFlushDelegate);
- SynchronizeMemory(address, size);
- });
- }
- else
- {
- _memoryTracking.RegisterAction(_externalFlushDelegate);
- SynchronizeMemory(Address, Size);
- }
- }
-
- /// <summary>
- /// Inherit modified ranges from another buffer.
- /// </summary>
- /// <param name="from">The buffer to inherit from</param>
- public void InheritModifiedRanges(Buffer from)
- {
- if (from._modifiedRanges != null && from._modifiedRanges.HasRanges)
- {
- if (from._syncActionRegistered && !_syncActionRegistered)
- {
- _context.RegisterSyncAction(SyncAction);
- _syncActionRegistered = true;
- }
-
- Action<ulong, ulong> registerRangeAction = (ulong address, ulong size) =>
- {
- if (_useGranular)
- {
- _memoryTrackingGranular.RegisterAction(address, size, _externalFlushDelegate);
- }
- else
- {
- _memoryTracking.RegisterAction(_externalFlushDelegate);
- }
- };
-
- EnsureRangeList();
-
- _modifiedRanges.InheritRanges(from._modifiedRanges, registerRangeAction);
- }
- }
-
- /// <summary>
- /// Determine if a given region of the buffer has been modified, and must be flushed.
- /// </summary>
- /// <param name="address">The start address of the region</param>
- /// <param name="size">The size of the region</param>
- /// <returns></returns>
- public bool IsModified(ulong address, ulong size)
- {
- if (_modifiedRanges != null)
- {
- return _modifiedRanges.HasRange(address, size);
- }
-
- return false;
- }
-
- /// <summary>
- /// Indicate that a region of the buffer was modified, and must be loaded from memory.
- /// </summary>
- /// <param name="mAddress">Start address of the modified region</param>
- /// <param name="mSize">Size of the modified region</param>
- private void RegionModified(ulong mAddress, ulong mSize)
- {
- if (mAddress < Address)
- {
- mAddress = Address;
- }
-
- ulong maxSize = Address + Size - mAddress;
-
- if (mSize > maxSize)
- {
- mSize = maxSize;
- }
-
- if (_modifiedRanges != null)
- {
- _modifiedRanges.ExcludeModifiedRegions(mAddress, mSize, _loadDelegate);
- }
- else
- {
- LoadRegion(mAddress, mSize);
- }
- }
-
- /// <summary>
- /// Load a region of the buffer from memory.
- /// </summary>
- /// <param name="mAddress">Start address of the modified region</param>
- /// <param name="mSize">Size of the modified region</param>
- private void LoadRegion(ulong mAddress, ulong mSize)
- {
- int offset = (int)(mAddress - Address);
-
- _context.Renderer.SetBufferData(Handle, offset, _physicalMemory.GetSpan(mAddress, (int)mSize));
- }
-
- /// <summary>
- /// Force a region of the buffer to be dirty. Avoids reprotection and nullifies sequence number check.
- /// </summary>
- /// <param name="mAddress">Start address of the modified region</param>
- /// <param name="mSize">Size of the region to force dirty</param>
- public void ForceDirty(ulong mAddress, ulong mSize)
- {
- _modifiedRanges?.Clear(mAddress, mSize);
-
- if (_useGranular)
- {
- _memoryTrackingGranular.ForceDirty(mAddress, mSize);
- }
- else
- {
- _memoryTracking.ForceDirty();
- _sequenceNumber--;
- }
- }
-
- /// <summary>
- /// Performs copy of all the buffer data from one buffer to another.
- /// </summary>
- /// <param name="destination">The destination buffer to copy the data into</param>
- /// <param name="dstOffset">The offset of the destination buffer to copy into</param>
- public void CopyTo(Buffer destination, int dstOffset)
- {
- _context.Renderer.Pipeline.CopyBuffer(Handle, destination.Handle, 0, dstOffset, (int)Size);
- }
-
- /// <summary>
- /// Flushes a range of the buffer.
- /// This writes the range data back into guest memory.
- /// </summary>
- /// <param name="address">Start address of the range</param>
- /// <param name="size">Size in bytes of the range</param>
- public void Flush(ulong address, ulong size)
- {
- int offset = (int)(address - Address);
-
- using PinnedSpan<byte> data = _context.Renderer.GetBufferData(Handle, offset, (int)size);
-
- // TODO: When write tracking shaders, they will need to be aware of changes in overlapping buffers.
- _physicalMemory.WriteUntracked(address, data.Get());
- }
-
- /// <summary>
- /// Align a given address and size region to page boundaries.
- /// </summary>
- /// <param name="address">The start address of the region</param>
- /// <param name="size">The size of the region</param>
- /// <returns>The page aligned address and size</returns>
- private static (ulong address, ulong size) PageAlign(ulong address, ulong size)
- {
- ulong pageMask = MemoryManager.PageMask;
- ulong rA = address & ~pageMask;
- ulong rS = ((address + size + pageMask) & ~pageMask) - rA;
- return (rA, rS);
- }
-
- /// <summary>
- /// Flush modified ranges of the buffer from another thread.
- /// This will flush all modifications made before the active SyncNumber was set, and may block to wait for GPU sync.
- /// </summary>
- /// <param name="address">Address of the memory action</param>
- /// <param name="size">Size in bytes</param>
- public void ExternalFlush(ulong address, ulong size)
- {
- _context.Renderer.BackgroundContextAction(() =>
- {
- var ranges = _modifiedRanges;
-
- if (ranges != null)
- {
- (address, size) = PageAlign(address, size);
- ranges.WaitForAndFlushRanges(address, size);
- }
- }, true);
- }
-
- /// <summary>
- /// An action to be performed when a precise memory access occurs to this resource.
- /// For buffers, this skips flush-on-write by punching holes directly into the modified range list.
- /// </summary>
- /// <param name="address">Address of the memory action</param>
- /// <param name="size">Size in bytes</param>
- /// <param name="write">True if the access was a write, false otherwise</param>
- private bool PreciseAction(ulong address, ulong size, bool write)
- {
- if (!write)
- {
- // We only want to skip flush-on-write.
- return false;
- }
-
- ulong maxAddress = Math.Max(address, Address);
- ulong minEndAddress = Math.Min(address + size, Address + Size);
-
- if (maxAddress >= minEndAddress)
- {
- // Access doesn't overlap.
- return false;
- }
-
- ForceDirty(maxAddress, minEndAddress - maxAddress);
-
- return true;
- }
-
- /// <summary>
- /// Called when part of the memory for this buffer has been unmapped.
- /// Calls are from non-GPU threads.
- /// </summary>
- /// <param name="address">Start address of the unmapped region</param>
- /// <param name="size">Size of the unmapped region</param>
- public void Unmapped(ulong address, ulong size)
- {
- BufferModifiedRangeList modifiedRanges = _modifiedRanges;
-
- modifiedRanges?.Clear(address, size);
-
- UnmappedSequence++;
- }
-
- /// <summary>
- /// Increments the buffer reference count.
- /// </summary>
- public void IncrementReferenceCount()
- {
- _referenceCount++;
- }
-
- /// <summary>
- /// Decrements the buffer reference count.
- /// </summary>
- public void DecrementReferenceCount()
- {
- if (--_referenceCount == 0)
- {
- DisposeData();
- }
- }
-
- /// <summary>
- /// Disposes the host buffer's data, not its tracking handles.
- /// </summary>
- public void DisposeData()
- {
- _modifiedRanges?.Clear();
-
- _context.Renderer.DeleteBuffer(Handle);
-
- UnmappedSequence++;
- }
-
- /// <summary>
- /// Disposes the host buffer.
- /// </summary>
- public void Dispose()
- {
- _memoryTrackingGranular?.Dispose();
- _memoryTracking?.Dispose();
-
- DecrementReferenceCount();
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs b/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs
deleted file mode 100644
index d513b7ad..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using Ryujinx.Graphics.Shader;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// Memory range used for buffers.
- /// </summary>
- readonly struct BufferBounds
- {
- /// <summary>
- /// Region virtual address.
- /// </summary>
- public ulong Address { get; }
-
- /// <summary>
- /// Region size in bytes.
- /// </summary>
- public ulong Size { get; }
-
- /// <summary>
- /// Buffer usage flags.
- /// </summary>
- public BufferUsageFlags Flags { get; }
-
- /// <summary>
- /// Creates a new buffer region.
- /// </summary>
- /// <param name="address">Region address</param>
- /// <param name="size">Region size</param>
- /// <param name="flags">Buffer usage flags</param>
- public BufferBounds(ulong address, ulong size, BufferUsageFlags flags = BufferUsageFlags.None)
- {
- Address = address;
- Size = size;
- Flags = flags;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs b/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
deleted file mode 100644
index a5a9b75e..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
+++ /dev/null
@@ -1,507 +0,0 @@
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Memory.Range;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// Buffer cache.
- /// </summary>
- class BufferCache : IDisposable
- {
- private const int OverlapsBufferInitialCapacity = 10;
- private const int OverlapsBufferMaxCapacity = 10000;
-
- private const ulong BufferAlignmentSize = 0x1000;
- private const ulong BufferAlignmentMask = BufferAlignmentSize - 1;
-
- private const ulong MaxDynamicGrowthSize = 0x100000;
-
- private readonly GpuContext _context;
- private readonly PhysicalMemory _physicalMemory;
-
- /// <remarks>
- /// Only modified from the GPU thread. Must lock for add/remove.
- /// Must lock for any access from other threads.
- /// </remarks>
- private readonly RangeList<Buffer> _buffers;
-
- private Buffer[] _bufferOverlaps;
-
- private readonly Dictionary<ulong, BufferCacheEntry> _dirtyCache;
- private readonly Dictionary<ulong, BufferCacheEntry> _modifiedCache;
- private bool _pruneCaches;
-
- public event Action NotifyBuffersModified;
-
- /// <summary>
- /// Creates a new instance of the buffer manager.
- /// </summary>
- /// <param name="context">The GPU context that the buffer manager belongs to</param>
- /// <param name="physicalMemory">Physical memory where the cached buffers are mapped</param>
- public BufferCache(GpuContext context, PhysicalMemory physicalMemory)
- {
- _context = context;
- _physicalMemory = physicalMemory;
-
- _buffers = new RangeList<Buffer>();
-
- _bufferOverlaps = new Buffer[OverlapsBufferInitialCapacity];
-
- _dirtyCache = new Dictionary<ulong, BufferCacheEntry>();
-
- // There are a lot more entries on the modified cache, so it is separate from the one for ForceDirty.
- _modifiedCache = new Dictionary<ulong, BufferCacheEntry>();
- }
-
- /// <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)
- {
- Buffer[] overlaps = new Buffer[10];
- int overlapCount;
-
- ulong address = ((MemoryManager)sender).Translate(e.Address);
- ulong size = e.Size;
-
- lock (_buffers)
- {
- overlapCount = _buffers.FindOverlaps(address, size, ref overlaps);
- }
-
- for (int i = 0; i < overlapCount; i++)
- {
- overlaps[i].Unmapped(address, size);
- }
- }
-
- /// <summary>
- /// Performs address translation of the GPU virtual address, and creates a
- /// new buffer, if needed, for the specified range.
- /// </summary>
- /// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
- /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
- /// <param name="size">Size in bytes of the buffer</param>
- /// <returns>CPU virtual address of the buffer, after address translation</returns>
- public ulong TranslateAndCreateBuffer(MemoryManager memoryManager, ulong gpuVa, ulong size)
- {
- if (gpuVa == 0)
- {
- return 0;
- }
-
- ulong address = memoryManager.Translate(gpuVa);
-
- if (address == MemoryManager.PteUnmapped)
- {
- return 0;
- }
-
- CreateBuffer(address, size);
-
- return address;
- }
-
- /// <summary>
- /// Creates a new buffer for the specified range, if it does not yet exist.
- /// This can be used to ensure the existance of a buffer.
- /// </summary>
- /// <param name="address">Address of the buffer in memory</param>
- /// <param name="size">Size of the buffer in bytes</param>
- public void CreateBuffer(ulong address, ulong size)
- {
- ulong endAddress = address + size;
-
- ulong alignedAddress = address & ~BufferAlignmentMask;
-
- ulong alignedEndAddress = (endAddress + BufferAlignmentMask) & ~BufferAlignmentMask;
-
- // The buffer must have the size of at least one page.
- if (alignedEndAddress == alignedAddress)
- {
- alignedEndAddress += BufferAlignmentSize;
- }
-
- CreateBufferAligned(alignedAddress, alignedEndAddress - alignedAddress);
- }
-
- /// <summary>
- /// Performs address translation of the GPU virtual address, and attempts to force
- /// the buffer in the region as dirty.
- /// The buffer lookup for this function is cached in a dictionary for quick access, which
- /// accelerates common UBO updates.
- /// </summary>
- /// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
- /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
- /// <param name="size">Size in bytes of the buffer</param>
- public void ForceDirty(MemoryManager memoryManager, ulong gpuVa, ulong size)
- {
- if (_pruneCaches)
- {
- Prune();
- }
-
- if (!_dirtyCache.TryGetValue(gpuVa, out BufferCacheEntry result) ||
- result.EndGpuAddress < gpuVa + size ||
- result.UnmappedSequence != result.Buffer.UnmappedSequence)
- {
- ulong address = TranslateAndCreateBuffer(memoryManager, gpuVa, size);
- result = new BufferCacheEntry(address, gpuVa, GetBuffer(address, size));
-
- _dirtyCache[gpuVa] = result;
- }
-
- result.Buffer.ForceDirty(result.Address, size);
- }
-
- /// <summary>
- /// Checks if the given buffer range has been GPU modifed.
- /// </summary>
- /// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
- /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
- /// <param name="size">Size in bytes of the buffer</param>
- /// <returns>True if modified, false otherwise</returns>
- public bool CheckModified(MemoryManager memoryManager, ulong gpuVa, ulong size, out ulong outAddr)
- {
- if (_pruneCaches)
- {
- Prune();
- }
-
- // Align the address to avoid creating too many entries on the quick lookup dictionary.
- ulong mask = BufferAlignmentMask;
- ulong alignedGpuVa = gpuVa & (~mask);
- ulong alignedEndGpuVa = (gpuVa + size + mask) & (~mask);
-
- size = alignedEndGpuVa - alignedGpuVa;
-
- if (!_modifiedCache.TryGetValue(alignedGpuVa, out BufferCacheEntry result) ||
- result.EndGpuAddress < alignedEndGpuVa ||
- result.UnmappedSequence != result.Buffer.UnmappedSequence)
- {
- ulong address = TranslateAndCreateBuffer(memoryManager, alignedGpuVa, size);
- result = new BufferCacheEntry(address, alignedGpuVa, GetBuffer(address, size));
-
- _modifiedCache[alignedGpuVa] = result;
- }
-
- outAddr = result.Address | (gpuVa & mask);
-
- return result.Buffer.IsModified(result.Address, size);
- }
-
- /// <summary>
- /// Creates a new buffer for the specified range, if needed.
- /// If a buffer where this range can be fully contained already exists,
- /// then the creation of a new buffer is not necessary.
- /// </summary>
- /// <param name="address">Address of the buffer in guest memory</param>
- /// <param name="size">Size in bytes of the buffer</param>
- private void CreateBufferAligned(ulong address, ulong size)
- {
- int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref _bufferOverlaps);
-
- if (overlapsCount != 0)
- {
- // The buffer already exists. We can just return the existing buffer
- // if the buffer we need is fully contained inside the overlapping buffer.
- // Otherwise, we must delete the overlapping buffers and create a bigger buffer
- // that fits all the data we need. We also need to copy the contents from the
- // old buffer(s) to the new buffer.
-
- ulong endAddress = address + size;
-
- if (_bufferOverlaps[0].Address > address || _bufferOverlaps[0].EndAddress < endAddress)
- {
- // Check if the following conditions are met:
- // - We have a single overlap.
- // - The overlap starts at or before the requested range. That is, the overlap happens at the end.
- // - The size delta between the new, merged buffer and the old one is of at most 2 pages.
- // In this case, we attempt to extend the buffer further than the requested range,
- // this can potentially avoid future resizes if the application keeps using overlapping
- // 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 &&
- address >= _bufferOverlaps[0].Address &&
- endAddress - _bufferOverlaps[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 = _bufferOverlaps[0].Size;
- ulong growthSize = (existingSize + Math.Min(existingSize >> 1, MaxDynamicGrowthSize)) & ~BufferAlignmentMask;
-
- size = Math.Max(size, growthSize);
- endAddress = address + size;
-
- overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref _bufferOverlaps);
- }
-
- for (int index = 0; index < overlapsCount; index++)
- {
- Buffer buffer = _bufferOverlaps[index];
-
- address = Math.Min(address, buffer.Address);
- endAddress = Math.Max(endAddress, buffer.EndAddress);
-
- lock (_buffers)
- {
- _buffers.Remove(buffer);
- }
- }
-
- ulong newSize = endAddress - address;
-
- Buffer newBuffer = new Buffer(_context, _physicalMemory, address, newSize, _bufferOverlaps.Take(overlapsCount));
-
- lock (_buffers)
- {
- _buffers.Add(newBuffer);
- }
-
- for (int index = 0; index < overlapsCount; index++)
- {
- Buffer buffer = _bufferOverlaps[index];
-
- int dstOffset = (int)(buffer.Address - newBuffer.Address);
-
- buffer.CopyTo(newBuffer, dstOffset);
- newBuffer.InheritModifiedRanges(buffer);
-
- buffer.DecrementReferenceCount();
- }
-
- newBuffer.SynchronizeMemory(address, newSize);
-
- // Existing buffers were modified, we need to rebind everything.
- NotifyBuffersModified?.Invoke();
- }
- }
- else
- {
- // No overlap, just create a new buffer.
- Buffer buffer = new Buffer(_context, _physicalMemory, address, size);
-
- lock (_buffers)
- {
- _buffers.Add(buffer);
- }
- }
-
- ShrinkOverlapsBufferIfNeeded();
- }
-
- /// <summary>
- /// Resizes the temporary buffer used for range list intersection results, if it has grown too much.
- /// </summary>
- private void ShrinkOverlapsBufferIfNeeded()
- {
- if (_bufferOverlaps.Length > OverlapsBufferMaxCapacity)
- {
- Array.Resize(ref _bufferOverlaps, OverlapsBufferMaxCapacity);
- }
- }
-
- /// <summary>
- /// Copy a buffer data from a given address to another.
- /// </summary>
- /// <remarks>
- /// This does a GPU side copy.
- /// </remarks>
- /// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
- /// <param name="srcVa">GPU virtual address of the copy source</param>
- /// <param name="dstVa">GPU virtual address of the copy destination</param>
- /// <param name="size">Size in bytes of the copy</param>
- public void CopyBuffer(MemoryManager memoryManager, ulong srcVa, ulong dstVa, ulong size)
- {
- ulong srcAddress = TranslateAndCreateBuffer(memoryManager, srcVa, size);
- ulong dstAddress = TranslateAndCreateBuffer(memoryManager, dstVa, size);
-
- Buffer srcBuffer = GetBuffer(srcAddress, size);
- Buffer dstBuffer = GetBuffer(dstAddress, size);
-
- int srcOffset = (int)(srcAddress - srcBuffer.Address);
- int dstOffset = (int)(dstAddress - dstBuffer.Address);
-
- _context.Renderer.Pipeline.CopyBuffer(
- srcBuffer.Handle,
- dstBuffer.Handle,
- srcOffset,
- dstOffset,
- (int)size);
-
- if (srcBuffer.IsModified(srcAddress, size))
- {
- dstBuffer.SignalModified(dstAddress, size);
- }
- else
- {
- // Optimization: If the data being copied is already in memory, then copy it directly instead of flushing from GPU.
-
- dstBuffer.ClearModified(dstAddress, size);
- memoryManager.Physical.WriteUntracked(dstAddress, memoryManager.Physical.GetSpan(srcAddress, (int)size));
- }
- }
-
- /// <summary>
- /// Clears a buffer at a given address with the specified value.
- /// </summary>
- /// <remarks>
- /// Both the address and size must be aligned to 4 bytes.
- /// </remarks>
- /// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
- /// <param name="gpuVa">GPU virtual address of the region to clear</param>
- /// <param name="size">Number of bytes to clear</param>
- /// <param name="value">Value to be written into the buffer</param>
- public void ClearBuffer(MemoryManager memoryManager, ulong gpuVa, ulong size, uint value)
- {
- ulong address = TranslateAndCreateBuffer(memoryManager, gpuVa, size);
-
- Buffer buffer = GetBuffer(address, size);
-
- int offset = (int)(address - buffer.Address);
-
- _context.Renderer.Pipeline.ClearBuffer(buffer.Handle, offset, (int)size, value);
-
- memoryManager.Physical.FillTrackedResource(address, size, value, ResourceKind.Buffer);
- }
-
- /// <summary>
- /// Gets a buffer sub-range starting at a given memory address.
- /// </summary>
- /// <param name="address">Start address of the memory range</param>
- /// <param name="size">Size in bytes of the memory range</param>
- /// <param name="write">Whether the buffer will be written to by this use</param>
- /// <returns>The buffer sub-range starting at the given memory address</returns>
- public BufferRange GetBufferRangeTillEnd(ulong address, ulong size, bool write = false)
- {
- return GetBuffer(address, size, write).GetRange(address);
- }
-
- /// <summary>
- /// Gets a buffer sub-range for a given memory range.
- /// </summary>
- /// <param name="address">Start address of the memory range</param>
- /// <param name="size">Size in bytes of the memory range</param>
- /// <param name="write">Whether the buffer will be written to by this use</param>
- /// <returns>The buffer sub-range for the given range</returns>
- public BufferRange GetBufferRange(ulong address, ulong size, bool write = false)
- {
- return GetBuffer(address, size, write).GetRange(address, size);
- }
-
- /// <summary>
- /// Gets a buffer for a given memory range.
- /// A buffer overlapping with the specified range is assumed to already exist on the cache.
- /// </summary>
- /// <param name="address">Start address of the memory range</param>
- /// <param name="size">Size in bytes of the memory range</param>
- /// <param name="write">Whether the buffer will be written to by this use</param>
- /// <returns>The buffer where the range is fully contained</returns>
- private Buffer GetBuffer(ulong address, ulong size, bool write = false)
- {
- Buffer buffer;
-
- if (size != 0)
- {
- buffer = _buffers.FindFirstOverlap(address, size);
-
- buffer.SynchronizeMemory(address, size);
-
- if (write)
- {
- buffer.SignalModified(address, size);
- }
- }
- else
- {
- buffer = _buffers.FindFirstOverlap(address, 1);
- }
-
- return buffer;
- }
-
- /// <summary>
- /// Performs guest to host memory synchronization of a given memory range.
- /// </summary>
- /// <param name="address">Start address of the memory range</param>
- /// <param name="size">Size in bytes of the memory range</param>
- public void SynchronizeBufferRange(ulong address, ulong size)
- {
- if (size != 0)
- {
- Buffer buffer = _buffers.FindFirstOverlap(address, size);
-
- buffer.SynchronizeMemory(address, size);
- }
- }
-
- /// <summary>
- /// Prune any invalid entries from a quick access dictionary.
- /// </summary>
- /// <param name="dictionary">Dictionary to prune</param>
- /// <param name="toDelete">List used to track entries to delete</param>
- private void Prune(Dictionary<ulong, BufferCacheEntry> dictionary, ref List<ulong> toDelete)
- {
- foreach (var entry in dictionary)
- {
- if (entry.Value.UnmappedSequence != entry.Value.Buffer.UnmappedSequence)
- {
- (toDelete ??= new()).Add(entry.Key);
- }
- }
-
- if (toDelete != null)
- {
- foreach (ulong entry in toDelete)
- {
- dictionary.Remove(entry);
- }
- }
- }
-
- /// <summary>
- /// Prune any invalid entries from the quick access dictionaries.
- /// </summary>
- private void Prune()
- {
- List<ulong> toDelete = null;
-
- Prune(_dirtyCache, ref toDelete);
-
- toDelete?.Clear();
-
- Prune(_modifiedCache, ref toDelete);
-
- _pruneCaches = false;
- }
-
- /// <summary>
- /// Queues a prune of invalid entries the next time a dictionary cache is accessed.
- /// </summary>
- public void QueuePrune()
- {
- _pruneCaches = true;
- }
-
- /// <summary>
- /// Disposes all buffers in the cache.
- /// It's an error to use the buffer manager after disposal.
- /// </summary>
- public void Dispose()
- {
- lock (_buffers)
- {
- foreach (Buffer buffer in _buffers)
- {
- buffer.Dispose();
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferCacheEntry.cs b/Ryujinx.Graphics.Gpu/Memory/BufferCacheEntry.cs
deleted file mode 100644
index fa38b54e..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/BufferCacheEntry.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// A cached entry for easily locating a buffer that is used often internally.
- /// </summary>
- class BufferCacheEntry
- {
- /// <summary>
- /// The CPU VA of the buffer destination.
- /// </summary>
- public ulong Address;
-
- /// <summary>
- /// The end GPU VA of the associated buffer, used to check if new data can fit.
- /// </summary>
- public ulong EndGpuAddress;
-
- /// <summary>
- /// The buffer associated with this cache entry.
- /// </summary>
- public Buffer Buffer;
-
- /// <summary>
- /// The UnmappedSequence of the buffer at the time of creation.
- /// If this differs from the value currently in the buffer, then this cache entry is outdated.
- /// </summary>
- public int UnmappedSequence;
-
- /// <summary>
- /// Create a new cache entry.
- /// </summary>
- /// <param name="address">The CPU VA of the buffer destination</param>
- /// <param name="gpuVa">The GPU VA of the buffer destination</param>
- /// <param name="buffer">The buffer object containing the target buffer</param>
- public BufferCacheEntry(ulong address, ulong gpuVa, Buffer buffer)
- {
- Address = address;
- EndGpuAddress = gpuVa + (buffer.EndAddress - address);
- Buffer = buffer;
- UnmappedSequence = buffer.UnmappedSequence;
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
deleted file mode 100644
index e20e1bb6..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
+++ /dev/null
@@ -1,754 +0,0 @@
-using Ryujinx.Common;
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Gpu.Image;
-using Ryujinx.Graphics.Gpu.Shader;
-using Ryujinx.Graphics.Shader;
-using System;
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// Buffer manager.
- /// </summary>
- class BufferManager
- {
- private readonly GpuContext _context;
- private readonly GpuChannel _channel;
-
- private int _unalignedStorageBuffers;
- public bool HasUnalignedStorageBuffers => _unalignedStorageBuffers > 0;
-
- private IndexBuffer _indexBuffer;
- private readonly VertexBuffer[] _vertexBuffers;
- private readonly BufferBounds[] _transformFeedbackBuffers;
- private readonly List<BufferTextureBinding> _bufferTextures;
- private readonly BufferAssignment[] _ranges;
-
- /// <summary>
- /// Holds shader stage buffer state and binding information.
- /// </summary>
- private class BuffersPerStage
- {
- /// <summary>
- /// Shader buffer binding information.
- /// </summary>
- public BufferDescriptor[] Bindings { get; private set; }
-
- /// <summary>
- /// Buffer regions.
- /// </summary>
- public BufferBounds[] Buffers { get; }
-
- /// <summary>
- /// Flag indicating if this binding is unaligned.
- /// </summary>
- public bool[] Unaligned { get; }
-
- /// <summary>
- /// Total amount of buffers used on the shader.
- /// </summary>
- public int Count { get; private set; }
-
- /// <summary>
- /// Creates a new instance of the shader stage buffer information.
- /// </summary>
- /// <param name="count">Maximum amount of buffers that the shader stage can use</param>
- public BuffersPerStage(int count)
- {
- Bindings = new BufferDescriptor[count];
- Buffers = new BufferBounds[count];
- Unaligned = new bool[count];
- }
-
- /// <summary>
- /// Sets the region of a buffer at a given slot.
- /// </summary>
- /// <param name="index">Buffer slot</param>
- /// <param name="address">Region virtual address</param>
- /// <param name="size">Region size in bytes</param>
- /// <param name="flags">Buffer usage flags</param>
- public void SetBounds(int index, ulong address, ulong size, BufferUsageFlags flags = BufferUsageFlags.None)
- {
- Buffers[index] = new BufferBounds(address, size, flags);
- }
-
- /// <summary>
- /// Sets shader buffer binding information.
- /// </summary>
- /// <param name="descriptors">Buffer binding information</param>
- public void SetBindings(BufferDescriptor[] descriptors)
- {
- if (descriptors == null)
- {
- Count = 0;
- return;
- }
-
- if ((Count = descriptors.Length) != 0)
- {
- Bindings = descriptors;
- }
- }
- }
-
- private readonly BuffersPerStage _cpStorageBuffers;
- private readonly BuffersPerStage _cpUniformBuffers;
- private readonly BuffersPerStage[] _gpStorageBuffers;
- private readonly BuffersPerStage[] _gpUniformBuffers;
-
- private bool _gpStorageBuffersDirty;
- private bool _gpUniformBuffersDirty;
-
- private bool _indexBufferDirty;
- private bool _vertexBuffersDirty;
- private uint _vertexBuffersEnableMask;
- private bool _transformFeedbackBuffersDirty;
-
- private bool _rebind;
-
- /// <summary>
- /// Creates a new instance of the buffer manager.
- /// </summary>
- /// <param name="context">GPU context that the buffer manager belongs to</param>
- /// <param name="channel">GPU channel that the buffer manager belongs to</param>
- public BufferManager(GpuContext context, GpuChannel channel)
- {
- _context = context;
- _channel = channel;
-
- _vertexBuffers = new VertexBuffer[Constants.TotalVertexBuffers];
-
- _transformFeedbackBuffers = new BufferBounds[Constants.TotalTransformFeedbackBuffers];
-
- _cpStorageBuffers = new BuffersPerStage(Constants.TotalCpStorageBuffers);
- _cpUniformBuffers = new BuffersPerStage(Constants.TotalCpUniformBuffers);
-
- _gpStorageBuffers = new BuffersPerStage[Constants.ShaderStages];
- _gpUniformBuffers = new BuffersPerStage[Constants.ShaderStages];
-
- for (int index = 0; index < Constants.ShaderStages; index++)
- {
- _gpStorageBuffers[index] = new BuffersPerStage(Constants.TotalGpStorageBuffers);
- _gpUniformBuffers[index] = new BuffersPerStage(Constants.TotalGpUniformBuffers);
- }
-
- _bufferTextures = new List<BufferTextureBinding>();
-
- _ranges = new BufferAssignment[Constants.TotalGpUniformBuffers * Constants.ShaderStages];
- }
-
-
- /// <summary>
- /// Sets the memory range with the index buffer data, to be used for subsequent draw calls.
- /// </summary>
- /// <param name="gpuVa">Start GPU virtual address of the index buffer</param>
- /// <param name="size">Size, in bytes, of the index buffer</param>
- /// <param name="type">Type of each index buffer element</param>
- public void SetIndexBuffer(ulong gpuVa, ulong size, IndexType type)
- {
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
-
- _indexBuffer.Address = address;
- _indexBuffer.Size = size;
- _indexBuffer.Type = type;
-
- _indexBufferDirty = true;
- }
-
- /// <summary>
- /// Sets a new index buffer that overrides the one set on the call to <see cref="CommitGraphicsBindings"/>.
- /// </summary>
- /// <param name="buffer">Buffer to be used as index buffer</param>
- /// <param name="type">Type of each index buffer element</param>
- public void SetIndexBuffer(BufferRange buffer, IndexType type)
- {
- _context.Renderer.Pipeline.SetIndexBuffer(buffer, type);
-
- _indexBufferDirty = true;
- }
-
- /// <summary>
- /// Sets the memory range with vertex buffer data, to be used for subsequent draw calls.
- /// </summary>
- /// <param name="index">Index of the vertex buffer (up to 16)</param>
- /// <param name="gpuVa">GPU virtual address of the buffer</param>
- /// <param name="size">Size in bytes of the buffer</param>
- /// <param name="stride">Stride of the buffer, defined as the number of bytes of each vertex</param>
- /// <param name="divisor">Vertex divisor of the buffer, for instanced draws</param>
- public void SetVertexBuffer(int index, ulong gpuVa, ulong size, int stride, int divisor)
- {
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
-
- _vertexBuffers[index].Address = address;
- _vertexBuffers[index].Size = size;
- _vertexBuffers[index].Stride = stride;
- _vertexBuffers[index].Divisor = divisor;
-
- _vertexBuffersDirty = true;
-
- if (address != 0)
- {
- _vertexBuffersEnableMask |= 1u << index;
- }
- else
- {
- _vertexBuffersEnableMask &= ~(1u << index);
- }
- }
-
- /// <summary>
- /// Sets a transform feedback buffer on the graphics pipeline.
- /// The output from the vertex transformation stages are written into the feedback buffer.
- /// </summary>
- /// <param name="index">Index of the transform feedback buffer</param>
- /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
- /// <param name="size">Size in bytes of the transform feedback buffer</param>
- public void SetTransformFeedbackBuffer(int index, ulong gpuVa, ulong size)
- {
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
-
- _transformFeedbackBuffers[index] = new BufferBounds(address, size);
- _transformFeedbackBuffersDirty = true;
- }
-
- /// <summary>
- /// Records the alignment of a storage buffer.
- /// Unaligned storage buffers disable some optimizations on the shader.
- /// </summary>
- /// <param name="buffers">The binding list to modify</param>
- /// <param name="index">Index of the storage buffer</param>
- /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
- private void RecordStorageAlignment(BuffersPerStage buffers, int index, ulong gpuVa)
- {
- bool unaligned = (gpuVa & (Constants.StorageAlignment - 1)) != 0;
-
- if (unaligned || HasUnalignedStorageBuffers)
- {
- // Check if the alignment changed for this binding.
-
- ref bool currentUnaligned = ref buffers.Unaligned[index];
-
- if (currentUnaligned != unaligned)
- {
- currentUnaligned = unaligned;
- _unalignedStorageBuffers += unaligned ? 1 : -1;
- }
- }
- }
-
- /// <summary>
- /// Sets a storage buffer on the compute pipeline.
- /// Storage buffers can be read and written to on shaders.
- /// </summary>
- /// <param name="index">Index of the storage buffer</param>
- /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
- /// <param name="size">Size in bytes of the storage buffer</param>
- /// <param name="flags">Buffer usage flags</param>
- public void SetComputeStorageBuffer(int index, ulong gpuVa, ulong size, BufferUsageFlags flags)
- {
- size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
-
- RecordStorageAlignment(_cpStorageBuffers, index, gpuVa);
-
- gpuVa = BitUtils.AlignDown<ulong>(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment);
-
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
-
- _cpStorageBuffers.SetBounds(index, address, size, flags);
- }
-
- /// <summary>
- /// Sets a storage buffer on the graphics pipeline.
- /// Storage buffers can be read and written to on shaders.
- /// </summary>
- /// <param name="stage">Index of the shader stage</param>
- /// <param name="index">Index of the storage buffer</param>
- /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
- /// <param name="size">Size in bytes of the storage buffer</param>
- /// <param name="flags">Buffer usage flags</param>
- public void SetGraphicsStorageBuffer(int stage, int index, ulong gpuVa, ulong size, BufferUsageFlags flags)
- {
- size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
-
- BuffersPerStage buffers = _gpStorageBuffers[stage];
-
- RecordStorageAlignment(buffers, index, gpuVa);
-
- gpuVa = BitUtils.AlignDown<ulong>(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment);
-
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
-
- if (buffers.Buffers[index].Address != address ||
- buffers.Buffers[index].Size != size)
- {
- _gpStorageBuffersDirty = true;
- }
-
- buffers.SetBounds(index, address, size, flags);
- }
-
- /// <summary>
- /// Sets a uniform buffer on the compute pipeline.
- /// Uniform buffers are read-only from shaders, and have a small capacity.
- /// </summary>
- /// <param name="index">Index of the uniform buffer</param>
- /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
- /// <param name="size">Size in bytes of the storage buffer</param>
- public void SetComputeUniformBuffer(int index, ulong gpuVa, ulong size)
- {
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
-
- _cpUniformBuffers.SetBounds(index, address, size);
- }
-
- /// <summary>
- /// Sets a uniform buffer on the graphics pipeline.
- /// Uniform buffers are read-only from shaders, and have a small capacity.
- /// </summary>
- /// <param name="stage">Index of the shader stage</param>
- /// <param name="index">Index of the uniform buffer</param>
- /// <param name="gpuVa">Start GPU virtual address of the buffer</param>
- /// <param name="size">Size in bytes of the storage buffer</param>
- public void SetGraphicsUniformBuffer(int stage, int index, ulong gpuVa, ulong size)
- {
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
-
- _gpUniformBuffers[stage].SetBounds(index, address, size);
- _gpUniformBuffersDirty = true;
- }
-
- /// <summary>
- /// Sets the binding points for the storage buffers bound on the compute pipeline.
- /// </summary>
- /// <param name="bindings">Bindings for the active shader</param>
- public void SetComputeBufferBindings(CachedShaderBindings bindings)
- {
- _cpStorageBuffers.SetBindings(bindings.StorageBufferBindings[0]);
- _cpUniformBuffers.SetBindings(bindings.ConstantBufferBindings[0]);
- }
-
- /// <summary>
- /// Sets the binding points for the storage buffers bound on the graphics pipeline.
- /// </summary>
- /// <param name="bindings">Bindings for the active shader</param>
- public void SetGraphicsBufferBindings(CachedShaderBindings bindings)
- {
- for (int i = 0; i < Constants.ShaderStages; i++)
- {
- _gpStorageBuffers[i].SetBindings(bindings.StorageBufferBindings[i]);
- _gpUniformBuffers[i].SetBindings(bindings.ConstantBufferBindings[i]);
- }
-
- _gpStorageBuffersDirty = true;
- _gpUniformBuffersDirty = true;
- }
-
- /// <summary>
- /// Gets a bit mask indicating which compute uniform buffers are currently bound.
- /// </summary>
- /// <returns>Mask where each bit set indicates a bound constant buffer</returns>
- public uint GetComputeUniformBufferUseMask()
- {
- uint mask = 0;
-
- for (int i = 0; i < _cpUniformBuffers.Buffers.Length; i++)
- {
- if (_cpUniformBuffers.Buffers[i].Address != 0)
- {
- mask |= 1u << i;
- }
- }
-
- return mask;
- }
-
- /// <summary>
- /// Gets a bit mask indicating which graphics uniform buffers are currently bound.
- /// </summary>
- /// <param name="stage">Index of the shader stage</param>
- /// <returns>Mask where each bit set indicates a bound constant buffer</returns>
- public uint GetGraphicsUniformBufferUseMask(int stage)
- {
- uint mask = 0;
-
- for (int i = 0; i < _gpUniformBuffers[stage].Buffers.Length; i++)
- {
- if (_gpUniformBuffers[stage].Buffers[i].Address != 0)
- {
- mask |= 1u << i;
- }
- }
-
- return mask;
- }
-
- /// <summary>
- /// Gets the address of the compute uniform buffer currently bound at the given index.
- /// </summary>
- /// <param name="index">Index of the uniform buffer binding</param>
- /// <returns>The uniform buffer address, or an undefined value if the buffer is not currently bound</returns>
- public ulong GetComputeUniformBufferAddress(int index)
- {
- return _cpUniformBuffers.Buffers[index].Address;
- }
-
- /// <summary>
- /// Gets the address of the graphics uniform buffer currently bound at the given index.
- /// </summary>
- /// <param name="stage">Index of the shader stage</param>
- /// <param name="index">Index of the uniform buffer binding</param>
- /// <returns>The uniform buffer address, or an undefined value if the buffer is not currently bound</returns>
- public ulong GetGraphicsUniformBufferAddress(int stage, int index)
- {
- return _gpUniformBuffers[stage].Buffers[index].Address;
- }
-
- /// <summary>
- /// Gets the bounds of the uniform buffer currently bound at the given index.
- /// </summary>
- /// <param name="isCompute">Indicates whenever the uniform is requested by the 3D or compute engine</param>
- /// <param name="stage">Index of the shader stage, if the uniform is for the 3D engine</param>
- /// <param name="index">Index of the uniform buffer binding</param>
- /// <returns>The uniform buffer bounds, or an undefined value if the buffer is not currently bound</returns>
- public ref BufferBounds GetUniformBufferBounds(bool isCompute, int stage, int index)
- {
- if (isCompute)
- {
- return ref _cpUniformBuffers.Buffers[index];
- }
- else
- {
- return ref _gpUniformBuffers[stage].Buffers[index];
- }
- }
-
- /// <summary>
- /// Ensures that the compute engine bindings are visible to the host GPU.
- /// Note: this actually performs the binding using the host graphics API.
- /// </summary>
- public void CommitComputeBindings()
- {
- var bufferCache = _channel.MemoryManager.Physical.BufferCache;
-
- BindBuffers(bufferCache, _cpStorageBuffers, isStorage: true);
- BindBuffers(bufferCache, _cpUniformBuffers, isStorage: false);
-
- CommitBufferTextureBindings();
-
- // Force rebind after doing compute work.
- Rebind();
- }
-
- /// <summary>
- /// Commit any queued buffer texture bindings.
- /// </summary>
- private void CommitBufferTextureBindings()
- {
- if (_bufferTextures.Count > 0)
- {
- foreach (var binding in _bufferTextures)
- {
- var isStore = binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
- var range = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(binding.Address, binding.Size, isStore);
- binding.Texture.SetStorage(range);
-
- // The texture must be rebound to use the new storage if it was updated.
-
- if (binding.IsImage)
- {
- _context.Renderer.Pipeline.SetImage(binding.BindingInfo.Binding, binding.Texture, binding.Format);
- }
- else
- {
- _context.Renderer.Pipeline.SetTextureAndSampler(binding.Stage, binding.BindingInfo.Binding, binding.Texture, null);
- }
- }
-
- _bufferTextures.Clear();
- }
- }
-
- /// <summary>
- /// Ensures that the graphics engine bindings are visible to the host GPU.
- /// Note: this actually performs the binding using the host graphics API.
- /// </summary>
- public void CommitGraphicsBindings()
- {
- var bufferCache = _channel.MemoryManager.Physical.BufferCache;
-
- if (_indexBufferDirty || _rebind)
- {
- _indexBufferDirty = false;
-
- if (_indexBuffer.Address != 0)
- {
- BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);
-
- _context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type);
- }
- }
- else if (_indexBuffer.Address != 0)
- {
- bufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
- }
-
- uint vbEnableMask = _vertexBuffersEnableMask;
-
- if (_vertexBuffersDirty || _rebind)
- {
- _vertexBuffersDirty = false;
-
- Span<VertexBufferDescriptor> vertexBuffers = stackalloc VertexBufferDescriptor[Constants.TotalVertexBuffers];
-
- for (int index = 0; (vbEnableMask >> index) != 0; index++)
- {
- VertexBuffer vb = _vertexBuffers[index];
-
- if (vb.Address == 0)
- {
- continue;
- }
-
- BufferRange buffer = bufferCache.GetBufferRange(vb.Address, vb.Size);
-
- vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor);
- }
-
- _context.Renderer.Pipeline.SetVertexBuffers(vertexBuffers);
- }
- else
- {
- for (int index = 0; (vbEnableMask >> index) != 0; index++)
- {
- VertexBuffer vb = _vertexBuffers[index];
-
- if (vb.Address == 0)
- {
- continue;
- }
-
- bufferCache.SynchronizeBufferRange(vb.Address, vb.Size);
- }
- }
-
- if (_transformFeedbackBuffersDirty || _rebind)
- {
- _transformFeedbackBuffersDirty = false;
-
- Span<BufferRange> tfbs = stackalloc BufferRange[Constants.TotalTransformFeedbackBuffers];
-
- for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
- {
- BufferBounds tfb = _transformFeedbackBuffers[index];
-
- if (tfb.Address == 0)
- {
- tfbs[index] = BufferRange.Empty;
- continue;
- }
-
- tfbs[index] = bufferCache.GetBufferRange(tfb.Address, tfb.Size, write: true);
- }
-
- _context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
- }
- else
- {
- for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
- {
- BufferBounds tfb = _transformFeedbackBuffers[index];
-
- if (tfb.Address == 0)
- {
- continue;
- }
-
- bufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size);
- }
- }
-
- if (_gpStorageBuffersDirty || _rebind)
- {
- _gpStorageBuffersDirty = false;
-
- BindBuffers(bufferCache, _gpStorageBuffers, isStorage: true);
- }
- else
- {
- UpdateBuffers(_gpStorageBuffers);
- }
-
- if (_gpUniformBuffersDirty || _rebind)
- {
- _gpUniformBuffersDirty = false;
-
- BindBuffers(bufferCache, _gpUniformBuffers, isStorage: false);
- }
- else
- {
- UpdateBuffers(_gpUniformBuffers);
- }
-
- CommitBufferTextureBindings();
-
- _rebind = false;
- }
-
- /// <summary>
- /// Bind respective buffer bindings on the host API.
- /// </summary>
- /// <param name="bufferCache">Buffer cache holding the buffers for the specified ranges</param>
- /// <param name="bindings">Buffer memory ranges to bind</param>
- /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage)
- {
- int rangesCount = 0;
-
- Span<BufferAssignment> ranges = _ranges;
-
- for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
- {
- ref var buffers = ref bindings[(int)stage - 1];
-
- for (int index = 0; index < buffers.Count; index++)
- {
- ref var bindingInfo = ref buffers.Bindings[index];
-
- BufferBounds bounds = buffers.Buffers[bindingInfo.Slot];
-
- if (bounds.Address != 0)
- {
- var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
- var range = isStorage
- ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
- : bufferCache.GetBufferRange(bounds.Address, bounds.Size);
-
- ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
- }
- }
- }
-
- if (rangesCount != 0)
- {
- SetHostBuffers(ranges, rangesCount, isStorage);
- }
- }
-
- /// <summary>
- /// Bind respective buffer bindings on the host API.
- /// </summary>
- /// <param name="bufferCache">Buffer cache holding the buffers for the specified ranges</param>
- /// <param name="buffers">Buffer memory ranges to bind</param>
- /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage)
- {
- int rangesCount = 0;
-
- Span<BufferAssignment> ranges = _ranges;
-
- for (int index = 0; index < buffers.Count; index++)
- {
- ref var bindingInfo = ref buffers.Bindings[index];
-
- BufferBounds bounds = buffers.Buffers[bindingInfo.Slot];
-
- if (bounds.Address != 0)
- {
- var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
- var range = isStorage
- ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
- : bufferCache.GetBufferRange(bounds.Address, bounds.Size);
-
- ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
- }
- }
-
- if (rangesCount != 0)
- {
- SetHostBuffers(ranges, rangesCount, isStorage);
- }
- }
-
- /// <summary>
- /// Bind respective buffer bindings on the host API.
- /// </summary>
- /// <param name="ranges">Host buffers to bind, with their offsets and sizes</param>
- /// <param name="first">First binding point</param>
- /// <param name="count">Number of bindings</param>
- /// <param name="isStorage">Indicates if the buffers are storage or uniform buffers</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void SetHostBuffers(ReadOnlySpan<BufferAssignment> ranges, int count, bool isStorage)
- {
- if (isStorage)
- {
- _context.Renderer.Pipeline.SetStorageBuffers(ranges.Slice(0, count));
- }
- else
- {
- _context.Renderer.Pipeline.SetUniformBuffers(ranges.Slice(0, count));
- }
- }
-
- /// <summary>
- /// Updates data for the already bound buffer bindings.
- /// </summary>
- /// <param name="bindings">Bindings to update</param>
- private void UpdateBuffers(BuffersPerStage[] bindings)
- {
- for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
- {
- ref var buffers = ref bindings[(int)stage - 1];
-
- for (int index = 0; index < buffers.Count; index++)
- {
- ref var binding = ref buffers.Bindings[index];
-
- BufferBounds bounds = buffers.Buffers[binding.Slot];
-
- if (bounds.Address == 0)
- {
- continue;
- }
-
- _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(bounds.Address, bounds.Size);
- }
- }
- }
-
- /// <summary>
- /// Sets the buffer storage of a buffer texture. This will be bound when the buffer manager commits bindings.
- /// </summary>
- /// <param name="stage">Shader stage accessing the texture</param>
- /// <param name="texture">Buffer texture</param>
- /// <param name="address">Address of the buffer in memory</param>
- /// <param name="size">Size of the buffer in bytes</param>
- /// <param name="bindingInfo">Binding info for the buffer texture</param>
- /// <param name="format">Format of the buffer texture</param>
- /// <param name="isImage">Whether the binding is for an image or a sampler</param>
- public void SetBufferTextureStorage(
- ShaderStage stage,
- ITexture texture,
- ulong address,
- ulong size,
- TextureBindingInfo bindingInfo,
- Format format,
- bool isImage)
- {
- _channel.MemoryManager.Physical.BufferCache.CreateBuffer(address, size);
-
- _bufferTextures.Add(new BufferTextureBinding(stage, texture, address, size, bindingInfo, format, isImage));
- }
-
- /// <summary>
- /// Force all bound textures and images to be rebound the next time CommitBindings is called.
- /// </summary>
- public void Rebind()
- {
- _rebind = true;
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferMigration.cs b/Ryujinx.Graphics.Gpu/Memory/BufferMigration.cs
deleted file mode 100644
index e020c0c3..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/BufferMigration.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-using System;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// A record of when buffer data was copied from one buffer to another, along with the SyncNumber when the migration will be complete.
- /// Keeps the source buffer alive for data flushes until the migration is complete.
- /// </summary>
- internal class BufferMigration : IDisposable
- {
- /// <summary>
- /// The offset for the migrated region.
- /// </summary>
- private readonly ulong _offset;
-
- /// <summary>
- /// The size for the migrated region.
- /// </summary>
- private readonly ulong _size;
-
- /// <summary>
- /// The buffer that was migrated from.
- /// </summary>
- private readonly Buffer _buffer;
-
- /// <summary>
- /// The source range action, to be called on overlap with an unreached sync number.
- /// </summary>
- private readonly Action<ulong, ulong> _sourceRangeAction;
-
- /// <summary>
- /// The source range list.
- /// </summary>
- private readonly BufferModifiedRangeList _source;
-
- /// <summary>
- /// The destination range list. This range list must be updated when flushing the source.
- /// </summary>
- public readonly BufferModifiedRangeList Destination;
-
- /// <summary>
- /// The sync number that needs to be reached for this migration to be removed. This is set to the pending sync number on creation.
- /// </summary>
- public readonly ulong SyncNumber;
-
- /// <summary>
- /// Creates a record for a buffer migration.
- /// </summary>
- /// <param name="buffer">The source buffer for this migration</param>
- /// <param name="sourceRangeAction">The flush action for the source buffer</param>
- /// <param name="source">The modified range list for the source buffer</param>
- /// <param name="dest">The modified range list for the destination buffer</param>
- /// <param name="syncNumber">The sync number for when the migration is complete</param>
- public BufferMigration(
- Buffer buffer,
- Action<ulong, ulong> sourceRangeAction,
- BufferModifiedRangeList source,
- BufferModifiedRangeList dest,
- ulong syncNumber)
- {
- _offset = buffer.Address;
- _size = buffer.Size;
- _buffer = buffer;
- _sourceRangeAction = sourceRangeAction;
- _source = source;
- Destination = dest;
- SyncNumber = syncNumber;
- }
-
- /// <summary>
- /// Determine if the given range overlaps this migration, and has not been completed yet.
- /// </summary>
- /// <param name="offset">Start offset</param>
- /// <param name="size">Range size</param>
- /// <param name="syncNumber">The sync number that was waited on</param>
- /// <returns>True if overlapping and in progress, false otherwise</returns>
- public bool Overlaps(ulong offset, ulong size, ulong syncNumber)
- {
- ulong end = offset + size;
- ulong destEnd = _offset + _size;
- long syncDiff = (long)(syncNumber - SyncNumber); // syncNumber is less if the copy has not completed.
-
- return !(end <= _offset || offset >= destEnd) && syncDiff < 0;
- }
-
- /// <summary>
- /// Determine if the given range matches this migration.
- /// </summary>
- /// <param name="offset">Start offset</param>
- /// <param name="size">Range size</param>
- /// <returns>True if the range exactly matches, false otherwise</returns>
- public bool FullyMatches(ulong offset, ulong size)
- {
- return _offset == offset && _size == size;
- }
-
- /// <summary>
- /// Perform the migration source's range action on the range provided, clamped to the bounds of the source buffer.
- /// </summary>
- /// <param name="offset">Start offset</param>
- /// <param name="size">Range size</param>
- /// <param name="syncNumber">Current sync number</param>
- /// <param name="parent">The modified range list that originally owned this range</param>
- public void RangeActionWithMigration(ulong offset, ulong size, ulong syncNumber, BufferModifiedRangeList parent)
- {
- ulong end = offset + size;
- end = Math.Min(_offset + _size, end);
- offset = Math.Max(_offset, offset);
-
- size = end - offset;
-
- _source.RangeActionWithMigration(offset, size, syncNumber, parent, _sourceRangeAction);
- }
-
- /// <summary>
- /// Removes this reference to the range list, potentially allowing for the source buffer to be disposed.
- /// </summary>
- public void Dispose()
- {
- Destination.RemoveMigration(this);
-
- _buffer.DecrementReferenceCount();
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs b/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs
deleted file mode 100644
index d0230b62..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/BufferModifiedRangeList.cs
+++ /dev/null
@@ -1,514 +0,0 @@
-using Ryujinx.Common.Logging;
-using Ryujinx.Common.Pools;
-using Ryujinx.Memory.Range;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// A range within a buffer that has been modified by the GPU.
- /// </summary>
- class BufferModifiedRange : IRange
- {
- /// <summary>
- /// Start address of the range in guest memory.
- /// </summary>
- public ulong Address { get; }
-
- /// <summary>
- /// Size of the range in bytes.
- /// </summary>
- public ulong Size { get; }
-
- /// <summary>
- /// End address of the range in guest memory.
- /// </summary>
- public ulong EndAddress => Address + Size;
-
- /// <summary>
- /// The GPU sync number at the time of the last modification.
- /// </summary>
- public ulong SyncNumber { get; internal set; }
-
- /// <summary>
- /// The range list that originally owned this range.
- /// </summary>
- public BufferModifiedRangeList Parent { get; internal set; }
-
- /// <summary>
- /// Creates a new instance of a modified range.
- /// </summary>
- /// <param name="address">Start address of the range</param>
- /// <param name="size">Size of the range in bytes</param>
- /// <param name="syncNumber">The GPU sync number at the time of creation</param>
- /// <param name="parent">The range list that owns this range</param>
- public BufferModifiedRange(ulong address, ulong size, ulong syncNumber, BufferModifiedRangeList parent)
- {
- Address = address;
- Size = size;
- SyncNumber = syncNumber;
- Parent = parent;
- }
-
- /// <summary>
- /// 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>
- /// <returns>True if the range overlaps, false otherwise</returns>
- public bool OverlapsWith(ulong address, ulong size)
- {
- return Address < address + size && address < EndAddress;
- }
- }
-
- /// <summary>
- /// A structure used to track GPU modified ranges within a buffer.
- /// </summary>
- class BufferModifiedRangeList : RangeList<BufferModifiedRange>
- {
- private const int BackingInitialSize = 8;
-
- private GpuContext _context;
- private Buffer _parent;
- private Action<ulong, ulong> _flushAction;
-
- private List<BufferMigration> _sources;
- private BufferMigration _migrationTarget;
-
- private object _lock = new object();
-
- /// <summary>
- /// Whether the modified range list has any entries or not.
- /// </summary>
- public bool HasRanges
- {
- get
- {
- lock (_lock)
- {
- return Count > 0;
- }
- }
- }
-
- /// <summary>
- /// Creates a new instance of a modified range list.
- /// </summary>
- /// <param name="context">GPU context that the buffer range list belongs to</param>
- /// <param name="parent">The parent buffer that owns this range list</param>
- /// <param name="flushAction">The flush action for the parent buffer</param>
- public BufferModifiedRangeList(GpuContext context, Buffer parent, Action<ulong, ulong> flushAction) : base(BackingInitialSize)
- {
- _context = context;
- _parent = parent;
- _flushAction = flushAction;
- }
-
- /// <summary>
- /// Given an input range, calls the given action with sub-ranges which exclude any of the modified regions.
- /// </summary>
- /// <param name="address">Start address of the query range</param>
- /// <param name="size">Size of the query range in bytes</param>
- /// <param name="action">Action to perform for each remaining sub-range of the input range</param>
- public void ExcludeModifiedRegions(ulong address, ulong size, Action<ulong, ulong> action)
- {
- lock (_lock)
- {
- // Slices a given region using the modified regions in the list. Calls the action for the new slices.
- ref var overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
-
- int count = FindOverlapsNonOverlapping(address, size, ref overlaps);
-
- for (int i = 0; i < count; i++)
- {
- BufferModifiedRange overlap = overlaps[i];
-
- if (overlap.Address > address)
- {
- // The start of the remaining region is uncovered by this overlap. Call the action for it.
- action(address, overlap.Address - address);
- }
-
- // Remaining region is after this overlap.
- size -= overlap.EndAddress - address;
- address = overlap.EndAddress;
- }
-
- if ((long)size > 0)
- {
- // If there is any region left after removing the overlaps, signal it.
- action(address, size);
- }
- }
- }
-
- /// <summary>
- /// Signal that a region of the buffer has been modified, and add the new region to the range list.
- /// Any overlapping ranges will be (partially) removed.
- /// </summary>
- /// <param name="address">Start address of the modified region</param>
- /// <param name="size">Size of the modified region in bytes</param>
- public void SignalModified(ulong address, ulong size)
- {
- // Must lock, as this can affect flushes from the background thread.
- lock (_lock)
- {
- // We may overlap with some existing modified regions. They must be cut into by the new entry.
- ref var overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
-
- int count = FindOverlapsNonOverlapping(address, size, ref overlaps);
-
- ulong endAddress = address + size;
- ulong syncNumber = _context.SyncNumber;
-
- for (int i = 0; i < count; i++)
- {
- // The overlaps must be removed or split.
-
- BufferModifiedRange overlap = overlaps[i];
-
- if (overlap.Address == address && overlap.Size == size)
- {
- // Region already exists. Just update the existing sync number.
- overlap.SyncNumber = syncNumber;
- overlap.Parent = this;
-
- return;
- }
-
- Remove(overlap);
-
- if (overlap.Address < address && overlap.EndAddress > address)
- {
- // A split item must be created behind this overlap.
-
- Add(new BufferModifiedRange(overlap.Address, address - overlap.Address, overlap.SyncNumber, overlap.Parent));
- }
-
- if (overlap.Address < endAddress && overlap.EndAddress > endAddress)
- {
- // A split item must be created after this overlap.
-
- Add(new BufferModifiedRange(endAddress, overlap.EndAddress - endAddress, overlap.SyncNumber, overlap.Parent));
- }
- }
-
- Add(new BufferModifiedRange(address, size, syncNumber, this));
- }
- }
-
- /// <summary>
- /// Gets modified ranges within the specified region, and then fires the given action for each range individually.
- /// </summary>
- /// <param name="address">Start address to query</param>
- /// <param name="size">Size to query</param>
- /// <param name="rangeAction">The action to call for each modified range</param>
- public void GetRanges(ulong address, ulong size, Action<ulong, ulong> rangeAction)
- {
- int count = 0;
-
- ref var overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
-
- // Range list must be consistent for this operation.
- lock (_lock)
- {
- count = FindOverlapsNonOverlapping(address, size, ref overlaps);
- }
-
- for (int i = 0; i < count; i++)
- {
- BufferModifiedRange overlap = overlaps[i];
- rangeAction(overlap.Address, overlap.Size);
- }
- }
-
- /// <summary>
- /// Queries if a range exists within the specified region.
- /// </summary>
- /// <param name="address">Start address to query</param>
- /// <param name="size">Size to query</param>
- /// <returns>True if a range exists in the specified region, false otherwise</returns>
- public bool HasRange(ulong address, ulong size)
- {
- // Range list must be consistent for this operation.
- lock (_lock)
- {
- return FindOverlapsNonOverlapping(address, size, ref ThreadStaticArray<BufferModifiedRange>.Get()) > 0;
- }
- }
-
- /// <summary>
- /// Performs the given range action, or one from a migration that overlaps and has not synced yet.
- /// </summary>
- /// <param name="offset">The offset to pass to the action</param>
- /// <param name="size">The size to pass to the action</param>
- /// <param name="syncNumber">The sync number that has been reached</param>
- /// <param name="parent">The modified range list that originally owned this range</param>
- /// <param name="rangeAction">The action to perform</param>
- public void RangeActionWithMigration(ulong offset, ulong size, ulong syncNumber, BufferModifiedRangeList parent, Action<ulong, ulong> rangeAction)
- {
- bool firstSource = true;
-
- if (parent != this)
- {
- lock (_lock)
- {
- if (_sources != null)
- {
- foreach (BufferMigration source in _sources)
- {
- if (source.Overlaps(offset, size, syncNumber))
- {
- if (firstSource && !source.FullyMatches(offset, size))
- {
- // Perform this buffer's action first. The migrations will run after.
- rangeAction(offset, size);
- }
-
- source.RangeActionWithMigration(offset, size, syncNumber, parent);
-
- firstSource = false;
- }
- }
- }
- }
- }
-
- if (firstSource)
- {
- // No overlapping migrations, or they are not meant for this range, flush the data using the given action.
- rangeAction(offset, size);
- }
- }
-
- /// <summary>
- /// Removes modified ranges ready by the sync number from the list, and flushes their buffer data within a given address range.
- /// </summary>
- /// <param name="overlaps">Overlapping ranges to check</param>
- /// <param name="rangeCount">Number of overlapping ranges</param>
- /// <param name="highestDiff">The highest difference between an overlapping range's sync number and the current one</param>
- /// <param name="currentSync">The current sync number</param>
- /// <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(
- BufferModifiedRange[] overlaps,
- int rangeCount,
- long highestDiff,
- ulong currentSync,
- ulong address,
- ulong endAddress)
- {
- lock (_lock)
- {
- if (_migrationTarget == null)
- {
- ulong waitSync = currentSync + (ulong)highestDiff;
-
- for (int i = 0; i < rangeCount; i++)
- {
- BufferModifiedRange overlap = overlaps[i];
-
- long diff = (long)(overlap.SyncNumber - currentSync);
-
- if (diff <= highestDiff)
- {
- ulong clampAddress = Math.Max(address, overlap.Address);
- ulong clampEnd = Math.Min(endAddress, overlap.EndAddress);
-
- ClearPart(overlap, clampAddress, clampEnd);
-
- RangeActionWithMigration(clampAddress, clampEnd - clampAddress, waitSync, overlap.Parent, _flushAction);
- }
- }
-
- return;
- }
- }
-
- // There is a migration target to call instead. This can't be changed after set so accessing it outside the lock is fine.
-
- _migrationTarget.Destination.RemoveRangesAndFlush(overlaps, rangeCount, highestDiff, currentSync, address, endAddress);
- }
-
- /// <summary>
- /// Gets modified ranges within the specified region, waits on ones from a previous sync number,
- /// and then fires the flush action for each range individually.
- /// </summary>
- /// <remarks>
- /// This function assumes it is called from the background thread.
- /// Modifications from the current sync number are ignored because the guest should not expect them to be available yet.
- /// They will remain reserved, so that any data sync prioritizes the data in the GPU.
- /// </remarks>
- /// <param name="address">Start address to query</param>
- /// <param name="size">Size to query</param>
- public void WaitForAndFlushRanges(ulong address, ulong size)
- {
- ulong endAddress = address + size;
- ulong currentSync = _context.SyncNumber;
-
- int rangeCount = 0;
-
- ref var overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
-
- // Range list must be consistent for this operation
- lock (_lock)
- {
- if (_migrationTarget != null)
- {
- rangeCount = -1;
- }
- else
- {
- rangeCount = FindOverlapsNonOverlapping(address, size, ref overlaps);
- }
- }
-
- if (rangeCount == -1)
- {
- _migrationTarget.Destination.WaitForAndFlushRanges(address, size);
-
- return;
- }
- else if (rangeCount == 0)
- {
- return;
- }
-
- // First, determine which syncpoint to wait on.
- // This is the latest syncpoint that is not equal to the current sync.
-
- long highestDiff = long.MinValue;
-
- for (int i = 0; i < rangeCount; i++)
- {
- BufferModifiedRange overlap = overlaps[i];
-
- long diff = (long)(overlap.SyncNumber - currentSync);
-
- if (diff < 0 && diff > highestDiff)
- {
- highestDiff = diff;
- }
- }
-
- if (highestDiff == long.MinValue)
- {
- return;
- }
-
- // Wait for the syncpoint.
- _context.Renderer.WaitSync(currentSync + (ulong)highestDiff);
-
- RemoveRangesAndFlush(overlaps, rangeCount, highestDiff, currentSync, address, endAddress);
- }
-
- /// <summary>
- /// Inherit ranges from another modified range list.
- /// </summary>
- /// <param name="ranges">The range list to inherit from</param>
- /// <param name="registerRangeAction">The action to call for each modified range</param>
- public void InheritRanges(BufferModifiedRangeList ranges, Action<ulong, ulong> registerRangeAction)
- {
- BufferModifiedRange[] inheritRanges;
-
- lock (ranges._lock)
- {
- BufferMigration migration = new(ranges._parent, ranges._flushAction, ranges, this, _context.SyncNumber);
-
- ranges._parent.IncrementReferenceCount();
- ranges._migrationTarget = migration;
-
- _context.RegisterBufferMigration(migration);
-
- inheritRanges = ranges.ToArray();
-
- lock (_lock)
- {
- (_sources ??= new List<BufferMigration>()).Add(migration);
-
- foreach (BufferModifiedRange range in inheritRanges)
- {
- Add(range);
- }
- }
- }
-
- ulong currentSync = _context.SyncNumber;
- foreach (BufferModifiedRange range in inheritRanges)
- {
- if (range.SyncNumber != currentSync)
- {
- registerRangeAction(range.Address, range.Size);
- }
- }
- }
-
- /// <summary>
- /// Removes a source buffer migration, indicating its copy has completed.
- /// </summary>
- /// <param name="migration">The migration to remove</param>
- public void RemoveMigration(BufferMigration migration)
- {
- lock (_lock)
- {
- _sources.Remove(migration);
- }
- }
-
- 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));
- }
- }
-
- /// <summary>
- /// Clear modified ranges within the specified area.
- /// </summary>
- /// <param name="address">Start address to clear</param>
- /// <param name="size">Size to clear</param>
- public void Clear(ulong address, ulong size)
- {
- lock (_lock)
- {
- // This function can be called from any thread, so it cannot use the arrays for background or foreground.
- BufferModifiedRange[] toClear = new BufferModifiedRange[1];
-
- int rangeCount = FindOverlapsNonOverlapping(address, size, ref toClear);
-
- ulong endAddress = address + size;
-
- for (int i = 0; i < rangeCount; i++)
- {
- BufferModifiedRange overlap = toClear[i];
-
- ClearPart(overlap, address, endAddress);
- }
- }
- }
-
- /// <summary>
- /// Clear all modified ranges.
- /// </summary>
- public void Clear()
- {
- lock (_lock)
- {
- Count = 0;
- }
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs b/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs
deleted file mode 100644
index b7a0e726..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Gpu.Image;
-using Ryujinx.Graphics.Shader;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// A buffer binding to apply to a buffer texture.
- /// </summary>
- readonly struct BufferTextureBinding
- {
- /// <summary>
- /// Shader stage accessing the texture.
- /// </summary>
- public ShaderStage Stage { get; }
-
- /// <summary>
- /// The buffer texture.
- /// </summary>
- public ITexture Texture { get; }
-
- /// <summary>
- /// The base address of the buffer binding.
- /// </summary>
- public ulong Address { get; }
-
- /// <summary>
- /// The size of the buffer binding in bytes.
- /// </summary>
- public ulong Size { get; }
-
- /// <summary>
- /// The image or sampler binding info for the buffer texture.
- /// </summary>
- public TextureBindingInfo BindingInfo { get; }
-
- /// <summary>
- /// The image format for the binding.
- /// </summary>
- public Format Format { get; }
-
- /// <summary>
- /// Whether the binding is for an image or a sampler.
- /// </summary>
- public bool IsImage { get; }
-
- /// <summary>
- /// Create a new buffer texture binding.
- /// </summary>
- /// <param name="stage">Shader stage accessing the texture</param>
- /// <param name="texture">Buffer texture</param>
- /// <param name="address">Base address</param>
- /// <param name="size">Size in bytes</param>
- /// <param name="bindingInfo">Binding info</param>
- /// <param name="format">Binding format</param>
- /// <param name="isImage">Whether the binding is for an image or a sampler</param>
- public BufferTextureBinding(
- ShaderStage stage,
- ITexture texture,
- ulong address,
- ulong size,
- TextureBindingInfo bindingInfo,
- Format format,
- bool isImage)
- {
- Stage = stage;
- Texture = texture;
- Address = address;
- Size = size;
- BindingInfo = bindingInfo;
- Format = format;
- IsImage = isImage;
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs b/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs
deleted file mode 100644
index e763a899..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/CounterCache.cs
+++ /dev/null
@@ -1,191 +0,0 @@
-using Ryujinx.Graphics.GAL;
-using System.Collections.Generic;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// Represents the GPU counter cache.
- /// </summary>
- class CounterCache
- {
- private readonly struct CounterEntry
- {
- public ulong Address { get; }
- public ICounterEvent Event { get; }
-
- public CounterEntry(ulong address, ICounterEvent evt)
- {
- Address = address;
- Event = evt;
- }
- }
-
- private readonly List<CounterEntry> _items;
-
- /// <summary>
- /// Creates a new instance of the GPU counter cache.
- /// </summary>
- public CounterCache()
- {
- _items = new List<CounterEntry>();
- }
-
- /// <summary>
- /// Adds a new counter to the counter cache, or updates a existing one.
- /// </summary>
- /// <param name="gpuVa">GPU virtual address where the counter will be written in memory</param>
- public void AddOrUpdate(ulong gpuVa, ICounterEvent evt)
- {
- int index = BinarySearch(gpuVa);
-
- CounterEntry entry = new CounterEntry(gpuVa, evt);
-
- if (index < 0)
- {
- _items.Insert(~index, entry);
- }
- else
- {
- _items[index] = entry;
- }
- }
-
- /// <summary>
- /// Handles removal of counters 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) => RemoveRange(e.Address, e.Size);
-
- private void RemoveRange(ulong gpuVa, ulong size)
- {
- int index = BinarySearch(gpuVa + size - 1);
-
- if (index < 0)
- {
- index = ~index;
- }
-
- if (index >= _items.Count || !InRange(gpuVa, size, _items[index].Address))
- {
- return;
- }
-
- int count = 1;
-
- while (index > 0 && InRange(gpuVa, size, _items[index - 1].Address))
- {
- index--;
- count++;
- }
-
- // Notify the removed counter events that their result should no longer be written out.
- for (int i = 0; i < count; i++)
- {
- ICounterEvent evt = _items[index + i].Event;
- if (evt != null)
- {
- evt.Invalid = true;
- }
- }
-
- _items.RemoveRange(index, count);
- }
-
- /// <summary>
- /// Checks whenever an address falls inside a given range.
- /// </summary>
- /// <param name="startVa">Range start address</param>
- /// <param name="size">Range size</param>
- /// <param name="gpuVa">Address being checked</param>
- /// <returns>True if the address falls inside the range, false otherwise</returns>
- private static bool InRange(ulong startVa, ulong size, ulong gpuVa)
- {
- return gpuVa >= startVa && gpuVa < startVa + size;
- }
-
- /// <summary>
- /// Check if any counter value was written to the specified GPU virtual memory address.
- /// </summary>
- /// <param name="gpuVa">GPU virtual address</param>
- /// <returns>True if any counter value was written on the specified address, false otherwise</returns>
- public bool Contains(ulong gpuVa)
- {
- return BinarySearch(gpuVa) >= 0;
- }
-
- /// <summary>
- /// Flush any counter value written to the specified GPU virtual memory address.
- /// </summary>
- /// <param name="gpuVa">GPU virtual address</param>
- /// <returns>True if any counter value was written on the specified address, false otherwise</returns>
- public bool FindAndFlush(ulong gpuVa)
- {
- int index = BinarySearch(gpuVa);
- if (index > 0)
- {
- _items[index].Event?.Flush();
-
- return true;
- }
- else
- {
- return false;
- }
- }
-
- /// <summary>
- /// Find any counter event that would write to the specified GPU virtual memory address.
- /// </summary>
- /// <param name="gpuVa">GPU virtual address</param>
- /// <returns>The counter event, or null if not present</returns>
- public ICounterEvent FindEvent(ulong gpuVa)
- {
- int index = BinarySearch(gpuVa);
- if (index > 0)
- {
- return _items[index].Event;
- }
- else
- {
- return null;
- }
- }
-
- /// <summary>
- /// Performs binary search of an address on the list.
- /// </summary>
- /// <param name="address">Address to search</param>
- /// <returns>Index of the item, or complement of the index of the nearest item with lower value</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);
-
- CounterEntry item = _items[middle];
-
- if (item.Address == address)
- {
- return middle;
- }
-
- if (address < item.Address)
- {
- right = middle - 1;
- }
- else
- {
- left = middle + 1;
- }
- }
-
- return ~left;
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/Memory/GpuRegionHandle.cs b/Ryujinx.Graphics.Gpu/Memory/GpuRegionHandle.cs
deleted file mode 100644
index bc07bfad..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/GpuRegionHandle.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-using Ryujinx.Cpu.Tracking;
-using Ryujinx.Memory.Tracking;
-using System;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// A tracking handle for a region of GPU VA, represented by one or more tracking handles in CPU VA.
- /// </summary>
- class GpuRegionHandle : IRegionHandle
- {
- private readonly CpuRegionHandle[] _cpuRegionHandles;
-
- public bool Dirty
- {
- get
- {
- foreach (var regionHandle in _cpuRegionHandles)
- {
- if (regionHandle.Dirty)
- {
- return true;
- }
- }
-
- return false;
- }
- }
-
- public ulong Address => throw new NotSupportedException();
- public ulong Size => throw new NotSupportedException();
- public ulong EndAddress => throw new NotSupportedException();
-
- /// <summary>
- /// Create a new GpuRegionHandle, made up of mulitple CpuRegionHandles.
- /// </summary>
- /// <param name="cpuRegionHandles">The CpuRegionHandles that make up this handle</param>
- public GpuRegionHandle(CpuRegionHandle[] cpuRegionHandles)
- {
- _cpuRegionHandles = cpuRegionHandles;
- }
-
- /// <summary>
- /// Dispose the child handles.
- /// </summary>
- public void Dispose()
- {
- foreach (var regionHandle in _cpuRegionHandles)
- {
- regionHandle.Dispose();
- }
- }
-
- /// <summary>
- /// Register an action to perform when the tracked region is read or written.
- /// The action is automatically removed after it runs.
- /// </summary>
- /// <param name="action">Action to call on read or write</param>
- public void RegisterAction(RegionSignal action)
- {
- foreach (var regionHandle in _cpuRegionHandles)
- {
- regionHandle.RegisterAction(action);
- }
- }
-
- /// <summary>
- /// Register an action to perform when a precise access occurs (one with exact address and size).
- /// If the action returns true, read/write tracking are skipped.
- /// </summary>
- /// <param name="action">Action to call on read or write</param>
- public void RegisterPreciseAction(PreciseRegionSignal action)
- {
- foreach (var regionHandle in _cpuRegionHandles)
- {
- regionHandle.RegisterPreciseAction(action);
- }
- }
-
- /// <summary>
- /// Consume the dirty flag for the handles, and reprotect so it can be set on the next write.
- /// </summary>
- public void Reprotect(bool asDirty = false)
- {
- foreach (var regionHandle in _cpuRegionHandles)
- {
- regionHandle.Reprotect(asDirty);
- }
- }
-
- /// <summary>
- /// Force the handles to be dirty, without reprotecting.
- /// </summary>
- public void ForceDirty()
- {
- foreach (var regionHandle in _cpuRegionHandles)
- {
- regionHandle.ForceDirty();
- }
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/Memory/IndexBuffer.cs b/Ryujinx.Graphics.Gpu/Memory/IndexBuffer.cs
deleted file mode 100644
index 7765e899..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/IndexBuffer.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Ryujinx.Graphics.GAL;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// GPU Index Buffer information.
- /// </summary>
- struct IndexBuffer
- {
- public ulong Address;
- public ulong Size;
-
- public IndexType Type;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
deleted file mode 100644
index b0f7e799..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
+++ /dev/null
@@ -1,713 +0,0 @@
-using Ryujinx.Memory;
-using Ryujinx.Memory.Range;
-using System;
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// GPU memory manager.
- /// </summary>
- public class MemoryManager : IWritableBlock
- {
- private const int PtLvl0Bits = 14;
- private const int PtLvl1Bits = 14;
- public const int PtPageBits = 12;
-
- private const ulong PtLvl0Size = 1UL << PtLvl0Bits;
- private const ulong PtLvl1Size = 1UL << PtLvl1Bits;
- public const ulong PageSize = 1UL << PtPageBits;
-
- private const ulong PtLvl0Mask = PtLvl0Size - 1;
- private const ulong PtLvl1Mask = PtLvl1Size - 1;
- public const ulong PageMask = PageSize - 1;
-
- private const int PtLvl0Bit = PtPageBits + PtLvl1Bits;
- private const int PtLvl1Bit = PtPageBits;
- private const int AddressSpaceBits = PtPageBits + PtLvl1Bits + PtLvl0Bits;
-
- public const ulong PteUnmapped = ulong.MaxValue;
-
- private readonly ulong[][] _pageTable;
-
- public event EventHandler<UnmapEventArgs> MemoryUnmapped;
-
- /// <summary>
- /// Physical memory where the virtual memory is mapped into.
- /// </summary>
- internal PhysicalMemory Physical { get; }
-
- /// <summary>
- /// Cache of GPU counters.
- /// </summary>
- internal CounterCache CounterCache { get; }
-
- /// <summary>
- /// Creates a new instance of the GPU memory manager.
- /// </summary>
- /// <param name="physicalMemory">Physical memory that this memory manager will map into</param>
- internal MemoryManager(PhysicalMemory physicalMemory)
- {
- Physical = physicalMemory;
- CounterCache = new CounterCache();
- _pageTable = new ulong[PtLvl0Size][];
- MemoryUnmapped += Physical.TextureCache.MemoryUnmappedHandler;
- MemoryUnmapped += Physical.BufferCache.MemoryUnmappedHandler;
- MemoryUnmapped += CounterCache.MemoryUnmappedHandler;
- }
-
- /// <summary>
- /// Reads data from GPU mapped memory.
- /// </summary>
- /// <typeparam name="T">Type of the data</typeparam>
- /// <param name="va">GPU virtual address where the data is located</param>
- /// <param name="tracked">True if read tracking is triggered on the memory region</param>
- /// <returns>The data at the specified memory location</returns>
- public T Read<T>(ulong va, bool tracked = false) where T : unmanaged
- {
- int size = Unsafe.SizeOf<T>();
-
- if (IsContiguous(va, size))
- {
- ulong address = Translate(va);
-
- if (tracked)
- {
- return Physical.ReadTracked<T>(address);
- }
- else
- {
- return Physical.Read<T>(address);
- }
- }
- else
- {
- Span<byte> data = new byte[size];
-
- ReadImpl(va, data, tracked);
-
- return MemoryMarshal.Cast<byte, T>(data)[0];
- }
- }
-
- /// <summary>
- /// Gets a read-only span of data from GPU mapped memory.
- /// </summary>
- /// <param name="va">GPU virtual address where the data is located</param>
- /// <param name="size">Size of the data</param>
- /// <param name="tracked">True if read tracking is triggered on the span</param>
- /// <returns>The span of the data at the specified memory location</returns>
- public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
- {
- if (IsContiguous(va, size))
- {
- return Physical.GetSpan(Translate(va), size, tracked);
- }
- else
- {
- Span<byte> data = new byte[size];
-
- ReadImpl(va, data, tracked);
-
- return data;
- }
- }
-
- /// <summary>
- /// Gets a read-only span of data from GPU mapped memory, up to the entire range specified,
- /// or the last mapped page if the range is not fully mapped.
- /// </summary>
- /// <param name="va">GPU virtual address where the data is located</param>
- /// <param name="size">Size of the data</param>
- /// <param name="tracked">True if read tracking is triggered on the span</param>
- /// <returns>The span of the data at the specified memory location</returns>
- public ReadOnlySpan<byte> GetSpanMapped(ulong va, int size, bool tracked = false)
- {
- bool isContiguous = true;
- int mappedSize;
-
- if (ValidateAddress(va) && GetPte(va) != PteUnmapped && Physical.IsMapped(Translate(va)))
- {
- ulong endVa = va + (ulong)size;
- ulong endVaAligned = (endVa + PageMask) & ~PageMask;
- ulong currentVa = va & ~PageMask;
-
- int pages = (int)((endVaAligned - currentVa) / PageSize);
-
- for (int page = 0; page < pages - 1; page++)
- {
- ulong nextVa = currentVa + PageSize;
- ulong nextPa = Translate(nextVa);
-
- if (!ValidateAddress(nextVa) || GetPte(nextVa) == PteUnmapped || !Physical.IsMapped(nextPa))
- {
- break;
- }
-
- if (Translate(currentVa) + PageSize != nextPa)
- {
- isContiguous = false;
- }
-
- currentVa += PageSize;
- }
-
- currentVa += PageSize;
-
- if (currentVa > endVa)
- {
- currentVa = endVa;
- }
-
- mappedSize = (int)(currentVa - va);
- }
- else
- {
- return ReadOnlySpan<byte>.Empty;
- }
-
- if (isContiguous)
- {
- return Physical.GetSpan(Translate(va), mappedSize, tracked);
- }
- else
- {
- Span<byte> data = new byte[mappedSize];
-
- ReadImpl(va, data, tracked);
-
- return data;
- }
- }
-
- /// <summary>
- /// Reads data from a possibly non-contiguous region of GPU mapped memory.
- /// </summary>
- /// <param name="va">GPU virtual address of the data</param>
- /// <param name="data">Span to write the read data into</param>
- /// <param name="tracked">True to enable write tracking on read, false otherwise</param>
- private void ReadImpl(ulong va, Span<byte> data, bool tracked)
- {
- if (data.Length == 0)
- {
- return;
- }
-
- int offset = 0, size;
-
- if ((va & PageMask) != 0)
- {
- ulong pa = Translate(va);
-
- size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask));
-
- Physical.GetSpan(pa, size, tracked).CopyTo(data.Slice(0, size));
-
- offset += size;
- }
-
- for (; offset < data.Length; offset += size)
- {
- ulong pa = Translate(va + (ulong)offset);
-
- size = Math.Min(data.Length - offset, (int)PageSize);
-
- Physical.GetSpan(pa, size, tracked).CopyTo(data.Slice(offset, size));
- }
- }
-
- /// <summary>
- /// Gets a writable region from GPU mapped memory.
- /// </summary>
- /// <param name="va">Start address of the range</param>
- /// <param name="size">Size in bytes to be range</param>
- /// <param name="tracked">True if write tracking is triggered on the span</param>
- /// <returns>A writable region with the data at the specified memory location</returns>
- public WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false)
- {
- if (IsContiguous(va, size))
- {
- return Physical.GetWritableRegion(Translate(va), size, tracked);
- }
- else
- {
- Memory<byte> memory = new byte[size];
-
- GetSpan(va, size).CopyTo(memory.Span);
-
- return new WritableRegion(this, va, memory, tracked);
- }
- }
-
- /// <summary>
- /// Writes data to GPU mapped memory.
- /// </summary>
- /// <typeparam name="T">Type of the data</typeparam>
- /// <param name="va">GPU virtual address to write the value into</param>
- /// <param name="value">The value to be written</param>
- public void Write<T>(ulong va, T value) where T : unmanaged
- {
- Write(va, MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateSpan(ref value, 1)));
- }
-
- /// <summary>
- /// Writes data to GPU mapped memory.
- /// </summary>
- /// <param name="va">GPU virtual address to write the data into</param>
- /// <param name="data">The data to be written</param>
- public void Write(ulong va, ReadOnlySpan<byte> data)
- {
- WriteImpl(va, data, Physical.Write);
- }
-
- /// <summary>
- /// Writes data to GPU mapped memory, destined for a tracked resource.
- /// </summary>
- /// <param name="va">GPU virtual address to write the data into</param>
- /// <param name="data">The data to be written</param>
- public void WriteTrackedResource(ulong va, ReadOnlySpan<byte> data)
- {
- WriteImpl(va, data, Physical.WriteTrackedResource);
- }
-
- /// <summary>
- /// Writes data to GPU mapped memory without write tracking.
- /// </summary>
- /// <param name="va">GPU virtual address to write the data into</param>
- /// <param name="data">The data to be written</param>
- public void WriteUntracked(ulong va, ReadOnlySpan<byte> data)
- {
- WriteImpl(va, data, Physical.WriteUntracked);
- }
-
- private delegate void WriteCallback(ulong address, ReadOnlySpan<byte> data);
-
- /// <summary>
- /// Writes data to possibly non-contiguous GPU mapped memory.
- /// </summary>
- /// <param name="va">GPU virtual address of the region to write into</param>
- /// <param name="data">Data to be written</param>
- /// <param name="writeCallback">Write callback</param>
- private void WriteImpl(ulong va, ReadOnlySpan<byte> data, WriteCallback writeCallback)
- {
- if (IsContiguous(va, data.Length))
- {
- writeCallback(Translate(va), data);
- }
- else
- {
- int offset = 0, size;
-
- if ((va & PageMask) != 0)
- {
- ulong pa = Translate(va);
-
- size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask));
-
- writeCallback(pa, data.Slice(0, size));
-
- offset += size;
- }
-
- for (; offset < data.Length; offset += size)
- {
- ulong pa = Translate(va + (ulong)offset);
-
- size = Math.Min(data.Length - offset, (int)PageSize);
-
- writeCallback(pa, data.Slice(offset, size));
- }
- }
- }
-
- /// <summary>
- /// Writes data to GPU mapped memory, stopping at the first unmapped page at the memory region, if any.
- /// </summary>
- /// <param name="va">GPU virtual address to write the data into</param>
- /// <param name="data">The data to be written</param>
- public void WriteMapped(ulong va, ReadOnlySpan<byte> data)
- {
- if (IsContiguous(va, data.Length))
- {
- Physical.Write(Translate(va), data);
- }
- else
- {
- int offset = 0, size;
-
- if ((va & PageMask) != 0)
- {
- ulong pa = Translate(va);
-
- size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask));
-
- if (pa != PteUnmapped && Physical.IsMapped(pa))
- {
- Physical.Write(pa, data.Slice(0, size));
- }
-
- offset += size;
- }
-
- for (; offset < data.Length; offset += size)
- {
- ulong pa = Translate(va + (ulong)offset);
-
- size = Math.Min(data.Length - offset, (int)PageSize);
-
- if (pa != PteUnmapped && Physical.IsMapped(pa))
- {
- Physical.Write(pa, data.Slice(offset, size));
- }
- }
- }
- }
-
- /// <summary>
- /// Maps a given range of pages to the specified CPU virtual address.
- /// </summary>
- /// <remarks>
- /// All addresses and sizes must be page aligned.
- /// </remarks>
- /// <param name="pa">CPU virtual address to map into</param>
- /// <param name="va">GPU virtual address to be mapped</param>
- /// <param name="size">Size in bytes of the mapping</param>
- /// <param name="kind">Kind of the resource located at the mapping</param>
- public void Map(ulong pa, ulong va, ulong size, PteKind kind)
- {
- lock (_pageTable)
- {
- MemoryUnmapped?.Invoke(this, new UnmapEventArgs(va, size));
-
- for (ulong offset = 0; offset < size; offset += PageSize)
- {
- SetPte(va + offset, PackPte(pa + offset, kind));
- }
- }
- }
-
- /// <summary>
- /// Unmaps a given range of pages at the specified GPU virtual memory region.
- /// </summary>
- /// <param name="va">GPU virtual address to unmap</param>
- /// <param name="size">Size in bytes of the region being unmapped</param>
- public void Unmap(ulong va, ulong size)
- {
- lock (_pageTable)
- {
- // Event handlers are not expected to be thread safe.
- MemoryUnmapped?.Invoke(this, new UnmapEventArgs(va, size));
-
- for (ulong offset = 0; offset < size; offset += PageSize)
- {
- SetPte(va + offset, PteUnmapped);
- }
- }
- }
-
- /// <summary>
- /// Checks if a region of GPU mapped memory is contiguous.
- /// </summary>
- /// <param name="va">GPU virtual address of the region</param>
- /// <param name="size">Size of the region</param>
- /// <returns>True if the region is contiguous, false otherwise</returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private bool IsContiguous(ulong va, int size)
- {
- if (!ValidateAddress(va) || GetPte(va) == PteUnmapped)
- {
- return false;
- }
-
- ulong endVa = (va + (ulong)size + PageMask) & ~PageMask;
-
- va &= ~PageMask;
-
- int pages = (int)((endVa - va) / PageSize);
-
- for (int page = 0; page < pages - 1; page++)
- {
- if (!ValidateAddress(va + PageSize) || GetPte(va + PageSize) == PteUnmapped)
- {
- return false;
- }
-
- if (Translate(va) + PageSize != Translate(va + PageSize))
- {
- return false;
- }
-
- va += PageSize;
- }
-
- return true;
- }
-
- /// <summary>
- /// Gets the physical regions that make up the given virtual address region.
- /// </summary>
- /// <param name="va">Virtual address of the range</param>
- /// <param name="size">Size of the range</param>
- /// <returns>Multi-range with the physical regions</returns>
- public MultiRange GetPhysicalRegions(ulong va, ulong size)
- {
- if (IsContiguous(va, (int)size))
- {
- return new MultiRange(Translate(va), size);
- }
-
- ulong regionStart = Translate(va);
- ulong regionSize = Math.Min(size, PageSize - (va & PageMask));
-
- ulong endVa = va + size;
- ulong endVaRounded = (endVa + PageMask) & ~PageMask;
-
- va &= ~PageMask;
-
- int pages = (int)((endVaRounded - va) / PageSize);
-
- var regions = new List<MemoryRange>();
-
- for (int page = 0; page < pages - 1; page++)
- {
- ulong currPa = Translate(va);
- ulong newPa = Translate(va + PageSize);
-
- if ((currPa != PteUnmapped || newPa != PteUnmapped) && currPa + PageSize != newPa)
- {
- regions.Add(new MemoryRange(regionStart, regionSize));
- regionStart = newPa;
- regionSize = 0;
- }
-
- va += PageSize;
- regionSize += Math.Min(endVa - va, PageSize);
- }
-
- regions.Add(new MemoryRange(regionStart, regionSize));
-
- return new MultiRange(regions.ToArray());
- }
-
- /// <summary>
- /// Checks if a given GPU virtual memory range is mapped to the same physical regions
- /// as the specified physical memory multi-range.
- /// </summary>
- /// <param name="range">Physical memory multi-range</param>
- /// <param name="va">GPU virtual memory address</param>
- /// <returns>True if the virtual memory region is mapped into the specified physical one, false otherwise</returns>
- public bool CompareRange(MultiRange range, ulong va)
- {
- va &= ~PageMask;
-
- for (int i = 0; i < range.Count; i++)
- {
- MemoryRange currentRange = range.GetSubRange(i);
-
- if (currentRange.Address != PteUnmapped)
- {
- ulong address = currentRange.Address & ~PageMask;
- ulong endAddress = (currentRange.EndAddress + PageMask) & ~PageMask;
-
- while (address < endAddress)
- {
- if (Translate(va) != address)
- {
- return false;
- }
-
- va += PageSize;
- address += PageSize;
- }
- }
- else
- {
- ulong endVa = va + (((currentRange.Size) + PageMask) & ~PageMask);
-
- while (va < endVa)
- {
- if (Translate(va) != PteUnmapped)
- {
- return false;
- }
-
- va += PageSize;
- }
- }
- }
-
- return true;
- }
-
- /// <summary>
- /// Validates a GPU virtual address.
- /// </summary>
- /// <param name="va">Address to validate</param>
- /// <returns>True if the address is valid, false otherwise</returns>
- private static bool ValidateAddress(ulong va)
- {
- return va < (1UL << AddressSpaceBits);
- }
-
- /// <summary>
- /// Checks if a given page is mapped.
- /// </summary>
- /// <param name="va">GPU virtual address of the page to check</param>
- /// <returns>True if the page is mapped, false otherwise</returns>
- public bool IsMapped(ulong va)
- {
- return Translate(va) != PteUnmapped;
- }
-
- /// <summary>
- /// Translates a GPU virtual address to a CPU virtual address.
- /// </summary>
- /// <param name="va">GPU virtual address to be translated</param>
- /// <returns>CPU virtual address, or <see cref="PteUnmapped"/> if unmapped</returns>
- public ulong Translate(ulong va)
- {
- if (!ValidateAddress(va))
- {
- return PteUnmapped;
- }
-
- ulong pte = GetPte(va);
-
- if (pte == PteUnmapped)
- {
- return PteUnmapped;
- }
-
- return UnpackPaFromPte(pte) + (va & PageMask);
- }
-
- /// <summary>
- /// Translates a GPU virtual address to a CPU virtual address on the first mapped page of memory
- /// on the specified region.
- /// If no page is mapped on the specified region, <see cref="PteUnmapped"/> is returned.
- /// </summary>
- /// <param name="va">GPU virtual address to be translated</param>
- /// <param name="size">Size of the range to be translated</param>
- /// <returns>CPU virtual address, or <see cref="PteUnmapped"/> if unmapped</returns>
- public ulong TranslateFirstMapped(ulong va, ulong size)
- {
- if (!ValidateAddress(va))
- {
- return PteUnmapped;
- }
-
- ulong endVa = va + size;
-
- ulong pte = GetPte(va);
-
- for (; va < endVa && pte == PteUnmapped; va += PageSize - (va & PageMask))
- {
- pte = GetPte(va);
- }
-
- if (pte == PteUnmapped)
- {
- return PteUnmapped;
- }
-
- return UnpackPaFromPte(pte) + (va & PageMask);
- }
-
- /// <summary>
- /// Gets the kind of a given memory page.
- /// This might indicate the type of resource that can be allocated on the page, and also texture tiling.
- /// </summary>
- /// <param name="va">GPU virtual address</param>
- /// <returns>Kind of the memory page</returns>
- public PteKind GetKind(ulong va)
- {
- if (!ValidateAddress(va))
- {
- return PteKind.Invalid;
- }
-
- ulong pte = GetPte(va);
-
- if (pte == PteUnmapped)
- {
- return PteKind.Invalid;
- }
-
- return UnpackKindFromPte(pte);
- }
-
- /// <summary>
- /// Gets the Page Table entry for a given GPU virtual address.
- /// </summary>
- /// <param name="va">GPU virtual address</param>
- /// <returns>Page table entry (CPU virtual address)</returns>
- private ulong GetPte(ulong va)
- {
- ulong l0 = (va >> PtLvl0Bit) & PtLvl0Mask;
- ulong l1 = (va >> PtLvl1Bit) & PtLvl1Mask;
-
- if (_pageTable[l0] == null)
- {
- return PteUnmapped;
- }
-
- return _pageTable[l0][l1];
- }
-
- /// <summary>
- /// Sets a Page Table entry at a given GPU virtual address.
- /// </summary>
- /// <param name="va">GPU virtual address</param>
- /// <param name="pte">Page table entry (CPU virtual address)</param>
- private void SetPte(ulong va, ulong pte)
- {
- ulong l0 = (va >> PtLvl0Bit) & PtLvl0Mask;
- ulong l1 = (va >> PtLvl1Bit) & PtLvl1Mask;
-
- if (_pageTable[l0] == null)
- {
- _pageTable[l0] = new ulong[PtLvl1Size];
-
- for (ulong index = 0; index < PtLvl1Size; index++)
- {
- _pageTable[l0][index] = PteUnmapped;
- }
- }
-
- _pageTable[l0][l1] = pte;
- }
-
- /// <summary>
- /// Creates a page table entry from a physical address and kind.
- /// </summary>
- /// <param name="pa">Physical address</param>
- /// <param name="kind">Kind</param>
- /// <returns>Page table entry</returns>
- private static ulong PackPte(ulong pa, PteKind kind)
- {
- return pa | ((ulong)kind << 56);
- }
-
- /// <summary>
- /// Unpacks kind from a page table entry.
- /// </summary>
- /// <param name="pte">Page table entry</param>
- /// <returns>Kind</returns>
- private static PteKind UnpackKindFromPte(ulong pte)
- {
- return (PteKind)(pte >> 56);
- }
-
- /// <summary>
- /// Unpacks physical address from a page table entry.
- /// </summary>
- /// <param name="pte">Page table entry</param>
- /// <returns>Physical address</returns>
- private static ulong UnpackPaFromPte(ulong pte)
- {
- return pte & 0xffffffffffffffUL;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Memory/MultiRangeWritableBlock.cs b/Ryujinx.Graphics.Gpu/Memory/MultiRangeWritableBlock.cs
deleted file mode 100644
index 155dda7b..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/MultiRangeWritableBlock.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using Ryujinx.Memory;
-using Ryujinx.Memory.Range;
-using System;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// A writable block that targets a given MultiRange within a PhysicalMemory instance.
- /// </summary>
- internal class MultiRangeWritableBlock : IWritableBlock
- {
- private readonly MultiRange _range;
- private readonly PhysicalMemory _physicalMemory;
-
- /// <summary>
- /// Creates a new MultiRangeWritableBlock.
- /// </summary>
- /// <param name="range">The MultiRange to write to</param>
- /// <param name="physicalMemory">The PhysicalMemory the given MultiRange addresses</param>
- public MultiRangeWritableBlock(MultiRange range, PhysicalMemory physicalMemory)
- {
- _range = range;
- _physicalMemory = physicalMemory;
- }
-
- /// <summary>
- /// Write data to the MultiRange.
- /// </summary>
- /// <param name="va">Offset address</param>
- /// <param name="data">Data to write</param>
- /// <exception cref="ArgumentException">Throw when a non-zero offset is given</exception>
- public void Write(ulong va, ReadOnlySpan<byte> data)
- {
- if (va != 0)
- {
- throw new ArgumentException($"{nameof(va)} cannot be non-zero for {nameof(MultiRangeWritableBlock)}.");
- }
-
- _physicalMemory.Write(_range, data);
- }
-
- /// <summary>
- /// Write data to the MultiRange, without tracking.
- /// </summary>
- /// <param name="va">Offset address</param>
- /// <param name="data">Data to write</param>
- /// <exception cref="ArgumentException">Throw when a non-zero offset is given</exception>
- public void WriteUntracked(ulong va, ReadOnlySpan<byte> data)
- {
- if (va != 0)
- {
- throw new ArgumentException($"{nameof(va)} cannot be non-zero for {nameof(MultiRangeWritableBlock)}.");
- }
-
- _physicalMemory.WriteUntracked(_range, data);
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
deleted file mode 100644
index bd33383e..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
+++ /dev/null
@@ -1,413 +0,0 @@
-using Ryujinx.Cpu;
-using Ryujinx.Cpu.Tracking;
-using Ryujinx.Graphics.Gpu.Image;
-using Ryujinx.Graphics.Gpu.Shader;
-using Ryujinx.Memory;
-using Ryujinx.Memory.Range;
-using Ryujinx.Memory.Tracking;
-using System;
-using System.Collections.Generic;
-using System.Runtime.InteropServices;
-using System.Threading;
-
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// Represents physical memory, accessible from the GPU.
- /// This is actually working CPU virtual addresses, of memory mapped on the application process.
- /// </summary>
- class PhysicalMemory : IDisposable
- {
- private readonly GpuContext _context;
- private IVirtualMemoryManagerTracked _cpuMemory;
- private int _referenceCount;
-
- /// <summary>
- /// Indicates whenever the memory manager supports 4KB pages.
- /// </summary>
- public bool Supports4KBPages => _cpuMemory.Supports4KBPages;
-
- /// <summary>
- /// In-memory shader cache.
- /// </summary>
- public ShaderCache ShaderCache { get; }
-
- /// <summary>
- /// GPU buffer manager.
- /// </summary>
- public BufferCache BufferCache { get; }
-
- /// <summary>
- /// GPU texture manager.
- /// </summary>
- public TextureCache TextureCache { get; }
-
- /// <summary>
- /// Creates a new instance of the physical memory.
- /// </summary>
- /// <param name="context">GPU context that the physical memory belongs to</param>
- /// <param name="cpuMemory">CPU memory manager of the application process</param>
- public PhysicalMemory(GpuContext context, IVirtualMemoryManagerTracked cpuMemory)
- {
- _context = context;
- _cpuMemory = cpuMemory;
- ShaderCache = new ShaderCache(context);
- BufferCache = new BufferCache(context, this);
- TextureCache = new TextureCache(context, this);
-
- if (cpuMemory is IRefCounted rc)
- {
- rc.IncrementReferenceCount();
- }
-
- _referenceCount = 1;
- }
-
- /// <summary>
- /// Increments the memory reference count.
- /// </summary>
- public void IncrementReferenceCount()
- {
- Interlocked.Increment(ref _referenceCount);
- }
-
- /// <summary>
- /// Decrements the memory reference count.
- /// </summary>
- public void DecrementReferenceCount()
- {
- if (Interlocked.Decrement(ref _referenceCount) == 0 && _cpuMemory is IRefCounted rc)
- {
- rc.DecrementReferenceCount();
- }
- }
-
- /// <summary>
- /// Gets a span of data from the application process.
- /// </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, bool tracked = false)
- {
- return _cpuMemory.GetSpan(address, size, tracked);
- }
-
- /// <summary>
- /// Gets a span of data from the application process.
- /// </summary>
- /// <param name="range">Ranges of physical memory where the data is located</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(MultiRange range, bool tracked = false)
- {
- if (range.Count == 1)
- {
- var singleRange = range.GetSubRange(0);
- if (singleRange.Address != MemoryManager.PteUnmapped)
- {
- return _cpuMemory.GetSpan(singleRange.Address, (int)singleRange.Size, tracked);
- }
- }
-
- Span<byte> data = new byte[range.GetSize()];
-
- int offset = 0;
-
- for (int i = 0; i < range.Count; i++)
- {
- var currentRange = range.GetSubRange(i);
- int size = (int)currentRange.Size;
- if (currentRange.Address != MemoryManager.PteUnmapped)
- {
- _cpuMemory.GetSpan(currentRange.Address, size, tracked).CopyTo(data.Slice(offset, size));
- }
- offset += size;
- }
-
- return data;
- }
-
- /// <summary>
- /// Gets a writable region from the application process.
- /// </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 write tracking is triggered on the span</param>
- /// <returns>A writable region with the data at the specified memory location</returns>
- public WritableRegion GetWritableRegion(ulong address, int size, bool tracked = false)
- {
- return _cpuMemory.GetWritableRegion(address, size, tracked);
- }
-
- /// <summary>
- /// Gets a writable region from GPU mapped memory.
- /// </summary>
- /// <param name="range">Range</param>
- /// <param name="tracked">True if write tracking is triggered on the span</param>
- /// <returns>A writable region with the data at the specified memory location</returns>
- public WritableRegion GetWritableRegion(MultiRange range, bool tracked = false)
- {
- if (range.Count == 1)
- {
- MemoryRange subrange = range.GetSubRange(0);
-
- return GetWritableRegion(subrange.Address, (int)subrange.Size, tracked);
- }
- else
- {
- Memory<byte> memory = new byte[range.GetSize()];
-
- int offset = 0;
- for (int i = 0; i < range.Count; i++)
- {
- var currentRange = range.GetSubRange(i);
- int size = (int)currentRange.Size;
- if (currentRange.Address != MemoryManager.PteUnmapped)
- {
- GetSpan(currentRange.Address, size).CopyTo(memory.Span.Slice(offset, size));
- }
- offset += size;
- }
-
- return new WritableRegion(new MultiRangeWritableBlock(range, this), 0, memory, tracked);
- }
- }
-
- /// <summary>
- /// Reads data from the application process.
- /// </summary>
- /// <typeparam name="T">Type of the structure</typeparam>
- /// <param name="address">Address to read from</param>
- /// <returns>The data at the specified memory location</returns>
- public T Read<T>(ulong address) where T : unmanaged
- {
- return _cpuMemory.Read<T>(address);
- }
-
- /// <summary>
- /// Reads data from the application process, with write tracking.
- /// </summary>
- /// <typeparam name="T">Type of the structure</typeparam>
- /// <param name="address">Address to read from</param>
- /// <returns>The data at the specified memory location</returns>
- public T ReadTracked<T>(ulong address) where T : unmanaged
- {
- return _cpuMemory.ReadTracked<T>(address);
- }
-
- /// <summary>
- /// Writes data to the application process, triggering a precise memory tracking event.
- /// </summary>
- /// <param name="address">Address to write into</param>
- /// <param name="data">Data to be written</param>
- public void WriteTrackedResource(ulong address, ReadOnlySpan<byte> data)
- {
- _cpuMemory.SignalMemoryTracking(address, (ulong)data.Length, true, precise: true);
- _cpuMemory.WriteUntracked(address, data);
- }
-
- /// <summary>
- /// Writes data to the application process.
- /// </summary>
- /// <param name="address">Address to write into</param>
- /// <param name="data">Data to be written</param>
- public void Write(ulong address, ReadOnlySpan<byte> data)
- {
- _cpuMemory.Write(address, data);
- }
-
- /// <summary>
- /// Writes data to the application process.
- /// </summary>
- /// <param name="range">Ranges of physical memory where the data is located</param>
- /// <param name="data">Data to be written</param>
- public void Write(MultiRange range, ReadOnlySpan<byte> data)
- {
- WriteImpl(range, data, _cpuMemory.Write);
- }
-
- /// <summary>
- /// Writes data to the application process, without any tracking.
- /// </summary>
- /// <param name="address">Address to write into</param>
- /// <param name="data">Data to be written</param>
- public void WriteUntracked(ulong address, ReadOnlySpan<byte> data)
- {
- _cpuMemory.WriteUntracked(address, data);
- }
-
- /// <summary>
- /// Writes data to the application process, without any tracking.
- /// </summary>
- /// <param name="range">Ranges of physical memory where the data is located</param>
- /// <param name="data">Data to be written</param>
- public void WriteUntracked(MultiRange range, ReadOnlySpan<byte> data)
- {
- WriteImpl(range, data, _cpuMemory.WriteUntracked);
- }
-
- /// <summary>
- /// Writes data to the application process, returning false if the data was not changed.
- /// This triggers read memory tracking, as a redundancy check would be useless if the data is not up to date.
- /// </summary>
- /// <remarks>The memory manager can return that memory has changed when it hasn't to avoid expensive data copies.</remarks>
- /// <param name="address">Address to write into</param>
- /// <param name="data">Data to be written</param>
- /// <returns>True if the data was changed, false otherwise</returns>
- public bool WriteWithRedundancyCheck(ulong address, ReadOnlySpan<byte> data)
- {
- return _cpuMemory.WriteWithRedundancyCheck(address, data);
- }
-
- private delegate void WriteCallback(ulong address, ReadOnlySpan<byte> data);
-
- /// <summary>
- /// Writes data to the application process, using the supplied callback method.
- /// </summary>
- /// <param name="range">Ranges of physical memory where the data is located</param>
- /// <param name="data">Data to be written</param>
- /// <param name="writeCallback">Callback method that will perform the write</param>
- private static void WriteImpl(MultiRange range, ReadOnlySpan<byte> data, WriteCallback writeCallback)
- {
- if (range.Count == 1)
- {
- var singleRange = range.GetSubRange(0);
- if (singleRange.Address != MemoryManager.PteUnmapped)
- {
- writeCallback(singleRange.Address, data);
- }
- }
- else
- {
- int offset = 0;
-
- for (int i = 0; i < range.Count; i++)
- {
- var currentRange = range.GetSubRange(i);
- int size = (int)currentRange.Size;
- if (currentRange.Address != MemoryManager.PteUnmapped)
- {
- writeCallback(currentRange.Address, data.Slice(offset, size));
- }
- offset += size;
- }
- }
- }
-
- /// <summary>
- /// Fills the specified memory region with a 32-bit integer value.
- /// </summary>
- /// <param name="address">CPU virtual address of the region</param>
- /// <param name="size">Size of the region</param>
- /// <param name="value">Value to fill the region with</param>
- /// <param name="kind">Kind of the resource being filled, which will not be signalled as CPU modified</param>
- public void FillTrackedResource(ulong address, ulong size, uint value, ResourceKind kind)
- {
- _cpuMemory.SignalMemoryTracking(address, size, write: true, precise: true, (int)kind);
-
- using WritableRegion region = _cpuMemory.GetWritableRegion(address, (int)size);
-
- MemoryMarshal.Cast<byte, uint>(region.Memory.Span).Fill(value);
- }
-
- /// <summary>
- /// 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="kind">Kind of the resource being tracked</param>
- /// <returns>The memory tracking handle</returns>
- public CpuRegionHandle BeginTracking(ulong address, ulong size, ResourceKind kind)
- {
- return _cpuMemory.BeginTracking(address, size, (int)kind);
- }
-
- /// <summary>
- /// Obtains a memory tracking handle for the given virtual region. This should be disposed when finished with.
- /// </summary>
- /// <param name="range">Ranges of physical memory where the data is located</param>
- /// <param name="kind">Kind of the resource being tracked</param>
- /// <returns>The memory tracking handle</returns>
- public GpuRegionHandle BeginTracking(MultiRange range, ResourceKind kind)
- {
- var cpuRegionHandles = new CpuRegionHandle[range.Count];
- int count = 0;
-
- for (int i = 0; i < range.Count; i++)
- {
- var currentRange = range.GetSubRange(i);
- if (currentRange.Address != MemoryManager.PteUnmapped)
- {
- cpuRegionHandles[count++] = _cpuMemory.BeginTracking(currentRange.Address, currentRange.Size, (int)kind);
- }
- }
-
- if (count != range.Count)
- {
- Array.Resize(ref cpuRegionHandles, count);
- }
-
- return new GpuRegionHandle(cpuRegionHandles);
- }
-
- /// <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="kind">Kind of the resource being tracked</param>
- /// <param name="handles">Handles to inherit state from or reuse</param>
- /// <param name="granularity">Desired granularity of write tracking</param>
- /// <returns>The memory tracking handle</returns>
- public CpuMultiRegionHandle BeginGranularTracking(ulong address, ulong size, ResourceKind kind, IEnumerable<IRegionHandle> handles = null, ulong granularity = 4096)
- {
- return _cpuMemory.BeginGranularTracking(address, size, handles, granularity, (int)kind);
- }
-
- /// <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="kind">Kind of the resource being tracked</param>
- /// <param name="granularity">Desired granularity of write tracking</param>
- /// <returns>The memory tracking handle</returns>
- public CpuSmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ResourceKind kind, ulong granularity = 4096)
- {
- return _cpuMemory.BeginSmartGranularTracking(address, size, granularity, (int)kind);
- }
-
- /// <summary>
- /// Checks if a given memory page is mapped.
- /// </summary>
- /// <param name="address">CPU virtual address of the page</param>
- /// <returns>True if mapped, false otherwise</returns>
- public bool IsMapped(ulong address)
- {
- return _cpuMemory.IsMapped(address);
- }
-
- /// <summary>
- /// Release our reference to the CPU memory manager.
- /// </summary>
- public void Dispose()
- {
- _context.DeferredActions.Enqueue(Destroy);
- }
-
- /// <summary>
- /// Performs disposal of the host GPU caches with resources mapped on this physical memory.
- /// This must only be called from the render thread.
- /// </summary>
- private void Destroy()
- {
- ShaderCache.Dispose();
- BufferCache.Dispose();
- TextureCache.Dispose();
-
- DecrementReferenceCount();
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Memory/PteKind.cs b/Ryujinx.Graphics.Gpu/Memory/PteKind.cs
deleted file mode 100644
index 4ceb6bcf..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/PteKind.cs
+++ /dev/null
@@ -1,268 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// Kind of the resource at the given memory mapping.
- /// </summary>
- public enum PteKind : byte
- {
- Invalid = 0xff,
- Pitch = 0x00,
- Z16 = 0x01,
- Z162C = 0x02,
- Z16MS22C = 0x03,
- Z16MS42C = 0x04,
- Z16MS82C = 0x05,
- Z16MS162C = 0x06,
- Z162Z = 0x07,
- Z16MS22Z = 0x08,
- Z16MS42Z = 0x09,
- Z16MS82Z = 0x0a,
- Z16MS162Z = 0x0b,
- Z162CZ = 0x36,
- Z16MS22CZ = 0x37,
- Z16MS42CZ = 0x38,
- Z16MS82CZ = 0x39,
- Z16MS162CZ = 0x5f,
- Z164CZ = 0x0c,
- Z16MS24CZ = 0x0d,
- Z16MS44CZ = 0x0e,
- Z16MS84CZ = 0x0f,
- Z16MS164CZ = 0x10,
- S8Z24 = 0x11,
- S8Z241Z = 0x12,
- S8Z24MS21Z = 0x13,
- S8Z24MS41Z = 0x14,
- S8Z24MS81Z = 0x15,
- S8Z24MS161Z = 0x16,
- S8Z242CZ = 0x17,
- S8Z24MS22CZ = 0x18,
- S8Z24MS42CZ = 0x19,
- S8Z24MS82CZ = 0x1a,
- S8Z24MS162CZ = 0x1b,
- S8Z242CS = 0x1c,
- S8Z24MS22CS = 0x1d,
- S8Z24MS42CS = 0x1e,
- S8Z24MS82CS = 0x1f,
- S8Z24MS162CS = 0x20,
- S8Z244CSZV = 0x21,
- S8Z24MS24CSZV = 0x22,
- S8Z24MS44CSZV = 0x23,
- S8Z24MS84CSZV = 0x24,
- S8Z24MS164CSZV = 0x25,
- V8Z24MS4VC12 = 0x26,
- V8Z24MS4VC4 = 0x27,
- V8Z24MS8VC8 = 0x28,
- V8Z24MS8VC24 = 0x29,
- V8Z24MS4VC121ZV = 0x2e,
- V8Z24MS4VC41ZV = 0x2f,
- V8Z24MS8VC81ZV = 0x30,
- V8Z24MS8VC241ZV = 0x31,
- V8Z24MS4VC122CS = 0x32,
- V8Z24MS4VC42CS = 0x33,
- V8Z24MS8VC82CS = 0x34,
- V8Z24MS8VC242CS = 0x35,
- V8Z24MS4VC122CZV = 0x3a,
- V8Z24MS4VC42CZV = 0x3b,
- V8Z24MS8VC82CZV = 0x3c,
- V8Z24MS8VC242CZV = 0x3d,
- V8Z24MS4VC122ZV = 0x3e,
- V8Z24MS4VC42ZV = 0x3f,
- V8Z24MS8VC82ZV = 0x40,
- V8Z24MS8VC242ZV = 0x41,
- V8Z24MS4VC124CSZV = 0x42,
- V8Z24MS4VC44CSZV = 0x43,
- V8Z24MS8VC84CSZV = 0x44,
- V8Z24MS8VC244CSZV = 0x45,
- Z24S8 = 0x46,
- Z24S81Z = 0x47,
- Z24S8MS21Z = 0x48,
- Z24S8MS41Z = 0x49,
- Z24S8MS81Z = 0x4a,
- Z24S8MS161Z = 0x4b,
- Z24S82CS = 0x4c,
- Z24S8MS22CS = 0x4d,
- Z24S8MS42CS = 0x4e,
- Z24S8MS82CS = 0x4f,
- Z24S8MS162CS = 0x50,
- Z24S82CZ = 0x51,
- Z24S8MS22CZ = 0x52,
- Z24S8MS42CZ = 0x53,
- Z24S8MS82CZ = 0x54,
- Z24S8MS162CZ = 0x55,
- Z24S84CSZV = 0x56,
- Z24S8MS24CSZV = 0x57,
- Z24S8MS44CSZV = 0x58,
- Z24S8MS84CSZV = 0x59,
- Z24S8MS164CSZV = 0x5a,
- Z24V8MS4VC12 = 0x5b,
- Z24V8MS4VC4 = 0x5c,
- Z24V8MS8VC8 = 0x5d,
- Z24V8MS8VC24 = 0x5e,
- YUVB8C12Y = 0x60,
- YUVB8C22Y = 0x61,
- YUVB10C12Y = 0x62,
- YUVB10C22Y = 0x6b,
- YUVB12C12Y = 0x6c,
- YUVB12C22Y = 0x6d,
- Z24V8MS4VC121ZV = 0x63,
- Z24V8MS4VC41ZV = 0x64,
- Z24V8MS8VC81ZV = 0x65,
- Z24V8MS8VC241ZV = 0x66,
- Z24V8MS4VC122CS = 0x67,
- Z24V8MS4VC42CS = 0x68,
- Z24V8MS8VC82CS = 0x69,
- Z24V8MS8VC242CS = 0x6a,
- Z24V8MS4VC122CZV = 0x6f,
- Z24V8MS4VC42CZV = 0x70,
- Z24V8MS8VC82CZV = 0x71,
- Z24V8MS8VC242CZV = 0x72,
- Z24V8MS4VC122ZV = 0x73,
- Z24V8MS4VC42ZV = 0x74,
- Z24V8MS8VC82ZV = 0x75,
- Z24V8MS8VC242ZV = 0x76,
- Z24V8MS4VC124CSZV = 0x77,
- Z24V8MS4VC44CSZV = 0x78,
- Z24V8MS8VC84CSZV = 0x79,
- Z24V8MS8VC244CSZV = 0x7a,
- ZF32 = 0x7b,
- ZF321Z = 0x7c,
- ZF32MS21Z = 0x7d,
- ZF32MS41Z = 0x7e,
- ZF32MS81Z = 0x7f,
- ZF32MS161Z = 0x80,
- ZF322CS = 0x81,
- ZF32MS22CS = 0x82,
- ZF32MS42CS = 0x83,
- ZF32MS82CS = 0x84,
- ZF32MS162CS = 0x85,
- ZF322CZ = 0x86,
- ZF32MS22CZ = 0x87,
- ZF32MS42CZ = 0x88,
- ZF32MS82CZ = 0x89,
- ZF32MS162CZ = 0x8a,
- X8Z24X16V8S8MS4VC12 = 0x8b,
- X8Z24X16V8S8MS4VC4 = 0x8c,
- X8Z24X16V8S8MS8VC8 = 0x8d,
- X8Z24X16V8S8MS8VC24 = 0x8e,
- X8Z24X16V8S8MS4VC121CS = 0x8f,
- X8Z24X16V8S8MS4VC41CS = 0x90,
- X8Z24X16V8S8MS8VC81CS = 0x91,
- X8Z24X16V8S8MS8VC241CS = 0x92,
- X8Z24X16V8S8MS4VC121ZV = 0x97,
- X8Z24X16V8S8MS4VC41ZV = 0x98,
- X8Z24X16V8S8MS8VC81ZV = 0x99,
- X8Z24X16V8S8MS8VC241ZV = 0x9a,
- X8Z24X16V8S8MS4VC121CZV = 0x9b,
- X8Z24X16V8S8MS4VC41CZV = 0x9c,
- X8Z24X16V8S8MS8VC81CZV = 0x9d,
- X8Z24X16V8S8MS8VC241CZV = 0x9e,
- X8Z24X16V8S8MS4VC122CS = 0x9f,
- X8Z24X16V8S8MS4VC42CS = 0xa0,
- X8Z24X16V8S8MS8VC82CS = 0xa1,
- X8Z24X16V8S8MS8VC242CS = 0xa2,
- X8Z24X16V8S8MS4VC122CSZV = 0xa3,
- X8Z24X16V8S8MS4VC42CSZV = 0xa4,
- X8Z24X16V8S8MS8VC82CSZV = 0xa5,
- X8Z24X16V8S8MS8VC242CSZV = 0xa6,
- ZF32X16V8S8MS4VC12 = 0xa7,
- ZF32X16V8S8MS4VC4 = 0xa8,
- ZF32X16V8S8MS8VC8 = 0xa9,
- ZF32X16V8S8MS8VC24 = 0xaa,
- ZF32X16V8S8MS4VC121CS = 0xab,
- ZF32X16V8S8MS4VC41CS = 0xac,
- ZF32X16V8S8MS8VC81CS = 0xad,
- ZF32X16V8S8MS8VC241CS = 0xae,
- ZF32X16V8S8MS4VC121ZV = 0xb3,
- ZF32X16V8S8MS4VC41ZV = 0xb4,
- ZF32X16V8S8MS8VC81ZV = 0xb5,
- ZF32X16V8S8MS8VC241ZV = 0xb6,
- ZF32X16V8S8MS4VC121CZV = 0xb7,
- ZF32X16V8S8MS4VC41CZV = 0xb8,
- ZF32X16V8S8MS8VC81CZV = 0xb9,
- ZF32X16V8S8MS8VC241CZV = 0xba,
- ZF32X16V8S8MS4VC122CS = 0xbb,
- ZF32X16V8S8MS4VC42CS = 0xbc,
- ZF32X16V8S8MS8VC82CS = 0xbd,
- ZF32X16V8S8MS8VC242CS = 0xbe,
- ZF32X16V8S8MS4VC122CSZV = 0xbf,
- ZF32X16V8S8MS4VC42CSZV = 0xc0,
- ZF32X16V8S8MS8VC82CSZV = 0xc1,
- ZF32X16V8S8MS8VC242CSZV = 0xc2,
- ZF32X24S8 = 0xc3,
- ZF32X24S81CS = 0xc4,
- ZF32X24S8MS21CS = 0xc5,
- ZF32X24S8MS41CS = 0xc6,
- ZF32X24S8MS81CS = 0xc7,
- ZF32X24S8MS161CS = 0xc8,
- ZF32X24S82CSZV = 0xce,
- ZF32X24S8MS22CSZV = 0xcf,
- ZF32X24S8MS42CSZV = 0xd0,
- ZF32X24S8MS82CSZV = 0xd1,
- ZF32X24S8MS162CSZV = 0xd2,
- ZF32X24S82CS = 0xd3,
- ZF32X24S8MS22CS = 0xd4,
- ZF32X24S8MS42CS = 0xd5,
- ZF32X24S8MS82CS = 0xd6,
- ZF32X24S8MS162CS = 0xd7,
- S8 = 0x2a,
- S82S = 0x2b,
- Generic16Bx2 = 0xfe,
- C322C = 0xd8,
- C322CBR = 0xd9,
- C322CBA = 0xda,
- C322CRA = 0xdb,
- C322BRA = 0xdc,
- C32MS22C = 0xdd,
- C32MS22CBR = 0xde,
- C32MS24CBRA = 0xcc,
- C32MS42C = 0xdf,
- C32MS42CBR = 0xe0,
- C32MS42CBA = 0xe1,
- C32MS42CRA = 0xe2,
- C32MS42BRA = 0xe3,
- C32MS44CBRA = 0x2c,
- C32MS8MS162C = 0xe4,
- C32MS8MS162CRA = 0xe5,
- C642C = 0xe6,
- C642CBR = 0xe7,
- C642CBA = 0xe8,
- C642CRA = 0xe9,
- C642BRA = 0xea,
- C64MS22C = 0xeb,
- C64MS22CBR = 0xec,
- C64MS24CBRA = 0xcd,
- C64MS42C = 0xed,
- C64MS42CBR = 0xee,
- C64MS42CBA = 0xef,
- C64MS42CRA = 0xf0,
- C64MS42BRA = 0xf1,
- C64MS44CBRA = 0x2d,
- C64MS8MS162C = 0xf2,
- C64MS8MS162CRA = 0xf3,
- C1282C = 0xf4,
- C1282CR = 0xf5,
- C128MS22C = 0xf6,
- C128MS22CR = 0xf7,
- C128MS42C = 0xf8,
- C128MS42CR = 0xf9,
- C128MS8MS162C = 0xfa,
- C128MS8MS162CR = 0xfb,
- X8C24 = 0xfc,
- PitchNoSwizzle = 0xfd,
- SmSkedMessage = 0xca,
- SmHostMessage = 0xcb
- }
-
- static class PteKindExtensions
- {
- /// <summary>
- /// Checks if the kind is pitch.
- /// </summary>
- /// <param name="kind">Kind to check</param>
- /// <returns>True if pitch, false otherwise</returns>
- public static bool IsPitch(this PteKind kind)
- {
- return kind == PteKind.Pitch || kind == PteKind.PitchNoSwizzle;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Memory/ResourceKind.cs b/Ryujinx.Graphics.Gpu/Memory/ResourceKind.cs
deleted file mode 100644
index 55d697b8..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/ResourceKind.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// Kind of a GPU resource.
- /// </summary>
- enum ResourceKind
- {
- None,
- Buffer,
- Texture,
- Pool
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/Memory/UnmapEventArgs.cs b/Ryujinx.Graphics.Gpu/Memory/UnmapEventArgs.cs
deleted file mode 100644
index 305747f8..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/UnmapEventArgs.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- public class UnmapEventArgs
- {
- public ulong Address { get; }
- public ulong Size { get; }
-
- public UnmapEventArgs(ulong address, ulong size)
- {
- Address = address;
- Size = size;
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/Memory/VertexBuffer.cs b/Ryujinx.Graphics.Gpu/Memory/VertexBuffer.cs
deleted file mode 100644
index 8f089125..00000000
--- a/Ryujinx.Graphics.Gpu/Memory/VertexBuffer.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.Memory
-{
- /// <summary>
- /// GPU Vertex Buffer information.
- /// </summary>
- struct VertexBuffer
- {
- public ulong Address;
- public ulong Size;
- public int Stride;
- public int Divisor;
- }
-} \ No newline at end of file