[video_core] better datastructures (deque -> devector) experiment, remove uneeded overhead from deque() on places where it wasn't needed
All checks were successful
eden-license / license-header (pull_request) Successful in 25s
All checks were successful
eden-license / license-header (pull_request) Successful in 25s
Signed-off-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
parent
d19a7c3782
commit
bb5222df52
5 changed files with 152 additions and 206 deletions
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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.elems[current_bank_id];
|
||||||
current_bank = &bank_pool.GetBank(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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue