diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 323fcbcb..ee71c14b 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -47,24 +47,44 @@ namespace dxvk { DxvkContextFlag::CpDirtyPipeline, DxvkContextFlag::CpDirtyPipelineState, DxvkContextFlag::CpDirtyResources); + + // Restart queries that were active during + // the last command buffer submission. + this->beginActiveQueries(); } Rc DxvkContext::endRecording() { this->renderPassEnd(); + this->endActiveQueries(); m_cmd->endRecording(); return std::exchange(m_cmd, nullptr); } - void DxvkContext::beginQuery(const Rc& query) { - // TODO implement + void DxvkContext::beginQuery(const DxvkQueryRevision& query) { + DxvkQueryHandle handle; // TODO = allocateQuery(...) + + m_cmd->cmdBeginQuery( + handle.queryPool, + handle.queryId, + 0); + + query.query->beginRecording(query.revision); + this->insertActiveQuery(query); } - void DxvkContext::endQuery(const Rc& query) { - // TODO implement + void DxvkContext::endQuery(const DxvkQueryRevision& query) { + DxvkQueryHandle handle = query.query->getHandle(); + + m_cmd->cmdEndQuery( + handle.queryPool, + handle.queryId); + + query.query->endRecording(query.revision); + this->eraseActiveQuery(query); } @@ -1581,4 +1601,51 @@ namespace dxvk { m_barriers.recordCommands(m_cmd); } + + void DxvkContext::resetQueryPool(const Rc& pool) { + this->renderPassEnd(); + + m_cmd->cmdResetQueryPool( + pool->handle(), 0, + pool->queryCount()); + } + + + void DxvkContext::beginActiveQueries() { + for (const DxvkQueryRevision& query : m_activeQueries) { + DxvkQueryHandle handle; // TODO = allocateQuery(...) + + m_cmd->cmdBeginQuery( + handle.queryPool, + handle.queryId, + 0); + } + } + + + 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 54a73270..f36f9348 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -5,7 +5,7 @@ #include "dxvk_cmdlist.h" #include "dxvk_context_state.h" #include "dxvk_data.h" -#include "dxvk_query.h" +#include "dxvk_query_pool.h" #include "dxvk_util.h" namespace dxvk { @@ -49,19 +49,18 @@ namespace dxvk { Rc endRecording(); /** - * \brief Begins gathering query data + * \brief Begins generating query data * \param [in] query The query to end */ void beginQuery( - const Rc& query); + const DxvkQueryRevision& query); /** - * \brief Ends gathering query data - * + * \brief Ends generating query data * \param [in] query The query to end */ void endQuery( - const Rc& query); + const DxvkQueryRevision& query); /** * \brief Sets framebuffer @@ -555,6 +554,8 @@ namespace dxvk { VkPipeline m_gpActivePipeline = VK_NULL_HANDLE; VkPipeline m_cpActivePipeline = VK_NULL_HANDLE; + std::vector m_activeQueries; + std::array m_rc; std::array m_descInfos; std::array m_descWrites; @@ -594,6 +595,19 @@ namespace dxvk { void commitComputeBarriers(); + void resetQueryPool( + const Rc& pool); + + void beginActiveQueries(); + + void endActiveQueries(); + + void insertActiveQuery( + const DxvkQueryRevision& query); + + void eraseActiveQuery( + const DxvkQueryRevision& query); + }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index a385b0cd..a678b9f3 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -145,6 +145,12 @@ namespace dxvk { } + Rc DxvkDevice::createQueryPool( + VkQueryType queryType) { + return new DxvkQueryPool(m_vkd, queryType); + } + + 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 17167fa6..0a56e92d 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -13,6 +13,7 @@ #include "dxvk_pipecache.h" #include "dxvk_pipemanager.h" #include "dxvk_queue.h" +#include "dxvk_query_pool.h" #include "dxvk_recycler.h" #include "dxvk_renderpass.h" #include "dxvk_sampler.h" @@ -206,6 +207,13 @@ namespace dxvk { const Rc& image, const DxvkImageViewCreateInfo& createInfo); + /** + * \brief Creates a query pool + * \param [in] queryType Query type + */ + Rc createQueryPool( + VkQueryType queryType); + /** * \brief Creates a sampler object * diff --git a/src/dxvk/dxvk_limits.h b/src/dxvk/dxvk_limits.h index ecf2f869..0ea5143d 100644 --- a/src/dxvk/dxvk_limits.h +++ b/src/dxvk/dxvk_limits.h @@ -13,7 +13,7 @@ namespace dxvk { MaxNumResourceSlots = 1096, MaxNumActiveBindings = 128, MaxNumQueuedCommandBuffers = 8, - MaxNumQueryCountPerPool = 16, + MaxNumQueryCountPerPool = 128, MaxVertexBindingStride = 2048, MaxPushConstantSize = 128, }; diff --git a/src/dxvk/dxvk_query.cpp b/src/dxvk/dxvk_query.cpp index df15dc8b..c90e1350 100644 --- a/src/dxvk/dxvk_query.cpp +++ b/src/dxvk/dxvk_query.cpp @@ -36,6 +36,11 @@ namespace dxvk { } + DxvkQueryHandle DxvkQuery::getHandle() { + return m_handle; + } + + void DxvkQuery::beginRecording(uint32_t revision) { std::unique_lock lock(m_mutex); @@ -47,16 +52,28 @@ namespace dxvk { void DxvkQuery::endRecording(uint32_t revision) { std::unique_lock lock(m_mutex); - if (m_revision == revision) - m_status = DxvkQueryStatus::Pending; + if (m_revision == revision) { + if (m_queryIndex < m_queryCount) { + m_status = DxvkQueryStatus::Pending; + } else { + m_status = DxvkQueryStatus::Available; + m_signal.notify_all(); + } + + m_handle = DxvkQueryHandle(); + } } - void DxvkQuery::associateQuery(uint32_t revision) { + void DxvkQuery::associateQuery(uint32_t revision, DxvkQueryHandle handle) { std::unique_lock lock(m_mutex); if (m_revision == revision) m_queryCount += 1; + + // Assign the handle either way as this + // will be used by the DXVK context. + m_handle = handle; } diff --git a/src/dxvk/dxvk_query.h b/src/dxvk/dxvk_query.h index e15c71b1..1cba8a59 100644 --- a/src/dxvk/dxvk_query.h +++ b/src/dxvk/dxvk_query.h @@ -71,6 +71,17 @@ namespace dxvk { DxvkQueryStatisticData statistic; }; + /** + * \brief Query entry + * + * Stores the pool handle and the + * index of a single Vulkan query. + */ + struct DxvkQueryHandle { + VkQueryPool queryPool = VK_NULL_HANDLE; + uint32_t queryId = 0; + }; + /** * \brief Query object * @@ -105,6 +116,12 @@ namespace dxvk { DxvkQueryStatus getData( DxvkQueryData& data); + /** + * \brief Gets current query handle + * \returns The current query handle + */ + DxvkQueryHandle getHandle(); + /** * \brief Begins recording the query * @@ -127,8 +144,11 @@ namespace dxvk { * The internal query count is used to determine * when the query data is actually available. * \param [in] revision Query version ID + * \param [in] handle The query handle */ - void associateQuery(uint32_t revision); + void associateQuery( + uint32_t revision, + DxvkQueryHandle handle); /** * \brief Updates query data @@ -151,6 +171,7 @@ namespace dxvk { DxvkQueryStatus m_status = DxvkQueryStatus::Reset; DxvkQueryData m_data = {}; + DxvkQueryHandle m_handle; uint32_t m_queryIndex = 0; uint32_t m_queryCount = 0; @@ -158,4 +179,15 @@ namespace dxvk { }; + /** + * \brief Query revision + * + * Stores the query object and the + * version ID for query operations. + */ + struct DxvkQueryRevision { + Rc query; + uint32_t revision; + }; + } \ No newline at end of file diff --git a/src/dxvk/dxvk_query_pool.cpp b/src/dxvk/dxvk_query_pool.cpp index c4d5957c..7321b9e9 100644 --- a/src/dxvk/dxvk_query_pool.cpp +++ b/src/dxvk/dxvk_query_pool.cpp @@ -3,15 +3,73 @@ namespace dxvk { DxvkQueryPool::DxvkQueryPool( - const Rc& fn, - VkQueryType queryType, - uint32_t queryCount) { + const Rc& vkd, + VkQueryType queryType) + : m_vkd(vkd), m_queryType(queryType) { + VkQueryPoolCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.queryType = queryType; + info.queryCount = MaxNumQueryCountPerPool; + info.pipelineStatistics = 0; + if (queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) { + info.pipelineStatistics + = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT + | VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT + | VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT + | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT + | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT + | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT + | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT + | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT + | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT + | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT + | VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT; + } + + if (m_vkd->vkCreateQueryPool(m_vkd->device(), &info, nullptr, &m_queryPool) != VK_SUCCESS) + Logger::err("DxvkQueryPool: Failed to create query pool"); } DxvkQueryPool::~DxvkQueryPool() { + m_vkd->vkDestroyQueryPool( + m_vkd->device(), m_queryPool, nullptr); + } + + + DxvkQueryHandle DxvkQueryPool::allocQuery(const DxvkQueryRevision& query) { + const DxvkQueryHandle result = { m_queryPool, m_queryId }; + query.query->associateQuery(query.revision, result); + m_queries.at(m_queryId) = query; + m_queryId += 1; + return result; + } + + + VkResult DxvkQueryPool::getData( + uint32_t queryIndex, + uint32_t queryCount) { + std::array results; + + const VkResult status = m_vkd->vkGetQueryPoolResults( + m_vkd->device(), m_queryPool, queryIndex, queryCount, + sizeof(DxvkQueryData) * MaxNumQueryCountPerPool, + results.data(), sizeof(DxvkQueryData), + VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); + + if (status != VK_SUCCESS) + return status; + + for (uint32_t i = 0; i < queryCount; i++) { + const DxvkQueryRevision& query = m_queries.at(queryIndex + i); + query.query->updateData(query.revision, results.at(i)); + } + + return VK_SUCCESS; } } \ No newline at end of file diff --git a/src/dxvk/dxvk_query_pool.h b/src/dxvk/dxvk_query_pool.h index b157cca0..a839e470 100644 --- a/src/dxvk/dxvk_query_pool.h +++ b/src/dxvk/dxvk_query_pool.h @@ -16,18 +16,56 @@ namespace dxvk { public: DxvkQueryPool( - const Rc& fn, - VkQueryType queryType, - uint32_t queryCount); + const Rc& vkd, + VkQueryType queryType); ~DxvkQueryPool(); + /** + * \brief Query pool handle + * \returns Query pool handle + */ + VkQueryPool handle() const { + return m_queryPool; + } + + /** + * \brief Query count + * \returns Query count + */ + uint32_t queryCount() const { + return MaxNumQueryCountPerPool; + } + + /** + * \brief Allocates a Vulkan query + * + * \param [in] revision Query revision + * \returns The query ID and pool handle + */ + DxvkQueryHandle allocQuery( + const DxvkQueryRevision& revision); + + /** + * \brief Writes back data for a range of queries + * + * \param [in] queryIndex First query in the range + * \param [in] queryCount Number of queries + * \returns Query result status + */ + VkResult getData( + uint32_t queryIndex, + uint32_t queryCount); + private: Rc m_vkd; - VkQueryPool m_queryPool = VK_NULL_HANDLE; - std::vector> m_queries; + VkQueryType m_queryType; + VkQueryPool m_queryPool = VK_NULL_HANDLE; + + std::array m_queries; + uint32_t m_queryId = 0; }; diff --git a/src/util/rc/util_rc_ptr.h b/src/util/rc/util_rc_ptr.h index b2b297e3..afd901d2 100644 --- a/src/util/rc/util_rc_ptr.h +++ b/src/util/rc/util_rc_ptr.h @@ -115,14 +115,6 @@ namespace dxvk { }; - - template - struct RcHash { - size_t operator () (const Rc& rc) const { - return std::hash()(rc.ptr()); - } - }; - } template