mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-03 22:24:13 +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) {
|
void DxvkContext::bindFramebuffer(const Rc<DxvkFramebuffer>& fb) {
|
||||||
if (m_state.om.framebuffer != fb) {
|
if (m_state.om.framebuffer != fb) {
|
||||||
this->renderPassEnd();
|
this->renderPassEnd();
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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_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',
|
||||||
|
Loading…
Reference in New Issue
Block a user