Adjust stagging buffer ring

This commit is contained in:
CamilleLaVey
2026-09-19 18:08:38 -04:00
parent b7b90c183f
commit d82a9c3ba5
5 changed files with 66 additions and 17 deletions
@@ -120,7 +120,14 @@ void StagingBufferPool::FreeDeferred(StagingBufferRef& ref) {
}
void StagingBufferPool::TickFrame() {
current_delete_level = (current_delete_level + 1) % NUM_LEVELS;
for (size_t step = 0; step < NUM_LEVELS; ++step) {
current_delete_level = (current_delete_level + 1) % NUM_LEVELS;
if (!device_local_cache[current_delete_level].entries.empty() ||
!upload_cache[current_delete_level].entries.empty() ||
!download_cache[current_delete_level].entries.empty()) {
break;
}
}
ReleaseCache(MemoryUsage::DeviceLocal);
ReleaseCache(MemoryUsage::Upload);
@@ -128,10 +135,12 @@ void StagingBufferPool::TickFrame() {
}
StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
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 size_t wanted_begin = Region(free_iterator) + 1;
const size_t wanted_end = (std::min)(Region(iterator + size) + 1, NUM_SYNCS);
if (AreRegionsActive(wanted_begin, wanted_end)) {
if (auto ref = OverflowStreamBuffer(size, wanted_begin, wanted_end)) {
return *ref;
}
}
const u64 current_tick = scheduler.CurrentTick();
std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + Region(iterator),
@@ -147,8 +156,9 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
free_iterator = size;
if (AreRegionsActive(0, Region(size) + 1)) {
// Avoid waiting for the previous usages to be free
return GetStagingBuffer(size, MemoryUsage::Upload);
if (auto ref = OverflowStreamBuffer(size, 0, Region(size) + 1)) {
return *ref;
}
}
}
const size_t offset = iterator;
@@ -164,6 +174,27 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
};
}
u64 StagingBufferPool::MaxRegionTick(size_t region_begin, size_t region_end) const {
u64 tick = 0;
for (size_t region = region_begin; region < region_end; ++region) {
tick = (std::max)(tick, sync_ticks[region]);
}
return tick;
}
std::optional<StagingBufferRef> StagingBufferPool::OverflowStreamBuffer(size_t size,
size_t region_begin,
size_t region_end) {
if (cache_bytes[static_cast<size_t>(MemoryUsage::Upload)] < stream_buffer_size) {
return GetStagingBuffer(size, MemoryUsage::Upload);
}
if (auto ref = TryGetReservedBuffer(size, MemoryUsage::Upload, false)) {
return ref;
}
scheduler.Wait(MaxRegionTick(region_begin, region_end));
return std::nullopt;
}
bool StagingBufferPool::AreRegionsActive(size_t region_begin, size_t region_end) const {
const u64 gpu_tick = scheduler.GetMasterSemaphore().KnownGpuTick();
return std::any_of(sync_ticks.begin() + region_begin, sync_ticks.begin() + region_end,
@@ -233,6 +264,7 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage
device.IsBufferDeviceAddressSupported()
? device.GetLogical().GetBufferDeviceAddress(*buffer)
: VkDeviceAddress{};
cache_bytes[static_cast<size_t>(usage)] += size_t{1} << log2_size;
StagingBuffer& entry = GetCache(usage)[log2_size].entries.emplace_back(StagingBuffer{
.buffer = std::move(buffer),
.device_address = buffer_address,
@@ -261,12 +293,12 @@ StagingBufferPool::StagingBuffersCache& StagingBufferPool::GetCache(MemoryUsage
}
void StagingBufferPool::ReleaseCache(MemoryUsage usage) {
ReleaseLevel(GetCache(usage), current_delete_level);
ReleaseLevel(usage, current_delete_level);
}
void StagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, size_t log2) {
void StagingBufferPool::ReleaseLevel(MemoryUsage usage, size_t log2) {
constexpr size_t deletions_per_tick = 16;
auto& staging = cache[log2];
auto& staging = GetCache(usage)[log2];
auto& entries = staging.entries;
const size_t old_size = entries.size();
@@ -280,6 +312,7 @@ void StagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, size_t log2) {
entries.erase(std::remove_if(begin, end, is_deletable), end);
const size_t new_size = entries.size();
cache_bytes[static_cast<size_t>(usage)] -= (old_size - new_size) << log2;
staging.delete_index += deletions_per_tick;
if (staging.delete_index >= new_size) {
staging.delete_index = 0;
@@ -7,6 +7,7 @@
#pragma once
#include <climits>
#include <optional>
#include <vector>
#include "common/common_types.h"
@@ -88,6 +89,11 @@ private:
bool AreRegionsActive(size_t region_begin, size_t region_end) const;
u64 MaxRegionTick(size_t region_begin, size_t region_end) const;
std::optional<StagingBufferRef> OverflowStreamBuffer(size_t size, size_t region_begin,
size_t region_end);
StagingBufferRef GetStagingBuffer(size_t size, MemoryUsage usage, bool deferred = false);
std::optional<StagingBufferRef> TryGetReservedBuffer(size_t size, MemoryUsage usage,
@@ -99,7 +105,7 @@ private:
void ReleaseCache(MemoryUsage usage);
void ReleaseLevel(StagingBuffersCache& cache, size_t log2);
void ReleaseLevel(MemoryUsage usage, size_t log2);
size_t Region(size_t iter) const noexcept {
return iter / region_size;
}
@@ -119,6 +125,8 @@ private:
size_t free_iterator = 0;
std::array<u64, NUM_SYNCS> sync_ticks{};
std::array<size_t, 4> cache_bytes{};
StagingBuffersCache device_local_cache;
StagingBuffersCache upload_cache;
StagingBuffersCache download_cache;
@@ -1091,11 +1091,12 @@ bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) {
}
VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL);
const size_t wanted_size = (std::max)(needed_size, size_t{1});
const auto level = (8 * sizeof(size_t)) - std::countl_zero(wanted_size - 1ULL);
if (buffers[level]) {
return *buffers[level];
}
const auto new_size = Common::NextPow2(needed_size);
const auto new_size = Common::NextPow2(wanted_size);
static constexpr VkBufferUsageFlags flags =
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
@@ -741,7 +741,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
.pHeapSizeLimit = nullptr,
.pVulkanFunctions = &functions,
.instance = instance,
.vulkanApiVersion = ApiVersion(),
.vulkanApiVersion = VK_API_VERSION_1_1,
.pTypeExternalMemoryHandleTypes = nullptr,
};
@@ -26,6 +26,13 @@ namespace {
: VkMemoryPropertyFlagBits{};
}
[[nodiscard]] VkMemoryPropertyFlags MemoryUsageRequiredVmaFlags(MemoryUsage usage) {
if (usage == MemoryUsage::Upload || usage == MemoryUsage::Download) {
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
}
return VkMemoryPropertyFlagBits{};
}
[[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) {
switch (usage) {
case MemoryUsage::Upload:
@@ -103,7 +110,7 @@ vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo &ci) const
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
.requiredFlags = 0,
.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
.memoryTypeBits = 0,
.memoryTypeBits = valid_memory_types,
.pool = VK_NULL_HANDLE,
.pUserData = nullptr,
.priority = 0.f,
@@ -138,7 +145,7 @@ vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo &ci, MemoryUsa
VmaAllocationCreateInfo alloc_ci = {
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage),
.usage = MemoryUsageVma(usage),
.requiredFlags = 0,
.requiredFlags = MemoryUsageRequiredVmaFlags(usage),
.preferredFlags = MemoryUsagePreferredVmaFlags(usage) | anv_flags,
.memoryTypeBits = usage == MemoryUsage::Stream ? 0u : valid_memory_types,
.pool = VK_NULL_HANDLE,
@@ -196,7 +203,7 @@ vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo &ci, MemoryUsa
VmaAllocationCreateInfo alloc_ci = {
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage),
.usage = MemoryUsageVma(usage),
.requiredFlags = 0,
.requiredFlags = MemoryUsageRequiredVmaFlags(usage),
.preferredFlags = MemoryUsagePreferredVmaFlags(usage) | anv_flags,
.memoryTypeBits = memory_type_bits,
.pool = VK_NULL_HANDLE,