vk_staging_buffer_pool: Get a staging buffer instead of waiting

Avoids waiting idle while the GPU finishes to do work, and fixes an
issue where we'd wait forever if a single command buffer (logic tick)
all the data.
This commit is contained in:
ReinUsesLisp 2021-01-21 01:07:11 -03:00
parent 75fd3f95a3
commit 7402442442
2 changed files with 18 additions and 9 deletions

View file

@ -130,10 +130,7 @@ StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage) {
if (usage == MemoryUsage::Upload && size <= MAX_STREAM_BUFFER_REQUEST_SIZE) { if (usage == MemoryUsage::Upload && size <= MAX_STREAM_BUFFER_REQUEST_SIZE) {
return GetStreamBuffer(size); return GetStreamBuffer(size);
} }
if (const std::optional<StagingBufferRef> ref = TryGetReservedBuffer(size, usage)) { return GetStagingBuffer(size, usage);
return *ref;
}
return CreateStagingBuffer(size, usage);
} }
void StagingBufferPool::TickFrame() { void StagingBufferPool::TickFrame() {
@ -145,17 +142,20 @@ void StagingBufferPool::TickFrame() {
} }
StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) { 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; for (size_t region = Region(used_iterator), region_end = Region(iterator); region < region_end;
++region) { ++region) {
sync_ticks[region] = scheduler.CurrentTick(); sync_ticks[region] = scheduler.CurrentTick();
} }
used_iterator = iterator; used_iterator = iterator;
for (size_t region = Region(free_iterator) + 1,
region_end = std::min(Region(iterator + size) + 1, NUM_SYNCS);
region < region_end; ++region) {
scheduler.Wait(sync_ticks[region]);
}
if (iterator + size > free_iterator) { if (iterator + size > free_iterator) {
free_iterator = iterator + size; free_iterator = iterator + size;
} }
@ -180,6 +180,13 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
}; };
} }
StagingBufferRef StagingBufferPool::GetStagingBuffer(size_t size, MemoryUsage usage) {
if (const std::optional<StagingBufferRef> ref = TryGetReservedBuffer(size, usage)) {
return *ref;
}
return CreateStagingBuffer(size, usage);
}
std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t size, std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t size,
MemoryUsage usage) { MemoryUsage usage) {
StagingBuffers& cache_level = GetCache(usage)[Common::Log2Ceil64(size)]; StagingBuffers& cache_level = GetCache(usage)[Common::Log2Ceil64(size)];

View file

@ -67,6 +67,8 @@ private:
StagingBufferRef GetStreamBuffer(size_t size); StagingBufferRef GetStreamBuffer(size_t size);
StagingBufferRef GetStagingBuffer(size_t size, MemoryUsage usage);
std::optional<StagingBufferRef> TryGetReservedBuffer(size_t size, MemoryUsage usage); std::optional<StagingBufferRef> TryGetReservedBuffer(size_t size, MemoryUsage usage);
StagingBufferRef CreateStagingBuffer(size_t size, MemoryUsage usage); StagingBufferRef CreateStagingBuffer(size_t size, MemoryUsage usage);