From 657093c14edbc14f50856da81fb968784ce30e78 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 31 Aug 2018 15:34:53 +0200 Subject: [PATCH] [dxvk] Refactor query management Moved all query-related state tracking and management into a separate class. This allows for new query types to be added in the future, and makes less dodgy assumptions about the current state when beginning or ending a query. --- src/dxvk/dxvk_context.cpp | 117 ++++-------------------- src/dxvk/dxvk_context.h | 22 +---- src/dxvk/dxvk_device.cpp | 7 -- src/dxvk/dxvk_device.h | 8 -- src/dxvk/dxvk_query_manager.cpp | 155 ++++++++++++++++++++++++++++++++ src/dxvk/dxvk_query_manager.h | 118 ++++++++++++++++++++++++ src/dxvk/dxvk_query_pool.h | 5 +- src/dxvk/meson.build | 1 + 8 files changed, 296 insertions(+), 137 deletions(-) create mode 100644 src/dxvk/dxvk_query_manager.cpp create mode 100644 src/dxvk/dxvk_query_manager.h diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 84dfb1b6..f3b3eab4 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -16,7 +16,8 @@ namespace dxvk { m_pipeMgr (pipelineManager), m_metaClear (metaClearObjects), m_metaMipGen (metaMipGenObjects), - m_metaResolve (metaResolveObjects) { } + m_metaResolve (metaResolveObjects), + m_queries (device->vkd()) { } DxvkContext::~DxvkContext() { @@ -50,10 +51,8 @@ namespace dxvk { Rc DxvkContext::endRecording() { this->spillRenderPass(); - this->trackQueryPool(m_queryPools[VK_QUERY_TYPE_OCCLUSION]); - this->trackQueryPool(m_queryPools[VK_QUERY_TYPE_PIPELINE_STATISTICS]); - this->trackQueryPool(m_queryPools[VK_QUERY_TYPE_TIMESTAMP]); - + m_queries.trackQueryPools(m_cmd); + m_barriers.recordCommands(m_cmd); m_cmd->endRecording(); @@ -63,31 +62,13 @@ namespace dxvk { void DxvkContext::beginQuery(const DxvkQueryRevision& query) { query.query->beginRecording(query.revision); - - if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) { - DxvkQueryHandle handle = this->allocQuery(query); - - m_cmd->cmdBeginQuery( - handle.queryPool, - handle.queryId, - handle.flags); - } - - this->insertActiveQuery(query); + m_queries.enableQuery(m_cmd, query); } void DxvkContext::endQuery(const DxvkQueryRevision& query) { - if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) { - DxvkQueryHandle handle = query.query->getHandle(); - - m_cmd->cmdEndQuery( - handle.queryPool, - handle.queryId); - } - + m_queries.disableQuery(m_cmd, query); query.query->endRecording(query.revision); - this->eraseActiveQuery(query); } @@ -1631,7 +1612,7 @@ namespace dxvk { void DxvkContext::writeTimestamp(const DxvkQueryRevision& query) { - DxvkQueryHandle handle = this->allocQuery(query); + DxvkQueryHandle handle = m_queries.allocQuery(m_cmd, query); m_cmd->cmdWriteTimestamp( VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, @@ -1803,7 +1784,10 @@ namespace dxvk { m_state.om.renderTargets, m_state.om.renderPassOps); - this->beginActiveQueries(); + // Begin occlusion queries + m_queries.beginQueries(m_cmd, { + VK_QUERY_TYPE_OCCLUSION, + VK_QUERY_TYPE_PIPELINE_STATISTICS }); } } @@ -1814,7 +1798,11 @@ namespace dxvk { if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) { m_flags.clr(DxvkContextFlag::GpRenderPassBound); - this->endActiveQueries(); + + m_queries.endQueries(m_cmd, { + VK_QUERY_TYPE_OCCLUSION, + VK_QUERY_TYPE_PIPELINE_STATISTICS }); + this->renderPassUnbindFramebuffer(); } } @@ -2514,77 +2502,4 @@ namespace dxvk { } } - - - DxvkQueryHandle DxvkContext::allocQuery(const DxvkQueryRevision& query) { - const VkQueryType queryType = query.query->type(); - - DxvkQueryHandle queryHandle = DxvkQueryHandle(); - Rc queryPool = m_queryPools[queryType]; - - if (queryPool != nullptr) - queryHandle = queryPool->allocQuery(query); - - if (queryHandle.queryPool == VK_NULL_HANDLE) { - if (queryPool != nullptr) - this->trackQueryPool(queryPool); - - m_queryPools[queryType] = m_device->createQueryPool(queryType, MaxNumQueryCountPerPool); - queryPool = m_queryPools[queryType]; - - queryPool->reset(m_cmd); - queryHandle = queryPool->allocQuery(query); - } - - return queryHandle; - } - - - void DxvkContext::trackQueryPool(const Rc& pool) { - if (pool != nullptr) { - DxvkQueryRange range = pool->getActiveQueryRange(); - - if (range.queryCount > 0) - m_cmd->trackQueryRange(std::move(range)); - } - } - - - void DxvkContext::beginActiveQueries() { - for (const DxvkQueryRevision& query : m_activeQueries) { - DxvkQueryHandle handle = this->allocQuery(query); - - m_cmd->cmdBeginQuery( - handle.queryPool, - handle.queryId, - handle.flags); - } - } - - - void DxvkContext::endActiveQueries() { - for (const DxvkQueryRevision& query : m_activeQueries) { - DxvkQueryHandle handle = query.query->getHandle(); - - m_cmd->cmdEndQuery( - handle.queryPool, - handle.queryId); - } - } - - - void DxvkContext::insertActiveQuery(const DxvkQueryRevision& query) { - m_activeQueries.push_back(query); - } - - - void DxvkContext::eraseActiveQuery(const DxvkQueryRevision& query) { - for (auto i = m_activeQueries.begin(); i != m_activeQueries.end(); i++) { - if (i->query == query.query && i->revision == query.revision) { - m_activeQueries.erase(i); - return; - } - } - } - } \ No newline at end of file diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index ed2065e6..3ee6964e 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -12,6 +12,7 @@ #include "dxvk_pipecache.h" #include "dxvk_pipemanager.h" #include "dxvk_query.h" +#include "dxvk_query_manager.h" #include "dxvk_query_pool.h" #include "dxvk_util.h" @@ -645,8 +646,7 @@ namespace dxvk { DxvkBarrierSet m_barriers; DxvkBarrierSet m_transitions; - // TODO implement this properly... - Rc m_queryPools[3] = { nullptr, nullptr, nullptr }; + DxvkQueryManager m_queries; VkPipeline m_gpActivePipeline = VK_NULL_HANDLE; VkPipeline m_cpActivePipeline = VK_NULL_HANDLE; @@ -654,8 +654,6 @@ namespace dxvk { VkDescriptorSet m_gpSet = VK_NULL_HANDLE; VkDescriptorSet m_cpSet = VK_NULL_HANDLE; - std::vector m_activeQueries; - std::array m_rc; std::array m_descInfos; std::array m_descOffsets; @@ -731,22 +729,6 @@ namespace dxvk { void commitComputeInitBarriers(); void commitComputePostBarriers(); - DxvkQueryHandle allocQuery( - const DxvkQueryRevision& query); - - void trackQueryPool( - const Rc& pool); - - void beginActiveQueries(); - - void endActiveQueries(); - - void insertActiveQuery( - const DxvkQueryRevision& query); - - void eraseActiveQuery( - const DxvkQueryRevision& query); - Rc getTransferBuffer(VkDeviceSize size); }; diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index 13f637c8..860b40c0 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -166,13 +166,6 @@ namespace dxvk { } - Rc DxvkDevice::createQueryPool( - VkQueryType queryType, - uint32_t queryCount) { - return new DxvkQueryPool(m_vkd, queryType, queryCount); - } - - Rc DxvkDevice::createSampler( const DxvkSamplerCreateInfo& createInfo) { return new DxvkSampler(m_vkd, createInfo); diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index d5409c75..3de76217 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -242,14 +242,6 @@ namespace dxvk { const Rc& image, const DxvkImageViewCreateInfo& createInfo); - /** - * \brief Creates a query pool - * \param [in] queryType Query type - */ - Rc createQueryPool( - VkQueryType queryType, - uint32_t queryCount); - /** * \brief Creates a sampler object * diff --git a/src/dxvk/dxvk_query_manager.cpp b/src/dxvk/dxvk_query_manager.cpp new file mode 100644 index 00000000..aab3d471 --- /dev/null +++ b/src/dxvk/dxvk_query_manager.cpp @@ -0,0 +1,155 @@ +#include "dxvk_query_manager.h" +#include "dxvk_query_pool.h" + +namespace dxvk { + + DxvkQueryManager::DxvkQueryManager(const Rc& vkd) + : m_vkd(vkd) { + + } + + + DxvkQueryManager::~DxvkQueryManager() { + + } + + + DxvkQueryHandle DxvkQueryManager::allocQuery( + const Rc& cmd, + const DxvkQueryRevision& query) { + const VkQueryType queryType = query.query->type(); + + DxvkQueryHandle queryHandle = DxvkQueryHandle(); + Rc& queryPool = this->getQueryPool(queryType); + + if (queryPool != nullptr) + queryHandle = queryPool->allocQuery(query); + + if (queryHandle.queryPool == VK_NULL_HANDLE) { + if (queryPool != nullptr) + this->trackQueryPool(cmd, queryPool); + + queryPool = new DxvkQueryPool(m_vkd, queryType, MaxNumQueryCountPerPool); + queryPool->reset(cmd); + + queryHandle = queryPool->allocQuery(query); + } + + return queryHandle; + } + + + void DxvkQueryManager::enableQuery( + const Rc& cmd, + const DxvkQueryRevision& query) { + m_activeQueries.push_back(query); + + if (m_activeTypes.test(query.query->type())) { + DxvkQueryHandle handle = this->allocQuery(cmd, query); + + cmd->cmdBeginQuery( + handle.queryPool, + handle.queryId, + handle.flags); + } + } + + + void DxvkQueryManager::disableQuery( + const Rc& cmd, + const DxvkQueryRevision& query) { + auto iter = m_activeQueries.begin(); + + while (iter != m_activeQueries.end()) { + if (iter->query == query.query + && iter->revision == query.revision) + break; + + iter++; + } + + if (iter != m_activeQueries.end()) { + if (m_activeTypes.test(iter->query->type())) { + DxvkQueryHandle handle = iter->query->getHandle(); + + cmd->cmdEndQuery( + handle.queryPool, + handle.queryId); + } + + m_activeQueries.erase(iter); + } + } + + + void DxvkQueryManager::beginQueries( + const Rc& cmd, + DxvkQueryTypeFlags types) { + m_activeTypes.set(types); + + for (const DxvkQueryRevision& query : m_activeQueries) { + if (types.test(query.query->type())) { + DxvkQueryHandle handle = this->allocQuery(cmd, query); + + cmd->cmdBeginQuery( + handle.queryPool, + handle.queryId, + handle.flags); + } + } + } + + + void DxvkQueryManager::endQueries( + const Rc& cmd, + DxvkQueryTypeFlags types) { + m_activeTypes.clr(types); + + for (const DxvkQueryRevision& query : m_activeQueries) { + if (types.test(query.query->type())) { + DxvkQueryHandle handle = query.query->getHandle(); + + cmd->cmdEndQuery( + handle.queryPool, + handle.queryId); + } + } + } + + + void DxvkQueryManager::trackQueryPools(const Rc& cmd) { + this->trackQueryPool(cmd, m_occlusion); + this->trackQueryPool(cmd, m_pipeStats); + this->trackQueryPool(cmd, m_timestamp); + } + + + void DxvkQueryManager::trackQueryPool( + const Rc& cmd, + const Rc& pool) { + if (pool != nullptr) { + DxvkQueryRange range = pool->getActiveQueryRange(); + + if (range.queryCount > 0) + cmd->trackQueryRange(std::move(range)); + } + } + + + Rc& DxvkQueryManager::getQueryPool(VkQueryType type) { + switch (type) { + case VK_QUERY_TYPE_OCCLUSION: + return m_occlusion; + + case VK_QUERY_TYPE_PIPELINE_STATISTICS: + return m_pipeStats; + + case VK_QUERY_TYPE_TIMESTAMP: + return m_timestamp; + + default: + throw DxvkError("DXVK: Invalid query type"); + } + } + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_query_manager.h b/src/dxvk/dxvk_query_manager.h new file mode 100644 index 00000000..cccf05ef --- /dev/null +++ b/src/dxvk/dxvk_query_manager.h @@ -0,0 +1,118 @@ +#pragma once + +#include + +#include "dxvk_cmdlist.h" +#include "dxvk_query.h" +#include "dxvk_query_pool.h" + +namespace dxvk { + + using DxvkQueryTypeFlags = Flags; + + /** + * \brief Query manager + * + * Manages Vulkan query pools + * and the current query state. + */ + class DxvkQueryManager { + + public: + + DxvkQueryManager(const Rc& vkd); + ~DxvkQueryManager(); + + /** + * \brief Allocates a Vulkan query + * + * Creates a query pool of the correct type if + * necessary, and allocates one query from it. + * \param [in] cmd The context's command list + * \param [in] query The DXVK query revision + * \returns Allocated query handle + */ + DxvkQueryHandle allocQuery( + const Rc& cmd, + const DxvkQueryRevision& query); + + /** + * \brief Enables a query + * + * Starts tracking a query. Depending on the + * query type, unterlying Vulkan queries will + * begin and end on render pass boundaries. + * \param [in] cmd The context's command list + * \param [in] query The query to enable + */ + void enableQuery( + const Rc& cmd, + const DxvkQueryRevision& query); + + /** + * \brief Disables a query + * + * Ends the query if it is currently active, + * and stops tracking any further state changes. + * \param [in] cmd The context's command list + * \param [in] query The query to enable + */ + void disableQuery( + const Rc& cmd, + const DxvkQueryRevision& query); + + /** + * \brief Begins active queries + * + * Creates a Vulkan query for each enabled + * query of the given types and begins them. + * \param [in] cmd The context's command list + * \param [in] types Query types to begin + */ + void beginQueries( + const Rc& cmd, + DxvkQueryTypeFlags types); + + /** + * \brief Ends active queries + * + * Ends active queries of the given types. + * \param [in] cmd The context's command list + * \param [in] types Query types to begin + */ + void endQueries( + const Rc& cmd, + DxvkQueryTypeFlags types); + + /** + * \brief Tracks query pools + * + * Adds all current non-empty query pools to + * the query tracker of the given command list. + * \param [in] cmd The context's command list + */ + void trackQueryPools( + const Rc& cmd); + + private: + + const Rc m_vkd; + + DxvkQueryTypeFlags m_activeTypes; + + Rc m_occlusion; + Rc m_pipeStats; + Rc m_timestamp; + + std::vector m_activeQueries; + + void trackQueryPool( + const Rc& cmd, + const Rc& pool); + + Rc& getQueryPool( + VkQueryType type); + + }; + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_query_pool.h b/src/dxvk/dxvk_query_pool.h index 7f5472b4..bfc68055 100644 --- a/src/dxvk/dxvk_query_pool.h +++ b/src/dxvk/dxvk_query_pool.h @@ -11,6 +11,9 @@ namespace dxvk { /** * \brief Query range + * + * Stores an index of a query in a query pool, + * and the number of queries to track. */ struct DxvkQueryRange { Rc queryPool; @@ -99,5 +102,5 @@ namespace dxvk { uint32_t m_queryRangeLength = 0; }; - + } \ No newline at end of file diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 8edb1179..c913ecad 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -64,6 +64,7 @@ dxvk_src = files([ 'dxvk_pipemanager.cpp', 'dxvk_query.cpp', 'dxvk_query_pool.cpp', + 'dxvk_query_manager.cpp', 'dxvk_query_tracker.cpp', 'dxvk_queue.cpp', 'dxvk_renderpass.cpp',