From 025fe458aef87d28c68dc0d4c0f2c43492b62c18 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 23 Jan 2021 17:59:32 -0300 Subject: vk_staging_buffer_pool: Fix softlock when stream buffer overflows There was still a code path that could wait on a timeline semaphore tick that would never be signalled. While we are at it, make use of more STL algorithms. --- .../renderer_vulkan/vk_staging_buffer_pool.cpp | 37 +++++++++++----------- .../renderer_vulkan/vk_staging_buffer_pool.h | 2 ++ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 4baf791d4..dfd8c8e5a 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp @@ -142,33 +142,27 @@ void StagingBufferPool::TickFrame() { } StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) { - for (size_t region = Region(free_iterator) + 1, - region_end = std::min(Region(iterator + size) + 1, NUM_SYNCS); - region < region_end; ++region) { - // If we'd have to wait, get a staging buffer to avoid waiting - if (!scheduler.IsFree(sync_ticks[region])) { - return GetStagingBuffer(size, MemoryUsage::Upload); - } - } - for (size_t region = Region(used_iterator), region_end = Region(iterator); region < region_end; - ++region) { - sync_ticks[region] = scheduler.CurrentTick(); + if (AreRegionsActive(Region(free_iterator) + 1, + std::min(Region(iterator + size) + 1, NUM_SYNCS))) { + // Avoid waiting for the previous usages to be free + return GetStagingBuffer(size, MemoryUsage::Upload); } + const u64 current_tick = scheduler.CurrentTick(); + std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + Region(iterator), + current_tick); used_iterator = iterator; + free_iterator = std::max(free_iterator, iterator + size); - if (iterator + size > free_iterator) { - free_iterator = iterator + size; - } if (iterator + size > STREAM_BUFFER_SIZE) { - for (size_t region = Region(used_iterator); region < NUM_SYNCS; ++region) { - sync_ticks[region] = scheduler.CurrentTick(); - } + std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + NUM_SYNCS, + current_tick); used_iterator = 0; iterator = 0; free_iterator = size; - for (size_t region = 0, region_end = Region(size); region <= region_end; ++region) { - scheduler.Wait(sync_ticks[region]); + if (AreRegionsActive(0, Region(size) + 1)) { + // Avoid waiting for the previous usages to be free + return GetStagingBuffer(size, MemoryUsage::Upload); } } const size_t offset = iterator; @@ -180,6 +174,11 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) { }; } +bool StagingBufferPool::AreRegionsActive(size_t region_begin, size_t region_end) const { + return std::any_of(sync_ticks.begin() + region_begin, sync_ticks.begin() + region_end, + [this](u64 sync_tick) { return !scheduler.IsFree(sync_tick); }); +}; + StagingBufferRef StagingBufferPool::GetStagingBuffer(size_t size, MemoryUsage usage) { if (const std::optional ref = TryGetReservedBuffer(size, usage)) { return *ref; diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index 8e4cadf9b..69f7618de 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h @@ -67,6 +67,8 @@ private: StagingBufferRef GetStreamBuffer(size_t size); + bool AreRegionsActive(size_t region_begin, size_t region_end) const; + StagingBufferRef GetStagingBuffer(size_t size, MemoryUsage usage); std::optional TryGetReservedBuffer(size_t size, MemoryUsage usage); -- cgit v1.2.3