// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include #include #include #include #include #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(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 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(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(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 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(query.second)] = false; } VKQueryCache::VKQueryCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer, const VKDevice& device, VKScheduler& scheduler) : VideoCommon::QueryCacheBase{system, rasterizer}, device{device}, scheduler{scheduler} { for (std::size_t i = 0; i < static_cast(VideoCore::NumQueryTypes); ++i) { query_pools[i].Initialize(device, static_cast(i)); } } VKQueryCache::~VKQueryCache() = default; std::pair VKQueryCache::AllocateQuery(VideoCore::QueryType type) { return query_pools[static_cast(type)].Commit(scheduler.GetFence()); } void VKQueryCache::Reserve(VideoCore::QueryType type, std::pair query) { query_pools[static_cast(type)].Reserve(query); } HostCounter::HostCounter(VKQueryCache& cache, std::shared_ptr dependency, VideoCore::QueryType type) : VideoCommon::HostCounterBase{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