1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-11 01:24:12 +01:00

[dxvk] Implemented virtual query class and query pool stub

This commit is contained in:
Philip Rebohle 2018-02-12 16:36:42 +01:00
parent 82d324384c
commit 5beae25bdf
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
7 changed files with 308 additions and 45 deletions

View File

@ -58,6 +58,16 @@ namespace dxvk {
} }
void DxvkContext::beginQuery(const Rc<DxvkQuery>& query) {
// TODO implement
}
void DxvkContext::endQuery(const Rc<DxvkQuery>& query) {
// TODO implement
}
void DxvkContext::bindFramebuffer(const Rc<DxvkFramebuffer>& fb) { void DxvkContext::bindFramebuffer(const Rc<DxvkFramebuffer>& fb) {
if (m_state.om.framebuffer != fb) { if (m_state.om.framebuffer != fb) {
this->renderPassEnd(); this->renderPassEnd();

View File

@ -5,6 +5,7 @@
#include "dxvk_cmdlist.h" #include "dxvk_cmdlist.h"
#include "dxvk_context_state.h" #include "dxvk_context_state.h"
#include "dxvk_data.h" #include "dxvk_data.h"
#include "dxvk_query.h"
#include "dxvk_util.h" #include "dxvk_util.h"
namespace dxvk { namespace dxvk {
@ -47,6 +48,21 @@ namespace dxvk {
*/ */
Rc<DxvkCommandList> endRecording(); Rc<DxvkCommandList> endRecording();
/**
* \brief Begins gathering query data
* \param [in] query The query to end
*/
void beginQuery(
const Rc<DxvkQuery>& query);
/**
* \brief Ends gathering query data
*
* \param [in] query The query to end
*/
void endQuery(
const Rc<DxvkQuery>& query);
/** /**
* \brief Sets framebuffer * \brief Sets framebuffer
* \param [in] fb Framebuffer * \param [in] fb Framebuffer

View File

@ -2,37 +2,102 @@
namespace dxvk { namespace dxvk {
DxvkQuery::DxvkQuery( DxvkQuery::DxvkQuery(VkQueryType type)
const Rc<vk::DeviceFn>& vkd, : m_type(type) {
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() { DxvkQuery::~DxvkQuery() {
m_vkd->vkDestroyQueryPool(
m_vkd->device(), m_queryPool, nullptr); }
uint32_t DxvkQuery::invalidate() {
std::unique_lock<std::mutex> 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<std::mutex> lock(m_mutex);
if (m_status == DxvkQueryStatus::Available)
data = m_data;
return m_status;
}
void DxvkQuery::beginRecording(uint32_t revision) {
std::unique_lock<std::mutex> lock(m_mutex);
if (m_revision == revision)
m_status = DxvkQueryStatus::Active;
}
void DxvkQuery::endRecording(uint32_t revision) {
std::unique_lock<std::mutex> lock(m_mutex);
if (m_revision == revision)
m_status = DxvkQueryStatus::Pending;
}
void DxvkQuery::associateQuery(uint32_t revision) {
std::unique_lock<std::mutex> lock(m_mutex);
if (m_revision == revision)
m_queryCount += 1;
}
void DxvkQuery::updateData(
uint32_t revision,
const DxvkQueryData& data) {
std::unique_lock<std::mutex> 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();
}
}
} }
} }

View File

@ -1,40 +1,160 @@
#pragma once #pragma once
#include <condition_variable>
#include <mutex>
#include "dxvk_limits.h" #include "dxvk_limits.h"
namespace dxvk { namespace dxvk {
/** /**
* \brief DXVK query object * \brief Query status
* *
* Creates a Vulkan query pool that acts as if it * Allows the application to query
* were a single query. This approach is necessary * the current status of the query.
* in order to keep evaluating the query across
* multiple command submissions.
*/ */
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: public:
DxvkQuery( DxvkQuery(VkQueryType type);
const Rc<vk::DeviceFn>& vkd,
VkQueryType type);
~DxvkQuery(); ~DxvkQuery();
/** /**
* \brief Query pool handle * \brief Resets the query object
* \returns Query pool handle *
* 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 { uint32_t invalidate();
return m_queryPool;
} /**
* \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: private:
Rc<vk::DeviceFn> m_vkd = nullptr; const VkQueryType m_type;
VkQueryType m_type = VK_QUERY_TYPE_END_RANGE;
VkQueryPool m_queryPool = VK_NULL_HANDLE; std::mutex m_mutex;
uint32_t m_queryId = 0; 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;
}; };

View File

@ -0,0 +1,17 @@
#include "dxvk_query_pool.h"
namespace dxvk {
DxvkQueryPool::DxvkQueryPool(
const Rc<vk::DeviceFn>& fn,
VkQueryType queryType,
uint32_t queryCount) {
}
DxvkQueryPool::~DxvkQueryPool() {
}
}

View File

@ -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<vk::DeviceFn>& fn,
VkQueryType queryType,
uint32_t queryCount);
~DxvkQueryPool();
private:
Rc<vk::DeviceFn> m_vkd;
VkQueryPool m_queryPool = VK_NULL_HANDLE;
std::vector<Rc<DxvkQuery>> m_queries;
};
}

View File

@ -29,6 +29,7 @@ dxvk_src = files([
'dxvk_pipelayout.cpp', 'dxvk_pipelayout.cpp',
'dxvk_pipemanager.cpp', 'dxvk_pipemanager.cpp',
'dxvk_query.cpp', 'dxvk_query.cpp',
'dxvk_query_pool.cpp',
'dxvk_queue.cpp', 'dxvk_queue.cpp',
'dxvk_renderpass.cpp', 'dxvk_renderpass.cpp',
'dxvk_resource.cpp', 'dxvk_resource.cpp',