Browse Source

[TEST] Extend coalescing to more gpu to cpu regions

vk-experiments8
CamilleLaVey 2 weeks ago
parent
commit
20e6c163a6
  1. 8
      src/video_core/buffer_cache/buffer_cache.h
  2. 2
      src/video_core/buffer_cache/buffer_cache_base.h
  3. 18
      src/video_core/buffer_cache/memory_tracker_base.h
  4. 18
      src/video_core/buffer_cache/word_manager.h
  5. 8
      src/video_core/renderer_vulkan/vk_rasterizer.cpp

8
src/video_core/buffer_cache/buffer_cache.h

@ -791,6 +791,11 @@ bool BufferCache<P>::IsRegionGpuModified(DAddr addr, size_t size) {
return is_dirty;
}
template <class P>
bool BufferCache<P>::IsRegionGpuModifiedCheap(DAddr addr, size_t size) {
return memory_tracker.IsRegionGpuModifiedCheap(addr, size);
}
template <class P>
bool BufferCache<P>::IsRegionRegistered(DAddr addr, size_t size) {
const DAddr end_addr = addr + size;
@ -1025,7 +1030,8 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
}();
const bool use_fast_buffer = needs_alignment_stream
|| (has_host_buffer && size <= channel_state->uniform_buffer_skip_cache_size
&& !memory_tracker.IsRegionGpuModified(device_addr, size));
&& !(memory_tracker.IsRegionGpuModifiedCheap(device_addr, size)
&& memory_tracker.IsRegionGpuModified(device_addr, size)));
if (use_fast_buffer) {
if constexpr (IS_OPENGL) {
if (runtime.HasFastBufferSubData()) {

2
src/video_core/buffer_cache/buffer_cache_base.h

@ -300,6 +300,8 @@ public:
/// Return true when a CPU region is modified from the GPU
[[nodiscard]] bool IsRegionGpuModified(DAddr addr, size_t size);
[[nodiscard]] bool IsRegionGpuModifiedCheap(DAddr addr, size_t size);
/// Return true when a region is registered on the cache
[[nodiscard]] bool IsRegionRegistered(DAddr addr, size_t size);

18
src/video_core/buffer_cache/memory_tracker_base.h

@ -69,6 +69,24 @@ public:
return false;
}
[[nodiscard]] bool IsRegionGpuModifiedCheap(VAddr query_cpu_addr, u64 query_size) noexcept {
std::size_t remaining_size{query_size};
std::size_t page_index{query_cpu_addr >> HIGHER_PAGE_BITS};
u64 page_offset{query_cpu_addr & HIGHER_PAGE_MASK};
while (remaining_size > 0) {
const std::size_t copy_amount{
std::min<std::size_t>(HIGHER_PAGE_SIZE - page_offset, remaining_size)};
const Manager* manager = top_tier[page_index].load(std::memory_order_acquire);
if (manager != nullptr && manager->GpuModifiedPageCount() != 0) {
return true;
}
page_index++;
page_offset = 0;
remaining_size -= copy_amount;
}
return false;
}
/// Returns true if a region has been modified from the CPU
[[nodiscard]] bool IsRegionCpuModified(VAddr query_cpu_addr, u64 query_size) noexcept {
return IteratePages<true>(query_cpu_addr, query_size, [](Manager* manager, u64 offset, size_t size) {

18
src/video_core/buffer_cache/word_manager.h

@ -127,6 +127,7 @@ struct WordManager {
[[maybe_unused]] std::span<u64> cached_words = Span(Type::CachedCPU);
std::vector<std::pair<VAddr, u64>> ranges;
s64 cpu_delta = 0;
s64 gpu_delta = 0;
IterateWords(dirty_addr - cpu_addr, size, [&](size_t index, u64 mask) {
if (type == Type::CPU || type == Type::CachedCPU) {
CollectChangedRanges(!enable, index, untracked_words[index], mask, ranges);
@ -134,6 +135,9 @@ struct WordManager {
if (type == Type::CPU) {
const u64 old = state_words[index];
cpu_delta += enable ? std::popcount(~old & mask) : -std::popcount(old & mask);
} else if (type == Type::GPU) {
const u64 old = state_words[index];
gpu_delta += enable ? std::popcount(~old & mask) : -std::popcount(old & mask);
}
if (enable) {
state_words[index] |= mask;
@ -152,6 +156,9 @@ struct WordManager {
if (cpu_delta != 0) {
cpu_modified_pages.fetch_add(static_cast<u32>(cpu_delta), std::memory_order_release);
}
if (gpu_delta != 0) {
gpu_modified_pages.fetch_add(static_cast<u32>(gpu_delta), std::memory_order_release);
}
if (!ranges.empty()) {
ApplyCollectedRanges(ranges, (!enable) ? 1 : -1);
}
@ -180,6 +187,7 @@ struct WordManager {
};
std::vector<std::pair<VAddr, u64>> ranges;
s64 cpu_delta = 0;
s64 gpu_delta = 0;
IterateWords(offset, size, [&](size_t index, u64 mask) {
if (type == Type::GPU)
mask &= ~untracked_words[index];
@ -190,6 +198,8 @@ struct WordManager {
}
if (type == Type::CPU)
cpu_delta -= std::popcount(word);
else if (type == Type::GPU)
gpu_delta -= std::popcount(word);
state_words[index] &= ~mask;
if (type == Type::CPU || type == Type::CachedCPU)
untracked_words[index] &= ~mask;
@ -214,6 +224,9 @@ struct WordManager {
if (cpu_delta != 0) {
cpu_modified_pages.fetch_add(static_cast<u32>(cpu_delta), std::memory_order_release);
}
if (gpu_delta != 0) {
gpu_modified_pages.fetch_add(static_cast<u32>(gpu_delta), std::memory_order_release);
}
if (pending) {
release();
}
@ -348,10 +361,15 @@ struct WordManager {
return cpu_modified_pages.load(std::memory_order_acquire);
}
[[nodiscard]] u32 GpuModifiedPageCount() const noexcept {
return gpu_modified_pages.load(std::memory_order_acquire);
}
std::array<u64, size_t(Type::Max) * num_words> heap = {};
DeviceTracker* tracker = nullptr;
VAddr cpu_addr = 0;
std::atomic<u32> cpu_modified_pages{0};
std::atomic<u32> gpu_modified_pages{0};
};
} // namespace VideoCommon

8
src/video_core/renderer_vulkan/vk_rasterizer.cpp

@ -684,9 +684,11 @@ void RasterizerVulkan::FlushRegion(DAddr addr, u64 size, VideoCommon::CacheType
bool RasterizerVulkan::MustFlushRegion(DAddr addr, u64 size, VideoCommon::CacheType which) {
if ((True(which & VideoCommon::CacheType::BufferCache))) {
std::scoped_lock lock{buffer_cache.mutex};
if (buffer_cache.IsRegionGpuModified(addr, size)) {
return true;
if (buffer_cache.IsRegionGpuModifiedCheap(addr, size)) {
std::scoped_lock lock{buffer_cache.mutex};
if (buffer_cache.IsRegionGpuModified(addr, size)) {
return true;
}
}
}
if (!Settings::IsGPULevelHigh()) {

Loading…
Cancel
Save