rasterizer_cache.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <mutex>
  6. #include <set>
  7. #include <unordered_map>
  8. #include <boost/icl/interval_map.hpp>
  9. #include <boost/range/iterator_range_core.hpp>
  10. #include "common/common_types.h"
  11. #include "core/settings.h"
  12. #include "video_core/gpu.h"
  13. #include "video_core/rasterizer_interface.h"
  14. class RasterizerCacheObject {
  15. public:
  16. explicit RasterizerCacheObject(const u8* host_ptr)
  17. : host_ptr{host_ptr}, cache_addr{ToCacheAddr(host_ptr)} {}
  18. virtual ~RasterizerCacheObject();
  19. CacheAddr GetCacheAddr() const {
  20. return cache_addr;
  21. }
  22. const u8* GetHostPtr() const {
  23. return host_ptr;
  24. }
  25. /// Gets the address of the shader in guest memory, required for cache management
  26. virtual VAddr GetCpuAddr() const = 0;
  27. /// Gets the size of the shader in guest memory, required for cache management
  28. virtual std::size_t GetSizeInBytes() const = 0;
  29. /// Wriets any cached resources back to memory
  30. virtual void Flush() = 0;
  31. /// Sets whether the cached object should be considered registered
  32. void SetIsRegistered(bool registered) {
  33. is_registered = registered;
  34. }
  35. /// Returns true if the cached object is registered
  36. bool IsRegistered() const {
  37. return is_registered;
  38. }
  39. /// Returns true if the cached object is dirty
  40. bool IsDirty() const {
  41. return is_dirty;
  42. }
  43. /// Returns ticks from when this cached object was last modified
  44. u64 GetLastModifiedTicks() const {
  45. return last_modified_ticks;
  46. }
  47. /// Marks an object as recently modified, used to specify whether it is clean or dirty
  48. template <class T>
  49. void MarkAsModified(bool dirty, T& cache) {
  50. is_dirty = dirty;
  51. last_modified_ticks = cache.GetModifiedTicks();
  52. }
  53. private:
  54. bool is_registered{}; ///< Whether the object is currently registered with the cache
  55. bool is_dirty{}; ///< Whether the object is dirty (out of sync with guest memory)
  56. u64 last_modified_ticks{}; ///< When the object was last modified, used for in-order flushing
  57. const u8* host_ptr{}; ///< Pointer to the memory backing this cached region
  58. CacheAddr cache_addr{}; ///< Cache address memory, unique from emulated virtual address space
  59. };
  60. template <class T>
  61. class RasterizerCache : NonCopyable {
  62. friend class RasterizerCacheObject;
  63. public:
  64. explicit RasterizerCache(VideoCore::RasterizerInterface& rasterizer) : rasterizer{rasterizer} {}
  65. /// Write any cached resources overlapping the specified region back to memory
  66. void FlushRegion(CacheAddr addr, std::size_t size) {
  67. std::lock_guard<std::recursive_mutex> lock{mutex};
  68. const auto& objects{GetSortedObjectsFromRegion(addr, size)};
  69. for (auto& object : objects) {
  70. FlushObject(object);
  71. }
  72. }
  73. /// Mark the specified region as being invalidated
  74. void InvalidateRegion(CacheAddr addr, u64 size) {
  75. std::lock_guard<std::recursive_mutex> lock{mutex};
  76. const auto& objects{GetSortedObjectsFromRegion(addr, size)};
  77. for (auto& object : objects) {
  78. if (!object->IsRegistered()) {
  79. // Skip duplicates
  80. continue;
  81. }
  82. Unregister(object);
  83. }
  84. }
  85. /// Invalidates everything in the cache
  86. void InvalidateAll() {
  87. std::lock_guard<std::recursive_mutex> lock{mutex};
  88. while (interval_cache.begin() != interval_cache.end()) {
  89. Unregister(*interval_cache.begin()->second.begin());
  90. }
  91. }
  92. protected:
  93. /// Tries to get an object from the cache with the specified cache address
  94. T TryGet(CacheAddr addr) const {
  95. const auto iter = map_cache.find(addr);
  96. if (iter != map_cache.end())
  97. return iter->second;
  98. return nullptr;
  99. }
  100. T TryGet(const void* addr) const {
  101. const auto iter = map_cache.find(ToCacheAddr(addr));
  102. if (iter != map_cache.end())
  103. return iter->second;
  104. return nullptr;
  105. }
  106. /// Register an object into the cache
  107. virtual void Register(const T& object) {
  108. std::lock_guard<std::recursive_mutex> lock{mutex};
  109. object->SetIsRegistered(true);
  110. interval_cache.add({GetInterval(object), ObjectSet{object}});
  111. map_cache.insert({object->GetCacheAddr(), object});
  112. rasterizer.UpdatePagesCachedCount(object->GetCpuAddr(), object->GetSizeInBytes(), 1);
  113. }
  114. /// Unregisters an object from the cache
  115. virtual void Unregister(const T& object) {
  116. std::lock_guard<std::recursive_mutex> lock{mutex};
  117. object->SetIsRegistered(false);
  118. rasterizer.UpdatePagesCachedCount(object->GetCpuAddr(), object->GetSizeInBytes(), -1);
  119. interval_cache.subtract({GetInterval(object), ObjectSet{object}});
  120. map_cache.erase(object->GetCacheAddr());
  121. }
  122. /// Returns a ticks counter used for tracking when cached objects were last modified
  123. u64 GetModifiedTicks() {
  124. std::lock_guard<std::recursive_mutex> lock{mutex};
  125. return ++modified_ticks;
  126. }
  127. /// Flushes the specified object, updating appropriate cache state as needed
  128. void FlushObject(const T& object) {
  129. std::lock_guard<std::recursive_mutex> lock{mutex};
  130. if (!object->IsDirty()) {
  131. return;
  132. }
  133. object->Flush();
  134. object->MarkAsModified(false, *this);
  135. }
  136. private:
  137. /// Returns a list of cached objects from the specified memory region, ordered by access time
  138. std::vector<T> GetSortedObjectsFromRegion(CacheAddr addr, u64 size) {
  139. if (size == 0) {
  140. return {};
  141. }
  142. std::vector<T> objects;
  143. const ObjectInterval interval{addr, addr + size};
  144. for (auto& pair : boost::make_iterator_range(interval_cache.equal_range(interval))) {
  145. for (auto& cached_object : pair.second) {
  146. if (!cached_object) {
  147. continue;
  148. }
  149. objects.push_back(cached_object);
  150. }
  151. }
  152. std::sort(objects.begin(), objects.end(), [](const T& a, const T& b) -> bool {
  153. return a->GetLastModifiedTicks() < b->GetLastModifiedTicks();
  154. });
  155. return objects;
  156. }
  157. using ObjectSet = std::set<T>;
  158. using ObjectCache = std::unordered_map<CacheAddr, T>;
  159. using IntervalCache = boost::icl::interval_map<CacheAddr, ObjectSet>;
  160. using ObjectInterval = typename IntervalCache::interval_type;
  161. static auto GetInterval(const T& object) {
  162. return ObjectInterval::right_open(object->GetCacheAddr(),
  163. object->GetCacheAddr() + object->GetSizeInBytes());
  164. }
  165. ObjectCache map_cache;
  166. IntervalCache interval_cache; ///< Cache of objects
  167. u64 modified_ticks{}; ///< Counter of cache state ticks, used for in-order flushing
  168. VideoCore::RasterizerInterface& rasterizer;
  169. std::recursive_mutex mutex;
  170. };