summaryrefslogtreecommitdiff
path: root/src/video_core/rasterizer_cache.h
diff options
context:
space:
mode:
authorGravatar bunnei2018-08-31 13:24:21 -0400
committerGravatar GitHub2018-08-31 13:24:21 -0400
commit42588493d5ad5d824fc557ac936e64e5e7fd7e44 (patch)
treed06ab2b0bd2f426a8fb129cea437ed99e29ed5e9 /src/video_core/rasterizer_cache.h
parentImplement BC6H_UF16 & BC6H_SF16 (#1092) (diff)
parentgl_rasterizer_cache: Use accurate framebuffer setting for accurate copies. (diff)
downloadyuzu-42588493d5ad5d824fc557ac936e64e5e7fd7e44.tar.gz
yuzu-42588493d5ad5d824fc557ac936e64e5e7fd7e44.tar.xz
yuzu-42588493d5ad5d824fc557ac936e64e5e7fd7e44.zip
Merge pull request #1205 from bunnei/improve-rasterizer-cache-2
Various fixes and improvements to rasterizer cache 2: Electric Boogaloo
Diffstat (limited to 'src/video_core/rasterizer_cache.h')
-rw-r--r--src/video_core/rasterizer_cache.h124
1 files changed, 49 insertions, 75 deletions
diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h
index 7a0492a4e..de1eab86b 100644
--- a/src/video_core/rasterizer_cache.h
+++ b/src/video_core/rasterizer_cache.h
@@ -4,113 +4,87 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <unordered_map> 7#include <set>
8
8#include <boost/icl/interval_map.hpp> 9#include <boost/icl/interval_map.hpp>
9#include <boost/range/iterator_range.hpp>
10 10
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/core.h"
12#include "core/memory.h" 13#include "core/memory.h"
13#include "video_core/memory_manager.h" 14#include "video_core/memory_manager.h"
15#include "video_core/rasterizer_interface.h"
16#include "video_core/renderer_base.h"
14 17
15template <class T> 18template <class T>
16class RasterizerCache : NonCopyable { 19class RasterizerCache : NonCopyable {
17public: 20public:
18 /// Mark the specified region as being invalidated 21 /// Mark the specified region as being invalidated
19 void InvalidateRegion(Tegra::GPUVAddr region_addr, size_t region_size) { 22 void InvalidateRegion(VAddr addr, u64 size) {
20 for (auto iter = cached_objects.cbegin(); iter != cached_objects.cend();) { 23 if (size == 0)
21 const auto& object{iter->second}; 24 return;
22 25
23 ++iter; 26 const ObjectInterval interval{addr, addr + size};
27 for (auto& pair : boost::make_iterator_range(object_cache.equal_range(interval))) {
28 for (auto& cached_object : pair.second) {
29 if (!cached_object)
30 continue;
24 31
25 if (object->GetAddr() <= (region_addr + region_size) && 32 remove_objects.emplace(cached_object);
26 region_addr <= (object->GetAddr() + object->GetSizeInBytes())) {
27 // Regions overlap, so invalidate
28 Unregister(object);
29 } 33 }
30 } 34 }
35
36 for (auto& remove_object : remove_objects) {
37 Unregister(remove_object);
38 }
39
40 remove_objects.clear();
41 }
42
43 /// Invalidates everything in the cache
44 void InvalidateAll() {
45 while (object_cache.begin() != object_cache.end()) {
46 Unregister(*object_cache.begin()->second.begin());
47 }
31 } 48 }
32 49
33protected: 50protected:
34 /// Tries to get an object from the cache with the specified address 51 /// Tries to get an object from the cache with the specified address
35 T TryGet(Tegra::GPUVAddr addr) const { 52 T TryGet(VAddr addr) const {
36 const auto& search{cached_objects.find(addr)}; 53 const ObjectInterval interval{addr};
37 if (search != cached_objects.end()) { 54 for (auto& pair : boost::make_iterator_range(object_cache.equal_range(interval))) {
38 return search->second; 55 for (auto& cached_object : pair.second) {
56 if (cached_object->GetAddr() == addr) {
57 return cached_object;
58 }
59 }
39 } 60 }
40
41 return nullptr; 61 return nullptr;
42 } 62 }
43 63
44 /// Gets a reference to the cache
45 const std::unordered_map<Tegra::GPUVAddr, T>& GetCache() const {
46 return cached_objects;
47 }
48
49 /// Register an object into the cache 64 /// Register an object into the cache
50 void Register(const T& object) { 65 void Register(const T& object) {
51 const auto& search{cached_objects.find(object->GetAddr())}; 66 object_cache.add({GetInterval(object), ObjectSet{object}});
52 if (search != cached_objects.end()) { 67 auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer();
53 // Registered already 68 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), 1);
54 return;
55 }
56
57 cached_objects[object->GetAddr()] = object;
58 UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), 1);
59 } 69 }
60 70
61 /// Unregisters an object from the cache 71 /// Unregisters an object from the cache
62 void Unregister(const T& object) { 72 void Unregister(const T& object) {
63 const auto& search{cached_objects.find(object->GetAddr())}; 73 auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer();
64 if (search == cached_objects.end()) { 74 rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1);
65 // Unregistered already 75 object_cache.subtract({GetInterval(object), ObjectSet{object}});
66 return;
67 }
68
69 UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1);
70 cached_objects.erase(search);
71 } 76 }
72 77
73private: 78private:
74 using PageMap = boost::icl::interval_map<u64, int>; 79 using ObjectSet = std::set<T>;
75 80 using ObjectCache = boost::icl::interval_map<VAddr, ObjectSet>;
76 template <typename Map, typename Interval> 81 using ObjectInterval = typename ObjectCache::interval_type;
77 constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
78 return boost::make_iterator_range(map.equal_range(interval));
79 }
80
81 /// Increase/decrease the number of object in pages touching the specified region
82 void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) {
83 const u64 page_start{addr >> Tegra::MemoryManager::PAGE_BITS};
84 const u64 page_end{(addr + size) >> Tegra::MemoryManager::PAGE_BITS};
85
86 // Interval maps will erase segments if count reaches 0, so if delta is negative we have to
87 // subtract after iterating
88 const auto pages_interval = PageMap::interval_type::right_open(page_start, page_end);
89 if (delta > 0)
90 cached_pages.add({pages_interval, delta});
91
92 for (const auto& pair : RangeFromInterval(cached_pages, pages_interval)) {
93 const auto interval = pair.first & pages_interval;
94 const int count = pair.second;
95
96 const Tegra::GPUVAddr interval_start_addr = boost::icl::first(interval)
97 << Tegra::MemoryManager::PAGE_BITS;
98 const Tegra::GPUVAddr interval_end_addr = boost::icl::last_next(interval)
99 << Tegra::MemoryManager::PAGE_BITS;
100 const u64 interval_size = interval_end_addr - interval_start_addr;
101
102 if (delta > 0 && count == delta)
103 Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
104 else if (delta < 0 && count == -delta)
105 Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
106 else
107 ASSERT(count >= 0);
108 }
109 82
110 if (delta < 0) 83 static auto GetInterval(const T& object) {
111 cached_pages.add({pages_interval, delta}); 84 return ObjectInterval::right_open(object->GetAddr(),
85 object->GetAddr() + object->GetSizeInBytes());
112 } 86 }
113 87
114 std::unordered_map<Tegra::GPUVAddr, T> cached_objects; 88 ObjectCache object_cache;
115 PageMap cached_pages; 89 ObjectSet remove_objects;
116}; 90};