mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-11-30 22:24:15 +01:00
[dxvk] Implemented virtual query class and query pool stub
This commit is contained in:
parent
82d324384c
commit
5beae25bdf
@ -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) {
|
||||
if (m_state.om.framebuffer != fb) {
|
||||
this->renderPassEnd();
|
||||
|
@ -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<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
|
||||
* \param [in] fb Framebuffer
|
||||
|
@ -2,37 +2,102 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkQuery::DxvkQuery(
|
||||
const Rc<vk::DeviceFn>& 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;
|
||||
DxvkQuery::DxvkQuery(VkQueryType type)
|
||||
: m_type(type) {
|
||||
|
||||
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<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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,40 +1,160 @@
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
#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<vk::DeviceFn>& 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<vk::DeviceFn> 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;
|
||||
|
||||
};
|
||||
|
||||
|
17
src/dxvk/dxvk_query_pool.cpp
Normal file
17
src/dxvk/dxvk_query_pool.cpp
Normal 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() {
|
||||
|
||||
}
|
||||
|
||||
}
|
34
src/dxvk/dxvk_query_pool.h
Normal file
34
src/dxvk/dxvk_query_pool.h
Normal 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;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user