diff options
Diffstat (limited to 'src/video_core/buffer_cache')
| -rw-r--r-- | src/video_core/buffer_cache/buffer_block.h | 27 | ||||
| -rw-r--r-- | src/video_core/buffer_cache/buffer_cache.h | 199 |
2 files changed, 112 insertions, 114 deletions
diff --git a/src/video_core/buffer_cache/buffer_block.h b/src/video_core/buffer_cache/buffer_block.h index e35ee0b67..e64170e66 100644 --- a/src/video_core/buffer_cache/buffer_block.h +++ b/src/video_core/buffer_cache/buffer_block.h | |||
| @@ -15,48 +15,47 @@ namespace VideoCommon { | |||
| 15 | 15 | ||
| 16 | class BufferBlock { | 16 | class BufferBlock { |
| 17 | public: | 17 | public: |
| 18 | bool Overlaps(const VAddr start, const VAddr end) const { | 18 | bool Overlaps(VAddr start, VAddr end) const { |
| 19 | return (cpu_addr < end) && (cpu_addr_end > start); | 19 | return (cpu_addr < end) && (cpu_addr_end > start); |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | bool IsInside(const VAddr other_start, const VAddr other_end) const { | 22 | bool IsInside(VAddr other_start, VAddr other_end) const { |
| 23 | return cpu_addr <= other_start && other_end <= cpu_addr_end; | 23 | return cpu_addr <= other_start && other_end <= cpu_addr_end; |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | std::size_t GetOffset(const VAddr in_addr) { | 26 | std::size_t Offset(VAddr in_addr) const { |
| 27 | return static_cast<std::size_t>(in_addr - cpu_addr); | 27 | return static_cast<std::size_t>(in_addr - cpu_addr); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | VAddr GetCpuAddr() const { | 30 | VAddr CpuAddr() const { |
| 31 | return cpu_addr; | 31 | return cpu_addr; |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | VAddr GetCpuAddrEnd() const { | 34 | VAddr CpuAddrEnd() const { |
| 35 | return cpu_addr_end; | 35 | return cpu_addr_end; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | void SetCpuAddr(const VAddr new_addr) { | 38 | void SetCpuAddr(VAddr new_addr) { |
| 39 | cpu_addr = new_addr; | 39 | cpu_addr = new_addr; |
| 40 | cpu_addr_end = new_addr + size; | 40 | cpu_addr_end = new_addr + size; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | std::size_t GetSize() const { | 43 | std::size_t Size() const { |
| 44 | return size; | 44 | return size; |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | void SetEpoch(u64 new_epoch) { | 47 | u64 Epoch() const { |
| 48 | epoch = new_epoch; | 48 | return epoch; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | u64 GetEpoch() { | 51 | void SetEpoch(u64 new_epoch) { |
| 52 | return epoch; | 52 | epoch = new_epoch; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | protected: | 55 | protected: |
| 56 | explicit BufferBlock(VAddr cpu_addr, const std::size_t size) : size{size} { | 56 | explicit BufferBlock(VAddr cpu_addr_, std::size_t size_) : size{size_} { |
| 57 | SetCpuAddr(cpu_addr); | 57 | SetCpuAddr(cpu_addr_); |
| 58 | } | 58 | } |
| 59 | ~BufferBlock() = default; | ||
| 60 | 59 | ||
| 61 | private: | 60 | private: |
| 62 | VAddr cpu_addr{}; | 61 | VAddr cpu_addr{}; |
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index b88fce2cd..efc480d08 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -30,12 +30,16 @@ | |||
| 30 | 30 | ||
| 31 | namespace VideoCommon { | 31 | namespace VideoCommon { |
| 32 | 32 | ||
| 33 | template <typename OwnerBuffer, typename BufferType, typename StreamBuffer> | 33 | template <typename Buffer, typename BufferType, typename StreamBuffer> |
| 34 | class BufferCache { | 34 | class BufferCache { |
| 35 | using IntervalSet = boost::icl::interval_set<VAddr>; | 35 | using IntervalSet = boost::icl::interval_set<VAddr>; |
| 36 | using IntervalType = typename IntervalSet::interval_type; | 36 | using IntervalType = typename IntervalSet::interval_type; |
| 37 | using VectorMapInterval = boost::container::small_vector<MapInterval*, 1>; | 37 | using VectorMapInterval = boost::container::small_vector<MapInterval*, 1>; |
| 38 | 38 | ||
| 39 | static constexpr u64 WRITE_PAGE_BIT = 11; | ||
| 40 | static constexpr u64 BLOCK_PAGE_BITS = 21; | ||
| 41 | static constexpr u64 BLOCK_PAGE_SIZE = 1ULL << BLOCK_PAGE_BITS; | ||
| 42 | |||
| 39 | public: | 43 | public: |
| 40 | using BufferInfo = std::pair<BufferType, u64>; | 44 | using BufferInfo = std::pair<BufferType, u64>; |
| 41 | 45 | ||
| @@ -82,7 +86,7 @@ public: | |||
| 82 | } | 86 | } |
| 83 | } | 87 | } |
| 84 | 88 | ||
| 85 | OwnerBuffer block = GetBlock(cpu_addr, size); | 89 | Buffer* const block = GetBlock(cpu_addr, size); |
| 86 | MapInterval* const map = MapAddress(block, gpu_addr, cpu_addr, size); | 90 | MapInterval* const map = MapAddress(block, gpu_addr, cpu_addr, size); |
| 87 | if (!map) { | 91 | if (!map) { |
| 88 | return {GetEmptyBuffer(size), 0}; | 92 | return {GetEmptyBuffer(size), 0}; |
| @@ -98,7 +102,7 @@ public: | |||
| 98 | } | 102 | } |
| 99 | } | 103 | } |
| 100 | 104 | ||
| 101 | return {ToHandle(block), static_cast<u64>(block->GetOffset(cpu_addr))}; | 105 | return {block->Handle(), static_cast<u64>(block->Offset(cpu_addr))}; |
| 102 | } | 106 | } |
| 103 | 107 | ||
| 104 | /// Uploads from a host memory. Returns the OpenGL buffer where it's located and its offset. | 108 | /// Uploads from a host memory. Returns the OpenGL buffer where it's located and its offset. |
| @@ -125,16 +129,18 @@ public: | |||
| 125 | return std::exchange(invalidated, false); | 129 | return std::exchange(invalidated, false); |
| 126 | } | 130 | } |
| 127 | 131 | ||
| 132 | /// Function called at the end of each frame, inteded for deferred operations | ||
| 128 | void TickFrame() { | 133 | void TickFrame() { |
| 129 | ++epoch; | 134 | ++epoch; |
| 135 | |||
| 130 | while (!pending_destruction.empty()) { | 136 | while (!pending_destruction.empty()) { |
| 131 | // Delay at least 4 frames before destruction. | 137 | // Delay at least 4 frames before destruction. |
| 132 | // This is due to triple buffering happening on some drivers. | 138 | // This is due to triple buffering happening on some drivers. |
| 133 | static constexpr u64 epochs_to_destroy = 5; | 139 | static constexpr u64 epochs_to_destroy = 5; |
| 134 | if (pending_destruction.front()->GetEpoch() + epochs_to_destroy > epoch) { | 140 | if (pending_destruction.front()->Epoch() + epochs_to_destroy > epoch) { |
| 135 | break; | 141 | break; |
| 136 | } | 142 | } |
| 137 | pending_destruction.pop_front(); | 143 | pending_destruction.pop(); |
| 138 | } | 144 | } |
| 139 | } | 145 | } |
| 140 | 146 | ||
| @@ -249,23 +255,21 @@ public: | |||
| 249 | 255 | ||
| 250 | protected: | 256 | protected: |
| 251 | explicit BufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system, | 257 | explicit BufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system, |
| 252 | std::unique_ptr<StreamBuffer> stream_buffer) | 258 | std::unique_ptr<StreamBuffer> stream_buffer_) |
| 253 | : rasterizer{rasterizer}, system{system}, stream_buffer{std::move(stream_buffer)}, | 259 | : rasterizer{rasterizer}, system{system}, stream_buffer{std::move(stream_buffer_)}, |
| 254 | stream_buffer_handle{this->stream_buffer->GetHandle()} {} | 260 | stream_buffer_handle{stream_buffer->Handle()} {} |
| 255 | 261 | ||
| 256 | ~BufferCache() = default; | 262 | ~BufferCache() = default; |
| 257 | 263 | ||
| 258 | virtual BufferType ToHandle(const OwnerBuffer& storage) = 0; | 264 | virtual std::shared_ptr<Buffer> CreateBlock(VAddr cpu_addr, std::size_t size) = 0; |
| 259 | 265 | ||
| 260 | virtual OwnerBuffer CreateBlock(VAddr cpu_addr, std::size_t size) = 0; | 266 | virtual void UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size, |
| 261 | |||
| 262 | virtual void UploadBlockData(const OwnerBuffer& buffer, std::size_t offset, std::size_t size, | ||
| 263 | const u8* data) = 0; | 267 | const u8* data) = 0; |
| 264 | 268 | ||
| 265 | virtual void DownloadBlockData(const OwnerBuffer& buffer, std::size_t offset, std::size_t size, | 269 | virtual void DownloadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size, |
| 266 | u8* data) = 0; | 270 | u8* data) = 0; |
| 267 | 271 | ||
| 268 | virtual void CopyBlock(const OwnerBuffer& src, const OwnerBuffer& dst, std::size_t src_offset, | 272 | virtual void CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset, |
| 269 | std::size_t dst_offset, std::size_t size) = 0; | 273 | std::size_t dst_offset, std::size_t size) = 0; |
| 270 | 274 | ||
| 271 | virtual BufferInfo ConstBufferUpload(const void* raw_pointer, std::size_t size) { | 275 | virtual BufferInfo ConstBufferUpload(const void* raw_pointer, std::size_t size) { |
| @@ -321,7 +325,7 @@ protected: | |||
| 321 | } | 325 | } |
| 322 | 326 | ||
| 323 | private: | 327 | private: |
| 324 | MapInterval* MapAddress(const OwnerBuffer& block, GPUVAddr gpu_addr, VAddr cpu_addr, | 328 | MapInterval* MapAddress(const Buffer* block, GPUVAddr gpu_addr, VAddr cpu_addr, |
| 325 | std::size_t size) { | 329 | std::size_t size) { |
| 326 | const VectorMapInterval overlaps = GetMapsInRange(cpu_addr, size); | 330 | const VectorMapInterval overlaps = GetMapsInRange(cpu_addr, size); |
| 327 | if (overlaps.empty()) { | 331 | if (overlaps.empty()) { |
| @@ -329,11 +333,11 @@ private: | |||
| 329 | const VAddr cpu_addr_end = cpu_addr + size; | 333 | const VAddr cpu_addr_end = cpu_addr + size; |
| 330 | if (memory_manager.IsGranularRange(gpu_addr, size)) { | 334 | if (memory_manager.IsGranularRange(gpu_addr, size)) { |
| 331 | u8* host_ptr = memory_manager.GetPointer(gpu_addr); | 335 | u8* host_ptr = memory_manager.GetPointer(gpu_addr); |
| 332 | UploadBlockData(block, block->GetOffset(cpu_addr), size, host_ptr); | 336 | UploadBlockData(*block, block->Offset(cpu_addr), size, host_ptr); |
| 333 | } else { | 337 | } else { |
| 334 | staging_buffer.resize(size); | 338 | staging_buffer.resize(size); |
| 335 | memory_manager.ReadBlockUnsafe(gpu_addr, staging_buffer.data(), size); | 339 | memory_manager.ReadBlockUnsafe(gpu_addr, staging_buffer.data(), size); |
| 336 | UploadBlockData(block, block->GetOffset(cpu_addr), size, staging_buffer.data()); | 340 | UploadBlockData(*block, block->Offset(cpu_addr), size, staging_buffer.data()); |
| 337 | } | 341 | } |
| 338 | return Register(MapInterval(cpu_addr, cpu_addr_end, gpu_addr)); | 342 | return Register(MapInterval(cpu_addr, cpu_addr_end, gpu_addr)); |
| 339 | } | 343 | } |
| @@ -376,7 +380,7 @@ private: | |||
| 376 | return map; | 380 | return map; |
| 377 | } | 381 | } |
| 378 | 382 | ||
| 379 | void UpdateBlock(const OwnerBuffer& block, VAddr start, VAddr end, | 383 | void UpdateBlock(const Buffer* block, VAddr start, VAddr end, |
| 380 | const VectorMapInterval& overlaps) { | 384 | const VectorMapInterval& overlaps) { |
| 381 | const IntervalType base_interval{start, end}; | 385 | const IntervalType base_interval{start, end}; |
| 382 | IntervalSet interval_set{}; | 386 | IntervalSet interval_set{}; |
| @@ -386,13 +390,13 @@ private: | |||
| 386 | interval_set.subtract(subtract); | 390 | interval_set.subtract(subtract); |
| 387 | } | 391 | } |
| 388 | for (auto& interval : interval_set) { | 392 | for (auto& interval : interval_set) { |
| 389 | std::size_t size = interval.upper() - interval.lower(); | 393 | const std::size_t size = interval.upper() - interval.lower(); |
| 390 | if (size > 0) { | 394 | if (size == 0) { |
| 391 | staging_buffer.resize(size); | 395 | continue; |
| 392 | system.Memory().ReadBlockUnsafe(interval.lower(), staging_buffer.data(), size); | ||
| 393 | UploadBlockData(block, block->GetOffset(interval.lower()), size, | ||
| 394 | staging_buffer.data()); | ||
| 395 | } | 396 | } |
| 397 | staging_buffer.resize(size); | ||
| 398 | system.Memory().ReadBlockUnsafe(interval.lower(), staging_buffer.data(), size); | ||
| 399 | UploadBlockData(*block, block->Offset(interval.lower()), size, staging_buffer.data()); | ||
| 396 | } | 400 | } |
| 397 | } | 401 | } |
| 398 | 402 | ||
| @@ -422,10 +426,14 @@ private: | |||
| 422 | } | 426 | } |
| 423 | 427 | ||
| 424 | void FlushMap(MapInterval* map) { | 428 | void FlushMap(MapInterval* map) { |
| 429 | const auto it = blocks.find(map->start >> BLOCK_PAGE_BITS); | ||
| 430 | ASSERT_OR_EXECUTE(it != blocks.end(), return;); | ||
| 431 | |||
| 432 | std::shared_ptr<Buffer> block = it->second; | ||
| 433 | |||
| 425 | const std::size_t size = map->end - map->start; | 434 | const std::size_t size = map->end - map->start; |
| 426 | OwnerBuffer block = blocks[map->start >> block_page_bits]; | ||
| 427 | staging_buffer.resize(size); | 435 | staging_buffer.resize(size); |
| 428 | DownloadBlockData(block, block->GetOffset(map->start), size, staging_buffer.data()); | 436 | DownloadBlockData(*block, block->Offset(map->start), size, staging_buffer.data()); |
| 429 | system.Memory().WriteBlockUnsafe(map->start, staging_buffer.data(), size); | 437 | system.Memory().WriteBlockUnsafe(map->start, staging_buffer.data(), size); |
| 430 | map->MarkAsModified(false, 0); | 438 | map->MarkAsModified(false, 0); |
| 431 | } | 439 | } |
| @@ -448,97 +456,89 @@ private: | |||
| 448 | buffer_offset = offset_aligned; | 456 | buffer_offset = offset_aligned; |
| 449 | } | 457 | } |
| 450 | 458 | ||
| 451 | OwnerBuffer EnlargeBlock(OwnerBuffer buffer) { | 459 | std::shared_ptr<Buffer> EnlargeBlock(std::shared_ptr<Buffer> buffer) { |
| 452 | const std::size_t old_size = buffer->GetSize(); | 460 | const std::size_t old_size = buffer->Size(); |
| 453 | const std::size_t new_size = old_size + block_page_size; | 461 | const std::size_t new_size = old_size + BLOCK_PAGE_SIZE; |
| 454 | const VAddr cpu_addr = buffer->GetCpuAddr(); | 462 | const VAddr cpu_addr = buffer->CpuAddr(); |
| 455 | OwnerBuffer new_buffer = CreateBlock(cpu_addr, new_size); | 463 | std::shared_ptr<Buffer> new_buffer = CreateBlock(cpu_addr, new_size); |
| 456 | CopyBlock(buffer, new_buffer, 0, 0, old_size); | 464 | CopyBlock(*buffer, *new_buffer, 0, 0, old_size); |
| 457 | buffer->SetEpoch(epoch); | 465 | QueueDestruction(std::move(buffer)); |
| 458 | pending_destruction.push_back(buffer); | 466 | |
| 459 | const VAddr cpu_addr_end = cpu_addr + new_size - 1; | 467 | const VAddr cpu_addr_end = cpu_addr + new_size - 1; |
| 460 | u64 page_start = cpu_addr >> block_page_bits; | 468 | const u64 page_end = cpu_addr_end >> BLOCK_PAGE_BITS; |
| 461 | const u64 page_end = cpu_addr_end >> block_page_bits; | 469 | for (u64 page_start = cpu_addr >> BLOCK_PAGE_BITS; page_start <= page_end; ++page_start) { |
| 462 | while (page_start <= page_end) { | 470 | blocks.insert_or_assign(page_start, new_buffer); |
| 463 | blocks[page_start] = new_buffer; | ||
| 464 | ++page_start; | ||
| 465 | } | 471 | } |
| 472 | |||
| 466 | return new_buffer; | 473 | return new_buffer; |
| 467 | } | 474 | } |
| 468 | 475 | ||
| 469 | OwnerBuffer MergeBlocks(OwnerBuffer first, OwnerBuffer second) { | 476 | std::shared_ptr<Buffer> MergeBlocks(std::shared_ptr<Buffer> first, |
| 470 | const std::size_t size_1 = first->GetSize(); | 477 | std::shared_ptr<Buffer> second) { |
| 471 | const std::size_t size_2 = second->GetSize(); | 478 | const std::size_t size_1 = first->Size(); |
| 472 | const VAddr first_addr = first->GetCpuAddr(); | 479 | const std::size_t size_2 = second->Size(); |
| 473 | const VAddr second_addr = second->GetCpuAddr(); | 480 | const VAddr first_addr = first->CpuAddr(); |
| 481 | const VAddr second_addr = second->CpuAddr(); | ||
| 474 | const VAddr new_addr = std::min(first_addr, second_addr); | 482 | const VAddr new_addr = std::min(first_addr, second_addr); |
| 475 | const std::size_t new_size = size_1 + size_2; | 483 | const std::size_t new_size = size_1 + size_2; |
| 476 | OwnerBuffer new_buffer = CreateBlock(new_addr, new_size); | 484 | |
| 477 | CopyBlock(first, new_buffer, 0, new_buffer->GetOffset(first_addr), size_1); | 485 | std::shared_ptr<Buffer> new_buffer = CreateBlock(new_addr, new_size); |
| 478 | CopyBlock(second, new_buffer, 0, new_buffer->GetOffset(second_addr), size_2); | 486 | CopyBlock(*first, *new_buffer, 0, new_buffer->Offset(first_addr), size_1); |
| 479 | first->SetEpoch(epoch); | 487 | CopyBlock(*second, *new_buffer, 0, new_buffer->Offset(second_addr), size_2); |
| 480 | second->SetEpoch(epoch); | 488 | QueueDestruction(std::move(first)); |
| 481 | pending_destruction.push_back(first); | 489 | QueueDestruction(std::move(second)); |
| 482 | pending_destruction.push_back(second); | 490 | |
| 483 | const VAddr cpu_addr_end = new_addr + new_size - 1; | 491 | const VAddr cpu_addr_end = new_addr + new_size - 1; |
| 484 | u64 page_start = new_addr >> block_page_bits; | 492 | const u64 page_end = cpu_addr_end >> BLOCK_PAGE_BITS; |
| 485 | const u64 page_end = cpu_addr_end >> block_page_bits; | 493 | for (u64 page_start = new_addr >> BLOCK_PAGE_BITS; page_start <= page_end; ++page_start) { |
| 486 | while (page_start <= page_end) { | 494 | blocks.insert_or_assign(page_start, new_buffer); |
| 487 | blocks[page_start] = new_buffer; | ||
| 488 | ++page_start; | ||
| 489 | } | 495 | } |
| 490 | return new_buffer; | 496 | return new_buffer; |
| 491 | } | 497 | } |
| 492 | 498 | ||
| 493 | OwnerBuffer GetBlock(const VAddr cpu_addr, const std::size_t size) { | 499 | Buffer* GetBlock(VAddr cpu_addr, std::size_t size) { |
| 494 | OwnerBuffer found; | 500 | std::shared_ptr<Buffer> found; |
| 501 | |||
| 495 | const VAddr cpu_addr_end = cpu_addr + size - 1; | 502 | const VAddr cpu_addr_end = cpu_addr + size - 1; |
| 496 | u64 page_start = cpu_addr >> block_page_bits; | 503 | const u64 page_end = cpu_addr_end >> BLOCK_PAGE_BITS; |
| 497 | const u64 page_end = cpu_addr_end >> block_page_bits; | 504 | for (u64 page_start = cpu_addr >> BLOCK_PAGE_BITS; page_start <= page_end; ++page_start) { |
| 498 | while (page_start <= page_end) { | ||
| 499 | auto it = blocks.find(page_start); | 505 | auto it = blocks.find(page_start); |
| 500 | if (it == blocks.end()) { | 506 | if (it == blocks.end()) { |
| 501 | if (found) { | 507 | if (found) { |
| 502 | found = EnlargeBlock(found); | 508 | found = EnlargeBlock(found); |
| 503 | } else { | 509 | continue; |
| 504 | const VAddr start_addr = (page_start << block_page_bits); | ||
| 505 | found = CreateBlock(start_addr, block_page_size); | ||
| 506 | blocks[page_start] = found; | ||
| 507 | } | ||
| 508 | } else { | ||
| 509 | if (found) { | ||
| 510 | if (found == it->second) { | ||
| 511 | ++page_start; | ||
| 512 | continue; | ||
| 513 | } | ||
| 514 | found = MergeBlocks(found, it->second); | ||
| 515 | } else { | ||
| 516 | found = it->second; | ||
| 517 | } | 510 | } |
| 511 | const VAddr start_addr = page_start << BLOCK_PAGE_BITS; | ||
| 512 | found = CreateBlock(start_addr, BLOCK_PAGE_SIZE); | ||
| 513 | blocks.insert_or_assign(page_start, found); | ||
| 514 | continue; | ||
| 515 | } | ||
| 516 | if (!found) { | ||
| 517 | found = it->second; | ||
| 518 | continue; | ||
| 519 | } | ||
| 520 | if (found != it->second) { | ||
| 521 | found = MergeBlocks(std::move(found), it->second); | ||
| 518 | } | 522 | } |
| 519 | ++page_start; | ||
| 520 | } | 523 | } |
| 521 | return found; | 524 | return found.get(); |
| 522 | } | 525 | } |
| 523 | 526 | ||
| 524 | void MarkRegionAsWritten(const VAddr start, const VAddr end) { | 527 | void MarkRegionAsWritten(VAddr start, VAddr end) { |
| 525 | u64 page_start = start >> write_page_bit; | 528 | const u64 page_end = end >> WRITE_PAGE_BIT; |
| 526 | const u64 page_end = end >> write_page_bit; | 529 | for (u64 page_start = start >> WRITE_PAGE_BIT; page_start <= page_end; ++page_start) { |
| 527 | while (page_start <= page_end) { | ||
| 528 | auto it = written_pages.find(page_start); | 530 | auto it = written_pages.find(page_start); |
| 529 | if (it != written_pages.end()) { | 531 | if (it != written_pages.end()) { |
| 530 | it->second = it->second + 1; | 532 | it->second = it->second + 1; |
| 531 | } else { | 533 | } else { |
| 532 | written_pages[page_start] = 1; | 534 | written_pages.insert_or_assign(page_start, 1); |
| 533 | } | 535 | } |
| 534 | ++page_start; | ||
| 535 | } | 536 | } |
| 536 | } | 537 | } |
| 537 | 538 | ||
| 538 | void UnmarkRegionAsWritten(const VAddr start, const VAddr end) { | 539 | void UnmarkRegionAsWritten(VAddr start, VAddr end) { |
| 539 | u64 page_start = start >> write_page_bit; | 540 | const u64 page_end = end >> WRITE_PAGE_BIT; |
| 540 | const u64 page_end = end >> write_page_bit; | 541 | for (u64 page_start = start >> WRITE_PAGE_BIT; page_start <= page_end; ++page_start) { |
| 541 | while (page_start <= page_end) { | ||
| 542 | auto it = written_pages.find(page_start); | 542 | auto it = written_pages.find(page_start); |
| 543 | if (it != written_pages.end()) { | 543 | if (it != written_pages.end()) { |
| 544 | if (it->second > 1) { | 544 | if (it->second > 1) { |
| @@ -547,22 +547,24 @@ private: | |||
| 547 | written_pages.erase(it); | 547 | written_pages.erase(it); |
| 548 | } | 548 | } |
| 549 | } | 549 | } |
| 550 | ++page_start; | ||
| 551 | } | 550 | } |
| 552 | } | 551 | } |
| 553 | 552 | ||
| 554 | bool IsRegionWritten(const VAddr start, const VAddr end) const { | 553 | bool IsRegionWritten(VAddr start, VAddr end) const { |
| 555 | u64 page_start = start >> write_page_bit; | 554 | const u64 page_end = end >> WRITE_PAGE_BIT; |
| 556 | const u64 page_end = end >> write_page_bit; | 555 | for (u64 page_start = start >> WRITE_PAGE_BIT; page_start <= page_end; ++page_start) { |
| 557 | while (page_start <= page_end) { | ||
| 558 | if (written_pages.count(page_start) > 0) { | 556 | if (written_pages.count(page_start) > 0) { |
| 559 | return true; | 557 | return true; |
| 560 | } | 558 | } |
| 561 | ++page_start; | ||
| 562 | } | 559 | } |
| 563 | return false; | 560 | return false; |
| 564 | } | 561 | } |
| 565 | 562 | ||
| 563 | void QueueDestruction(std::shared_ptr<Buffer> buffer) { | ||
| 564 | buffer->SetEpoch(epoch); | ||
| 565 | pending_destruction.push(std::move(buffer)); | ||
| 566 | } | ||
| 567 | |||
| 566 | void MarkForAsyncFlush(MapInterval* map) { | 568 | void MarkForAsyncFlush(MapInterval* map) { |
| 567 | if (!uncommitted_flushes) { | 569 | if (!uncommitted_flushes) { |
| 568 | uncommitted_flushes = std::make_shared<std::unordered_set<MapInterval*>>(); | 570 | uncommitted_flushes = std::make_shared<std::unordered_set<MapInterval*>>(); |
| @@ -574,7 +576,7 @@ private: | |||
| 574 | Core::System& system; | 576 | Core::System& system; |
| 575 | 577 | ||
| 576 | std::unique_ptr<StreamBuffer> stream_buffer; | 578 | std::unique_ptr<StreamBuffer> stream_buffer; |
| 577 | BufferType stream_buffer_handle{}; | 579 | BufferType stream_buffer_handle; |
| 578 | 580 | ||
| 579 | bool invalidated = false; | 581 | bool invalidated = false; |
| 580 | 582 | ||
| @@ -586,18 +588,15 @@ private: | |||
| 586 | boost::intrusive::set<MapInterval, boost::intrusive::compare<MapIntervalCompare>> | 588 | boost::intrusive::set<MapInterval, boost::intrusive::compare<MapIntervalCompare>> |
| 587 | mapped_addresses; | 589 | mapped_addresses; |
| 588 | 590 | ||
| 589 | static constexpr u64 write_page_bit = 11; | ||
| 590 | std::unordered_map<u64, u32> written_pages; | 591 | std::unordered_map<u64, u32> written_pages; |
| 592 | std::unordered_map<u64, std::shared_ptr<Buffer>> blocks; | ||
| 591 | 593 | ||
| 592 | static constexpr u64 block_page_bits = 21; | 594 | std::queue<std::shared_ptr<Buffer>> pending_destruction; |
| 593 | static constexpr u64 block_page_size = 1ULL << block_page_bits; | ||
| 594 | std::unordered_map<u64, OwnerBuffer> blocks; | ||
| 595 | |||
| 596 | std::list<OwnerBuffer> pending_destruction; | ||
| 597 | u64 epoch = 0; | 595 | u64 epoch = 0; |
| 598 | u64 modified_ticks = 0; | 596 | u64 modified_ticks = 0; |
| 599 | 597 | ||
| 600 | std::vector<u8> staging_buffer; | 598 | std::vector<u8> staging_buffer; |
| 599 | |||
| 601 | std::list<MapInterval*> marked_for_unregister; | 600 | std::list<MapInterval*> marked_for_unregister; |
| 602 | 601 | ||
| 603 | std::shared_ptr<std::unordered_set<MapInterval*>> uncommitted_flushes; | 602 | std::shared_ptr<std::unordered_set<MapInterval*>> uncommitted_flushes; |