WIP: [video_core] better datastructures (deque -> devector) experiment, remove uneeded overhead from deque() on places where it wasn't needed #2604

Closed
Lizzie wants to merge 2 commits from liz-deque-to-devec into master
17 changed files with 200 additions and 235 deletions

View file

@ -1,11 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <deque> #include <vector>
#include <memory>
#include <type_traits> #include <type_traits>
#include <boost/container/devector.hpp>
#include "common/common_types.h" #include "common/common_types.h"
@ -130,8 +133,8 @@ private:
} }
} }
std::deque<Item> item_pool; std::vector<Item> item_pool;
std::deque<size_t> free_items; boost::container::devector<size_t> free_items;
Item* first_item{}; Item* first_item{};
Item* last_item{}; Item* last_item{};
}; };

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2012 PPSSPP Project // SPDX-FileCopyrightText: 2012 PPSSPP Project
// SPDX-FileCopyrightText: 2014 Dolphin Emulator Project // SPDX-FileCopyrightText: 2014 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -5,7 +8,7 @@
#pragma once #pragma once
#include <array> #include <array>
#include <deque> #include <boost/container/devector.hpp>
namespace Common { namespace Common {
@ -145,7 +148,7 @@ private:
// Points to the next active priority, skipping over ones that have never been used. // Points to the next active priority, skipping over ones that have never been used.
Queue* next_nonempty = UnlinkedTag(); Queue* next_nonempty = UnlinkedTag();
// Double-ended queue of threads in this priority level // Double-ended queue of threads in this priority level
std::deque<T> data; boost::container::devector<T> data;
}; };
/// Special tag used to mark priority levels that have never been used. /// Special tag used to mark priority levels that have never been used.

View file

@ -566,7 +566,7 @@ struct System::Impl {
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
gpu_dirty_memory_managers; gpu_dirty_memory_managers;
std::deque<std::vector<u8>> user_channel; boost::container::devector<std::vector<u8>> user_channel;
}; };
System::System() : impl{std::make_unique<Impl>(*this)} {} System::System() : impl{std::make_unique<Impl>(*this)} {}
@ -976,7 +976,7 @@ void System::ExecuteProgram(std::size_t program_index) {
} }
} }
std::deque<std::vector<u8>>& System::GetUserChannel() { boost::container::devector<std::vector<u8>>& System::GetUserChannel() {
return impl->user_channel; return impl->user_channel;
} }

View file

@ -14,6 +14,7 @@
#include <span> #include <span>
#include <string> #include <string>
#include <vector> #include <vector>
#include <boost/container/devector.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/file_sys/vfs/vfs_types.h" #include "core/file_sys/vfs/vfs_types.h"
@ -426,7 +427,7 @@ public:
* Gets a reference to the user channel stack. * Gets a reference to the user channel stack.
* It is used to transfer data between programs. * It is used to transfer data between programs.
*/ */
[[nodiscard]] std::deque<std::vector<u8>>& GetUserChannel(); [[nodiscard]] boost::container::devector<std::vector<u8>>& GetUserChannel();
/// Type used for the frontend to designate a callback for System to exit the application. /// Type used for the frontend to designate a callback for System to exit the application.
using ExitCallback = std::function<void()>; using ExitCallback = std::function<void()>;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -6,9 +9,9 @@
#include <array> #include <array>
#include <atomic> #include <atomic>
#include <bit> #include <bit>
#include <deque>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <boost/container/devector.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/range_mutex.h" #include "common/range_mutex.h"
@ -162,8 +165,8 @@ private:
// Process memory interfaces // Process memory interfaces
std::deque<size_t> id_pool; boost::container::devector<size_t> id_pool;
std::deque<Memory::Memory*> registered_processes; boost::container::devector<Memory::Memory*> registered_processes;
// Memory protection management // Memory protection management

View file

