diff options
| author | 2021-07-04 18:08:49 +0200 | |
|---|---|---|
| committer | 2021-07-09 22:20:36 +0200 | |
| commit | 0e4d4b4beba3521dbadfe489b54309ba33dc65f2 (patch) | |
| tree | ec9087c006f1a2dc65886e3db646020e0ef7f56c /src/video_core/buffer_cache | |
| parent | Merge pull request #6573 from lat9nq/cpu-settings-cleanup-2 (diff) | |
| download | yuzu-0e4d4b4beba3521dbadfe489b54309ba33dc65f2.tar.gz yuzu-0e4d4b4beba3521dbadfe489b54309ba33dc65f2.tar.xz yuzu-0e4d4b4beba3521dbadfe489b54309ba33dc65f2.zip | |
Buffer Cache: Fix High Downloads and don't predownload on Extreme.
Diffstat (limited to 'src/video_core/buffer_cache')
| -rw-r--r-- | src/video_core/buffer_cache/buffer_base.h | 14 | ||||
| -rw-r--r-- | src/video_core/buffer_cache/buffer_cache.h | 195 |
2 files changed, 120 insertions, 89 deletions
diff --git a/src/video_core/buffer_cache/buffer_base.h b/src/video_core/buffer_cache/buffer_base.h index b121d36a3..a56b4c3a8 100644 --- a/src/video_core/buffer_cache/buffer_base.h +++ b/src/video_core/buffer_cache/buffer_base.h | |||
| @@ -226,19 +226,19 @@ public: | |||
| 226 | /// Call 'func' for each CPU modified range and unmark those pages as CPU modified | 226 | /// Call 'func' for each CPU modified range and unmark those pages as CPU modified |
| 227 | template <typename Func> | 227 | template <typename Func> |
| 228 | void ForEachUploadRange(VAddr query_cpu_range, u64 size, Func&& func) { | 228 | void ForEachUploadRange(VAddr query_cpu_range, u64 size, Func&& func) { |
| 229 | ForEachModifiedRange<Type::CPU>(query_cpu_range, size, func); | 229 | ForEachModifiedRange<Type::CPU>(query_cpu_range, size, true, func); |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | /// Call 'func' for each GPU modified range and unmark those pages as GPU modified | 232 | /// Call 'func' for each GPU modified range and unmark those pages as GPU modified |
| 233 | template <typename Func> | 233 | template <typename Func> |
| 234 | void ForEachDownloadRange(VAddr query_cpu_range, u64 size, Func&& func) { | 234 | void ForEachDownloadRange(VAddr query_cpu_range, u64 size, bool clear, Func&& func) { |
| 235 | ForEachModifiedRange<Type::GPU>(query_cpu_range, size, func); | 235 | ForEachModifiedRange<Type::GPU>(query_cpu_range, size, clear, func); |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | /// Call 'func' for each GPU modified range and unmark those pages as GPU modified | 238 | /// Call 'func' for each GPU modified range and unmark those pages as GPU modified |
| 239 | template <typename Func> | 239 | template <typename Func> |
| 240 | void ForEachDownloadRange(Func&& func) { | 240 | void ForEachDownloadRange(Func&& func) { |
| 241 | ForEachModifiedRange<Type::GPU>(cpu_addr, SizeBytes(), func); | 241 | ForEachModifiedRange<Type::GPU>(cpu_addr, SizeBytes(), true, func); |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | /// Mark buffer as picked | 244 | /// Mark buffer as picked |
| @@ -415,7 +415,7 @@ private: | |||
| 415 | * @param func Function to call for each turned off region | 415 | * @param func Function to call for each turned off region |
| 416 | */ | 416 | */ |
| 417 | template <Type type, typename Func> | 417 | template <Type type, typename Func> |
| 418 | void ForEachModifiedRange(VAddr query_cpu_range, s64 size, Func&& func) { | 418 | void ForEachModifiedRange(VAddr query_cpu_range, s64 size, bool clear, Func&& func) { |
| 419 | static_assert(type != Type::Untracked); | 419 | static_assert(type != Type::Untracked); |
| 420 | 420 | ||
| 421 | const s64 difference = query_cpu_range - cpu_addr; | 421 | const s64 difference = query_cpu_range - cpu_addr; |
| @@ -467,7 +467,9 @@ private: | |||
| 467 | bits = (bits << left_offset) >> left_offset; | 467 | bits = (bits << left_offset) >> left_offset; |
| 468 | 468 | ||
| 469 | const u64 current_word = state_words[word_index] & bits; | 469 | const u64 current_word = state_words[word_index] & bits; |
| 470 | state_words[word_index] &= ~bits; | 470 | if (clear) { |
| 471 | state_words[word_index] &= ~bits; | ||
| 472 | } | ||
| 471 | 473 | ||
| 472 | if constexpr (type == Type::CPU) { | 474 | if constexpr (type == Type::CPU) { |
| 473 | const u64 current_bits = untracked_words[word_index] & bits; | 475 | const u64 current_bits = untracked_words[word_index] & bits; |
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index cad7f902d..d28930e80 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <unordered_map> | 14 | #include <unordered_map> |
| 15 | #include <vector> | 15 | #include <vector> |
| 16 | 16 | ||
| 17 | #include <boost/icl/interval_set.hpp> | ||
| 17 | #include <boost/container/small_vector.hpp> | 18 | #include <boost/container/small_vector.hpp> |
| 18 | 19 | ||
| 19 | #include "common/common_types.h" | 20 | #include "common/common_types.h" |
| @@ -77,6 +78,9 @@ class BufferCache { | |||
| 77 | using Runtime = typename P::Runtime; | 78 | using Runtime = typename P::Runtime; |
| 78 | using Buffer = typename P::Buffer; | 79 | using Buffer = typename P::Buffer; |
| 79 | 80 | ||
| 81 | using IntervalSet = boost::icl::interval_set<VAddr>; | ||
| 82 | using IntervalType = typename IntervalSet::interval_type; | ||
| 83 | |||
| 80 | struct Empty {}; | 84 | struct Empty {}; |
| 81 | 85 | ||
| 82 | struct OverlapResult { | 86 | struct OverlapResult { |
| @@ -153,6 +157,7 @@ public: | |||
| 153 | 157 | ||
| 154 | /// Commit asynchronous downloads | 158 | /// Commit asynchronous downloads |
| 155 | void CommitAsyncFlushes(); | 159 | void CommitAsyncFlushes(); |
| 160 | void CommitAsyncFlushesHigh(); | ||
| 156 | 161 | ||
| 157 | /// Pop asynchronous downloads | 162 | /// Pop asynchronous downloads |
| 158 | void PopAsyncFlushes(); | 163 | void PopAsyncFlushes(); |
| @@ -160,6 +165,9 @@ public: | |||
| 160 | /// Return true when a CPU region is modified from the GPU | 165 | /// Return true when a CPU region is modified from the GPU |
| 161 | [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size); | 166 | [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size); |
| 162 | 167 | ||
| 168 | /// Return true when a CPU region is modified from the GPU | ||
| 169 | [[nodiscard]] bool IsRegionCpuModified(VAddr addr, size_t size); | ||
| 170 | |||
| 163 | std::mutex mutex; | 171 | std::mutex mutex; |
| 164 | 172 | ||
| 165 | private: | 173 | private: |
| @@ -272,8 +280,6 @@ private: | |||
| 272 | 280 | ||
| 273 | void DeleteBuffer(BufferId buffer_id); | 281 | void DeleteBuffer(BufferId buffer_id); |
| 274 | 282 | ||
| 275 | void ReplaceBufferDownloads(BufferId old_buffer_id, BufferId new_buffer_id); | ||
| 276 | |||
| 277 | void NotifyBufferDeletion(); | 283 | void NotifyBufferDeletion(); |
| 278 | 284 | ||
| 279 | [[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr) const; | 285 | [[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr) const; |
| @@ -328,8 +334,9 @@ private: | |||
| 328 | std::vector<BufferId> cached_write_buffer_ids; | 334 | std::vector<BufferId> cached_write_buffer_ids; |
| 329 | 335 | ||
| 330 | // TODO: This data structure is not optimal and it should be reworked | 336 | // TODO: This data structure is not optimal and it should be reworked |
| 331 | std::vector<BufferId> uncommitted_downloads; | 337 | IntervalSet uncommitted_ranges; |
| 332 | std::deque<std::vector<BufferId>> committed_downloads; | 338 | std::deque<IntervalSet> committed_ranges; |
| 339 | std::deque<boost::container::small_vector<BufferCopy, 4>> pending_downloads; | ||
| 333 | 340 | ||
| 334 | size_t immediate_buffer_capacity = 0; | 341 | size_t immediate_buffer_capacity = 0; |
| 335 | std::unique_ptr<u8[]> immediate_buffer_alloc; | 342 | std::unique_ptr<u8[]> immediate_buffer_alloc; |
| @@ -547,82 +554,101 @@ void BufferCache<P>::FlushCachedWrites() { | |||
| 547 | 554 | ||
| 548 | template <class P> | 555 | template <class P> |
| 549 | bool BufferCache<P>::HasUncommittedFlushes() const noexcept { | 556 | bool BufferCache<P>::HasUncommittedFlushes() const noexcept { |
| 550 | return !uncommitted_downloads.empty(); | 557 | return !uncommitted_ranges.empty(); |
| 551 | } | 558 | } |
| 552 | 559 | ||
| 553 | template <class P> | 560 | template <class P> |
| 554 | bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept { | 561 | bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept { |
| 555 | return !committed_downloads.empty() && !committed_downloads.front().empty(); | 562 | return false; |
| 556 | } | ||
| 557 | |||
| 558 | template <class P> | ||
| 559 | void BufferCache<P>::CommitAsyncFlushes() { | ||
| 560 | // This is intentionally passing the value by copy | ||
| 561 | committed_downloads.push_front(uncommitted_downloads); | ||
| 562 | uncommitted_downloads.clear(); | ||
| 563 | } | 563 | } |
| 564 | 564 | ||
| 565 | template <class P> | 565 | template <class P> |
| 566 | void BufferCache<P>::PopAsyncFlushes() { | 566 | void BufferCache<P>::CommitAsyncFlushesHigh() { |
| 567 | if (committed_downloads.empty()) { | 567 | const IntervalSet& intervals = uncommitted_ranges; |
| 568 | return; | 568 | if (intervals.empty()) { |
| 569 | } | 569 | return; |
| 570 | auto scope_exit_pop_download = detail::ScopeExit([this] { committed_downloads.pop_back(); }); | 570 | } |
| 571 | const std::span<const BufferId> download_ids = committed_downloads.back(); | 571 | MICROPROFILE_SCOPE(GPU_DownloadMemory); |
| 572 | if (download_ids.empty()) { | 572 | |
| 573 | return; | 573 | boost::container::small_vector<std::pair<BufferCopy, BufferId>, 1> downloads; |
| 574 | } | 574 | u64 total_size_bytes = 0; |
| 575 | MICROPROFILE_SCOPE(GPU_DownloadMemory); | 575 | u64 largest_copy = 0; |
| 576 | 576 | for (auto& interval : intervals) { | |
| 577 | boost::container::small_vector<std::pair<BufferCopy, BufferId>, 1> downloads; | 577 | const std::size_t size = interval.upper() - interval.lower(); |
| 578 | u64 total_size_bytes = 0; | 578 | const VAddr cpu_addr = interval.lower(); |
| 579 | u64 largest_copy = 0; | 579 | const VAddr cpu_addr_end = interval.upper(); |
| 580 | for (const BufferId buffer_id : download_ids) { | 580 | ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) { |
| 581 | slot_buffers[buffer_id].ForEachDownloadRange([&](u64 range_offset, u64 range_size) { | 581 | boost::container::small_vector<BufferCopy, 1> copies; |
| 582 | buffer.ForEachDownloadRange(cpu_addr, size, false, [&](u64 range_offset, u64 range_size) { | ||
| 583 | VAddr cpu_addr_base = buffer.CpuAddr() + range_offset; | ||
| 584 | VAddr cpu_addr_end2 = cpu_addr_base + range_size; | ||
| 585 | const s64 difference = s64(cpu_addr_end2 - cpu_addr_end); | ||
| 586 | cpu_addr_end2 -= u64(std::max<s64>(difference, 0)); | ||
| 587 | const s64 difference2 = s64(cpu_addr - cpu_addr_base); | ||
| 588 | cpu_addr_base += u64(std::max<s64>(difference2, 0)); | ||
| 589 | const u64 new_size = cpu_addr_end2 - cpu_addr_base; | ||
| 590 | const u64 new_offset = cpu_addr_base - buffer.CpuAddr(); | ||
| 591 | ASSERT(!IsRegionCpuModified(cpu_addr_base, new_size)); | ||
| 582 | downloads.push_back({ | 592 | downloads.push_back({ |
| 583 | BufferCopy{ | 593 | BufferCopy{ |
| 584 | .src_offset = range_offset, | 594 | .src_offset = new_offset, |
| 585 | .dst_offset = total_size_bytes, | 595 | .dst_offset = total_size_bytes, |
| 586 | .size = range_size, | 596 | .size = new_size, |
| 587 | }, | 597 | }, |
| 588 | buffer_id, | 598 | buffer_id, |
| 589 | }); | 599 | }); |
| 590 | total_size_bytes += range_size; | 600 | total_size_bytes += new_size; |
| 591 | largest_copy = std::max(largest_copy, range_size); | 601 | buffer.UnmarkRegionAsGpuModified(cpu_addr_base, new_size); |
| 592 | }); | 602 | largest_copy = std::max(largest_copy, new_size); |
| 593 | } | 603 | }); |
| 594 | if (downloads.empty()) { | 604 | }); |
| 595 | return; | 605 | } |
| 596 | } | 606 | if (downloads.empty()) { |
| 597 | if constexpr (USE_MEMORY_MAPS) { | 607 | return; |
| 598 | auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes); | 608 | } |
| 599 | for (auto& [copy, buffer_id] : downloads) { | 609 | if constexpr (USE_MEMORY_MAPS) { |
| 600 | // Have in mind the staging buffer offset for the copy | 610 | auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes); |
| 601 | copy.dst_offset += download_staging.offset; | 611 | for (auto& [copy, buffer_id] : downloads) { |
| 602 | const std::array copies{copy}; | 612 | // Have in mind the staging buffer offset for the copy |
| 603 | runtime.CopyBuffer(download_staging.buffer, slot_buffers[buffer_id], copies); | 613 | copy.dst_offset += download_staging.offset; |
| 604 | } | 614 | const std::array copies{copy}; |
| 605 | runtime.Finish(); | 615 | runtime.CopyBuffer(download_staging.buffer, slot_buffers[buffer_id], copies); |
| 606 | for (const auto& [copy, buffer_id] : downloads) { | 616 | } |
| 607 | const Buffer& buffer = slot_buffers[buffer_id]; | 617 | runtime.Finish(); |
| 608 | const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset; | 618 | for (const auto& [copy, buffer_id] : downloads) { |
| 609 | // Undo the modified offset | 619 | const Buffer& buffer = slot_buffers[buffer_id]; |
| 610 | const u64 dst_offset = copy.dst_offset - download_staging.offset; | 620 | const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset; |
| 611 | const u8* read_mapped_memory = download_staging.mapped_span.data() + dst_offset; | 621 | // Undo the modified offset |
| 612 | cpu_memory.WriteBlockUnsafe(cpu_addr, read_mapped_memory, copy.size); | 622 | const u64 dst_offset = copy.dst_offset - download_staging.offset; |
| 613 | } | 623 | const u8* read_mapped_memory = download_staging.mapped_span.data() + dst_offset; |
| 624 | cpu_memory.WriteBlockUnsafe(cpu_addr, read_mapped_memory, copy.size); | ||
| 625 | } | ||
| 626 | } else { | ||
| 627 | const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy); | ||
| 628 | for (const auto& [copy, buffer_id] : downloads) { | ||
| 629 | Buffer& buffer = slot_buffers[buffer_id]; | ||
| 630 | buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size)); | ||
| 631 | const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset; | ||
| 632 | cpu_memory.WriteBlockUnsafe(cpu_addr, immediate_buffer.data(), copy.size); | ||
| 633 | } | ||
| 634 | } | ||
| 635 | } | ||
| 636 | |||
| 637 | template <class P> | ||
| 638 | void BufferCache<P>::CommitAsyncFlushes() { | ||
| 639 | if (Settings::values.gpu_accuracy.GetValue() == Settings::GPUAccuracy::High) { | ||
| 640 | CommitAsyncFlushesHigh(); | ||
| 614 | } else { | 641 | } else { |
| 615 | const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy); | 642 | uncommitted_ranges.clear(); |
| 616 | for (const auto& [copy, buffer_id] : downloads) { | ||
| 617 | Buffer& buffer = slot_buffers[buffer_id]; | ||
| 618 | buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size)); | ||
| 619 | const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset; | ||
| 620 | cpu_memory.WriteBlockUnsafe(cpu_addr, immediate_buffer.data(), copy.size); | ||
| 621 | } | ||
| 622 | } | 643 | } |
| 623 | } | 644 | } |
| 624 | 645 | ||
| 625 | template <class P> | 646 | template <class P> |
| 647 | void BufferCache<P>::PopAsyncFlushes() { | ||
| 648 | |||
| 649 | } | ||
| 650 | |||
| 651 | template <class P> | ||
| 626 | bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) { | 652 | bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) { |
| 627 | const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE); | 653 | const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE); |
| 628 | for (u64 page = addr >> PAGE_BITS; page < page_end;) { | 654 | for (u64 page = addr >> PAGE_BITS; page < page_end;) { |
| @@ -642,6 +668,25 @@ bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) { | |||
| 642 | } | 668 | } |
| 643 | 669 | ||
| 644 | template <class P> | 670 | template <class P> |
| 671 | bool BufferCache<P>::IsRegionCpuModified(VAddr addr, size_t size) { | ||
| 672 | const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE); | ||
| 673 | for (u64 page = addr >> PAGE_BITS; page < page_end;) { | ||
| 674 | const BufferId image_id = page_table[page]; | ||
| 675 | if (!image_id) { | ||
| 676 | ++page; | ||
| 677 | continue; | ||
| 678 | } | ||
| 679 | Buffer& buffer = slot_buffers[image_id]; | ||
| 680 | if (buffer.IsRegionCpuModified(addr, size)) { | ||
| 681 | return true; | ||
| 682 | } | ||
| 683 | const VAddr end_addr = buffer.CpuAddr() + buffer.SizeBytes(); | ||
| 684 | page = Common::DivCeil(end_addr, PAGE_SIZE); | ||
| 685 | } | ||
| 686 | return false; | ||
| 687 | } | ||
| 688 | |||
| 689 | template <class P> | ||
| 645 | void BufferCache<P>::BindHostIndexBuffer() { | 690 | void BufferCache<P>::BindHostIndexBuffer() { |
| 646 | Buffer& buffer = slot_buffers[index_buffer.buffer_id]; | 691 | Buffer& buffer = slot_buffers[index_buffer.buffer_id]; |
| 647 | TouchBuffer(buffer); | 692 | TouchBuffer(buffer); |
| @@ -1010,16 +1055,13 @@ void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 s | |||
| 1010 | Buffer& buffer = slot_buffers[buffer_id]; | 1055 | Buffer& buffer = slot_buffers[buffer_id]; |
| 1011 | buffer.MarkRegionAsGpuModified(cpu_addr, size); | 1056 | buffer.MarkRegionAsGpuModified(cpu_addr, size); |
| 1012 | 1057 | ||
| 1013 | const bool is_accuracy_high = Settings::IsGPULevelHigh(); | 1058 | const bool is_accuracy_high = Settings::values.gpu_accuracy.GetValue() == Settings::GPUAccuracy::High; |
| 1014 | const bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue(); | 1059 | const bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue(); |
| 1015 | if (!is_accuracy_high || !is_async) { | 1060 | if (!is_async && !is_accuracy_high) { |
| 1016 | return; | ||
| 1017 | } | ||
| 1018 | if (std::ranges::find(uncommitted_downloads, buffer_id) != uncommitted_downloads.end()) { | ||
| 1019 | // Already inserted | ||
| 1020 | return; | 1061 | return; |
| 1021 | } | 1062 | } |
| 1022 | uncommitted_downloads.push_back(buffer_id); | 1063 | const IntervalType base_interval{cpu_addr, cpu_addr + size}; |
| 1064 | uncommitted_ranges.add(base_interval); | ||
| 1023 | } | 1065 | } |
| 1024 | 1066 | ||
| 1025 | template <class P> | 1067 | template <class P> |
| @@ -1103,7 +1145,6 @@ void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, | |||
| 1103 | if (!copies.empty()) { | 1145 | if (!copies.empty()) { |
| 1104 | runtime.CopyBuffer(slot_buffers[new_buffer_id], overlap, copies); | 1146 | runtime.CopyBuffer(slot_buffers[new_buffer_id], overlap, copies); |
| 1105 | } | 1147 | } |
| 1106 | ReplaceBufferDownloads(overlap_id, new_buffer_id); | ||
| 1107 | DeleteBuffer(overlap_id); | 1148 | DeleteBuffer(overlap_id); |
| 1108 | } | 1149 | } |
| 1109 | 1150 | ||
| @@ -1244,7 +1285,7 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 si | |||
| 1244 | boost::container::small_vector<BufferCopy, 1> copies; | 1285 | boost::container::small_vector<BufferCopy, 1> copies; |
| 1245 | u64 total_size_bytes = 0; | 1286 | u64 total_size_bytes = 0; |
| 1246 | u64 largest_copy = 0; | 1287 | u64 largest_copy = 0; |
| 1247 | buffer.ForEachDownloadRange(cpu_addr, size, [&](u64 range_offset, u64 range_size) { | 1288 | buffer.ForEachDownloadRange(cpu_addr, size, true, [&](u64 range_offset, u64 range_size) { |
| 1248 | copies.push_back(BufferCopy{ | 1289 | copies.push_back(BufferCopy{ |
| 1249 | .src_offset = range_offset, | 1290 | .src_offset = range_offset, |
| 1250 | .dst_offset = total_size_bytes, | 1291 | .dst_offset = total_size_bytes, |
| @@ -1316,18 +1357,6 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id) { | |||
| 1316 | } | 1357 | } |
| 1317 | 1358 | ||
| 1318 | template <class P> | 1359 | template <class P> |
| 1319 | void BufferCache<P>::ReplaceBufferDownloads(BufferId old_buffer_id, BufferId new_buffer_id) { | ||
| 1320 | const auto replace = [old_buffer_id, new_buffer_id](std::vector<BufferId>& buffers) { | ||
| 1321 | std::ranges::replace(buffers, old_buffer_id, new_buffer_id); | ||
| 1322 | if (auto it = std::ranges::find(buffers, new_buffer_id); it != buffers.end()) { | ||
| 1323 | buffers.erase(std::remove(it + 1, buffers.end(), new_buffer_id), buffers.end()); | ||
| 1324 | } | ||
| 1325 | }; | ||
| 1326 | replace(uncommitted_downloads); | ||
| 1327 | std::ranges::for_each(committed_downloads, replace); | ||
| 1328 | } | ||
| 1329 | |||
| 1330 | template <class P> | ||
| 1331 | void BufferCache<P>::NotifyBufferDeletion() { | 1360 | void BufferCache<P>::NotifyBufferDeletion() { |
| 1332 | if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) { | 1361 | if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) { |
| 1333 | dirty_uniform_buffers.fill(~u32{0}); | 1362 | dirty_uniform_buffers.fill(~u32{0}); |