memory_manager.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <map>
  6. #include <optional>
  7. #include "common/common_types.h"
  8. #include "common/page_table.h"
  9. namespace VideoCore {
  10. class RasterizerInterface;
  11. }
  12. namespace Core {
  13. class System;
  14. }
  15. namespace Tegra {
  16. /**
  17. * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space
  18. * with homogeneous attributes across its extents. In this particular implementation each VMA is
  19. * also backed by a single host memory allocation.
  20. */
  21. struct VirtualMemoryArea {
  22. enum class Type : u8 {
  23. Unmapped,
  24. Allocated,
  25. Mapped,
  26. };
  27. /// Virtual base address of the region.
  28. GPUVAddr base{};
  29. /// Size of the region.
  30. u64 size{};
  31. /// Memory area mapping type.
  32. Type type{Type::Unmapped};
  33. /// CPU memory mapped address corresponding to this memory area.
  34. VAddr backing_addr{};
  35. /// Offset into the backing_memory the mapping starts from.
  36. std::size_t offset{};
  37. /// Pointer backing this VMA.
  38. u8* backing_memory{};
  39. /// Tests if this area can be merged to the right with `next`.
  40. bool CanBeMergedWith(const VirtualMemoryArea& next) const;
  41. };
  42. class MemoryManager final {
  43. public:
  44. explicit MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer);
  45. ~MemoryManager();
  46. GPUVAddr AllocateSpace(u64 size, u64 align);
  47. GPUVAddr AllocateSpace(GPUVAddr addr, u64 size, u64 align);
  48. GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size);
  49. GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr addr, u64 size);
  50. GPUVAddr UnmapBuffer(GPUVAddr addr, u64 size);
  51. std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;
  52. template <typename T>
  53. T Read(GPUVAddr addr) const;
  54. template <typename T>
  55. void Write(GPUVAddr addr, T data);
  56. u8* GetPointer(GPUVAddr addr);
  57. const u8* GetPointer(GPUVAddr addr) const;
  58. /// Returns true if the block is continuous in host memory, false otherwise
  59. bool IsBlockContinuous(GPUVAddr start, std::size_t size) const;
  60. /**
  61. * ReadBlock and WriteBlock are full read and write operations over virtual
  62. * GPU Memory. It's important to use these when GPU memory may not be continuous
  63. * in the Host Memory counterpart. Note: This functions cause Host GPU Memory
  64. * Flushes and Invalidations, respectively to each operation.
  65. */
  66. void ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const;
  67. void WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size);
  68. void CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size);
  69. /**
  70. * ReadBlockUnsafe and WriteBlockUnsafe are special versions of ReadBlock and
  71. * WriteBlock respectively. In this versions, no flushing or invalidation is actually
  72. * done and their performance is similar to a memcpy. This functions can be used
  73. * on either of this 2 scenarios instead of their safe counterpart:
  74. * - Memory which is sure to never be represented in the Host GPU.
  75. * - Memory Managed by a Cache Manager. Example: Texture Flushing should use
  76. * WriteBlockUnsafe instead of WriteBlock since it shouldn't invalidate the texture
  77. * being flushed.
  78. */
  79. void ReadBlockUnsafe(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const;
  80. void WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size);
  81. void CopyBlockUnsafe(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size);
  82. /**
  83. * IsGranularRange checks if a gpu region can be simply read with a pointer
  84. */
  85. bool IsGranularRange(GPUVAddr gpu_addr, std::size_t size);
  86. private:
  87. using VMAMap = std::map<GPUVAddr, VirtualMemoryArea>;
  88. using VMAHandle = VMAMap::const_iterator;
  89. using VMAIter = VMAMap::iterator;
  90. bool IsAddressValid(GPUVAddr addr) const;
  91. void MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type,
  92. VAddr backing_addr = 0);
  93. void MapMemoryRegion(GPUVAddr base, u64 size, u8* target, VAddr backing_addr);
  94. void UnmapRegion(GPUVAddr base, u64 size);
  95. /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
  96. VMAHandle FindVMA(GPUVAddr target) const;
  97. VMAHandle AllocateMemory(GPUVAddr target, std::size_t offset, u64 size);
  98. /**
  99. * Maps an unmanaged host memory pointer at a given address.
  100. *
  101. * @param target The guest address to start the mapping at.
  102. * @param memory The memory to be mapped.
  103. * @param size Size of the mapping in bytes.
  104. * @param backing_addr The base address of the range to back this mapping.
  105. */
  106. VMAHandle MapBackingMemory(GPUVAddr target, u8* memory, u64 size, VAddr backing_addr);
  107. /// Unmaps a range of addresses, splitting VMAs as necessary.
  108. void UnmapRange(GPUVAddr target, u64 size);
  109. /// Converts a VMAHandle to a mutable VMAIter.
  110. VMAIter StripIterConstness(const VMAHandle& iter);
  111. /// Marks as the specified VMA as allocated.
  112. VMAIter Allocate(VMAIter vma);
  113. /**
  114. * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing
  115. * the appropriate error checking.
  116. */
  117. VMAIter CarveVMA(GPUVAddr base, u64 size);
  118. /**
  119. * Splits the edges of the given range of non-Free VMAs so that there is a VMA split at each
  120. * end of the range.
  121. */
  122. VMAIter CarveVMARange(GPUVAddr base, u64 size);
  123. /**
  124. * Splits a VMA in two, at the specified offset.
  125. * @returns the right side of the split, with the original iterator becoming the left side.
  126. */
  127. VMAIter SplitVMA(VMAIter vma, u64 offset_in_vma);
  128. /**
  129. * Checks for and merges the specified VMA with adjacent ones if possible.
  130. * @returns the merged VMA or the original if no merging was possible.
  131. */
  132. VMAIter MergeAdjacent(VMAIter vma);
  133. /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
  134. void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
  135. /// Finds a free (unmapped region) of the specified size starting at the specified address.
  136. GPUVAddr FindFreeRegion(GPUVAddr region_start, u64 size) const;
  137. private:
  138. static constexpr u64 page_bits{16};
  139. static constexpr u64 page_size{1 << page_bits};
  140. static constexpr u64 page_mask{page_size - 1};
  141. /// Address space in bits, according to Tegra X1 TRM
  142. static constexpr u32 address_space_width{40};
  143. /// Start address for mapping, this is fairly arbitrary but must be non-zero.
  144. static constexpr GPUVAddr address_space_base{0x100000};
  145. /// End of address space, based on address space in bits.
  146. static constexpr GPUVAddr address_space_end{1ULL << address_space_width};
  147. Common::PageTable page_table;
  148. VMAMap vma_map;
  149. VideoCore::RasterizerInterface& rasterizer;
  150. Core::System& system;
  151. };
  152. } // namespace Tegra