memory_manager.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <atomic>
  5. #include <map>
  6. #include <optional>
  7. #include <vector>
  8. #include "common/common_types.h"
  9. #include "common/multi_level_page_table.h"
  10. #include "common/virtual_buffer.h"
  11. namespace VideoCore {
  12. class RasterizerInterface;
  13. }
  14. namespace Core {
  15. class DeviceMemory;
  16. namespace Memory {
  17. class Memory;
  18. } // namespace Memory
  19. class System;
  20. } // namespace Core
  21. namespace Tegra {
  22. class MemoryManager final {
  23. public:
  24. explicit MemoryManager(Core::System& system_, u64 address_space_bits_ = 40,
  25. u64 big_page_bits_ = 16, u64 page_bits_ = 12);
  26. ~MemoryManager();
  27. size_t GetID() const {
  28. return unique_identifier;
  29. }
  30. /// Binds a renderer to the memory manager.
  31. void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
  32. [[nodiscard]] std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;
  33. [[nodiscard]] std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr, std::size_t size) const;
  34. template <typename T>
  35. [[nodiscard]] T Read(GPUVAddr addr) const;
  36. template <typename T>
  37. void Write(GPUVAddr addr, T data);
  38. [[nodiscard]] u8* GetPointer(GPUVAddr addr);
  39. [[nodiscard]] const u8* GetPointer(GPUVAddr addr) const;
  40. /**
  41. * ReadBlock and WriteBlock are full read and write operations over virtual
  42. * GPU Memory. It's important to use these when GPU memory may not be continuous
  43. * in the Host Memory counterpart. Note: This functions cause Host GPU Memory
  44. * Flushes and Invalidations, respectively to each operation.
  45. */
  46. void ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const;
  47. void WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size);
  48. void CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size);
  49. /**
  50. * ReadBlockUnsafe and WriteBlockUnsafe are special versions of ReadBlock and
  51. * WriteBlock respectively. In this versions, no flushing or invalidation is actually
  52. * done and their performance is similar to a memcpy. This functions can be used
  53. * on either of this 2 scenarios instead of their safe counterpart:
  54. * - Memory which is sure to never be represented in the Host GPU.
  55. * - Memory Managed by a Cache Manager. Example: Texture Flushing should use
  56. * WriteBlockUnsafe instead of WriteBlock since it shouldn't invalidate the texture
  57. * being flushed.
  58. */
  59. void ReadBlockUnsafe(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const;
  60. void WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size);
  61. /**
  62. * Checks if a gpu region can be simply read with a pointer.
  63. */
  64. [[nodiscard]] bool IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const;
  65. /**
  66. * Checks if a gpu region is mapped by a single range of cpu addresses.
  67. */
  68. [[nodiscard]] bool IsContinousRange(GPUVAddr gpu_addr, std::size_t size) const;
  69. /**
  70. * Checks if a gpu region is mapped entirely.
  71. */
  72. [[nodiscard]] bool IsFullyMappedRange(GPUVAddr gpu_addr, std::size_t size) const;
  73. /**
  74. * Returns a vector with all the subranges of cpu addresses mapped beneath.
  75. * if the region is continous, a single pair will be returned. If it's unmapped, an empty vector
  76. * will be returned;
  77. */
  78. std::vector<std::pair<GPUVAddr, std::size_t>> GetSubmappedRange(GPUVAddr gpu_addr,
  79. std::size_t size) const;
  80. GPUVAddr Map(GPUVAddr gpu_addr, VAddr cpu_addr, std::size_t size, bool is_big_pages = true);
  81. GPUVAddr MapSparse(GPUVAddr gpu_addr, std::size_t size, bool is_big_pages = true);
  82. void Unmap(GPUVAddr gpu_addr, std::size_t size);
  83. void FlushRegion(GPUVAddr gpu_addr, size_t size) const;
  84. void InvalidateRegion(GPUVAddr gpu_addr, size_t size) const;
  85. bool IsMemoryDirty(GPUVAddr gpu_addr, size_t size) const;
  86. size_t MaxContinousRange(GPUVAddr gpu_addr, size_t size) const;
  87. bool IsWithinGPUAddressRange(GPUVAddr gpu_addr) const {
  88. return gpu_addr < address_space_size;
  89. }
  90. private:
  91. template <bool is_big_pages, typename FuncMapped, typename FuncReserved, typename FuncUnmapped>
  92. inline void MemoryOperation(GPUVAddr gpu_src_addr, std::size_t size, FuncMapped&& func_mapped,
  93. FuncReserved&& func_reserved, FuncUnmapped&& func_unmapped) const;
  94. template <bool is_safe>
  95. void ReadBlockImpl(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const;
  96. template <bool is_safe>
  97. void WriteBlockImpl(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size);
  98. template <bool is_big_page>
  99. [[nodiscard]] inline std::size_t PageEntryIndex(GPUVAddr gpu_addr) const {
  100. if constexpr (is_big_page) {
  101. return (gpu_addr >> big_page_bits) & big_page_table_mask;
  102. } else {
  103. return (gpu_addr >> page_bits) & page_table_mask;
  104. }
  105. }
  106. inline bool IsBigPageContinous(size_t big_page_index) const;
  107. inline void SetBigPageContinous(size_t big_page_index, bool value);
  108. Core::System& system;
  109. Core::Memory::Memory& memory;
  110. Core::DeviceMemory& device_memory;
  111. const u64 address_space_bits;
  112. const u64 page_bits;
  113. u64 address_space_size;
  114. u64 page_size;
  115. u64 page_mask;
  116. u64 page_table_mask;
  117. static constexpr u64 cpu_page_bits{12};
  118. const u64 big_page_bits;
  119. u64 big_page_size;
  120. u64 big_page_mask;
  121. u64 big_page_table_mask;
  122. VideoCore::RasterizerInterface* rasterizer = nullptr;
  123. enum class EntryType : u64 {
  124. Free = 0,
  125. Reserved = 1,
  126. Mapped = 2,
  127. };
  128. std::vector<u64> entries;
  129. std::vector<u64> big_entries;
  130. template <EntryType entry_type>
  131. GPUVAddr PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, size_t size);
  132. template <EntryType entry_type>
  133. GPUVAddr BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, size_t size);
  134. template <bool is_big_page>
  135. inline EntryType GetEntry(size_t position) const;
  136. template <bool is_big_page>
  137. inline void SetEntry(size_t position, EntryType entry);
  138. Common::MultiLevelPageTable<u32> page_table;
  139. Common::VirtualBuffer<u32> big_page_table_cpu;
  140. std::vector<u64> big_page_continous;
  141. constexpr static size_t continous_bits = 64;
  142. const size_t unique_identifier;
  143. static std::atomic<size_t> unique_identifier_generator;
  144. };
  145. } // namespace Tegra