aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
diff options
context:
space:
mode:
authorsharmander <saldabain.dev@gmail.com>2020-12-09 17:26:05 -0500
committerGitHub <noreply@github.com>2020-12-09 19:26:05 -0300
commit06aa8a7578c794dd4b16f12df5ce1bbeabc1d1c1 (patch)
tree627b1840a1d1f428c2fdff1e45a19e1951f46965 /Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
parent48278905d1470f89be31668c738397f569af156a (diff)
GPU - Improve Memory Allocation (#1722)
* Implement TreeMap from scratch. Begin implementation of MemoryBlockManager * Implement GetFreePosition using MemoryBlocks * Implementation of Memory Management using a Tree. Still some issues to work around, but promising thus far. * Resolved invalid mapping issue. Performance appears promising. * Add tick metrics * Use the logger instead * Use debug loggin instead of info. * Remove unnecessary code. Add descriptions of added functions. * Improve memory allocation even further. As well as improve speed of position fetching. * Add TreeDictionary to Ryujinx Commons Removed Unnecessary Usigns * Add a Performance Profiler + Improve ReserveFixed * Begin transition to allocation in nvdrv * Create singleton nvmemallocator * Moved Allocation into Nv Related Files As requested by gdkchan, any allocation of memory has been moved into the driver files. Mapping remains in the GPU MemoryManager. * Remove unnecessary usings * Add missing descriptions * Correct descriptions * Fix formatting. * Remove unnecessary whitespace * Formatting / Convention Updates * Changes / Fixes Made syntax and convention changes as requested by gdkchan. Fixed an issue where IsRegionUsed would return the wrong boolean. Fixed an issue where GetFreePosition was asked for an address instead of a size. * Undo commenting of Assert in shader cache * Update Ryujinx.Common/Collections/TreeDictionary.cs Co-authored-by: gdkchan <gab.dark.100@gmail.com> * Resolved many suggestions * Implement Improved TreeDictionary Based off of Pseudo code and custom implementations. * Rename _set to _dictionary * Remove unused code * Remove unused code. * Remove unnecessary MapLow function. * Resolve data-structure based issues * Make adjustments to memory management. Deactive de-allocation for now, it causes more harm than good. * Minor refactorings + Re-implement deallocation Also cleaned up unnecessary code. * Add Tests for TreeDictionary * Update data structure to properly balance the tree * Experimental Implementation: 1. Reduce Time to Next Node to O(1) Runtime 2. Reduce While Loop Ct To 2 (In Most Cases) * Address issues w/ Deallocating Memory * Final Build + Fully Implement Dictionary Interface for new Data Structure + Cover All Memory Allocation Edge Cases, particularly w/ Games that De-Allocate a lot. * Minor Corrections Give TreeDictionary its own count (do not depend on inner dictionary) Properly remove adjacent allocations * Add AsList * Fix bug where internal dictionary wasn't being updated w/ new node for overwritten key. * Address comments in review. * Fix issue where block wouldn't break out (Fixes UE4 issues) * Update descriptions * Update descriptions * Reduce Node visibility to protect TreeDictionary Integrity + Remove usage of struct. * Update tests to use new TreeDictionary implementation. * Remove usage of dictionary in TreeDictionary * Refactoring / Renaming * Remove unneeded memoryblock class. * Add space for while * Add space for if * Formatting / descriptions * Clarified some descriptions * Reduce visibility of memory allocator * Edit method names to make more sense as memory blocks are no longer in use. * Make names consistent. * Protect against npe when sucessorof is called against keys that don't exist. (Not in use by memory manager, this is for other prs that might use this data structure) * Possible edge-case resolve * Update Ryujinx.Common/Collections/TreeDictionary.cs Co-authored-by: gdkchan <gab.dark.100@gmail.com> * Update Ryujinx.HLE/HOS/Services/Nv/NvMemoryAllocator.cs Co-authored-by: gdkchan <gab.dark.100@gmail.com> * Reduce # of unnecessary duplicate variables / Reduce visibility of variables only internally used. * Rename count to _count * Update Description of Add method. * Fix copypasta * Address comments * Address comments * Remove whitespace * Address comments, condense variables. * Consolidate vars * Fix whitespace. * Nit * Fix exception msg * Fix arrayIndex check * Fix arrayIndex check + indexer * Remove whitespace from cast Co-authored-by: gdkchan <gab.dark.100@gmail.com>
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs191
1 files changed, 2 insertions, 189 deletions
diff --git a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
index 91575e20..2990fb52 100644
--- a/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
@@ -10,10 +10,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary>
public class MemoryManager
{
- private const ulong AddressSpaceSize = 1UL << 40;
-
- public const ulong BadAddress = ulong.MaxValue;
-
private const int PtLvl0Bits = 14;
private const int PtLvl1Bits = 14;
public const int PtPageBits = 12;
@@ -29,8 +25,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
private const int PtLvl0Bit = PtPageBits + PtLvl1Bits;
private const int PtLvl1Bit = PtPageBits;
- private const ulong PteUnmapped = 0xffffffff_ffffffff;
- private const ulong PteReserved = 0xffffffff_fffffffe;
+ public const ulong PteUnmapped = 0xffffffff_ffffffff;
private readonly ulong[][] _pageTable;
@@ -137,116 +132,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
- /// Maps a given range of pages to an allocated GPU virtual address.
- /// The memory is automatically allocated by the memory manager.
- /// </summary>
- /// <param name="pa">CPU virtual address to map into</param>
- /// <param name="size">Size in bytes of the mapping</param>
- /// <param name="alignment">Required alignment of the GPU virtual address in bytes</param>
- /// <returns>GPU virtual address where the range was mapped, or an all ones mask in case of failure</returns>
- public ulong MapAllocate(ulong pa, ulong size, ulong alignment)
- {
- lock (_pageTable)
- {
- ulong va = GetFreePosition(size, alignment);
-
- if (va != PteUnmapped)
- {
- for (ulong offset = 0; offset < size; offset += PageSize)
- {
- SetPte(va + offset, pa + offset);
- }
- }
-
- return va;
- }
- }
-
- /// <summary>
- /// Maps a given range of pages to an allocated GPU virtual address.
- /// The memory is automatically allocated by the memory manager.
- /// This also ensures that the mapping is always done in the first 4GB of GPU address space.
- /// </summary>
- /// <param name="pa">CPU virtual address to map into</param>
- /// <param name="size">Size in bytes of the mapping</param>
- /// <returns>GPU virtual address where the range was mapped, or an all ones mask in case of failure</returns>
- public ulong MapLow(ulong pa, ulong size)
- {
- lock (_pageTable)
- {
- ulong va = GetFreePosition(size, 1, PageSize);
-
- if (va != PteUnmapped && va <= uint.MaxValue && (va + size) <= uint.MaxValue)
- {
- for (ulong offset = 0; offset < size; offset += PageSize)
- {
- SetPte(va + offset, pa + offset);
- }
- }
- else
- {
- va = PteUnmapped;
- }
-
- return va;
- }
- }
-
- /// <summary>
- /// Reserves memory at a fixed GPU memory location.
- /// This prevents the reserved region from being used for memory allocation for map.
- /// </summary>
- /// <param name="va">GPU virtual address to reserve</param>
- /// <param name="size">Size in bytes of the reservation</param>
- /// <returns>GPU virtual address of the reservation, or an all ones mask in case of failure</returns>
- public ulong ReserveFixed(ulong va, ulong size)
- {
- lock (_pageTable)
- {
- MemoryUnmapped?.Invoke(this, new UnmapEventArgs(va, size));
-
- for (ulong offset = 0; offset < size; offset += PageSize)
- {
- if (IsPageInUse(va + offset))
- {
- return PteUnmapped;
- }
- }
-
- for (ulong offset = 0; offset < size; offset += PageSize)
- {
- SetPte(va + offset, PteReserved);
- }
- }
-
- return va;
- }
-
- /// <summary>
- /// Reserves memory at any GPU memory location.
- /// </summary>
- /// <param name="size">Size in bytes of the reservation</param>
- /// <param name="alignment">Reservation address alignment in bytes</param>
- /// <returns>GPU virtual address of the reservation, or an all ones mask in case of failure</returns>
- public ulong Reserve(ulong size, ulong alignment)
- {
- lock (_pageTable)
- {
- ulong address = GetFreePosition(size, alignment);
-
- if (address != PteUnmapped)
- {
- for (ulong offset = 0; offset < size; offset += PageSize)
- {
- SetPte(address + offset, PteReserved);
- }
- }
-
- return address;
- }
- }
-
- /// <summary>
/// Frees memory that was previously allocated by a map or reserved.
/// </summary>
/// <param name="va">GPU virtual address to free</param>
@@ -266,55 +151,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
- /// Gets the address of an unused (free) region of the specified size.
- /// </summary>
- /// <param name="size">Size of the region in bytes</param>
- /// <param name="alignment">Required alignment of the region address in bytes</param>
- /// <param name="start">Start address of the search on the address space</param>
- /// <returns>GPU virtual address of the allocation, or an all ones mask in case of failure</returns>
- private ulong GetFreePosition(ulong size, ulong alignment = 1, ulong start = 1UL << 32)
- {
- // Note: Address 0 is not considered valid by the driver,
- // when 0 is returned it's considered a mapping error.
- ulong address = start;
- ulong freeSize = 0;
-
- if (alignment == 0)
- {
- alignment = 1;
- }
-
- alignment = (alignment + PageMask) & ~PageMask;
-
- while (address + freeSize < AddressSpaceSize)
- {
- if (!IsPageInUse(address + freeSize))
- {
- freeSize += PageSize;
-
- if (freeSize >= size)
- {
- return address;
- }
- }
- else
- {
- address += freeSize + PageSize;
- freeSize = 0;
-
- ulong remainder = address % alignment;
-
- if (remainder != 0)
- {
- address = (address - remainder) + alignment;
- }
- }
- }
-
- return PteUnmapped;
- }
-
- /// <summary>
/// Checks if a given page is mapped.
/// </summary>
/// <param name="gpuVa">GPU virtual address of the page to check</param>
@@ -333,7 +169,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
ulong baseAddress = GetPte(gpuVa);
- if (baseAddress == PteUnmapped || baseAddress == PteReserved)
+ if (baseAddress == PteUnmapped)
{
return PteUnmapped;
}
@@ -342,29 +178,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
- /// Checks if a given memory page is mapped or reserved.
- /// </summary>
- /// <param name="gpuVa">GPU virtual address of the page</param>
- /// <returns>True if the page is mapped or reserved, false otherwise</returns>
- private bool IsPageInUse(ulong gpuVa)
- {
- if (gpuVa >> PtLvl0Bits + PtLvl1Bits + PtPageBits != 0)
- {
- return false;
- }
-
- ulong l0 = (gpuVa >> PtLvl0Bit) & PtLvl0Mask;
- ulong l1 = (gpuVa >> PtLvl1Bit) & PtLvl1Mask;
-
- if (_pageTable[l0] == null)
- {
- return false;
- }
-
- return _pageTable[l0][l1] != PteUnmapped;
- }
-
- /// <summary>
/// Gets the Page Table entry for a given GPU virtual address.
/// </summary>
/// <param name="gpuVa">GPU virtual address</param>