11 changed files with 327 additions and 20 deletions
-
2src/video_core/CMakeLists.txt
-
37src/video_core/query_cache.h
-
11src/video_core/renderer_opengl/gl_query_cache.cpp
-
11src/video_core/renderer_opengl/gl_query_cache.h
-
10src/video_core/renderer_vulkan/vk_device.cpp
-
122src/video_core/renderer_vulkan/vk_query_cache.cpp
-
104src/video_core/renderer_vulkan/vk_query_cache.h
-
21src/video_core/renderer_vulkan/vk_rasterizer.cpp
-
6src/video_core/renderer_vulkan/vk_rasterizer.h
-
8src/video_core/renderer_vulkan/vk_scheduler.cpp
-
15src/video_core/renderer_vulkan/vk_scheduler.h
@ -0,0 +1,122 @@ |
|||||
|
// Copyright 2020 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include <algorithm>
|
||||
|
#include <cstddef>
|
||||
|
#include <cstdint>
|
||||
|
#include <utility>
|
||||
|
#include <vector>
|
||||
|
|
||||
|
#include "video_core/renderer_vulkan/declarations.h"
|
||||
|
#include "video_core/renderer_vulkan/vk_device.h"
|
||||
|
#include "video_core/renderer_vulkan/vk_query_cache.h"
|
||||
|
#include "video_core/renderer_vulkan/vk_resource_manager.h"
|
||||
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
|
|
||||
|
namespace Vulkan { |
||||
|
|
||||
|
namespace { |
||||
|
|
||||
|
constexpr std::array QUERY_TARGETS = {vk::QueryType::eOcclusion}; |
||||
|
|
||||
|
constexpr vk::QueryType GetTarget(VideoCore::QueryType type) { |
||||
|
return QUERY_TARGETS[static_cast<std::size_t>(type)]; |
||||
|
} |
||||
|
|
||||
|
} // Anonymous namespace
|
||||
|
|
||||
|
QueryPool::QueryPool() : VKFencedPool{GROW_STEP} {} |
||||
|
|
||||
|
QueryPool::~QueryPool() = default; |
||||
|
|
||||
|
void QueryPool::Initialize(const VKDevice& device_, VideoCore::QueryType type_) { |
||||
|
device = &device_; |
||||
|
type = type_; |
||||
|
} |
||||
|
|
||||
|
std::pair<vk::QueryPool, std::uint32_t> QueryPool::Commit(VKFence& fence) { |
||||
|
std::size_t index; |
||||
|
do { |
||||
|
index = CommitResource(fence); |
||||
|
} while (usage[index]); |
||||
|
usage[index] = true; |
||||
|
|
||||
|
return {*pools[index / GROW_STEP], static_cast<std::uint32_t>(index % GROW_STEP)}; |
||||
|
} |
||||
|
|
||||
|
void QueryPool::Allocate(std::size_t begin, std::size_t end) { |
||||
|
usage.resize(end); |
||||
|
|
||||
|
const auto dev = device->GetLogical(); |
||||
|
const u32 size = static_cast<u32>(end - begin); |
||||
|
const vk::QueryPoolCreateInfo query_pool_ci({}, GetTarget(type), size, {}); |
||||
|
pools.push_back(dev.createQueryPoolUnique(query_pool_ci, nullptr, device->GetDispatchLoader())); |
||||
|
} |
||||
|
|
||||
|
void QueryPool::Reserve(std::pair<vk::QueryPool, std::uint32_t> query) { |
||||
|
const auto it = |
||||
|
std::find_if(std::begin(pools), std::end(pools), |
||||
|
[query_pool = query.first](auto& pool) { return query_pool == *pool; }); |
||||
|
ASSERT(it != std::end(pools)); |
||||
|
|
||||
|
const std::ptrdiff_t pool_index = std::distance(std::begin(pools), it); |
||||
|
usage[pool_index * GROW_STEP + static_cast<std::ptrdiff_t>(query.second)] = false; |
||||
|
} |
||||
|
|
||||
|
VKQueryCache::VKQueryCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer, |
||||
|
const VKDevice& device, VKScheduler& scheduler) |
||||
|
: VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter, |
||||
|
QueryPool>{system, rasterizer}, |
||||
|
device{device}, scheduler{scheduler} { |
||||
|
for (std::size_t i = 0; i < static_cast<std::size_t>(VideoCore::NumQueryTypes); ++i) { |
||||
|
query_pools[i].Initialize(device, static_cast<VideoCore::QueryType>(i)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
VKQueryCache::~VKQueryCache() = default; |
||||
|
|
||||
|
std::pair<vk::QueryPool, std::uint32_t> VKQueryCache::AllocateQuery(VideoCore::QueryType type) { |
||||
|
return query_pools[static_cast<std::size_t>(type)].Commit(scheduler.GetFence()); |
||||
|
} |
||||
|
|
||||
|
void VKQueryCache::Reserve(VideoCore::QueryType type, |
||||
|
std::pair<vk::QueryPool, std::uint32_t> query) { |
||||
|
query_pools[static_cast<std::size_t>(type)].Reserve(query); |
||||
|
} |
||||
|
|
||||
|
HostCounter::HostCounter(VKQueryCache& cache, std::shared_ptr<HostCounter> dependency, |
||||
|
VideoCore::QueryType type) |
||||
|
: VideoCommon::HostCounterBase<VKQueryCache, HostCounter>{std::move(dependency)}, cache{cache}, |
||||
|
type{type}, query{cache.AllocateQuery(type)}, ticks{cache.Scheduler().Ticks()} { |
||||
|
const auto dev = cache.Device().GetLogical(); |
||||
|
cache.Scheduler().Record([dev, query = query](vk::CommandBuffer cmdbuf, auto& dld) { |
||||
|
dev.resetQueryPoolEXT(query.first, query.second, 1, dld); |
||||
|
cmdbuf.beginQuery(query.first, query.second, vk::QueryControlFlagBits::ePrecise, dld); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
HostCounter::~HostCounter() { |
||||
|
cache.Reserve(type, query); |
||||
|
} |
||||
|
|
||||
|
void HostCounter::EndQuery() { |
||||
|
cache.Scheduler().Record([query = query](auto cmdbuf, auto& dld) { |
||||
|
cmdbuf.endQuery(query.first, query.second, dld); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
u64 HostCounter::BlockingQuery() const { |
||||
|
if (ticks >= cache.Scheduler().Ticks()) { |
||||
|
cache.Scheduler().Flush(); |
||||
|
} |
||||
|
|
||||
|
const auto dev = cache.Device().GetLogical(); |
||||
|
const auto& dld = cache.Device().GetDispatchLoader(); |
||||
|
u64 value; |
||||
|
dev.getQueryPoolResults(query.first, query.second, 1, sizeof(value), &value, sizeof(value), |
||||
|
vk::QueryResultFlagBits::e64 | vk::QueryResultFlagBits::eWait, dld); |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
} // namespace Vulkan
|
||||
@ -0,0 +1,104 @@ |
|||||
|
// Copyright 2020 yuzu Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <cstddef> |
||||
|
#include <cstdint> |
||||
|
#include <memory> |
||||
|
#include <utility> |
||||
|
#include <vector> |
||||
|
|
||||
|
#include "common/common_types.h" |
||||
|
#include "video_core/query_cache.h" |
||||
|
#include "video_core/renderer_vulkan/declarations.h" |
||||
|
#include "video_core/renderer_vulkan/vk_resource_manager.h" |
||||
|
|
||||
|
namespace VideoCore { |
||||
|
class RasterizerInterface; |
||||
|
} |
||||
|
|
||||
|
namespace Vulkan { |
||||
|
|
||||
|
class CachedQuery; |
||||
|
class HostCounter; |
||||
|
class VKDevice; |
||||
|
class VKQueryCache; |
||||
|
class VKScheduler; |
||||
|
|
||||
|
using CounterStream = VideoCommon::CounterStreamBase<VKQueryCache, HostCounter>; |
||||
|
|
||||
|
class QueryPool final : public VKFencedPool { |
||||
|
public: |
||||
|
explicit QueryPool(); |
||||
|
~QueryPool() override; |
||||
|
|
||||
|
void Initialize(const VKDevice& device, VideoCore::QueryType type); |
||||
|
|
||||
|
std::pair<vk::QueryPool, std::uint32_t> Commit(VKFence& fence); |
||||
|
|
||||
|
void Reserve(std::pair<vk::QueryPool, std::uint32_t> query); |
||||
|
|
||||
|
protected: |
||||
|
void Allocate(std::size_t begin, std::size_t end) override; |
||||
|
|
||||
|
private: |
||||
|
static constexpr std::size_t GROW_STEP = 512; |
||||
|
|
||||
|
const VKDevice* device = nullptr; |
||||
|
VideoCore::QueryType type = {}; |
||||
|
|
||||
|
std::vector<UniqueQueryPool> pools; |
||||
|
std::vector<bool> usage; |
||||
|
}; |
||||
|
|
||||
|
class VKQueryCache final |
||||
|
: public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter, |
||||
|
QueryPool> { |
||||
|
public: |
||||
|
explicit VKQueryCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer, |
||||
|
const VKDevice& device, VKScheduler& scheduler); |
||||
|
~VKQueryCache(); |
||||
|
|
||||
|
std::pair<vk::QueryPool, std::uint32_t> AllocateQuery(VideoCore::QueryType type); |
||||
|
|
||||
|
void Reserve(VideoCore::QueryType type, std::pair<vk::QueryPool, std::uint32_t> query); |
||||
|
|
||||
|
const VKDevice& Device() const noexcept { |
||||
|
return device; |
||||
|
} |
||||
|
|
||||
|
VKScheduler& Scheduler() const noexcept { |
||||
|
return scheduler; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
const VKDevice& device; |
||||
|
VKScheduler& scheduler; |
||||
|
}; |
||||
|
|
||||
|
class HostCounter final : public VideoCommon::HostCounterBase<VKQueryCache, HostCounter> { |
||||
|
public: |
||||
|
explicit HostCounter(VKQueryCache& cache, std::shared_ptr<HostCounter> dependency, |
||||
|
VideoCore::QueryType type); |
||||
|
~HostCounter(); |
||||
|
|
||||
|
void EndQuery(); |
||||
|
|
||||
|
private: |
||||
|
u64 BlockingQuery() const override; |
||||
|
|
||||
|
VKQueryCache& cache; |
||||
|
const VideoCore::QueryType type; |
||||
|
const std::pair<vk::QueryPool, std::uint32_t> query; |
||||
|
const u64 ticks; |
||||
|
}; |
||||
|
|
||||
|
class CachedQuery : public VideoCommon::CachedQueryBase<HostCounter> { |
||||
|
public: |
||||
|
explicit CachedQuery(VKQueryCache&, VideoCore::QueryType, VAddr cpu_addr, u8* host_ptr) |
||||
|
: VideoCommon::CachedQueryBase<HostCounter>{cpu_addr, host_ptr} {} |
||||
|
}; |
||||
|
|
||||
|
} // namespace Vulkan |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue