From 5beae25bdf481427ff9a038d532ac2b566628063 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Mon, 12 Feb 2018 16:36:42 +0100 Subject: [PATCH] [dxvk] Implemented virtual query class and query pool stub --- src/dxvk/dxvk_context.cpp | 10 +++ src/dxvk/dxvk_context.h | 16 ++++ src/dxvk/dxvk_query.cpp | 119 ++++++++++++++++++++------ src/dxvk/dxvk_query.h | 156 +++++++++++++++++++++++++++++++---- src/dxvk/dxvk_query_pool.cpp | 17 ++++ src/dxvk/dxvk_query_pool.h | 34 ++++++++ src/dxvk/meson.build | 1 + 7 files changed, 308 insertions(+), 45 deletions(-) create mode 100644 src/dxvk/dxvk_query_pool.cpp create mode 100644 src/dxvk/dxvk_query_pool.h diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index a6fd259b3..323fcbcbb 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -58,6 +58,16 @@ namespace dxvk { } + void DxvkContext::beginQuery(const Rc& query) { + // TODO implement + } + + + void DxvkContext::endQuery(const Rc& query) { + // TODO implement + } + + void DxvkContext::bindFramebuffer(const Rc& fb) { if (m_state.om.framebuffer != fb) { this->renderPassEnd(); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index d42f8a1d6..54a73270d 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -5,6 +5,7 @@ #include "dxvk_cmdlist.h" #include "dxvk_context_state.h" #include "dxvk_data.h" +#include "dxvk_query.h" #include "dxvk_util.h" namespace dxvk { @@ -47,6 +48,21 @@ namespace dxvk { */ Rc endRecording(); + /** + * \brief Begins gathering query data + * \param [in] query The query to end + */ + void beginQuery( + const Rc& query); + + /** + * \brief Ends gathering query data + * + * \param [in] query The query to end + */ + void endQuery( + const Rc& query); + /** * \brief Sets framebuffer * \param [in] fb Framebuffer diff --git a/src/dxvk/dxvk_query.cpp b/src/dxvk/dxvk_query.cpp index 9d591408b..df15dc8b8 100644 --- a/src/dxvk/dxvk_query.cpp +++ b/src/dxvk/dxvk_query.cpp @@ -1,38 +1,103 @@ #include "dxvk_query.h" namespace dxvk { + + DxvkQuery::DxvkQuery(VkQueryType type) + : m_type(type) { - DxvkQuery::DxvkQuery( - const Rc& vkd, - VkQueryType type) - : m_vkd(vkd), m_type(type) { - VkQueryPoolCreateInfo info; - info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; - info.pNext = nullptr; - info.flags = 0; - info.queryType = type; - info.queryCount = MaxNumQueryCountPerPool; - 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) - throw DxvkError("DXVK: Failed to create query pool"); } DxvkQuery::~DxvkQuery() { - m_vkd->vkDestroyQueryPool( - m_vkd->device(), m_queryPool, nullptr); + + } + + + uint32_t DxvkQuery::invalidate() { + std::unique_lock lock(m_mutex); + + m_status = DxvkQueryStatus::Reset; + m_data = DxvkQueryData { }; + + m_queryIndex = 0; + m_queryCount = 0; + + return ++m_revision; + } + + + DxvkQueryStatus DxvkQuery::getData(DxvkQueryData& data) { + std::unique_lock lock(m_mutex); + + if (m_status == DxvkQueryStatus::Available) + data = m_data; + + return m_status; + } + + + void DxvkQuery::beginRecording(uint32_t revision) { + std::unique_lock lock(m_mutex); + + if (m_revision == revision) + m_status = DxvkQueryStatus::Active; + } + + + void DxvkQuery::endRecording(uint32_t revision) { + std::unique_lock lock(m_mutex); + + if (m_revision == revision) + m_status = DxvkQueryStatus::Pending; + } + + + void DxvkQuery::associateQuery(uint32_t revision) { + std::unique_lock lock(m_mutex); + + if (m_revision == revision) + m_queryCount += 1; + } + + + void DxvkQuery::updateData( + uint32_t revision, + const DxvkQueryData& data) { + std::unique_lock lock(m_mutex); + + if (m_revision == revision) { + switch (m_type) { + case VK_QUERY_TYPE_OCCLUSION: + m_data.occlusion.samplesPassed += data.occlusion.samplesPassed; + break; + + case VK_QUERY_TYPE_TIMESTAMP: + m_data.timestamp.time = data.timestamp.time; + break; + + case VK_QUERY_TYPE_PIPELINE_STATISTICS: + m_data.statistic.iaVertices += data.statistic.iaVertices; + m_data.statistic.iaPrimitives += data.statistic.iaPrimitives; + m_data.statistic.vsInvocations += data.statistic.vsInvocations; + m_data.statistic.gsInvocations += data.statistic.gsInvocations; + m_data.statistic.gsPrimitives += data.statistic.gsPrimitives; + m_data.statistic.clipInvocations += data.statistic.clipInvocations; + m_data.statistic.clipPrimitives += data.statistic.clipPrimitives; + m_data.statistic.fsInvocations += data.statistic.fsInvocations; + m_data.statistic.tcsPatches += data.statistic.tcsPatches; + m_data.statistic.tesInvocations += data.statistic.tesInvocations; + m_data.statistic.csInvocations += data.statistic.csInvocations; + break; + + default: + Logger::err(str::format("DxvkQuery: Unhandled query type: ", m_type)); + } + + if (++m_queryIndex == m_queryCount && m_status == DxvkQueryStatus::Pending) { + m_status = DxvkQueryStatus::Available; + m_signal.notify_all(); + } + } } } \ No newline at end of file diff --git a/src/dxvk/dxvk_query.h b/src/dxvk/dxvk_query.h index aa4923692..e15c71b1e 100644 --- a/src/dxvk/dxvk_query.h +++ b/src/dxvk/dxvk_query.h @@ -1,40 +1,160 @@ #pragma once +#include +#include + #include "dxvk_limits.h" namespace dxvk { /** - * \brief DXVK query object + * \brief Query status * - * Creates a Vulkan query pool that acts as if it - * were a single query. This approach is necessary - * in order to keep evaluating the query across - * multiple command submissions. + * Allows the application to query + * the current status of the query. */ - class DxvkQuery { + enum class DxvkQueryStatus : uint32_t { + Reset = 0, ///< Query is reset + Active = 1, ///< Query is being recorded + Pending = 2, ///< Query has been recorded + Available = 3, ///< Query results can be retrieved + }; + + /** + * \brief Occlusion query data + * + * Stores the number of samples + * that passes fragment tests. + */ + struct DxvkQueryOcclusionData { + uint64_t samplesPassed; + }; + + /** + * \brief Timestamp data + * + * Stores a GPU time stamp. + */ + struct DxvkQueryTimestampData { + uint64_t time; + }; + + /** + * \brief Pipeline statistics + * + * Stores the counters for + * pipeline statistics queries. + */ + struct DxvkQueryStatisticData { + uint64_t iaVertices; + uint64_t iaPrimitives; + uint64_t vsInvocations; + uint64_t gsInvocations; + uint64_t gsPrimitives; + uint64_t clipInvocations; + uint64_t clipPrimitives; + uint64_t fsInvocations; + uint64_t tcsPatches; + uint64_t tesInvocations; + uint64_t csInvocations; + }; + + /** + * \brief Query data + * + * A union that stores query data. Select an + * appropriate member based on the query type. + */ + union DxvkQueryData { + DxvkQueryOcclusionData occlusion; + DxvkQueryTimestampData timestamp; + DxvkQueryStatisticData statistic; + }; + + /** + * \brief Query object + * + * Represents a single virtual query. Since queries + * in Vulkan cannot be active across command buffer + * submissions, we need to + */ + class DxvkQuery : public RcObject { public: - DxvkQuery( - const Rc& vkd, - VkQueryType type); + DxvkQuery(VkQueryType type); ~DxvkQuery(); /** - * \brief Query pool handle - * \returns Query pool handle + * \brief Resets the query object + * + * Increments the revision number which will + * be used to determine when query data becomes + * available. All asynchronous query operations + * will take the revision number as an argument. + * \returns The new query revision number */ - VkQueryPool handle() const { - return m_queryPool; - } + uint32_t invalidate(); + + /** + * \brief Retrieves query data + * + * \param [out] data Query data + * \returns Query status + */ + DxvkQueryStatus getData( + DxvkQueryData& data); + + /** + * \brief Begins recording the query + * + * Sets internal query state to 'active'. + * \param [in] revision Query version ID + */ + void beginRecording(uint32_t revision); + + /** + * \brief Ends recording the query + * + * Sets internal query state to 'pending'. + * \param [in] revision Query version ID + */ + void endRecording(uint32_t revision); + + /** + * \brief Increments internal query count + * + * The internal query count is used to determine + * when the query data is actually available. + * \param [in] revision Query version ID + */ + void associateQuery(uint32_t revision); + + /** + * \brief Updates query data + * + * Called by the command submission thread after + * the Vulkan queries have been evaluated. + * \param [in] revision Query version ID + * \param [in] data Query data + */ + void updateData( + uint32_t revision, + const DxvkQueryData& data); private: - Rc m_vkd = nullptr; - VkQueryType m_type = VK_QUERY_TYPE_END_RANGE; - VkQueryPool m_queryPool = VK_NULL_HANDLE; - uint32_t m_queryId = 0; + const VkQueryType m_type; + + std::mutex m_mutex; + std::condition_variable m_signal; + + DxvkQueryStatus m_status = DxvkQueryStatus::Reset; + DxvkQueryData m_data = {}; + + uint32_t m_queryIndex = 0; + uint32_t m_queryCount = 0; + uint64_t m_revision = 0; }; diff --git a/src/dxvk/dxvk_query_pool.cpp b/src/dxvk/dxvk_query_pool.cpp new file mode 100644 index 000000000..c4d5957c1 --- /dev/null +++ b/src/dxvk/dxvk_query_pool.cpp @@ -0,0 +1,17 @@ +#include "dxvk_query_pool.h" + +namespace dxvk { + + DxvkQueryPool::DxvkQueryPool( + const Rc& fn, + VkQueryType queryType, + uint32_t queryCount) { + + } + + + DxvkQueryPool::~DxvkQueryPool() { + + } + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_query_pool.h b/src/dxvk/dxvk_query_pool.h new file mode 100644 index 000000000..b157cca0a --- /dev/null +++ b/src/dxvk/dxvk_query_pool.h @@ -0,0 +1,34 @@ +#pragma once + +#include "dxvk_query.h" + +namespace dxvk { + + /** + * \brief Query pool + * + * Manages a Vulkan query pool. This is used + * to allocate actual query objects for virtual + * query objects. + */ + class DxvkQueryPool : public RcObject { + + public: + + DxvkQueryPool( + const Rc& fn, + VkQueryType queryType, + uint32_t queryCount); + + ~DxvkQueryPool(); + + private: + + Rc m_vkd; + VkQueryPool m_queryPool = VK_NULL_HANDLE; + + std::vector> m_queries; + + }; + +} \ No newline at end of file diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index c4fab4019..824d45656 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -29,6 +29,7 @@ dxvk_src = files([ 'dxvk_pipelayout.cpp', 'dxvk_pipemanager.cpp', 'dxvk_query.cpp', + 'dxvk_query_pool.cpp', 'dxvk_queue.cpp', 'dxvk_renderpass.cpp', 'dxvk_resource.cpp',