mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-06 14:09:58 +00:00
Adjust stagging buffer ring
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user