diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp index dfc3f2050..9545e828b 100644 --- a/src/video_core/buffer_cache/buffer_cache.cpp +++ b/src/video_core/buffer_cache/buffer_cache.cpp @@ -817,7 +817,7 @@ void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size, bool is_texel_buffer) { boost::container::small_vector copies; VAddr buffer_start = buffer.CpuAddr(); - memory_tracker->ForEachUploadRange( + memory_tracker->ForEachUploadRange( device_addr, size, is_written, [&](u64 device_addr_out, u64 range_size) { const u64 offset = staging_buffer.Copy(device_addr_out, range_size); copies.push_back(vk::BufferCopy{ @@ -997,6 +997,7 @@ void BufferCache::SynchronizeBuffersInRange(VAddr device_addr, u64 size) { void BufferCache::SynchronizeBuffersForDma() { RENDERER_TRACE; + LOG_WARNING(Render_Vulkan, "SYNC RANGES FOR DMA"); boost::container::small_vector buffers; boost::container::small_vector barriers; boost::container::small_vector copies; @@ -1028,7 +1029,7 @@ void BufferCache::SynchronizeBuffersForDma() { .pBufferMemoryBarriers = barriers.data(), }); for (auto* buffer : buffers) { - memory_tracker->ForEachUploadRange( + memory_tracker->ForEachUploadRange( buffer->CpuAddr(), buffer->SizeBytes(), false, [&](u64 device_addr_out, u64 range_size) { const u64 offset = staging_buffer.Copy(device_addr_out, range_size); @@ -1041,8 +1042,8 @@ void BufferCache::SynchronizeBuffersForDma() { cmdbuf.copyBuffer(staging_buffer.Handle(), buffer->Handle(), copies); copies.clear(); } - memory_tracker->UnmarkAllRegionsAsCpuModified(); MemoryBarrier(); + memory_tracker->PerformDeferredProtections(); memory_tracker->Unlock(); } diff --git a/src/video_core/buffer_cache/memory_tracker.h b/src/video_core/buffer_cache/memory_tracker.h index 6a93ee31b..b78b841fb 100644 --- a/src/video_core/buffer_cache/memory_tracker.h +++ b/src/video_core/buffer_cache/memory_tracker.h @@ -45,38 +45,29 @@ public: } /// Mark region as CPU modified, notifying the device_tracker about this change - template + template void MarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) { IterateRegions(dirty_cpu_addr, query_size, [](RegionManager* manager, u64 offset, size_t size) { std::scoped_lock lk{manager->lock}; - manager->template ChangeRegionState( + manager->template ChangeRegionState( manager->GetCpuAddr() + offset, size); }); } - /// Unmark all regions as CPU modified, notifying the device_tracker about this change - template - void UnmarkAllRegionsAsCpuModified() noexcept { - ForEachRegion([](RegionManager* manager) { - std::scoped_lock lk{manager->lock}; - manager->template ChangeAllRegionState(); - }); - } - /// Unmark region as modified from the host GPU - template + template void UnmarkRegionAsGpuModified(VAddr dirty_cpu_addr, u64 query_size) noexcept { IterateRegions(dirty_cpu_addr, query_size, [](RegionManager* manager, u64 offset, size_t size) { std::scoped_lock lk{manager->lock}; - manager->template ChangeRegionState( + manager->template ChangeRegionState( manager->GetCpuAddr() + offset, size); }); } /// Removes all protection from a page and ensures GPU data has been flushed if requested - template + template void InvalidateRegion(VAddr cpu_addr, u64 size, bool try_flush, auto&& on_flush) noexcept { IterateRegions( cpu_addr, size, @@ -90,7 +81,7 @@ public: if (try_flush && manager->template IsRegionModified(offset, size)) { return true; } - manager->template ChangeRegionState( + manager->template ChangeRegionState( manager->GetCpuAddr() + offset, size); return false; }(); @@ -101,32 +92,43 @@ public: } /// Call 'func' for each CPU modified range and unmark those pages as CPU modified - template + template void ForEachUploadRange(VAddr query_cpu_range, u64 query_size, bool is_written, auto&& func) { IterateRegions( query_cpu_range, query_size, [&func, is_written](RegionManager* manager, u64 offset, size_t size) { std::scoped_lock lk{manager->lock}; - manager->template ForEachModifiedRange( + manager->template ForEachModifiedRange( manager->GetCpuAddr() + offset, size, func); - if (is_written && clear) { - manager->template ChangeRegionState( + if (is_written) { + manager->template ChangeRegionState( manager->GetCpuAddr() + offset, size); } }); } /// Call 'func' for each GPU modified range and unmark those pages as GPU modified - template + template void ForEachDownloadRange(VAddr query_cpu_range, u64 query_size, auto&& func) { IterateRegions(query_cpu_range, query_size, [&func](RegionManager* manager, u64 offset, size_t size) { std::scoped_lock lk{manager->lock}; - manager->template ForEachModifiedRange( + manager->template ForEachModifiedRange( manager->GetCpuAddr() + offset, size, func); }); } + /// Notifies deferred protection changes to the tracker. + template + void PerformDeferredProtections() { + ForEachRegion([&](RegionManager* manager) { + std::scoped_lock lk{manager->lock}; + manager->template PerformDeferredProtections(); + }); + } + + /// Notifies all deferred protection changes to the tracker. + /// Lck the memory tracker. void Lock() { global_lock.lock(); diff --git a/src/video_core/buffer_cache/region_definitions.h b/src/video_core/buffer_cache/region_definitions.h index 76e7ee263..af25226f5 100644 --- a/src/video_core/buffer_cache/region_definitions.h +++ b/src/video_core/buffer_cache/region_definitions.h @@ -4,6 +4,7 @@ #pragma once #include "common/bit_array.h" +#include "common/enum.h" #include "common/types.h" namespace VideoCore { @@ -17,9 +18,12 @@ constexpr u64 TRACKER_HIGHER_PAGE_MASK = TRACKER_HIGHER_PAGE_SIZE - 1ULL; constexpr u64 NUM_PAGES_PER_REGION = TRACKER_HIGHER_PAGE_SIZE / TRACKER_BYTES_PER_PAGE; enum class Type { - CPU, - GPU, + None = 0, + CPU = 1 << 0, + GPU = 1 << 1, }; +DECLARE_ENUM_FLAG_OPERATORS(Type) + using RegionBits = Common::BitArray; diff --git a/src/video_core/buffer_cache/region_manager.h b/src/video_core/buffer_cache/region_manager.h index b21f4e406..8eff058ff 100644 --- a/src/video_core/buffer_cache/region_manager.h +++ b/src/video_core/buffer_cache/region_manager.h @@ -70,13 +70,27 @@ public: } } + template + void PerformDeferredProtections() { + bool was_deferred = True(deferred_protection & type); + if (!was_deferred) { + return; + } + deferred_protection &= ~type; + if constexpr (type == Type::CPU) { + UpdateProtection(); + } else if constexpr (type == Type::GPU) { + UpdateProtection(); + } + } + /** * Change the state of a range of pages * * @param dirty_addr Base address to mark or unmark as modified * @param size Size in bytes to mark or unmark as modified */ - template + template void ChangeRegionState(u64 dirty_addr, u64 size) noexcept(type == Type::GPU) { RENDERER_TRACE; const size_t offset = dirty_addr - cpu_addr; @@ -93,7 +107,9 @@ public: } else { bits.UnsetRange(start_page, end_page); } - if constexpr (type == Type::CPU) { + if constexpr (defer_protect) { + deferred_protection |= type; + } else if constexpr (type == Type::CPU) { UpdateProtection(); } else if (Config::readbacks()) { UpdateProtection(); @@ -108,7 +124,7 @@ public: * @param size Size in bytes of the CPU range to loop over * @param func Function to call for each turned off region */ - template + template void ForEachModifiedRange(VAddr query_cpu_range, s64 size, auto&& func) { RENDERER_TRACE; const size_t offset = query_cpu_range - cpu_addr; @@ -124,7 +140,9 @@ public: if constexpr (clear) { bits.UnsetRange(start_page, end_page); - if constexpr (type == Type::CPU) { + if constexpr (defer_protect) { + deferred_protection |= type; + } else if constexpr (type == Type::CPU) { UpdateProtection(); } else if (Config::readbacks()) { UpdateProtection(); @@ -136,24 +154,6 @@ public: } } - /** - * Chagnes state of all pages in the region - */ - template - void ChangeAllRegionState() noexcept { - RENDERER_TRACE; - if constexpr (enable) { - GetRegionBits().Fill(); - } else { - GetRegionBits().Clear(); - } - if constexpr (type == Type::CPU) { - UpdateProtection(); - } else if (Config::readbacks()) { - UpdateProtection(); - } - } - /** * Returns true when a region has been modified * @@ -204,6 +204,7 @@ private: PageManager* tracker; VAddr cpu_addr = 0; + Type deferred_protection = Type::None; RegionBits cpu; RegionBits gpu; RegionBits writeable;