@ -4,7 +4,7 @@
#include <atomic> #include <atomic>
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <type_traits> #include <boost/container/devector.hpp>
#include "common/address_space.h" #include "common/address_space.h"
#include "common/address_space.inc" #include "common/address_space.inc"
@ -119,8 +119,8 @@ private:
u32 value{}; u32 value{};
}; };
std::deque<Entry> storage; boost::container::devector<Entry> storage;
std::deque<u32> free_entries; boost::container::devector<u32> free_entries;
}; };
struct EmptyAllocator { struct EmptyAllocator {

View file

@ -9,6 +9,7 @@
#include <deque> #include <deque>
#include <mutex> #include <mutex>
#include <stack> #include <stack>
#include <boost/container/devector.hpp>
#include "common/math_util.h" #include "common/math_util.h"
#include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/apm/apm_controller.h"
@ -95,9 +96,9 @@ struct Applet {
bool request_exit_to_library_applet_at_execute_next_program_enabled{}; bool request_exit_to_library_applet_at_execute_next_program_enabled{};
// Channels // Channels
std::deque<std::vector<u8>> user_channel_launch_parameter{}; boost::container::devector<std::vector<u8>> user_channel_launch_parameter{};
std::deque<std::vector<u8>> preselected_user_launch_parameter{}; boost::container::devector<std::vector<u8>> preselected_user_launch_parameter{};
std::deque<std::vector<u8>> friend_invitation_storage_channel{}; boost::container::devector<std::vector<u8>> friend_invitation_storage_channel{};
// Context Stack // Context Stack
std::stack<SharedPointer<IStorage>> context_stack{}; std::stack<SharedPointer<IStorage>> context_stack{};

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -13,12 +16,12 @@
// https://link.springer.com/chapter/10.1007/978-3-642-37051-9_6 // https://link.springer.com/chapter/10.1007/978-3-642-37051-9_6
// //
#include <deque>
#include <map> #include <map>
#include <span> #include <span>
#include <unordered_map> #include <unordered_map>
#include <variant> #include <variant>
#include <vector> #include <boost/container/small_vector.hpp>
#include <boost/container/devector.hpp>
#include "shader_recompiler/frontend/ir/basic_block.h" #include "shader_recompiler/frontend/ir/basic_block.h"
#include "shader_recompiler/frontend/ir/opcodes.h" #include "shader_recompiler/frontend/ir/opcodes.h"
@ -370,7 +373,7 @@ void VisitBlock(Pass& pass, IR::Block* block) {
} }
IR::Type GetConcreteType(IR::Inst* inst) { IR::Type GetConcreteType(IR::Inst* inst) {
std::deque<IR::Inst*> queue; boost::container::devector<IR::Inst*> queue;
queue.push_back(inst); queue.push_back(inst);
while (!queue.empty()) { while (!queue.empty()) {
IR::Inst* current = queue.front(); IR::Inst* current = queue.front();

View file

@ -6,15 +6,11 @@
#pragma once #pragma once
#include <algorithm>
#include <array> #include <array>
#include <functional>
#include <memory>
#include <mutex> #include <mutex>
#include <numeric>
#include <span> #include <span>
#include <unordered_map> #include <boost/container/deque.hpp>
#include <vector> #include <boost/container/devector.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/div_ceil.h" #include "common/div_ceil.h"
@ -455,15 +451,14 @@ private:
MemoryTracker memory_tracker; MemoryTracker memory_tracker;
Common::RangeSet<DAddr> uncommitted_gpu_modified_ranges; Common::RangeSet<DAddr> uncommitted_gpu_modified_ranges;
Common::RangeSet<DAddr> gpu_modified_ranges; Common::RangeSet<DAddr> gpu_modified_ranges;
std::deque<Common::RangeSet<DAddr>> committed_gpu_modified_ranges;
// Async Buffers // Async Buffers
Common::OverlapRangeSet<DAddr> async_downloads; Common::OverlapRangeSet<DAddr> async_downloads;
std::deque<std::optional<Async_Buffer>> async_buffers;
std::deque<boost::container::small_vector<BufferCopy, 4>> pending_downloads;
std::optional<Async_Buffer> current_buffer; std::optional<Async_Buffer> current_buffer;
std::vector<Async_Buffer> async_buffers_death_ring;
std::deque<Async_Buffer> async_buffers_death_ring; std::vector<Common::RangeSet<DAddr>> committed_gpu_modified_ranges;
boost::container::devector<std::optional<Async_Buffer>> async_buffers;
boost::container::devector<boost::container::small_vector<BufferCopy, 4>> pending_downloads;
size_t immediate_buffer_capacity = 0; size_t immediate_buffer_capacity = 0;
Common::ScratchBuffer<u8> immediate_buffer_alloc; Common::ScratchBuffer<u8> immediate_buffer_alloc;

View file

@ -8,11 +8,11 @@
#include <algorithm> #include <algorithm>
#include <bit> #include <bit>
#include <deque>
#include <limits> #include <limits>
#include <type_traits> #include <type_traits>
#include <unordered_set> #include <unordered_set>
#include <utility> #include <utility>
#include <boost/container/devector.hpp>
#include "common/alignment.h" #include "common/alignment.h"
#include "common/common_types.h" #include "common/common_types.h"
@ -289,9 +289,8 @@ private:
return on_return(); return on_return();
} }
std::deque<std::array<Manager, MANAGER_POOL_SIZE>> manager_pool; boost::container::devector<std::array<Manager, MANAGER_POOL_SIZE>> manager_pool;
std::deque<Manager*> free_managers; boost::container::devector<Manager*> free_managers;
std::array<Manager*, NUM_HIGH_PAGES> top_tier{}; std::array<Manager*, NUM_HIGH_PAGES> top_tier{};
std::unordered_set<u32> cached_pages; std::unordered_set<u32> cached_pages;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -9,6 +12,7 @@
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <boost/container/devector.hpp>
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
@ -131,7 +135,7 @@ private:
std::mutex command_mutex; std::mutex command_mutex;
std::condition_variable_any command_cv; std::condition_variable_any command_cv;
std::deque<ChCommandHeaderList> command_lists; boost::container::devector<ChCommandHeaderList> command_lists;
std::jthread thread; std::jthread thread;
ThiRegisters thi_regs{}; ThiRegisters thi_regs{};

View file

@ -10,6 +10,7 @@
#include <condition_variable> #include <condition_variable>
#include <list> #include <list>
#include <memory> #include <memory>
#include <boost/container/devector.hpp>
#include "common/assert.h" #include "common/assert.h"
#include "common/settings.h" #include "common/settings.h"
@ -378,8 +379,8 @@ struct GPU::Impl {
Tegra::Control::ChannelState* current_channel; Tegra::Control::ChannelState* current_channel;
s32 bound_channel{-1}; s32 bound_channel{-1};
std::deque<size_t> free_swap_counters; boost::container::devector<size_t> free_swap_counters;
std::deque<size_t> request_swap_counters; std::vector<size_t> request_swap_counters;
std::mutex request_swap_mutex; std::mutex request_swap_mutex;
}; };

View file

@ -1,105 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
#pragma once #pragma once
#include <atomic>
#include <deque>
#include <utility>
#include "common/common_types.h"
namespace VideoCommon { namespace VideoCommon {
class BankBase {
protected:
const size_t base_bank_size{};
size_t bank_size{};
std::atomic<size_t> references{};
size_t current_slot{};
public:
explicit BankBase(size_t bank_size_) : base_bank_size{bank_size_}, bank_size(bank_size_) {}
virtual ~BankBase() = default;
virtual std::pair<bool, size_t> Reserve() {
if (IsClosed()) {
return {false, bank_size};
}
const size_t result = current_slot++;
return {true, result};
}
virtual void Reset() {
current_slot = 0;
references = 0;
bank_size = base_bank_size;
}
size_t Size() const {
return bank_size;
}
void AddReference(size_t how_many = 1) {
references.fetch_add(how_many, std::memory_order_relaxed);
}
void CloseReference(size_t how_many = 1) {
if (how_many > references.load(std::memory_order_relaxed)) {
UNREACHABLE();
}
references.fetch_sub(how_many, std::memory_order_relaxed);
}
void Close() {
bank_size = current_slot;
}
bool IsClosed() const {
return current_slot >= bank_size;
}
bool IsDead() const {
return IsClosed() && references == 0;
}
};
template <typename BankType>
class BankPool {
private:
std::deque<BankType> bank_pool;
std::deque<size_t> bank_indices;
public:
BankPool() = default;
~BankPool() = default;
// Reserve a bank from the pool and return its index
template <typename Func>
size_t ReserveBank(Func&& builder) {
if (!bank_indices.empty() && bank_pool[bank_indices.front()].IsDead()) {
size_t new_index = bank_indices.front();
bank_indices.pop_front();
bank_pool[new_index].Reset();
bank_indices.push_back(new_index);
return new_index;
}
size_t new_index = bank_pool.size();
builder(bank_pool, new_index);
bank_indices.push_back(new_index);
return new_index;
}
// Get a reference to a bank using its index
BankType& GetBank(size_t index) {
return bank_pool[index];
}
// Get the total number of banks in the pool
size_t BankCount() const {
return bank_pool.size();
}
};
} // namespace VideoCommon } // namespace VideoCommon

View file

@ -7,11 +7,12 @@
#pragma once #pragma once
#include <array> #include <array>
#include <deque>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include <boost/container/devector.hpp>
#include <boost/container/small_vector.hpp>
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
@ -22,7 +23,6 @@
#include "video_core/gpu.h" #include "video_core/gpu.h"
#include "video_core/host1x/gpu_device_memory_manager.h" #include "video_core/host1x/gpu_device_memory_manager.h"
#include "video_core/memory_manager.h" #include "video_core/memory_manager.h"
#include "video_core/query_cache/bank_base.h"
#include "video_core/query_cache/query_base.h" #include "video_core/query_cache/query_base.h"
#include "video_core/query_cache/query_cache_base.h" #include "video_core/query_cache/query_cache_base.h"
#include "video_core/query_cache/query_stream.h" #include "video_core/query_cache/query_stream.h"
@ -87,7 +87,7 @@ public:
private: private:
RuntimeType& runtime; RuntimeType& runtime;
std::deque<size_t> pending_sync; std::vector<size_t> pending_sync;
}; };
template <typename Traits> template <typename Traits>
@ -168,7 +168,7 @@ struct QueryCacheBase<Traits>::QueryCacheBaseImpl {
std::array<StreamerInterface*, static_cast<size_t>(QueryType::MaxQueryTypes)> streamers; std::array<StreamerInterface*, static_cast<size_t>(QueryType::MaxQueryTypes)> streamers;
u64 streamer_mask; u64 streamer_mask;
std::mutex flush_guard; std::mutex flush_guard;
std::deque<u64> flushes_pending; boost::container::devector<u64> flushes_pending;
std::vector<QueryCacheBase<Traits>::QueryLocation> pending_unregister; std::vector<QueryCacheBase<Traits>::QueryLocation> pending_unregister;
}; };

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
@ -9,7 +12,6 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/query_cache/bank_base.h"
#include "video_core/query_cache/query_base.h" #include "video_core/query_cache/query_base.h"
namespace VideoCommon { namespace VideoCommon {

View file

@ -13,6 +13,8 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/container/devector.hpp>
#include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "common/bit_util.h" #include "common/bit_util.h"
#include "common/common_types.h" #include "common/common_types.h"
@ -37,12 +39,71 @@ using Tegra::Engines::Maxwell3D;
using VideoCommon::QueryType; using VideoCommon::QueryType;
namespace { namespace {
class SamplesQueryBank : public VideoCommon::BankBase { struct BankBase {
public: explicit BankBase(size_t index_, size_t bank_size_) : index{index_}, base_bank_size{bank_size_}, bank_size(bank_size_) {}
~BankBase() = default;
std::pair<bool, size_t> Reserve() {
if (IsClosed())
return {false, bank_size};
const size_t result = current_slot++;
return {true, result};
}
void Reset() {
current_slot = 0;
references = 0;
bank_size = base_bank_size;
}
size_t Size() const {
return bank_size;
}
void AddReference(size_t how_many = 1) {
references.fetch_add(how_many, std::memory_order_relaxed);
}
void CloseReference(size_t how_many = 1) {
ASSERT(how_many <= references.load(std::memory_order_relaxed));
references.fetch_sub(how_many, std::memory_order_relaxed);
}
void Close() {
bank_size = current_slot;
}
bool IsClosed() const {
return current_slot >= bank_size;
}
bool IsDead() const {
return IsClosed() && references.load(std::memory_order_relaxed) == 0;
}
size_t index;
size_t base_bank_size{};
size_t bank_size{};
size_t current_slot{};
std::atomic<size_t> references{};
};
template<typename T>
struct BankPool {
// Reserve a bank from the pool and return its index
template <typename Func>
size_t ReserveBank(Func&& builder) {
if (!indices.empty() && elems[indices.front()].IsDead()) {
size_t new_index = indices.front();
indices.pop_front();
elems[new_index].Reset();
indices.push_back(new_index);
return new_index;
}
size_t new_index = elems.size();
builder(elems, new_index);
indices.push_back(new_index);
return new_index;
}
boost::container::deque<T> elems;
boost::container::devector<size_t> indices;
};
struct SamplesQueryBank final : public BankBase {
static constexpr size_t BANK_SIZE = 256; static constexpr size_t BANK_SIZE = 256;
static constexpr size_t QUERY_SIZE = 8; static constexpr size_t QUERY_SIZE = 8;
explicit SamplesQueryBank(const Device& device_, size_t index_) explicit SamplesQueryBank(const Device& device_, size_t index_)
: BankBase(BANK_SIZE), device{device_}, index{index_} { : BankBase(index_, BANK_SIZE), device{device_} {
const auto& dev = device.GetLogical(); const auto& dev = device.GetLogical();
query_pool = dev.CreateQueryPool({ query_pool = dev.CreateQueryPool({
.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
@ -54,12 +115,11 @@ public:
}); });
Reset(); Reset();
} }
~SamplesQueryBank() = default; ~SamplesQueryBank() = default;
void Reset() override { void Reset() {
ASSERT(references == 0); ASSERT(references == 0);
VideoCommon::BankBase::Reset(); BankBase::Reset();
const auto& dev = device.GetLogical(); const auto& dev = device.GetLogical();
dev.ResetQueryPool(*query_pool, 0, BANK_SIZE); dev.ResetQueryPool(*query_pool, 0, BANK_SIZE);
host_results.fill(0ULL); host_results.fill(0ULL);
@ -85,22 +145,62 @@ public:
VkQueryPool GetInnerPool() { VkQueryPool GetInnerPool() {
return *query_pool; return *query_pool;
} }
size_t GetIndex() const { size_t GetIndex() const {
return index; return index;
} }
const std::array<u64, BANK_SIZE>& GetResults() const { const std::array<u64, BANK_SIZE>& GetResults() const {
return host_results; return host_results;
} }
Device const& device;
size_t next_bank;
private:
const Device& device;
const size_t index;
vk::QueryPool query_pool;
std::array<u64, BANK_SIZE> host_results; std::array<u64, BANK_SIZE> host_results;
vk::QueryPool query_pool;
size_t next_bank;
};
// Transform feedback queries
struct TFBQueryBank final : public BankBase {
static constexpr size_t BANK_SIZE = 1024;
static constexpr size_t QUERY_SIZE = 4;
explicit TFBQueryBank(Scheduler& scheduler_, const MemoryAllocator& memory_allocator, size_t index_)
: BankBase(index_, BANK_SIZE), scheduler{scheduler_} {
const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = QUERY_SIZE * BANK_SIZE,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
};
buffer = memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal);
}
~TFBQueryBank() = default;
void Reset() {
ASSERT(references == 0);
BankBase::Reset();
}
void Sync(StagingBufferRef& stagging_buffer, size_t extra_offset, size_t start, size_t size) {
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([this, dst_buffer = stagging_buffer.buffer, extra_offset, start,
size](vk::CommandBuffer cmdbuf) {
std::array<VkBufferCopy, 1> copy{VkBufferCopy{
.srcOffset = start * QUERY_SIZE,
.dstOffset = extra_offset,
.size = size * QUERY_SIZE,
}};
cmdbuf.CopyBuffer(*buffer, dst_buffer, copy);
});
}
size_t GetIndex() const {
return index;
}
VkBuffer GetBuffer() const {
return *buffer;
}
private:
Scheduler& scheduler;
vk::Buffer buffer;
}; };
using BaseStreamer = VideoCommon::SimpleStreamer<VideoCommon::HostQueryBase>; using BaseStreamer = VideoCommon::SimpleStreamer<VideoCommon::HostQueryBase>;
@ -413,7 +513,7 @@ private:
size_t banks_set = query->size_banks; size_t banks_set = query->size_banks;
size_t start_slot = query->start_slot; size_t start_slot = query->start_slot;
for (size_t i = 0; i < banks_set; i++) { for (size_t i = 0; i < banks_set; i++) {
auto& the_bank = bank_pool.GetBank(bank_id); auto& the_bank = bank_pool.elems[bank_id];
size_t amount = (std::min)(the_bank.Size() - start_slot, size_slots); size_t amount = (std::min)(the_bank.Size() - start_slot, size_slots);
func(&the_bank, start_slot, amount); func(&the_bank, start_slot, amount);
bank_id = the_bank.next_bank - 1; bank_id = the_bank.next_bank - 1;
@ -439,20 +539,19 @@ private:
}); });
} }
for (auto& cont : indexer) { for (auto& cont : indexer) {
func(&bank_pool.GetBank(cont.first), cont.second.first, func(&bank_pool.elems[cont.first], cont.second.first,
cont.second.second - cont.second.first); cont.second.second - cont.second.first);
} }
} }
void ReserveBank() { void ReserveBank() {
current_bank_id = current_bank_id = bank_pool.ReserveBank([this](auto& queue, size_t index) {
bank_pool.ReserveBank([this](std::deque<SamplesQueryBank>& queue, size_t index) {
queue.emplace_back(device, index); queue.emplace_back(device, index);
}); });
if (current_bank) { if (current_bank) {
current_bank->next_bank = current_bank_id + 1; current_bank->next_bank = current_bank_id + 1;
} }
current_bank = &bank_pool.GetBank(current_bank_id); current_bank = &bank_pool.elems[current_bank_id];
current_query_pool = current_bank->GetInnerPool(); current_query_pool = current_bank->GetInnerPool();
} }
@ -474,7 +573,7 @@ private:
size_t banks_set = current_query->size_banks - 1; size_t banks_set = current_query->size_banks - 1;
bool found = bank_id == current_bank_id; bool found = bank_id == current_bank_id;
while (!found && banks_set > 0) { while (!found && banks_set > 0) {
SamplesQueryBank& some_bank = bank_pool.GetBank(bank_id); SamplesQueryBank& some_bank = bank_pool.elems[bank_id];
bank_id = some_bank.next_bank - 1; bank_id = some_bank.next_bank - 1;
found = bank_id == current_bank_id; found = bank_id == current_bank_id;
banks_set--; banks_set--;
@ -577,12 +676,12 @@ private:
const Device& device; const Device& device;
Scheduler& scheduler; Scheduler& scheduler;
const MemoryAllocator& memory_allocator; const MemoryAllocator& memory_allocator;
VideoCommon::BankPool<SamplesQueryBank> bank_pool; BankPool<SamplesQueryBank> bank_pool;
std::deque<vk::Buffer> buffers; boost::container::devector<vk::Buffer> buffers;
std::array<size_t, 32> resolve_table{}; std::array<size_t, 32> resolve_table{};
std::array<size_t, 32> intermediary_table{}; std::array<size_t, 32> intermediary_table{};
vk::Buffer accumulation_buffer; vk::Buffer accumulation_buffer;
std::deque<std::vector<HostSyncValues>> sync_values_stash; boost::container::devector<std::vector<HostSyncValues>> sync_values_stash;
std::vector<size_t> resolve_buffers; std::vector<size_t> resolve_buffers;
// syncing queue // syncing queue
@ -590,7 +689,7 @@ private:
// flush levels // flush levels
std::vector<size_t> pending_flush_queries; std::vector<size_t> pending_flush_queries;
std::deque<std::vector<size_t>> pending_flush_sets; boost::container::devector<std::vector<size_t>> pending_flush_sets;
// State Machine // State Machine
size_t current_bank_slot; size_t current_bank_slot;
@ -609,61 +708,6 @@ private:
std::unique_ptr<QueriesPrefixScanPass> queries_prefix_scan_pass; std::unique_ptr<QueriesPrefixScanPass> queries_prefix_scan_pass;
}; };
// Transform feedback queries
class TFBQueryBank : public VideoCommon::BankBase {
public:
static constexpr size_t BANK_SIZE = 1024;
static constexpr size_t QUERY_SIZE = 4;
explicit TFBQueryBank(Scheduler& scheduler_, const MemoryAllocator& memory_allocator,
size_t index_)
: BankBase(BANK_SIZE), scheduler{scheduler_}, index{index_} {
const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = QUERY_SIZE * BANK_SIZE,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
};
buffer = memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal);
}
~TFBQueryBank() = default;
void Reset() override {
ASSERT(references == 0);
VideoCommon::BankBase::Reset();
}
void Sync(StagingBufferRef& stagging_buffer, size_t extra_offset, size_t start, size_t size) {
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([this, dst_buffer = stagging_buffer.buffer, extra_offset, start,
size](vk::CommandBuffer cmdbuf) {
std::array<VkBufferCopy, 1> copy{VkBufferCopy{
.srcOffset = start * QUERY_SIZE,
.dstOffset = extra_offset,
.size = size * QUERY_SIZE,
}};
cmdbuf.CopyBuffer(*buffer, dst_buffer, copy);
});
}
size_t GetIndex() const {
return index;
}
VkBuffer GetBuffer() const {
return *buffer;
}
private:
Scheduler& scheduler;
const size_t index;
vk::Buffer buffer;
};
class PrimitivesSucceededStreamer; class PrimitivesSucceededStreamer;
class TFBCounterStreamer : public BaseStreamer { class TFBCounterStreamer : public BaseStreamer {
@ -753,7 +797,7 @@ public:
}); });
} }
for (auto& p : sync_values_stash) { for (auto& p : sync_values_stash) {
auto& bank = bank_pool.GetBank(p.first); auto& bank = bank_pool.elems[p.first];
runtime.template SyncValues<HostSyncValues>(p.second, bank.GetBuffer()); runtime.template SyncValues<HostSyncValues>(p.second, bank.GetBuffer());
} }
pending_sync.clear(); pending_sync.clear();
@ -813,7 +857,7 @@ public:
size_t offset_base = staging_ref.offset; size_t offset_base = staging_ref.offset;
for (auto q : pending_flush_queries) { for (auto q : pending_flush_queries) {
auto* query = GetQuery(q); auto* query = GetQuery(q);
auto& bank = bank_pool.GetBank(query->start_bank_id); auto& bank = bank_pool.elems[query->start_bank_id];
bank.Sync(staging_ref, offset_base, query->start_slot, 1); bank.Sync(staging_ref, offset_base, query->start_slot, 1);
offset_base += TFBQueryBank::QUERY_SIZE; offset_base += TFBQueryBank::QUERY_SIZE;
bank.CloseReference(); bank.CloseReference();
@ -925,11 +969,10 @@ private:
std::pair<size_t, size_t> ProduceCounterBuffer(size_t stream) { std::pair<size_t, size_t> ProduceCounterBuffer(size_t stream) {
if (current_bank == nullptr || current_bank->IsClosed()) { if (current_bank == nullptr || current_bank->IsClosed()) {
current_bank_id = current_bank_id = bank_pool.ReserveBank([this](auto& queue, size_t index) {
bank_pool.ReserveBank([this](std::deque<TFBQueryBank>& queue, size_t index) {
queue.emplace_back(scheduler, memory_allocator, index); queue.emplace_back(scheduler, memory_allocator, index);
}); });
current_bank = &bank_pool.GetBank(current_bank_id); current_bank = &bank_pool.elems[current_bank_id];
} }
auto [dont_care, other] = current_bank->Reserve(); auto [dont_care, other] = current_bank->Reserve();
const size_t slot = other; // workaround to compile bug. const size_t slot = other; // workaround to compile bug.
@ -974,7 +1017,7 @@ private:
Scheduler& scheduler; Scheduler& scheduler;
const MemoryAllocator& memory_allocator; const MemoryAllocator& memory_allocator;
StagingBufferPool& staging_pool; StagingBufferPool& staging_pool;
VideoCommon::BankPool<TFBQueryBank> bank_pool; BankPool<TFBQueryBank> bank_pool;
size_t current_bank_id; size_t current_bank_id;
TFBQueryBank* current_bank; TFBQueryBank* current_bank;
vk::Buffer counters_buffer; vk::Buffer counters_buffer;
@ -984,8 +1027,8 @@ private:
// flush levels // flush levels
std::vector<size_t> pending_flush_queries; std::vector<size_t> pending_flush_queries;
std::deque<StagingBufferRef> download_buffers; boost::container::devector<StagingBufferRef> download_buffers;
std::deque<std::vector<size_t>> pending_flush_sets; boost::container::devector<std::vector<size_t>> pending_flush_sets;
std::vector<StagingBufferRef> free_queue; std::vector<StagingBufferRef> free_queue;
std::mutex flush_guard; std::mutex flush_guard;
@ -1167,7 +1210,7 @@ private:
// flush levels // flush levels
std::vector<size_t> pending_flush_queries; std::vector<size_t> pending_flush_queries;
std::deque<std::vector<size_t>> pending_flush_sets; boost::container::devector<std::vector<size_t>> pending_flush_sets;
std::mutex flush_guard; std::mutex flush_guard;
}; };

View file

@ -10,6 +10,7 @@
#include <deque> #include <deque>
#include <memory> #include <memory>
#include <string> #include <string>
#include <boost/container/devector.hpp>
#include <QList> #include <QList>
#include <QObject> #include <QObject>
@ -92,7 +93,7 @@ private:
std::mutex lock; std::mutex lock;
std::condition_variable cv; std::condition_variable cv;
std::deque<std::function<void(GameList*)>> queued_events; boost::container::devector<std::function<void(GameList*)>> queued_events;
std::atomic_bool stop_requested = false; std::atomic_bool stop_requested = false;
Common::Event processing_completed; Common::Event processing_completed;