summaryrefslogtreecommitdiff
path: root/src/video_core/buffer_cache
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/buffer_cache')
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h93
-rw-r--r--src/video_core/buffer_cache/map_interval.h23
2 files changed, 104 insertions, 12 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 7c1737fe2..4ea43a6c4 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -43,8 +43,24 @@ public:
43 } 43 }
44 const auto cache_addr = ToCacheAddr(host_ptr); 44 const auto cache_addr = ToCacheAddr(host_ptr);
45 45
46 // Cache management is a big overhead, so only cache entries with a given size.
47 // TODO: Figure out which size is the best for given games.
48 constexpr std::size_t max_stream_size = 0x800;
49 if (size < max_stream_size) {
50 if (!is_written && !IsRegionWritten(cache_addr, cache_addr + size - 1)) {
51 return StreamBufferUpload(host_ptr, size, alignment);
52 }
53 }
54
46 auto block = GetBlock(cache_addr, size); 55 auto block = GetBlock(cache_addr, size);
47 MapAddress(block, gpu_addr, cache_addr, size); 56 auto map = MapAddress(block, gpu_addr, cache_addr, size);
57 if (is_written) {
58 map->MarkAsModified(true, GetModifiedTicks());
59 if (!map->IsWritten()) {
60 map->MarkAsWritten(true);
61 MarkRegionAsWritten(map->GetStart(), map->GetEnd() - 1);
62 }
63 }
48 64
49 const u64 offset = static_cast<u64>(block->GetOffset(cache_addr)); 65 const u64 offset = static_cast<u64>(block->GetOffset(cache_addr));
50 66
@@ -124,7 +140,7 @@ protected:
124 std::size_t dst_offset, std::size_t size) = 0; 140 std::size_t dst_offset, std::size_t size) = 0;
125 141
126 /// Register an object into the cache 142 /// Register an object into the cache
127 void Register(const MapInterval& new_map) { 143 void Register(const MapInterval& new_map, bool inherit_written = false) {
128 const CacheAddr cache_ptr = new_map->GetStart(); 144 const CacheAddr cache_ptr = new_map->GetStart();
129 const std::optional<VAddr> cpu_addr = 145 const std::optional<VAddr> cpu_addr =
130 system.GPU().MemoryManager().GpuToCpuAddress(new_map->GetGpuAddress()); 146 system.GPU().MemoryManager().GpuToCpuAddress(new_map->GetGpuAddress());
@@ -139,6 +155,10 @@ protected:
139 const IntervalType interval{new_map->GetStart(), new_map->GetEnd()}; 155 const IntervalType interval{new_map->GetStart(), new_map->GetEnd()};
140 mapped_addresses.insert({interval, new_map}); 156 mapped_addresses.insert({interval, new_map});
141 rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1); 157 rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1);
158 if (inherit_written) {
159 MarkRegionAsWritten(new_map->GetStart(), new_map->GetEnd() - 1);
160 new_map->MarkAsWritten(true);
161 }
142 } 162 }
143 163
144 /// Unregisters an object from the cache 164 /// Unregisters an object from the cache
@@ -146,6 +166,9 @@ protected:
146 const std::size_t size = map->GetEnd() - map->GetStart(); 166 const std::size_t size = map->GetEnd() - map->GetStart();
147 rasterizer.UpdatePagesCachedCount(map->GetCpuAddress(), size, -1); 167 rasterizer.UpdatePagesCachedCount(map->GetCpuAddress(), size, -1);
148 map->MarkAsRegistered(false); 168 map->MarkAsRegistered(false);
169 if (map->IsWritten()) {
170 UnmarkRegionAsWritten(map->GetStart(), map->GetEnd() - 1);
171 }
149 const IntervalType delete_interval{map->GetStart(), map->GetEnd()}; 172 const IntervalType delete_interval{map->GetStart(), map->GetEnd()};
150 mapped_addresses.erase(delete_interval); 173 mapped_addresses.erase(delete_interval);
151 } 174 }
@@ -155,8 +178,8 @@ private:
155 return std::make_shared<MapIntervalBase>(start, end, gpu_addr); 178 return std::make_shared<MapIntervalBase>(start, end, gpu_addr);
156 } 179 }
157 180
158 void MapAddress(const TBuffer& block, const GPUVAddr gpu_addr, const CacheAddr cache_addr, 181 MapInterval MapAddress(const TBuffer& block, const GPUVAddr gpu_addr,
159 const std::size_t size) { 182 const CacheAddr cache_addr, const std::size_t size) {
160 183
161 std::vector<MapInterval> overlaps = GetMapsInRange(cache_addr, size); 184 std::vector<MapInterval> overlaps = GetMapsInRange(cache_addr, size);
162 if (overlaps.empty()) { 185 if (overlaps.empty()) {
@@ -165,22 +188,24 @@ private:
165 u8* host_ptr = FromCacheAddr(cache_addr); 188 u8* host_ptr = FromCacheAddr(cache_addr);
166 UploadBlockData(block, block->GetOffset(cache_addr), size, host_ptr); 189 UploadBlockData(block, block->GetOffset(cache_addr), size, host_ptr);
167 Register(new_map); 190 Register(new_map);
168 return; 191 return new_map;
169 } 192 }
170 193
171 const CacheAddr cache_addr_end = cache_addr + size; 194 const CacheAddr cache_addr_end = cache_addr + size;
172 if (overlaps.size() == 1) { 195 if (overlaps.size() == 1) {
173 const MapInterval& current_map = overlaps[0]; 196 MapInterval& current_map = overlaps[0];
174 if (current_map->IsInside(cache_addr, cache_addr_end)) { 197 if (current_map->IsInside(cache_addr, cache_addr_end)) {
175 return; 198 return current_map;
176 } 199 }
177 } 200 }
178 CacheAddr new_start = cache_addr; 201 CacheAddr new_start = cache_addr;
179 CacheAddr new_end = cache_addr_end; 202 CacheAddr new_end = cache_addr_end;
203 bool write_inheritance = false;
180 // Calculate new buffer parameters 204 // Calculate new buffer parameters
181 for (auto& overlap : overlaps) { 205 for (auto& overlap : overlaps) {
182 new_start = std::min(overlap->GetStart(), new_start); 206 new_start = std::min(overlap->GetStart(), new_start);
183 new_end = std::max(overlap->GetEnd(), new_end); 207 new_end = std::max(overlap->GetEnd(), new_end);
208 write_inheritance |= overlap->IsWritten();
184 } 209 }
185 GPUVAddr new_gpu_addr = gpu_addr + new_start - cache_addr; 210 GPUVAddr new_gpu_addr = gpu_addr + new_start - cache_addr;
186 for (auto& overlap : overlaps) { 211 for (auto& overlap : overlaps) {
@@ -188,7 +213,8 @@ private:
188 } 213 }
189 UpdateBlock(block, new_start, new_end, overlaps); 214 UpdateBlock(block, new_start, new_end, overlaps);
190 MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr); 215 MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr);
191 Register(new_map); 216 Register(new_map, write_inheritance);
217 return new_map;
192 } 218 }
193 219
194 void UpdateBlock(const TBuffer& block, CacheAddr start, CacheAddr end, 220 void UpdateBlock(const TBuffer& block, CacheAddr start, CacheAddr end,
@@ -320,6 +346,48 @@ private:
320 return found; 346 return found;
321 } 347 }
322 348
349 void MarkRegionAsWritten(const CacheAddr start, const CacheAddr end) {
350 u64 page_start = start >> write_page_bit;
351 const u64 page_end = end >> write_page_bit;
352 while (page_start <= page_end) {
353 auto it = written_pages.find(page_start);
354 if (it != written_pages.end()) {
355 it->second = it->second + 1;
356 } else {
357 written_pages[page_start] = 1;
358 }
359 page_start++;
360 }
361 }
362
363 void UnmarkRegionAsWritten(const CacheAddr start, const CacheAddr end) {
364 u64 page_start = start >> write_page_bit;
365 const u64 page_end = end >> write_page_bit;
366 while (page_start <= page_end) {
367 auto it = written_pages.find(page_start);
368 if (it != written_pages.end()) {
369 if (it->second > 1) {
370 it->second = it->second - 1;
371 } else {
372 written_pages.erase(it);
373 }
374 }
375 page_start++;
376 }
377 }
378
379 bool IsRegionWritten(const CacheAddr start, const CacheAddr end) const {
380 u64 page_start = start >> write_page_bit;
381 const u64 page_end = end >> write_page_bit;
382 while (page_start <= page_end) {
383 if (written_pages.count(page_start) > 0) {
384 return true;
385 }
386 page_start++;
387 }
388 return false;
389 }
390
323 std::unique_ptr<StreamBuffer> stream_buffer; 391 std::unique_ptr<StreamBuffer> stream_buffer;
324 TBufferType stream_buffer_handle{}; 392 TBufferType stream_buffer_handle{};
325 393
@@ -334,11 +402,14 @@ private:
334 using IntervalType = typename IntervalCache::interval_type; 402 using IntervalType = typename IntervalCache::interval_type;
335 IntervalCache mapped_addresses{}; 403 IntervalCache mapped_addresses{};
336 404
337 static constexpr u64 block_page_bits{24}; 405 static constexpr u64 write_page_bit{11};
406 std::unordered_map<u64, u32> written_pages{};
407
408 static constexpr u64 block_page_bits{21};
338 static constexpr u64 block_page_size{1 << block_page_bits}; 409 static constexpr u64 block_page_size{1 << block_page_bits};
339 std::unordered_map<u64, TBuffer> blocks; 410 std::unordered_map<u64, TBuffer> blocks{};
340 411
341 std::list<TBuffer> pending_destruction; 412 std::list<TBuffer> pending_destruction{};
342 u64 epoch{}; 413 u64 epoch{};
343 u64 modified_ticks{}; 414 u64 modified_ticks{};
344 VideoCore::RasterizerInterface& rasterizer; 415 VideoCore::RasterizerInterface& rasterizer;
diff --git a/src/video_core/buffer_cache/map_interval.h b/src/video_core/buffer_cache/map_interval.h
index a01eddf49..3a104d5cd 100644
--- a/src/video_core/buffer_cache/map_interval.h
+++ b/src/video_core/buffer_cache/map_interval.h
@@ -54,12 +54,33 @@ public:
54 return end; 54 return end;
55 } 55 }
56 56
57 void MarkAsModified(const bool is_modified_, const u64 tick) {
58 is_modified = is_modified_;
59 ticks = tick;
60 }
61
62 bool IsModified() const {
63 return is_modified;
64 }
65
66 u64 GetModificationTick() const {
67 return ticks;
68 }
69
70 void MarkAsWritten(const bool is_written_) {
71 is_written = is_written_;
72 }
73
74 bool IsWritten() const {
75 return is_written;
76 }
77
57private: 78private:
58 CacheAddr start; 79 CacheAddr start;
59 CacheAddr end; 80 CacheAddr end;
60 GPUVAddr gpu_addr; 81 GPUVAddr gpu_addr;
61 VAddr cpu_addr{}; 82 VAddr cpu_addr{};
62 bool is_write{}; 83 bool is_written{};
63 bool is_modified{}; 84 bool is_modified{};
64 bool is_registered{}; 85 bool is_registered{};
65 u64 ticks{}; 86 u64 ticks{};