diff options
| author | 2019-07-20 11:42:53 -0400 | |
|---|---|---|
| committer | 2019-08-21 12:14:25 -0400 | |
| commit | 286f4c446ae2396da41ca09173070ae5beb10e8e (patch) | |
| tree | 8f11d51473813ccb0bf7cf0a2662131075f81695 /src/video_core/buffer_cache | |
| parent | BufferCache: Rework mapping caching. (diff) | |
| download | yuzu-286f4c446ae2396da41ca09173070ae5beb10e8e.tar.gz yuzu-286f4c446ae2396da41ca09173070ae5beb10e8e.tar.xz yuzu-286f4c446ae2396da41ca09173070ae5beb10e8e.zip | |
Buffer_Cache: Optimize and track written areas.
Diffstat (limited to 'src/video_core/buffer_cache')
| -rw-r--r-- | src/video_core/buffer_cache/buffer_cache.h | 93 | ||||
| -rw-r--r-- | src/video_core/buffer_cache/map_interval.h | 23 |
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 | |||
| 57 | private: | 78 | private: |
| 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{}; |