buffer_cache.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // Copyright 2019 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <array>
  6. #include <memory>
  7. #include <mutex>
  8. #include <unordered_map>
  9. #include <unordered_set>
  10. #include <utility>
  11. #include <vector>
  12. #include "common/alignment.h"
  13. #include "common/common_types.h"
  14. #include "core/core.h"
  15. #include "video_core/memory_manager.h"
  16. #include "video_core/rasterizer_cache.h"
  17. namespace VideoCore {
  18. class RasterizerInterface;
  19. }
  20. namespace VideoCommon {
  21. template <typename BufferStorageType>
  22. class CachedBuffer final : public RasterizerCacheObject {
  23. public:
  24. explicit CachedBuffer(VAddr cpu_addr, u8* host_ptr)
  25. : RasterizerCacheObject{host_ptr}, host_ptr{host_ptr}, cpu_addr{cpu_addr} {}
  26. ~CachedBuffer() override = default;
  27. VAddr GetCpuAddr() const override {
  28. return cpu_addr;
  29. }
  30. std::size_t GetSizeInBytes() const override {
  31. return size;
  32. }
  33. u8* GetWritableHostPtr() const {
  34. return host_ptr;
  35. }
  36. std::size_t GetSize() const {
  37. return size;
  38. }
  39. std::size_t GetCapacity() const {
  40. return capacity;
  41. }
  42. bool IsInternalized() const {
  43. return is_internal;
  44. }
  45. const BufferStorageType& GetBuffer() const {
  46. return buffer;
  47. }
  48. void SetSize(std::size_t new_size) {
  49. size = new_size;
  50. }
  51. void SetInternalState(bool is_internal_) {
  52. is_internal = is_internal_;
  53. }
  54. BufferStorageType ExchangeBuffer(BufferStorageType buffer_, std::size_t new_capacity) {
  55. capacity = new_capacity;
  56. std::swap(buffer, buffer_);
  57. return buffer_;
  58. }
  59. private:
  60. u8* host_ptr{};
  61. VAddr cpu_addr{};
  62. std::size_t size{};
  63. std::size_t capacity{};
  64. bool is_internal{};
  65. BufferStorageType buffer;
  66. };
  67. template <typename BufferStorageType, typename BufferType, typename StreamBuffer>
  68. class BufferCache : public RasterizerCache<std::shared_ptr<CachedBuffer<BufferStorageType>>> {
  69. public:
  70. using Buffer = std::shared_ptr<CachedBuffer<BufferStorageType>>;
  71. using BufferInfo = std::pair<const BufferType*, u64>;
  72. explicit BufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
  73. std::unique_ptr<StreamBuffer> stream_buffer)
  74. : RasterizerCache<Buffer>{rasterizer}, system{system},
  75. stream_buffer{std::move(stream_buffer)}, stream_buffer_handle{
  76. this->stream_buffer->GetHandle()} {}
  77. ~BufferCache() = default;
  78. void Unregister(const Buffer& entry) override {
  79. std::lock_guard lock{RasterizerCache<Buffer>::mutex};
  80. if (entry->IsInternalized()) {
  81. internalized_entries.erase(entry->GetCacheAddr());
  82. }
  83. ReserveBuffer(entry);
  84. RasterizerCache<Buffer>::Unregister(entry);
  85. }
  86. void TickFrame() {
  87. marked_for_destruction_index =
  88. (marked_for_destruction_index + 1) % marked_for_destruction_ring_buffer.size();
  89. MarkedForDestruction().clear();
  90. }
  91. [[nodiscard]] BufferInfo UploadMemory(GPUVAddr gpu_addr, std::size_t size,
  92. std::size_t alignment = 4, bool internalize = false,
  93. bool is_written = false) {
  94. std::lock_guard lock{RasterizerCache<Buffer>::mutex};
  95. auto& memory_manager = system.GPU().MemoryManager();
  96. const auto host_ptr = memory_manager.GetPointer(gpu_addr);
  97. if (!host_ptr) {
  98. return {GetEmptyBuffer(size), 0};
  99. }
  100. const auto cache_addr = ToCacheAddr(host_ptr);
  101. // Cache management is a big overhead, so only cache entries with a given size.
  102. // TODO: Figure out which size is the best for given games.
  103. constexpr std::size_t max_stream_size = 0x800;
  104. if (!internalize && size < max_stream_size &&
  105. internalized_entries.find(cache_addr) == internalized_entries.end()) {
  106. return StreamBufferUpload(host_ptr, size, alignment);
  107. }
  108. auto entry = RasterizerCache<Buffer>::TryGet(cache_addr);
  109. if (!entry) {
  110. return FixedBufferUpload(gpu_addr, host_ptr, size, internalize, is_written);
  111. }
  112. if (entry->GetSize() < size) {
  113. IncreaseBufferSize(entry, size);
  114. }
  115. if (is_written) {
  116. entry->MarkAsModified(true, *this);
  117. }
  118. return {ToHandle(entry->GetBuffer()), 0};
  119. }
  120. /// Uploads from a host memory. Returns the OpenGL buffer where it's located and its offset.
  121. [[nodiscard]] BufferInfo UploadHostMemory(const void* raw_pointer, std::size_t size,
  122. std::size_t alignment = 4) {
  123. std::lock_guard lock{RasterizerCache<Buffer>::mutex};
  124. return StreamBufferUpload(raw_pointer, size, alignment);
  125. }
  126. void Map(std::size_t max_size) {
  127. std::tie(buffer_ptr, buffer_offset_base, invalidated) = stream_buffer->Map(max_size, 4);
  128. buffer_offset = buffer_offset_base;
  129. }
  130. /// Finishes the upload stream, returns true on bindings invalidation.
  131. bool Unmap() {
  132. stream_buffer->Unmap(buffer_offset - buffer_offset_base);
  133. return std::exchange(invalidated, false);
  134. }
  135. protected:
  136. void FlushObjectInner(const Buffer& entry) override {
  137. DownloadBufferData(entry->GetBuffer(), 0, entry->GetSize(), entry->GetWritableHostPtr());
  138. }
  139. virtual BufferStorageType CreateBuffer(std::size_t size) = 0;
  140. virtual const BufferType* ToHandle(const BufferStorageType& storage) = 0;
  141. virtual const BufferType* GetEmptyBuffer(std::size_t size) = 0;
  142. virtual void UploadBufferData(const BufferStorageType& buffer, std::size_t offset,
  143. std::size_t size, const u8* data) = 0;
  144. virtual void DownloadBufferData(const BufferStorageType& buffer, std::size_t offset,
  145. std::size_t size, u8* data) = 0;
  146. virtual void CopyBufferData(const BufferStorageType& src, const BufferStorageType& dst,
  147. std::size_t src_offset, std::size_t dst_offset,
  148. std::size_t size) = 0;
  149. private:
  150. BufferInfo StreamBufferUpload(const void* raw_pointer, std::size_t size,
  151. std::size_t alignment) {
  152. AlignBuffer(alignment);
  153. const std::size_t uploaded_offset = buffer_offset;
  154. std::memcpy(buffer_ptr, raw_pointer, size);
  155. buffer_ptr += size;
  156. buffer_offset += size;
  157. return {&stream_buffer_handle, uploaded_offset};
  158. }
  159. BufferInfo FixedBufferUpload(GPUVAddr gpu_addr, u8* host_ptr, std::size_t size,
  160. bool internalize, bool is_written) {
  161. auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager();
  162. const auto cpu_addr = memory_manager.GpuToCpuAddress(gpu_addr);
  163. ASSERT(cpu_addr);
  164. auto entry = GetUncachedBuffer(*cpu_addr, host_ptr);
  165. entry->SetSize(size);
  166. entry->SetInternalState(internalize);
  167. RasterizerCache<Buffer>::Register(entry);
  168. if (internalize) {
  169. internalized_entries.emplace(ToCacheAddr(host_ptr));
  170. }
  171. if (is_written) {
  172. entry->MarkAsModified(true, *this);
  173. }
  174. if (entry->GetCapacity() < size) {
  175. MarkedForDestruction().push_back(entry->ExchangeBuffer(CreateBuffer(size), size));
  176. }
  177. UploadBufferData(entry->GetBuffer(), 0, size, host_ptr);
  178. return {ToHandle(entry->GetBuffer()), 0};
  179. }
  180. void IncreaseBufferSize(Buffer& entry, std::size_t new_size) {
  181. const std::size_t old_size = entry->GetSize();
  182. if (entry->GetCapacity() < new_size) {
  183. const auto& old_buffer = entry->GetBuffer();
  184. auto new_buffer = CreateBuffer(new_size);
  185. // Copy bits from the old buffer to the new buffer.
  186. CopyBufferData(old_buffer, new_buffer, 0, 0, old_size);
  187. MarkedForDestruction().push_back(
  188. entry->ExchangeBuffer(std::move(new_buffer), new_size));
  189. // This buffer could have been used
  190. invalidated = true;
  191. }
  192. // Upload the new bits.
  193. const std::size_t size_diff = new_size - old_size;
  194. UploadBufferData(entry->GetBuffer(), old_size, size_diff, entry->GetHostPtr() + old_size);
  195. // Update entry's size in the object and in the cache.
  196. Unregister(entry);
  197. entry->SetSize(new_size);
  198. RasterizerCache<Buffer>::Register(entry);
  199. }
  200. Buffer GetUncachedBuffer(VAddr cpu_addr, u8* host_ptr) {
  201. if (auto entry = TryGetReservedBuffer(host_ptr)) {
  202. return entry;
  203. }
  204. return std::make_shared<Buffer::element_type>(cpu_addr, host_ptr);
  205. }
  206. Buffer TryGetReservedBuffer(u8* host_ptr) {
  207. const auto it = buffer_reserve.find(ToCacheAddr(host_ptr));
  208. if (it == buffer_reserve.end()) {
  209. return {};
  210. }
  211. auto& reserve = it->second;
  212. auto entry = reserve.back();
  213. reserve.pop_back();
  214. return entry;
  215. }
  216. void ReserveBuffer(Buffer entry) {
  217. buffer_reserve[entry->GetCacheAddr()].push_back(std::move(entry));
  218. }
  219. void AlignBuffer(std::size_t alignment) {
  220. // Align the offset, not the mapped pointer
  221. const std::size_t offset_aligned = Common::AlignUp(buffer_offset, alignment);
  222. buffer_ptr += offset_aligned - buffer_offset;
  223. buffer_offset = offset_aligned;
  224. }
  225. std::vector<BufferStorageType>& MarkedForDestruction() {
  226. return marked_for_destruction_ring_buffer[marked_for_destruction_index];
  227. }
  228. Core::System& system;
  229. std::unique_ptr<StreamBuffer> stream_buffer;
  230. BufferType stream_buffer_handle{};
  231. bool invalidated = false;
  232. u8* buffer_ptr = nullptr;
  233. u64 buffer_offset = 0;
  234. u64 buffer_offset_base = 0;
  235. std::size_t marked_for_destruction_index = 0;
  236. std::array<std::vector<BufferStorageType>, 4> marked_for_destruction_ring_buffer;
  237. std::unordered_set<CacheAddr> internalized_entries;
  238. std::unordered_map<CacheAddr, std::vector<Buffer>> buffer_reserve;
  239. };
  240. } // namespace VideoCommon