|
|
|
@ -1,5 +1,5 @@ |
|
|
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <utility>
|
|
|
|
@ -94,7 +94,7 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem |
|
|
|
.flags = 0, |
|
|
|
.size = STREAM_BUFFER_SIZE, |
|
|
|
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | |
|
|
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, |
|
|
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT , |
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
|
|
|
.queueFamilyIndexCount = 0, |
|
|
|
.pQueueFamilyIndices = nullptr, |
|
|
|
@ -142,11 +142,23 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem |
|
|
|
|
|
|
|
StagingBufferPool::~StagingBufferPool() = default; |
|
|
|
|
|
|
|
StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage) { |
|
|
|
if (usage == MemoryUsage::Upload && size <= MAX_STREAM_BUFFER_REQUEST_SIZE) { |
|
|
|
StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage, bool deferred) { |
|
|
|
if (!deferred && usage == MemoryUsage::Upload && size <= MAX_STREAM_BUFFER_REQUEST_SIZE) { |
|
|
|
return GetStreamBuffer(size); |
|
|
|
} |
|
|
|
return GetStagingBuffer(size, usage); |
|
|
|
return GetStagingBuffer(size, usage, deferred); |
|
|
|
} |
|
|
|
|
|
|
|
void StagingBufferPool::FreeDeferred(StagingBufferRef& ref) { |
|
|
|
auto& entries = GetCache(ref.usage)[ref.log2_level].entries; |
|
|
|
const auto is_this_one = [&ref](const StagingBuffer& entry) { |
|
|
|
return entry.index == ref.index; |
|
|
|
}; |
|
|
|
auto it = std::find_if(entries.begin(), entries.end(), is_this_one); |
|
|
|
ASSERT(it != entries.end()); |
|
|
|
ASSERT(it->deferred); |
|
|
|
it->tick = scheduler.CurrentTick(); |
|
|
|
it->deferred = false; |
|
|
|
} |
|
|
|
|
|
|
|
void StagingBufferPool::TickFrame() { |
|
|
|
@ -196,19 +208,21 @@ bool StagingBufferPool::AreRegionsActive(size_t region_begin, size_t region_end) |
|
|
|
[gpu_tick](u64 sync_tick) { return gpu_tick < sync_tick; }); |
|
|
|
}; |
|
|
|
|
|
|
|
StagingBufferRef StagingBufferPool::GetStagingBuffer(size_t size, MemoryUsage usage) { |
|
|
|
if (const std::optional<StagingBufferRef> ref = TryGetReservedBuffer(size, usage)) { |
|
|
|
StagingBufferRef StagingBufferPool::GetStagingBuffer(size_t size, MemoryUsage usage, |
|
|
|
bool deferred) { |
|
|
|
if (const std::optional<StagingBufferRef> ref = TryGetReservedBuffer(size, usage, deferred)) { |
|
|
|
return *ref; |
|
|
|
} |
|
|
|
return CreateStagingBuffer(size, usage); |
|
|
|
return CreateStagingBuffer(size, usage, deferred); |
|
|
|
} |
|
|
|
|
|
|
|
std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t size, |
|
|
|
MemoryUsage usage) { |
|
|
|
MemoryUsage usage, |
|
|
|
bool deferred) { |
|
|
|
StagingBuffers& cache_level = GetCache(usage)[Common::Log2Ceil64(size)]; |
|
|
|
|
|
|
|
const auto is_free = [this](const StagingBuffer& entry) { |
|
|
|
return scheduler.IsFree(entry.tick); |
|
|
|
return !entry.deferred && scheduler.IsFree(entry.tick); |
|
|
|
}; |
|
|
|
auto& entries = cache_level.entries; |
|
|
|
const auto hint_it = entries.begin() + cache_level.iterate_index; |
|
|
|
@ -220,11 +234,14 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s |
|
|
|
} |
|
|
|
} |
|
|
|
cache_level.iterate_index = std::distance(entries.begin(), it) + 1; |
|
|
|
it->tick = scheduler.CurrentTick(); |
|
|
|
it->tick = deferred ? std::numeric_limits<u64>::max() : scheduler.CurrentTick(); |
|
|
|
ASSERT(!it->deferred); |
|
|
|
it->deferred = deferred; |
|
|
|
return it->Ref(); |
|
|
|
} |
|
|
|
|
|
|
|
StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage) { |
|
|
|
StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, |
|
|
|
bool deferred) { |
|
|
|
const u32 log2 = Common::Log2Ceil64(size); |
|
|
|
vk::Buffer buffer = device.GetLogical().CreateBuffer({ |
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
|
|
|
@ -233,7 +250,7 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage |
|
|
|
.size = 1ULL << log2, |
|
|
|
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
|
|
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | |
|
|
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, |
|
|
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT , |
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
|
|
|
.queueFamilyIndexCount = 0, |
|
|
|
.pQueueFamilyIndices = nullptr, |
|
|
|
@ -249,7 +266,11 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage |
|
|
|
.buffer = std::move(buffer), |
|
|
|
.commit = std::move(commit), |
|
|
|
.mapped_span = mapped_span, |
|
|
|
.tick = scheduler.CurrentTick(), |
|
|
|
.usage = usage, |
|
|
|
.log2_level = log2, |
|
|
|
.index = unique_ids++, |
|
|
|
.tick = deferred ? std::numeric_limits<u64>::max() : scheduler.CurrentTick(), |
|
|
|
.deferred = deferred, |
|
|
|
}); |
|
|
|
return entry.Ref(); |
|
|
|
} |
|
|
|
|