From f241f88558b3fe90d76fc21123bd06b9e4c3d2da Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Mon, 22 Jan 2024 17:14:46 -0300
Subject: Add a separate device memory manager (#6153)

* Add a separate device memory manager

* Still need this

* Device writes are always tracked

* Device writes are always tracked (2)

* Rename more instances of gmm to mm
---
 src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs | 395 +++++++++++++++++++++
 .../ISynchronizationManager.cs                     |  39 ++
 .../Ryujinx.Graphics.Device.csproj                 |   4 +
 src/Ryujinx.Graphics.Gpu/GpuContext.cs             |  17 +
 src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs   |  43 ---
 src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs  |  10 +
 .../Synchronization/SynchronizationManager.cs      |  27 +-
 src/Ryujinx.Graphics.Host1x/Host1xClass.cs         |   5 +-
 src/Ryujinx.Graphics.Host1x/Host1xDevice.cs        |   3 +-
 .../Ryujinx.Graphics.Host1x.csproj                 |   1 -
 src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs   |   6 +-
 src/Ryujinx.Graphics.Nvdec/H264Decoder.cs          |   8 +-
 src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs   |  12 +-
 src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs  |   8 +-
 src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs  |  18 +-
 src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs     |  14 +-
 src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs          |   5 +-
 src/Ryujinx.Graphics.Nvdec/ResourceManager.cs      |   8 +-
 .../Ryujinx.Graphics.Nvdec.csproj                  |   1 -
 src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs           |   6 +-
 src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs           |  24 +-
 src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs    |   4 +-
 src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs    |   4 +-
 src/Ryujinx.Graphics.Vic/ResourceManager.cs        |   8 +-
 .../Ryujinx.Graphics.Vic.csproj                    |   1 -
 src/Ryujinx.Graphics.Vic/VicDevice.cs              |  11 +-
 src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs   |   6 +-
 .../NvHostAsGpu/NvHostAsGpuDeviceFile.cs           |   2 +-
 .../NvHostChannel/NvHostChannelDeviceFile.cs       |   8 +-
 .../Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs      |   6 +-
 .../Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs    |   2 +-
 .../Nv/NvDrvServices/NvMap/Types/NvMapFree.cs      |   2 +-
 .../Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs    |   4 +-
 33 files changed, 555 insertions(+), 157 deletions(-)
 create mode 100644 src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs
 create mode 100644 src/Ryujinx.Graphics.Device/ISynchronizationManager.cs

(limited to 'src')

diff --git a/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs b/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs
new file mode 100644
index 00000000..d64ed309
--- /dev/null
+++ b/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs
@@ -0,0 +1,395 @@
+using Ryujinx.Memory;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Graphics.Device
+{
+    /// <summary>
+    /// Device memory manager.
+    /// </summary>
+    public class DeviceMemoryManager : IWritableBlock
+    {
+        private const int PtLvl0Bits = 10;
+        private const int PtLvl1Bits = 10;
+        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;
+
+        private readonly IVirtualMemoryManager _physical;
+
+        /// <summary>
+        /// Creates a new instance of the GPU memory manager.
+        /// </summary>
+        /// <param name="physicalMemory">Physical memory that this memory manager will map into</param>
+        public DeviceMemoryManager(IVirtualMemoryManager physicalMemory)
+        {
+            _physical = physicalMemory;
+            _pageTable = new ulong[PtLvl0Size][];
+        }
+
+        /// <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>
+        /// <returns>The data at the specified memory location</returns>
+        public T Read<T>(ulong va) where T : unmanaged
+        {
+            int size = Unsafe.SizeOf<T>();
+
+            if (IsContiguous(va, size))
+            {
+                return _physical.Read<T>(Translate(va));
+            }
+            else
+            {
+                Span<byte> data = new byte[size];
+
+                ReadImpl(va, data);
+
+                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>
+        /// <returns>The span of the data at the specified memory location</returns>
+        public ReadOnlySpan<byte> GetSpan(ulong va, int size)
+        {
+            if (IsContiguous(va, size))
+            {
+                return _physical.GetSpan(Translate(va), size);
+            }
+            else
+            {
+                Span<byte> data = new byte[size];
+
+                ReadImpl(va, data);
+
+                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>
+        private void ReadImpl(ulong va, Span<byte> data)
+        {
+            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));
+
+                if (pa != PteUnmapped && _physical.IsMapped(pa))
+                {
+                    _physical.GetSpan(pa, size).CopyTo(data[..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.GetSpan(pa, size).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>
+        /// <returns>A writable region with the data at the specified memory location</returns>
+        public WritableRegion GetWritableRegion(ulong va, int size)
+        {
+            if (IsContiguous(va, size))
+            {
+                return _physical.GetWritableRegion(Translate(va), size, tracked: true);
+            }
+            else
+            {
+                Memory<byte> memory = new byte[size];
+
+                GetSpan(va, size).CopyTo(memory.Span);
+
+                return new WritableRegion(this, va, memory, tracked: true);
+            }
+        }
+
+        /// <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)
+        {
+            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[..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>
+        /// 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)
+        {
+            throw new NotSupportedException();
+        }
+
+        /// <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="kind">Kind of the resource located at the mapping</param>
+        public void Map(ulong pa, ulong va, ulong size)
+        {
+            lock (_pageTable)
+            {
+                for (ulong offset = 0; offset < size; offset += PageSize)
+                {
+                    SetPte(va + offset, PackPte(pa + offset));
+                }
+            }
+        }
+
+        /// <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)
+            {
+                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>
+        /// 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>
+        /// 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>
+        /// <returns>Page table entry</returns>
+        private static ulong PackPte(ulong pa)
+        {
+            return pa;
+        }
+
+        /// <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;
+        }
+    }
+}
diff --git a/src/Ryujinx.Graphics.Device/ISynchronizationManager.cs b/src/Ryujinx.Graphics.Device/ISynchronizationManager.cs
new file mode 100644
index 00000000..2a8d1d9b
--- /dev/null
+++ b/src/Ryujinx.Graphics.Device/ISynchronizationManager.cs
@@ -0,0 +1,39 @@
+using Ryujinx.Common.Logging;
+using System;
+using System.Threading;
+
+namespace Ryujinx.Graphics.Device
+{
+    /// <summary>
+    /// Synchronization manager interface.
+    /// </summary>
+    public interface ISynchronizationManager
+    {
+        /// <summary>
+        /// Increment the value of a syncpoint with a given id.
+        /// </summary>
+        /// <param name="id">The id of the syncpoint</param>
+        /// <exception cref="System.ArgumentOutOfRangeException">Thrown when id >= MaxHardwareSyncpoints</exception>
+        /// <returns>The incremented value of the syncpoint</returns>
+        uint IncrementSyncpoint(uint id);
+
+        /// <summary>
+        /// Get the value of a syncpoint with a given id.
+        /// </summary>
+        /// <param name="id">The id of the syncpoint</param>
+        /// <exception cref="System.ArgumentOutOfRangeException">Thrown when id >= MaxHardwareSyncpoints</exception>
+        /// <returns>The value of the syncpoint</returns>
+        uint GetSyncpointValue(uint id);
+
+        /// <summary>
+        /// Wait on a syncpoint with a given id at a target threshold.
+        /// The callback will be called once the threshold is reached and will automatically be unregistered.
+        /// </summary>
+        /// <param name="id">The id of the syncpoint</param>
+        /// <param name="threshold">The target threshold</param>
+        /// <param name="timeout">The timeout</param>
+        /// <exception cref="System.ArgumentOutOfRangeException">Thrown when id >= MaxHardwareSyncpoints</exception>
+        /// <returns>True if timed out</returns>
+        bool WaitOnSyncpoint(uint id, uint threshold, TimeSpan timeout);
+    }
+}
diff --git a/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj b/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj
index ae2821ed..973a9e26 100644
--- a/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj
+++ b/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj
@@ -4,4 +4,8 @@
     <TargetFramework>net8.0</TargetFramework>
   </PropertyGroup>
 
+  <ItemGroup>
+    <ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
+  </ItemGroup>
+
 </Project>
diff --git a/src/Ryujinx.Graphics.Gpu/GpuContext.cs b/src/Ryujinx.Graphics.Gpu/GpuContext.cs
index aaf03ff7..aa0084fd 100644
--- a/src/Ryujinx.Graphics.Gpu/GpuContext.cs
+++ b/src/Ryujinx.Graphics.Gpu/GpuContext.cs
@@ -1,4 +1,5 @@
 using Ryujinx.Common;
+using Ryujinx.Graphics.Device;
 using Ryujinx.Graphics.GAL;
 using Ryujinx.Graphics.Gpu.Engine.GPFifo;
 using Ryujinx.Graphics.Gpu.Memory;
@@ -163,6 +164,22 @@ namespace Ryujinx.Graphics.Gpu
             return new MemoryManager(physicalMemory);
         }
 
+        /// <summary>
+        /// Creates a new device memory manager.
+        /// </summary>
+        /// <param name="pid">ID of the process that owns the memory manager</param>
+        /// <returns>The memory manager</returns>
+        /// <exception cref="ArgumentException">Thrown when <paramref name="pid"/> is invalid</exception>
+        public DeviceMemoryManager CreateDeviceMemoryManager(ulong pid)
+        {
+            if (!PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory))
+            {
+                throw new ArgumentException("The PID is invalid or the process was not registered", nameof(pid));
+            }
+
+            return physicalMemory.CreateDeviceMemoryManager();
+        }
+
         /// <summary>
         /// Registers virtual memory used by a process for GPU memory access, caching and read/write tracking.
         /// </summary>
diff --git a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
index 5e19bddc..74d52705 100644
--- a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
+++ b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
@@ -329,49 +329,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
             }
         }
 
-        /// <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[..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>
         /// Runs remap actions that are added to an unmap event.
         /// These must run after the mapping completes.
diff --git a/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
index 1ca6071b..69a3054a 100644
--- a/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
+++ b/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
@@ -1,4 +1,5 @@
 using Ryujinx.Cpu;
+using Ryujinx.Graphics.Device;
 using Ryujinx.Graphics.Gpu.Image;
 using Ryujinx.Graphics.Gpu.Shader;
 using Ryujinx.Memory;
@@ -82,6 +83,15 @@ namespace Ryujinx.Graphics.Gpu.Memory
             }
         }
 
+        /// <summary>
+        /// Creates a new device memory manager.
+        /// </summary>
+        /// <returns>The memory manager</returns>
+        public DeviceMemoryManager CreateDeviceMemoryManager()
+        {
+            return new DeviceMemoryManager(_cpuMemory);
+        }
+
         /// <summary>
         /// Gets a host pointer for a given range of application memory.
         /// If the memory region is not a single contiguous block, this method returns 0.
diff --git a/src/Ryujinx.Graphics.Gpu/Synchronization/SynchronizationManager.cs b/src/Ryujinx.Graphics.Gpu/Synchronization/SynchronizationManager.cs
index c2fa4c24..1042a4db 100644
--- a/src/Ryujinx.Graphics.Gpu/Synchronization/SynchronizationManager.cs
+++ b/src/Ryujinx.Graphics.Gpu/Synchronization/SynchronizationManager.cs
@@ -1,4 +1,5 @@
 using Ryujinx.Common.Logging;
+using Ryujinx.Graphics.Device;
 using System;
 using System.Threading;
 
@@ -7,7 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization
     /// <summary>
     /// GPU synchronization manager.
     /// </summary>
-    public class SynchronizationManager
+    public class SynchronizationManager : ISynchronizationManager
     {
         /// <summary>
         /// The maximum number of syncpoints supported by the GM20B.
@@ -29,12 +30,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization
             }
         }
 
-        /// <summary>
-        /// Increment the value of a syncpoint with a given id.
-        /// </summary>
-        /// <param name="id">The id of the syncpoint</param>
-        /// <exception cref="System.ArgumentOutOfRangeException">Thrown when id >= MaxHardwareSyncpoints</exception>
-        /// <returns>The incremented value of the syncpoint</returns>
+        /// <inheritdoc/>
         public uint IncrementSyncpoint(uint id)
         {
             ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(id, (uint)MaxHardwareSyncpoints);
@@ -42,12 +38,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization
             return _syncpoints[id].Increment();
         }
 
-        /// <summary>
-        /// Get the value of a syncpoint with a given id.
-        /// </summary>
-        /// <param name="id">The id of the syncpoint</param>
-        /// <exception cref="System.ArgumentOutOfRangeException">Thrown when id >= MaxHardwareSyncpoints</exception>
-        /// <returns>The value of the syncpoint</returns>
+        /// <inheritdoc/>
         public uint GetSyncpointValue(uint id)
         {
             ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(id, (uint)MaxHardwareSyncpoints);
@@ -84,15 +75,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization
             _syncpoints[id].UnregisterCallback(waiterInformation);
         }
 
-        /// <summary>
-        /// Wait on a syncpoint with a given id at a target threshold.
-        /// The callback will be called once the threshold is reached and will automatically be unregistered.
-        /// </summary>
-        /// <param name="id">The id of the syncpoint</param>
-        /// <param name="threshold">The target threshold</param>
-        /// <param name="timeout">The timeout</param>
-        /// <exception cref="System.ArgumentOutOfRangeException">Thrown when id >= MaxHardwareSyncpoints</exception>
-        /// <returns>True if timed out</returns>
+        /// <inheritdoc/>
         public bool WaitOnSyncpoint(uint id, uint threshold, TimeSpan timeout)
         {
             ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(id, (uint)MaxHardwareSyncpoints);
diff --git a/src/Ryujinx.Graphics.Host1x/Host1xClass.cs b/src/Ryujinx.Graphics.Host1x/Host1xClass.cs
index 4327b93c..3ffc87ba 100644
--- a/src/Ryujinx.Graphics.Host1x/Host1xClass.cs
+++ b/src/Ryujinx.Graphics.Host1x/Host1xClass.cs
@@ -1,5 +1,4 @@
 using Ryujinx.Graphics.Device;
-using Ryujinx.Graphics.Gpu.Synchronization;
 using System.Collections.Generic;
 using System.Threading;
 
@@ -7,10 +6,10 @@ namespace Ryujinx.Graphics.Host1x
 {
     public class Host1xClass : IDeviceState
     {
-        private readonly SynchronizationManager _syncMgr;
+        private readonly ISynchronizationManager _syncMgr;
         private readonly DeviceState<Host1xClassRegisters> _state;
 
-        public Host1xClass(SynchronizationManager syncMgr)
+        public Host1xClass(ISynchronizationManager syncMgr)
         {
             _syncMgr = syncMgr;
             _state = new DeviceState<Host1xClassRegisters>(new Dictionary<string, RwCallback>
diff --git a/src/Ryujinx.Graphics.Host1x/Host1xDevice.cs b/src/Ryujinx.Graphics.Host1x/Host1xDevice.cs
index 6733b32a..2db74ce5 100644
--- a/src/Ryujinx.Graphics.Host1x/Host1xDevice.cs
+++ b/src/Ryujinx.Graphics.Host1x/Host1xDevice.cs
@@ -1,7 +1,6 @@
 using Ryujinx.Common;
 using Ryujinx.Common.Logging;
 using Ryujinx.Graphics.Device;
-using Ryujinx.Graphics.Gpu.Synchronization;
 using System;
 using System.Numerics;
 
@@ -35,7 +34,7 @@ namespace Ryujinx.Graphics.Host1x
         private int _mask;
         private bool _incrementing;
 
-        public Host1xDevice(SynchronizationManager syncMgr)
+        public Host1xDevice(ISynchronizationManager syncMgr)
         {
             _syncptIncrMgr = new SyncptIncrManager(syncMgr);
             _commandQueue = new AsyncWorkQueue<Command>(Process, "Ryujinx.Host1xProcessor");
diff --git a/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj b/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj
index 22959fad..d631d039 100644
--- a/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj
+++ b/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj
@@ -6,7 +6,6 @@
 
   <ItemGroup>
     <ProjectReference Include="..\Ryujinx.Graphics.Device\Ryujinx.Graphics.Device.csproj" />
-    <ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
   </ItemGroup>
 
 </Project>
diff --git a/src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs b/src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs
index 164d15ec..a5ee1198 100644
--- a/src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs
+++ b/src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs
@@ -1,11 +1,11 @@
-using Ryujinx.Graphics.Gpu.Synchronization;
+using Ryujinx.Graphics.Device;
 using System.Collections.Generic;
 
 namespace Ryujinx.Graphics.Host1x
 {
     class SyncptIncrManager
     {
-        private readonly SynchronizationManager _syncMgr;
+        private readonly ISynchronizationManager _syncMgr;
 
         private readonly struct SyncptIncr
         {
@@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.Host1x
 
         private uint _currentId;
 
-        public SyncptIncrManager(SynchronizationManager syncMgr)
+        public SyncptIncrManager(ISynchronizationManager syncMgr)
         {
             _syncMgr = syncMgr;
         }
diff --git a/src/Ryujinx.Graphics.Nvdec/H264Decoder.cs b/src/Ryujinx.Graphics.Nvdec/H264Decoder.cs
index ef8ab908..6058f72d 100644
--- a/src/Ryujinx.Graphics.Nvdec/H264Decoder.cs
+++ b/src/Ryujinx.Graphics.Nvdec/H264Decoder.cs
@@ -12,10 +12,10 @@ namespace Ryujinx.Graphics.Nvdec
 
         public static void Decode(NvdecDecoderContext context, ResourceManager rm, ref NvdecRegisters state)
         {
-            PictureInfo pictureInfo = rm.Gmm.DeviceRead<PictureInfo>(state.SetDrvPicSetupOffset);
+            PictureInfo pictureInfo = rm.MemoryManager.DeviceRead<PictureInfo>(state.SetDrvPicSetupOffset);
             H264PictureInfo info = pictureInfo.Convert();
 
-            ReadOnlySpan<byte> bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize);
+            ReadOnlySpan<byte> bitstream = rm.MemoryManager.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize);
 
             int width = (int)pictureInfo.PicWidthInMbs * MbSizeInPixels;
             int height = (int)pictureInfo.PicHeightInMbs * MbSizeInPixels;
@@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Nvdec
                 if (outputSurface.Field == FrameField.Progressive)
                 {
                     SurfaceWriter.Write(
-                        rm.Gmm,
+                        rm.MemoryManager,
                         outputSurface,
                         lumaOffset + pictureInfo.LumaFrameOffset,
                         chromaOffset + pictureInfo.ChromaFrameOffset);
@@ -42,7 +42,7 @@ namespace Ryujinx.Graphics.Nvdec
                 else
                 {
                     SurfaceWriter.WriteInterlaced(
-                        rm.Gmm,
+                        rm.MemoryManager,
                         outputSurface,
                         lumaOffset + pictureInfo.LumaTopFieldOffset,
                         chromaOffset + pictureInfo.ChromaTopFieldOffset,
diff --git a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs
index 4a4e1a3f..7359b330 100644
--- a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs
+++ b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Graphics.Gpu.Memory;
+using Ryujinx.Graphics.Device;
 using Ryujinx.Graphics.Video;
 using System;
 using System.Diagnostics;
@@ -27,11 +27,11 @@ namespace Ryujinx.Graphics.Nvdec.Image
 
         private readonly CacheItem[] _pool = new CacheItem[MaxItems];
 
-        private readonly MemoryManager _gmm;
+        private readonly DeviceMemoryManager _mm;
 
-        public SurfaceCache(MemoryManager gmm)
+        public SurfaceCache(DeviceMemoryManager mm)
         {
-            _gmm = gmm;
+            _mm = mm;
         }
 
         public ISurface Get(IDecoder decoder, uint lumaOffset, uint chromaOffset, int width, int height)
@@ -77,7 +77,7 @@ namespace Ryujinx.Graphics.Nvdec.Image
 
                             if ((lumaOffset | chromaOffset) != 0)
                             {
-                                SurfaceReader.Read(_gmm, surface, lumaOffset, chromaOffset);
+                                SurfaceReader.Read(_mm, surface, lumaOffset, chromaOffset);
                             }
 
                             MoveToFront(i);
@@ -100,7 +100,7 @@ namespace Ryujinx.Graphics.Nvdec.Image
 
                         if ((lumaOffset | chromaOffset) != 0)
                         {
-                            SurfaceReader.Read(_gmm, surface, lumaOffset, chromaOffset);
+                            SurfaceReader.Read(_mm, surface, lumaOffset, chromaOffset);
                         }
 
                         MoveToFront(MaxItems - 1);
diff --git a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs
index e8795685..f510c128 100644
--- a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs
+++ b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs
@@ -1,5 +1,5 @@
 using Ryujinx.Common;
-using Ryujinx.Graphics.Gpu.Memory;
+using Ryujinx.Graphics.Device;
 using Ryujinx.Graphics.Texture;
 using Ryujinx.Graphics.Video;
 using System;
@@ -11,13 +11,13 @@ namespace Ryujinx.Graphics.Nvdec.Image
 {
     static class SurfaceReader
     {
-        public static void Read(MemoryManager gmm, ISurface surface, uint lumaOffset, uint chromaOffset)
+        public static void Read(DeviceMemoryManager mm, ISurface surface, uint lumaOffset, uint chromaOffset)
         {
             int width = surface.Width;
             int height = surface.Height;
             int stride = surface.Stride;
 
-            ReadOnlySpan<byte> luma = gmm.DeviceGetSpan(lumaOffset, GetBlockLinearSize(width, height, 1));
+            ReadOnlySpan<byte> luma = mm.DeviceGetSpan(lumaOffset, GetBlockLinearSize(width, height, 1));
 
             ReadLuma(surface.YPlane.AsSpan(), luma, stride, width, height);
 
@@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Nvdec.Image
             int uvHeight = surface.UvHeight;
             int uvStride = surface.UvStride;
 
-            ReadOnlySpan<byte> chroma = gmm.DeviceGetSpan(chromaOffset, GetBlockLinearSize(uvWidth, uvHeight, 2));
+            ReadOnlySpan<byte> chroma = mm.DeviceGetSpan(chromaOffset, GetBlockLinearSize(uvWidth, uvHeight, 2));
 
             ReadChroma(surface.UPlane.AsSpan(), surface.VPlane.AsSpan(), chroma, uvStride, uvWidth, uvHeight);
         }
diff --git a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs
index b4f02899..043be1f2 100644
--- a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs
+++ b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs
@@ -1,5 +1,5 @@
 using Ryujinx.Common;
-using Ryujinx.Graphics.Gpu.Memory;
+using Ryujinx.Graphics.Device;
 using Ryujinx.Graphics.Texture;
 using Ryujinx.Graphics.Video;
 using System;
@@ -12,11 +12,11 @@ namespace Ryujinx.Graphics.Nvdec.Image
 {
     static class SurfaceWriter
     {
-        public static void Write(MemoryManager gmm, ISurface surface, uint lumaOffset, uint chromaOffset)
+        public static void Write(DeviceMemoryManager mm, ISurface surface, uint lumaOffset, uint chromaOffset)
         {
             int lumaSize = GetBlockLinearSize(surface.Width, surface.Height, 1);
 
-            using var luma = gmm.GetWritableRegion(ExtendOffset(lumaOffset), lumaSize);
+            using var luma = mm.GetWritableRegion(ExtendOffset(lumaOffset), lumaSize);
 
             WriteLuma(
                 luma.Memory.Span,
@@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.Nvdec.Image
 
             int chromaSize = GetBlockLinearSize(surface.UvWidth, surface.UvHeight, 2);
 
-            using var chroma = gmm.GetWritableRegion(ExtendOffset(chromaOffset), chromaSize);
+            using var chroma = mm.GetWritableRegion(ExtendOffset(chromaOffset), chromaSize);
 
             WriteChroma(
                 chroma.Memory.Span,
@@ -39,7 +39,7 @@ namespace Ryujinx.Graphics.Nvdec.Image
         }
 
         public static void WriteInterlaced(
-            MemoryManager gmm,
+            DeviceMemoryManager mm,
             ISurface surface,
             uint lumaTopOffset,
             uint chromaTopOffset,
@@ -48,8 +48,8 @@ namespace Ryujinx.Graphics.Nvdec.Image
         {
             int lumaSize = GetBlockLinearSize(surface.Width, surface.Height / 2, 1);
 
-            using var lumaTop = gmm.GetWritableRegion(ExtendOffset(lumaTopOffset), lumaSize);
-            using var lumaBottom = gmm.GetWritableRegion(ExtendOffset(lumaBottomOffset), lumaSize);
+            using var lumaTop = mm.GetWritableRegion(ExtendOffset(lumaTopOffset), lumaSize);
+            using var lumaBottom = mm.GetWritableRegion(ExtendOffset(lumaBottomOffset), lumaSize);
 
             WriteLuma(
                 lumaTop.Memory.Span,
@@ -67,8 +67,8 @@ namespace Ryujinx.Graphics.Nvdec.Image
 
             int chromaSize = GetBlockLinearSize(surface.UvWidth, surface.UvHeight / 2, 2);
 
-            using var chromaTop = gmm.GetWritableRegion(ExtendOffset(chromaTopOffset), chromaSize);
-            using var chromaBottom = gmm.GetWritableRegion(ExtendOffset(chromaBottomOffset), chromaSize);
+            using var chromaTop = mm.GetWritableRegion(ExtendOffset(chromaTopOffset), chromaSize);
+            using var chromaBottom = mm.GetWritableRegion(ExtendOffset(chromaBottomOffset), chromaSize);
 
             WriteChroma(
                 chromaTop.Memory.Span,
diff --git a/src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs b/src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs
index 28d42a8b..1477ed91 100644
--- a/src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs
+++ b/src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs
@@ -1,23 +1,23 @@
-using Ryujinx.Graphics.Gpu.Memory;
+using Ryujinx.Graphics.Device;
 using System;
 
 namespace Ryujinx.Graphics.Nvdec
 {
     static class MemoryExtensions
     {
-        public static T DeviceRead<T>(this MemoryManager gmm, uint offset) where T : unmanaged
+        public static T DeviceRead<T>(this DeviceMemoryManager gmm, uint offset) where T : unmanaged
         {
-            return gmm.Read<T>((ulong)offset << 8);
+            return gmm.Read<T>(ExtendOffset(offset));
         }
 
-        public static ReadOnlySpan<byte> DeviceGetSpan(this MemoryManager gmm, uint offset, int size)
+        public static ReadOnlySpan<byte> DeviceGetSpan(this DeviceMemoryManager gmm, uint offset, int size)
         {
-            return gmm.GetSpan((ulong)offset << 8, size);
+            return gmm.GetSpan(ExtendOffset(offset), size);
         }
 
-        public static void DeviceWrite(this MemoryManager gmm, uint offset, ReadOnlySpan<byte> data)
+        public static void DeviceWrite(this DeviceMemoryManager gmm, uint offset, ReadOnlySpan<byte> data)
         {
-            gmm.Write((ulong)offset << 8, data);
+            gmm.Write(ExtendOffset(offset), data);
         }
 
         public static ulong ExtendOffset(uint offset)
diff --git a/src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs b/src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs
index 77e29554..29e260d6 100644
--- a/src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs
+++ b/src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs
@@ -1,6 +1,5 @@
 using Ryujinx.Common.Logging;
 using Ryujinx.Graphics.Device;
-using Ryujinx.Graphics.Gpu.Memory;
 using Ryujinx.Graphics.Nvdec.Image;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
@@ -17,9 +16,9 @@ namespace Ryujinx.Graphics.Nvdec
         private readonly ConcurrentDictionary<long, NvdecDecoderContext> _contexts;
         private NvdecDecoderContext _currentContext;
 
-        public NvdecDevice(MemoryManager gmm)
+        public NvdecDevice(DeviceMemoryManager mm)
         {
-            _rm = new ResourceManager(gmm, new SurfaceCache(gmm));
+            _rm = new ResourceManager(mm, new SurfaceCache(mm));
             _state = new DeviceState<NvdecRegisters>(new Dictionary<string, RwCallback>
             {
                 { nameof(NvdecRegisters.Execute), new RwCallback(Execute, null) },
diff --git a/src/Ryujinx.Graphics.Nvdec/ResourceManager.cs b/src/Ryujinx.Graphics.Nvdec/ResourceManager.cs
index 200d3a1b..da0ded91 100644
--- a/src/Ryujinx.Graphics.Nvdec/ResourceManager.cs
+++ b/src/Ryujinx.Graphics.Nvdec/ResourceManager.cs
@@ -1,16 +1,16 @@
-using Ryujinx.Graphics.Gpu.Memory;
+using Ryujinx.Graphics.Device;
 using Ryujinx.Graphics.Nvdec.Image;
 
 namespace Ryujinx.Graphics.Nvdec
 {
     readonly struct ResourceManager
     {
-        public MemoryManager Gmm { get; }
+        public DeviceMemoryManager MemoryManager { get; }
         public SurfaceCache Cache { get; }
 
-        public ResourceManager(MemoryManager gmm, SurfaceCache cache)
+        public ResourceManager(DeviceMemoryManager mm, SurfaceCache cache)
         {
-            Gmm = gmm;
+            MemoryManager = mm;
             Cache = cache;
         }
     }
diff --git a/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj b/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj
index fd49a7c8..6c00e9a7 100644
--- a/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj
+++ b/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj
@@ -8,7 +8,6 @@
   <ItemGroup>
     <ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
     <ProjectReference Include="..\Ryujinx.Graphics.Device\Ryujinx.Graphics.Device.csproj" />
-    <ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
     <ProjectReference Include="..\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj" />
     <ProjectReference Include="..\Ryujinx.Graphics.Nvdec.Vp9\Ryujinx.Graphics.Nvdec.Vp9.csproj" />
     <ProjectReference Include="..\Ryujinx.Graphics.Texture\Ryujinx.Graphics.Texture.csproj" />
diff --git a/src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs b/src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs
index 0a7d5840..3d2543c4 100644
--- a/src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs
+++ b/src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs
@@ -10,8 +10,8 @@ namespace Ryujinx.Graphics.Nvdec
     {
         public static void Decode(NvdecDecoderContext context, ResourceManager rm, ref NvdecRegisters state)
         {
-            PictureInfo pictureInfo = rm.Gmm.DeviceRead<PictureInfo>(state.SetDrvPicSetupOffset);
-            ReadOnlySpan<byte> bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.VLDBufferSize);
+            PictureInfo pictureInfo = rm.MemoryManager.DeviceRead<PictureInfo>(state.SetDrvPicSetupOffset);
+            ReadOnlySpan<byte> bitstream = rm.MemoryManager.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.VLDBufferSize);
 
             Decoder decoder = context.GetVp8Decoder();
 
@@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Nvdec
 
             if (decoder.Decode(ref info, outputSurface, bitstream))
             {
-                SurfaceWriter.Write(rm.Gmm, outputSurface, lumaOffset, chromaOffset);
+                SurfaceWriter.Write(rm.MemoryManager, outputSurface, lumaOffset, chromaOffset);
             }
 
             rm.Cache.Put(outputSurface);
diff --git a/src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs b/src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs
index 03795056..5ed50864 100644
--- a/src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs
+++ b/src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs
@@ -1,5 +1,5 @@
 using Ryujinx.Common;
-using Ryujinx.Graphics.Gpu.Memory;
+using Ryujinx.Graphics.Device;
 using Ryujinx.Graphics.Nvdec.Image;
 using Ryujinx.Graphics.Nvdec.Types.Vp9;
 using Ryujinx.Graphics.Nvdec.Vp9;
@@ -17,8 +17,8 @@ namespace Ryujinx.Graphics.Nvdec
 
         public unsafe static void Decode(ResourceManager rm, ref NvdecRegisters state)
         {
-            PictureInfo pictureInfo = rm.Gmm.DeviceRead<PictureInfo>(state.SetDrvPicSetupOffset);
-            EntropyProbs entropy = rm.Gmm.DeviceRead<EntropyProbs>(state.Vp9SetProbTabBufOffset);
+            PictureInfo pictureInfo = rm.MemoryManager.DeviceRead<PictureInfo>(state.SetDrvPicSetupOffset);
+            EntropyProbs entropy = rm.MemoryManager.DeviceRead<EntropyProbs>(state.Vp9SetProbTabBufOffset);
 
             ISurface Rent(uint lumaOffset, uint chromaOffset, FrameSize size)
             {
@@ -38,19 +38,19 @@ namespace Ryujinx.Graphics.Nvdec
 
             entropy.Convert(ref info.Entropy);
 
-            ReadOnlySpan<byte> bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize);
+            ReadOnlySpan<byte> bitstream = rm.MemoryManager.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize);
 
             ReadOnlySpan<Vp9MvRef> mvsIn = ReadOnlySpan<Vp9MvRef>.Empty;
 
             if (info.UsePrevInFindMvRefs)
             {
-                mvsIn = GetMvsInput(rm.Gmm, pictureInfo.CurrentFrameSize, state.Vp9SetColMvReadBufOffset);
+                mvsIn = GetMvsInput(rm.MemoryManager, pictureInfo.CurrentFrameSize, state.Vp9SetColMvReadBufOffset);
             }
 
             int miCols = BitUtils.DivRoundUp(pictureInfo.CurrentFrameSize.Width, 8);
             int miRows = BitUtils.DivRoundUp(pictureInfo.CurrentFrameSize.Height, 8);
 
-            using var mvsRegion = rm.Gmm.GetWritableRegion(ExtendOffset(state.Vp9SetColMvWriteBufOffset), miRows * miCols * 16);
+            using var mvsRegion = rm.MemoryManager.GetWritableRegion(ExtendOffset(state.Vp9SetColMvWriteBufOffset), miRows * miCols * 16);
 
             Span<Vp9MvRef> mvsOut = MemoryMarshal.Cast<byte, Vp9MvRef>(mvsRegion.Memory.Span);
 
@@ -59,10 +59,10 @@ namespace Ryujinx.Graphics.Nvdec
 
             if (_decoder.Decode(ref info, currentSurface, bitstream, mvsIn, mvsOut))
             {
-                SurfaceWriter.Write(rm.Gmm, currentSurface, lumaOffset, chromaOffset);
+                SurfaceWriter.Write(rm.MemoryManager, currentSurface, lumaOffset, chromaOffset);
             }
 
-            WriteBackwardUpdates(rm.Gmm, state.Vp9SetCtxCounterBufOffset, ref info.BackwardUpdateCounts);
+            WriteBackwardUpdates(rm.MemoryManager, state.Vp9SetCtxCounterBufOffset, ref info.BackwardUpdateCounts);
 
             rm.Cache.Put(lastSurface);
             rm.Cache.Put(goldenSurface);
@@ -70,17 +70,17 @@ namespace Ryujinx.Graphics.Nvdec
             rm.Cache.Put(currentSurface);
         }
 
-        private static ReadOnlySpan<Vp9MvRef> GetMvsInput(MemoryManager gmm, FrameSize size, uint offset)
+        private static ReadOnlySpan<Vp9MvRef> GetMvsInput(DeviceMemoryManager mm, FrameSize size, uint offset)
         {
             int miCols = BitUtils.DivRoundUp(size.Width, 8);
             int miRows = BitUtils.DivRoundUp(size.Height, 8);
 
-            return MemoryMarshal.Cast<byte, Vp9MvRef>(gmm.DeviceGetSpan(offset, miRows * miCols * 16));
+            return MemoryMarshal.Cast<byte, Vp9MvRef>(mm.DeviceGetSpan(offset, miRows * miCols * 16));
         }
 
-        private static void WriteBackwardUpdates(MemoryManager gmm, uint offset, ref Vp9BackwardUpdates counts)
+        private static void WriteBackwardUpdates(DeviceMemoryManager mm, uint offset, ref Vp9BackwardUpdates counts)
         {
-            using var backwardUpdatesRegion = gmm.GetWritableRegion(ExtendOffset(offset), Unsafe.SizeOf<BackwardUpdates>());
+            using var backwardUpdatesRegion = mm.GetWritableRegion(ExtendOffset(offset), Unsafe.SizeOf<BackwardUpdates>());
 
             ref var backwardUpdates = ref MemoryMarshal.Cast<byte, BackwardUpdates>(backwardUpdatesRegion.Memory.Span)[0];
 
diff --git a/src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs b/src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs
index 8a9acd91..83f00f34 100644
--- a/src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs
+++ b/src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs
@@ -454,7 +454,7 @@ namespace Ryujinx.Graphics.Vic.Image
             int srcStride = GetPitch(width, bytesPerPixel);
             int inSize = srcStride * height;
 
-            ReadOnlySpan<byte> src = rm.Gmm.GetSpan(ExtendOffset(offset), inSize);
+            ReadOnlySpan<byte> src = rm.MemoryManager.GetSpan(ExtendOffset(offset), inSize);
 
             int outSize = dstStride * height;
             int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer);
@@ -481,7 +481,7 @@ namespace Ryujinx.Graphics.Vic.Image
         {
             int inSize = GetBlockLinearSize(width, height, bytesPerPixel, gobBlocksInY);
 
-            ReadOnlySpan<byte> src = rm.Gmm.GetSpan(ExtendOffset(offset), inSize);
+            ReadOnlySpan<byte> src = rm.MemoryManager.GetSpan(ExtendOffset(offset), inSize);
 
             int outSize = dstStride * height;
             int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer);
diff --git a/src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs b/src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs
index b0664049..b5008b7b 100644
--- a/src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs
+++ b/src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs
@@ -636,7 +636,7 @@ namespace Ryujinx.Graphics.Vic.Image
         {
             if (linear)
             {
-                rm.Gmm.WriteMapped(ExtendOffset(offset), src);
+                rm.MemoryManager.Write(ExtendOffset(offset), src);
                 return;
             }
 
@@ -659,7 +659,7 @@ namespace Ryujinx.Graphics.Vic.Image
 
             LayoutConverter.ConvertLinearToBlockLinear(dst, width, height, dstStride, bytesPerPixel, gobBlocksInY, src);
 
-            rm.Gmm.WriteMapped(ExtendOffset(offset), dst);
+            rm.MemoryManager.Write(ExtendOffset(offset), dst);
 
             rm.BufferPool.Return(dstIndex);
         }
diff --git a/src/Ryujinx.Graphics.Vic/ResourceManager.cs b/src/Ryujinx.Graphics.Vic/ResourceManager.cs
index b0ff8e10..e7d7ef74 100644
--- a/src/Ryujinx.Graphics.Vic/ResourceManager.cs
+++ b/src/Ryujinx.Graphics.Vic/ResourceManager.cs
@@ -1,17 +1,17 @@
-using Ryujinx.Graphics.Gpu.Memory;
+using Ryujinx.Graphics.Device;
 using Ryujinx.Graphics.Vic.Image;
 
 namespace Ryujinx.Graphics.Vic
 {
     readonly struct ResourceManager
     {
-        public MemoryManager Gmm { get; }
+        public DeviceMemoryManager MemoryManager { get; }
         public BufferPool<Pixel> SurfacePool { get; }
         public BufferPool<byte> BufferPool { get; }
 
-        public ResourceManager(MemoryManager gmm, BufferPool<Pixel> surfacePool, BufferPool<byte> bufferPool)
+        public ResourceManager(DeviceMemoryManager mm, BufferPool<Pixel> surfacePool, BufferPool<byte> bufferPool)
         {
-            Gmm = gmm;
+            MemoryManager = mm;
             SurfacePool = surfacePool;
             BufferPool = bufferPool;
         }
diff --git a/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj b/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj
index cfebcfa2..b3f39f2e 100644
--- a/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj
+++ b/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj
@@ -8,7 +8,6 @@
   <ItemGroup>
     <ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
     <ProjectReference Include="..\Ryujinx.Graphics.Device\Ryujinx.Graphics.Device.csproj" />
-    <ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
     <ProjectReference Include="..\Ryujinx.Graphics.Host1x\Ryujinx.Graphics.Host1x.csproj" />
     <ProjectReference Include="..\Ryujinx.Graphics.Texture\Ryujinx.Graphics.Texture.csproj" />
   </ItemGroup>
diff --git a/src/Ryujinx.Graphics.Vic/VicDevice.cs b/src/Ryujinx.Graphics.Vic/VicDevice.cs
index 2ddb94a4..2b25a74c 100644
--- a/src/Ryujinx.Graphics.Vic/VicDevice.cs
+++ b/src/Ryujinx.Graphics.Vic/VicDevice.cs
@@ -1,5 +1,4 @@
 using Ryujinx.Graphics.Device;
-using Ryujinx.Graphics.Gpu.Memory;
 using Ryujinx.Graphics.Vic.Image;
 using Ryujinx.Graphics.Vic.Types;
 using System;
@@ -9,14 +8,14 @@ namespace Ryujinx.Graphics.Vic
 {
     public class VicDevice : IDeviceState
     {
-        private readonly MemoryManager _gmm;
+        private readonly DeviceMemoryManager _mm;
         private readonly ResourceManager _rm;
         private readonly DeviceState<VicRegisters> _state;
 
-        public VicDevice(MemoryManager gmm)
+        public VicDevice(DeviceMemoryManager mm)
         {
-            _gmm = gmm;
-            _rm = new ResourceManager(gmm, new BufferPool<Pixel>(), new BufferPool<byte>());
+            _mm = mm;
+            _rm = new ResourceManager(mm, new BufferPool<Pixel>(), new BufferPool<byte>());
             _state = new DeviceState<VicRegisters>(new Dictionary<string, RwCallback>
             {
                 { nameof(VicRegisters.Execute), new RwCallback(Execute, null) },
@@ -68,7 +67,7 @@ namespace Ryujinx.Graphics.Vic
 
         private T ReadIndirect<T>(uint offset) where T : unmanaged
         {
-            return _gmm.Read<T>((ulong)offset << 8);
+            return _mm.Read<T>((ulong)offset << 8);
         }
     }
 }
diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs b/src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs
index 371edbec..7c7ebf22 100644
--- a/src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Graphics.Gpu.Memory;
+using Ryujinx.Graphics.Device;
 using Ryujinx.Graphics.Host1x;
 using Ryujinx.Graphics.Nvdec;
 using Ryujinx.Graphics.Vic;
@@ -9,7 +9,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
 {
     class Host1xContext : IDisposable
     {
-        public MemoryManager Smmu { get; }
+        public DeviceMemoryManager Smmu { get; }
         public NvMemoryAllocator MemoryAllocator { get; }
         public Host1xDevice Host1x { get; }
 
@@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
         {
             MemoryAllocator = new NvMemoryAllocator();
             Host1x = new Host1xDevice(gpu.Synchronization);
-            Smmu = gpu.CreateMemoryManager(pid);
+            Smmu = gpu.CreateDeviceMemoryManager(pid);
             var nvdec = new NvdecDevice(Smmu);
             var vic = new VicDevice(Smmu);
             Host1x.RegisterDevice(ClassId.Nvdec, nvdec);
diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs
index 03c4ed86..ff9a6764 100644
--- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs
@@ -266,7 +266,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
 
             if (size == 0)
             {
-                size = (uint)map.Size;
+                size = map.Size;
             }
 
             NvInternalResult result = NvInternalResult.Success;
diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs
index 53db5eca..bc70b05c 100644
--- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs
@@ -250,12 +250,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
                 {
                     if (map.DmaMapAddress == 0)
                     {
-                        ulong va = _host1xContext.MemoryAllocator.GetFreeAddress((ulong)map.Size, out ulong freeAddressStartPosition, 1, MemoryManager.PageSize);
+                        ulong va = _host1xContext.MemoryAllocator.GetFreeAddress(map.Size, out ulong freeAddressStartPosition, 1, MemoryManager.PageSize);
 
-                        if (va != NvMemoryAllocator.PteUnmapped && va <= uint.MaxValue && (va + (uint)map.Size) <= uint.MaxValue)
+                        if (va != NvMemoryAllocator.PteUnmapped && va <= uint.MaxValue && (va + map.Size) <= uint.MaxValue)
                         {
-                            _host1xContext.MemoryAllocator.AllocateRange(va, (uint)map.Size, freeAddressStartPosition);
-                            _host1xContext.Smmu.Map(map.Address, va, (uint)map.Size, PteKind.Pitch); // FIXME: This should not use the GMMU.
+                            _host1xContext.MemoryAllocator.AllocateRange(va, map.Size, freeAddressStartPosition);
+                            _host1xContext.Smmu.Map(map.Address, va, map.Size);
                             map.DmaMapAddress = va;
                         }
                         else
diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs
index abe0a4de..6a0ac58b 100644
--- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs
@@ -69,7 +69,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
                 return NvInternalResult.InvalidInput;
             }
 
-            int size = BitUtils.AlignUp(arguments.Size, (int)MemoryManager.PageSize);
+            uint size = BitUtils.AlignUp(arguments.Size, (uint)MemoryManager.PageSize);
 
             arguments.Handle = CreateHandleFromMap(new NvMapHandle(size));
 
@@ -128,7 +128,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
                 map.Align = arguments.Align;
                 map.Kind = (byte)arguments.Kind;
 
-                int size = BitUtils.AlignUp(map.Size, (int)MemoryManager.PageSize);
+                uint size = BitUtils.AlignUp(map.Size, (uint)MemoryManager.PageSize);
 
                 ulong address = arguments.Address;
 
@@ -191,7 +191,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
             switch (arguments.Param)
             {
                 case NvMapHandleParam.Size:
-                    arguments.Result = map.Size;
+                    arguments.Result = (int)map.Size;
                     break;
                 case NvMapHandleParam.Align:
                     arguments.Result = map.Align;
diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs
index 5380c45c..f4047497 100644
--- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs
@@ -5,7 +5,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
     [StructLayout(LayoutKind.Sequential)]
     struct NvMapCreate
     {
-        public int Size;
+        public uint Size;
         public int Handle;
     }
 }
diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs
index b0b3fa2d..ce93e9e5 100644
--- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs
@@ -8,7 +8,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
         public int Handle;
         public int Padding;
         public ulong Address;
-        public int Size;
+        public uint Size;
         public int Flags;
     }
 }
diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs
index 30117974..e821b571 100644
--- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs
@@ -8,7 +8,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
         public int Handle;
         public int Id;
 #pragma warning restore CS0649
-        public int Size;
+        public uint Size;
         public int Align;
         public int Kind;
         public ulong Address;
@@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
             _dupes = 1;
         }
 
-        public NvMapHandle(int size) : this()
+        public NvMapHandle(uint size) : this()
         {
             Size = size;
         }
-- 
cgit v1.2.3-70-g09d2