1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-02 04:29:14 +01:00

[dxvk] Add new query implementation

This commit is contained in:
Philip Rebohle 2018-11-17 10:11:56 +01:00
parent 8c3900c533
commit 772fa3074f
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
5 changed files with 868 additions and 0 deletions

View File

@ -124,6 +124,7 @@ namespace dxvk {
void DxvkCommandList::reset() {
m_statCounters.reset();
m_bufferTracker.reset();
m_gpuQueryTracker.reset();
m_gpuEventTracker.reset();
m_eventTracker.reset();
m_queryTracker.reset();

View File

@ -7,6 +7,7 @@
#include "dxvk_descriptor.h"
#include "dxvk_event.h"
#include "dxvk_gpu_event.h"
#include "dxvk_gpu_query.h"
#include "dxvk_lifetime.h"
#include "dxvk_limits.h"
#include "dxvk_pipelayout.h"
@ -176,6 +177,17 @@ namespace dxvk {
m_gpuEventTracker.trackEvent(handle);
}
/**
* \brief Tracks a GPU query
*
* The query handle will be returned to its allocator
* after the command buffer has finished executing.
* \param [in] handle Event handle
*/
void trackGpuQuery(DxvkGpuQueryHandle handle) {
m_gpuQueryTracker.trackQuery(handle);
}
/**
* \brief Signals tracked events
*
@ -552,6 +564,23 @@ namespace dxvk {
m_vkd->vkCmdPushConstants(m_execBuffer,
layout, stageFlags, offset, size, pValues);
}
void cmdResetQuery(
VkQueryPool queryPool,
uint32_t queryId,
VkEvent event) {
m_cmdBuffersUsed.set(DxvkCmdBufferFlag::InitBuffer);
m_vkd->vkResetEvent(
m_vkd->device(), event);
m_vkd->vkCmdResetQueryPool(
m_initBuffer, queryPool, queryId, 1);
m_vkd->vkCmdSetEvent(m_initBuffer,
event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
}
void cmdResetQueryPool(
@ -681,6 +710,7 @@ namespace dxvk {
DxvkQueryTracker m_queryTracker;
DxvkEventTracker m_eventTracker;
DxvkGpuEventTracker m_gpuEventTracker;
DxvkGpuQueryTracker m_gpuQueryTracker;
DxvkBufferTracker m_bufferTracker;
DxvkStatCounters m_statCounters;

451
src/dxvk/dxvk_gpu_query.cpp Normal file
View File

@ -0,0 +1,451 @@
#include <algorithm>
#include "dxvk_cmdlist.h"
#include "dxvk_gpu_query.h"
namespace dxvk {
DxvkGpuQuery::DxvkGpuQuery(
const Rc<vk::DeviceFn>& vkd,
VkQueryType type,
VkQueryControlFlags flags,
uint32_t index)
: m_vkd(vkd), m_type(type), m_flags(flags),
m_index(index), m_ended(false) {
}
DxvkGpuQuery::~DxvkGpuQuery() {
if (m_handle.queryPool)
m_handle.allocator->freeQuery(m_handle);
for (DxvkGpuQueryHandle handle : m_handles)
handle.allocator->freeQuery(handle);
}
bool DxvkGpuQuery::isIndexed() const {
return m_type == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
}
DxvkGpuQueryStatus DxvkGpuQuery::getData(DxvkQueryData& queryData) const {
queryData = DxvkQueryData();
if (!m_ended)
return DxvkGpuQueryStatus::Invalid;
// Empty begin/end pair
if (!m_handle.queryPool)
return DxvkGpuQueryStatus::Available;
// Get query data from all associated handles
DxvkGpuQueryStatus status = getDataForHandle(queryData, m_handle);
for (size_t i = 0; i < m_handles.size()
&& status == DxvkGpuQueryStatus::Available; i++)
status = getDataForHandle(queryData, m_handles[i]);
// Treat non-precise occlusion queries as available
// if we already know the result will be non-zero
if ((status == DxvkGpuQueryStatus::Pending)
&& (m_type == VK_QUERY_TYPE_OCCLUSION)
&& !(m_flags & VK_QUERY_CONTROL_PRECISE_BIT)
&& (queryData.occlusion.samplesPassed))
status = DxvkGpuQueryStatus::Available;
return status;
}
void DxvkGpuQuery::begin(const Rc<DxvkCommandList>& cmd) {
m_ended = false;
cmd->trackGpuQuery(m_handle);
m_handle = DxvkGpuQueryHandle();
for (const auto& handle : m_handles)
cmd->trackGpuQuery(handle);
m_handles.clear();
}
void DxvkGpuQuery::end() {
m_ended = true;
}
void DxvkGpuQuery::addQueryHandle(const DxvkGpuQueryHandle& handle) {
if (m_handle.queryPool)
m_handles.push_back(m_handle);
m_handle = handle;
}
DxvkGpuQueryStatus DxvkGpuQuery::getDataForHandle(
DxvkQueryData& queryData,
const DxvkGpuQueryHandle& handle) const {
DxvkQueryData tmpData;
// Wait for the query to be reset first
VkResult result = m_vkd->vkGetEventStatus(
m_vkd->device(), handle.resetEvent);
if (result == VK_EVENT_RESET)
return DxvkGpuQueryStatus::Pending;
else if (result != VK_EVENT_SET)
return DxvkGpuQueryStatus::Failed;
// Try to copy query data to temporary structure
result = m_vkd->vkGetQueryPoolResults(m_vkd->device(),
handle.queryPool, handle.queryId, 1,
sizeof(DxvkQueryData), &tmpData,
sizeof(DxvkQueryData), VK_QUERY_RESULT_64_BIT);
if (result == VK_NOT_READY)
return DxvkGpuQueryStatus::Pending;
else if (result != VK_SUCCESS)
return DxvkGpuQueryStatus::Failed;;
// Add numbers to the destination structure
switch (m_type) {
case VK_QUERY_TYPE_OCCLUSION:
queryData.occlusion.samplesPassed += tmpData.occlusion.samplesPassed;
break;
case VK_QUERY_TYPE_TIMESTAMP:
queryData.timestamp.time = tmpData.timestamp.time;
break;
case VK_QUERY_TYPE_PIPELINE_STATISTICS:
queryData.statistic.iaVertices += tmpData.statistic.iaVertices;
queryData.statistic.iaPrimitives += tmpData.statistic.iaPrimitives;
queryData.statistic.vsInvocations += tmpData.statistic.vsInvocations;
queryData.statistic.gsInvocations += tmpData.statistic.gsInvocations;
queryData.statistic.gsPrimitives += tmpData.statistic.gsPrimitives;
queryData.statistic.clipInvocations += tmpData.statistic.clipInvocations;
queryData.statistic.clipPrimitives += tmpData.statistic.clipPrimitives;
queryData.statistic.fsInvocations += tmpData.statistic.fsInvocations;
queryData.statistic.tcsPatches += tmpData.statistic.tcsPatches;
queryData.statistic.tesInvocations += tmpData.statistic.tesInvocations;
queryData.statistic.csInvocations += tmpData.statistic.csInvocations;
break;
case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT:
queryData.xfbStream.primitivesWritten += tmpData.xfbStream.primitivesWritten;
queryData.xfbStream.primitivesNeeded += tmpData.xfbStream.primitivesNeeded;
break;
default:
Logger::err(str::format("DXVK: Unhandled query type: ", m_type));
return DxvkGpuQueryStatus::Invalid;
}
return DxvkGpuQueryStatus::Available;
}
DxvkGpuQueryAllocator::DxvkGpuQueryAllocator(
const Rc<vk::DeviceFn>& vkd,
VkQueryType queryType,
uint32_t queryPoolSize)
: m_vkd (vkd),
m_queryType (queryType),
m_queryPoolSize (queryPoolSize) {
}
DxvkGpuQueryAllocator::~DxvkGpuQueryAllocator() {
for (DxvkGpuQueryHandle handle : m_handles) {
m_vkd->vkDestroyEvent(m_vkd->device(),
handle.resetEvent, nullptr);
}
for (VkQueryPool pool : m_pools) {
m_vkd->vkDestroyQueryPool(
m_vkd->device(), pool, nullptr);
}
}
DxvkGpuQueryHandle DxvkGpuQueryAllocator::allocQuery() {
std::lock_guard<std::mutex> lock(m_mutex);
if (m_handles.size() == 0)
this->createQueryPool();
if (m_handles.size() == 0)
return DxvkGpuQueryHandle();
DxvkGpuQueryHandle result = m_handles.back();
m_handles.pop_back();
return result;
}
void DxvkGpuQueryAllocator::freeQuery(DxvkGpuQueryHandle handle) {
std::lock_guard<std::mutex> lock(m_mutex);
m_handles.push_back(handle);
}
void DxvkGpuQueryAllocator::createQueryPool() {
VkQueryPoolCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.queryType = m_queryType;
info.queryCount = m_queryPoolSize;
info.pipelineStatistics = 0;
if (m_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;
}
VkQueryPool queryPool = VK_NULL_HANDLE;
if (m_vkd->vkCreateQueryPool(m_vkd->device(), &info, nullptr, &queryPool)) {
Logger::err(str::format("DXVK: Failed to create query pool (", m_queryType, "; ", m_queryPoolSize, ")"));
return;
}
m_pools.push_back(queryPool);
VkEventCreateInfo eventInfo;
eventInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
eventInfo.pNext = nullptr;
eventInfo.flags = 0;
for (uint32_t i = 0; i < m_queryPoolSize; i++) {
VkEvent event = VK_NULL_HANDLE;
if (m_vkd->vkCreateEvent(m_vkd->device(), &eventInfo, nullptr, &event)) {
Logger::err("DXVK: Failed to create query reset event");
return;
}
m_handles.push_back({ this, event, queryPool, i });
}
}
DxvkGpuQueryPool::DxvkGpuQueryPool(const Rc<vk::DeviceFn>& vkd)
: m_occlusion(vkd, VK_QUERY_TYPE_OCCLUSION, 256),
m_statistic(vkd, VK_QUERY_TYPE_PIPELINE_STATISTICS, 64),
m_timestamp(vkd, VK_QUERY_TYPE_TIMESTAMP, 64),
m_xfbStream(vkd, VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 64) {
}
DxvkGpuQueryPool::~DxvkGpuQueryPool() {
}
DxvkGpuQueryHandle DxvkGpuQueryPool::allocQuery(VkQueryType type) {
switch (type) {
case VK_QUERY_TYPE_OCCLUSION:
return m_occlusion.allocQuery();
case VK_QUERY_TYPE_PIPELINE_STATISTICS:
return m_statistic.allocQuery();
case VK_QUERY_TYPE_TIMESTAMP:
return m_timestamp.allocQuery();
case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT:
return m_xfbStream.allocQuery();
default:
Logger::err(str::format("DXVK: Unhandled query type: ", type));
return DxvkGpuQueryHandle();
}
}
DxvkGpuQueryManager::DxvkGpuQueryManager(
const Rc<DxvkGpuQueryPool>& pool)
: m_pool(pool), m_activeTypes(0) {
}
DxvkGpuQueryManager::~DxvkGpuQueryManager() {
}
void DxvkGpuQueryManager::enableQuery(
const Rc<DxvkCommandList>& cmd,
const Rc<DxvkGpuQuery>& query) {
query->begin(cmd);
m_activeQueries.push_back(query);
if (m_activeTypes & getQueryTypeBit(query->type()))
beginSingleQuery(cmd, query);
}
void DxvkGpuQueryManager::disableQuery(
const Rc<DxvkCommandList>& cmd,
const Rc<DxvkGpuQuery>& query) {
auto iter = std::find(
m_activeQueries.begin(),
m_activeQueries.end(),
query);
if (iter != m_activeQueries.end()) {
m_activeQueries.erase(iter);
if (m_activeTypes & getQueryTypeBit((*iter)->type()))
endSingleQuery(cmd, query);
query->end();
}
}
void DxvkGpuQueryManager::writeTimestamp(
const Rc<DxvkCommandList>& cmd,
const Rc<DxvkGpuQuery>& query) {
DxvkGpuQueryHandle handle = m_pool->allocQuery(query->type());
query->begin(cmd);
query->addQueryHandle(handle);
query->end();
cmd->cmdResetQuery(
handle.queryPool,
handle.queryId,
handle.resetEvent);
cmd->cmdWriteTimestamp(
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
handle.queryPool,
handle.queryId);
cmd->trackResource(query);
}
void DxvkGpuQueryManager::beginQueries(
const Rc<DxvkCommandList>& cmd,
VkQueryType type) {
m_activeTypes |= getQueryTypeBit(type);
for (size_t i = 0; i < m_activeQueries.size(); i++) {
if (m_activeQueries[i]->type() == type)
beginSingleQuery(cmd, m_activeQueries[i]);
}
}
void DxvkGpuQueryManager::endQueries(
const Rc<DxvkCommandList>& cmd,
VkQueryType type) {
m_activeTypes &= ~getQueryTypeBit(type);
for (size_t i = 0; i < m_activeQueries.size(); i++) {
if (m_activeQueries[i]->type() == type)
endSingleQuery(cmd, m_activeQueries[i]);
}
}
void DxvkGpuQueryManager::beginSingleQuery(
const Rc<DxvkCommandList>& cmd,
const Rc<DxvkGpuQuery>& query) {
DxvkGpuQueryHandle handle = m_pool->allocQuery(query->type());
cmd->cmdResetQuery(
handle.queryPool,
handle.queryId,
handle.resetEvent);
if (query->isIndexed()) {
cmd->cmdBeginQueryIndexed(
handle.queryPool,
handle.queryId,
query->flags(),
query->index());
} else {
cmd->cmdBeginQuery(
handle.queryPool,
handle.queryId,
query->flags());
}
query->addQueryHandle(handle);
}
void DxvkGpuQueryManager::endSingleQuery(
const Rc<DxvkCommandList>& cmd,
const Rc<DxvkGpuQuery>& query) {
DxvkGpuQueryHandle handle = query->handle();
if (query->isIndexed()) {
cmd->cmdEndQueryIndexed(
handle.queryPool,
handle.queryId,
query->index());
} else {
cmd->cmdEndQuery(
handle.queryPool,
handle.queryId);
}
cmd->trackResource(query);
}
uint32_t DxvkGpuQueryManager::getQueryTypeBit(
VkQueryType type) {
switch (type) {
case VK_QUERY_TYPE_OCCLUSION: return 0x01;
case VK_QUERY_TYPE_PIPELINE_STATISTICS: return 0x02;
case VK_QUERY_TYPE_TIMESTAMP: return 0x04;
case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT: return 0x08;
default: return 0;
}
}
DxvkGpuQueryTracker::DxvkGpuQueryTracker() { }
DxvkGpuQueryTracker::~DxvkGpuQueryTracker() { }
void DxvkGpuQueryTracker::trackQuery(DxvkGpuQueryHandle handle) {
if (handle.queryPool)
m_handles.push_back(handle);
}
void DxvkGpuQueryTracker::reset() {
for (DxvkGpuQueryHandle handle : m_handles)
handle.allocator->freeQuery(handle);
m_handles.clear();
}
}

385
src/dxvk/dxvk_gpu_query.h Normal file
View File

@ -0,0 +1,385 @@
#pragma once
#include <mutex>
#include <vector>
#include "dxvk_query.h"
#include "dxvk_resource.h"
namespace dxvk {
class DxvkCommandList;
class DxvkGpuQueryPool;
class DxvkGpuQueryAllocator;
/**
* \brief Query status
*
* Reports whether a query is in
* signaled or unsignaled state.
*/
enum class DxvkGpuQueryStatus : uint32_t {
Invalid = 0,
Pending = 1,
Available = 2,
Failed = 3,
};
/**
* \brief Query handle
*
* Stores the query allocator, as well as
* the actual pool and query index. Since
* query pools have to be reset on the GPU,
* this also comes with a reset event.
*/
struct DxvkGpuQueryHandle {
DxvkGpuQueryAllocator* allocator = nullptr;
VkEvent resetEvent = VK_NULL_HANDLE;
VkQueryPool queryPool = VK_NULL_HANDLE;
uint32_t queryId = 0;
};
/**
* \brief Query object
*
* Manages Vulkan queries that are sub-allocated
* from larger query pools
*/
class DxvkGpuQuery : public DxvkResource {
public:
DxvkGpuQuery(
const Rc<vk::DeviceFn>& vkd,
VkQueryType type,
VkQueryControlFlags flags,
uint32_t index);
~DxvkGpuQuery();
/**
* \brief Query type
* \returns Query type
*/
VkQueryType type() const {
return m_type;
}
/**
* \brief Query control flags
* \returns Query control flags
*/
VkQueryControlFlags flags() const {
return m_flags;
}
/**
* \brief Retrieves current handle
*
* Note that the query handle will change
* when calling \ref addQueryHandle.
* \returns Current query handle
*/
DxvkGpuQueryHandle handle() const {
return m_handle;
}
/**
* \brief Query index
*
* Only valid for indexed query types.
* For non-zero values, indexed query
* functions must be used.
* \returns Query index
*/
uint32_t index() const {
return m_index;
}
/**
* \brief Checks whether query is indexed
* \returns \c true for indexed query types
*/
bool isIndexed() const;
/**
* \brief Retrieves query data
*
* If all query data is available, this will
* return \c DxvkGpuQueryStatus::Signaled, and
* the destination structure will be filled
* with the data retrieved from all associated
* query handles.
* \param [out] queryData Query data
* \returns Current query status
*/
DxvkGpuQueryStatus getData(
DxvkQueryData& queryData) const;
/**
* \brief Begins query
*
* Moves all current query handles to the given
* command list and sets the query into active
* state. No data can be retrieved while the
* query is active.
* \param [in] cmd Command list
*/
void begin(
const Rc<DxvkCommandList>& cmd);
/**
* \brief Ends query
*
* Sets query into pending state. Calling
* \c getData is legal after calling this.
*/
void end();
/**
* \brief Adds a query handle to the query
*
* The given query handle shall be used when
* retrieving query data. A query can have
* multiple handles attached.
* \param [in] handle The query handle
*/
void addQueryHandle(
const DxvkGpuQueryHandle& handle);
private:
Rc<vk::DeviceFn> m_vkd;
VkQueryType m_type;
VkQueryControlFlags m_flags;
uint32_t m_index;
bool m_ended;
DxvkGpuQueryHandle m_handle;
std::vector<DxvkGpuQueryHandle> m_handles;
DxvkGpuQueryStatus getDataForHandle(
DxvkQueryData& queryData,
const DxvkGpuQueryHandle& handle) const;
};
/**
* \brief Query allocator
*
* Creates query pools and allocates
* queries for a single query type.
*/
class DxvkGpuQueryAllocator {
public:
DxvkGpuQueryAllocator(
const Rc<vk::DeviceFn>& vkd,
VkQueryType queryType,
uint32_t queryPoolSize);
~DxvkGpuQueryAllocator();
/**
* \brief Allocates a query
*
* If possible, this returns a free query
* from an existing query pool. Otherwise,
* a new query pool will be created.
* \returns Query handle
*/
DxvkGpuQueryHandle allocQuery();
/**
* \brief Recycles a query
*
* Returns a query back to the allocator
* so that it can be reused. The query
* must not be in pending state.
* \param [in] handle Query to reset
*/
void freeQuery(DxvkGpuQueryHandle handle);
private:
Rc<vk::DeviceFn> m_vkd;
VkQueryType m_queryType;
uint32_t m_queryPoolSize;
std::mutex m_mutex;
std::vector<DxvkGpuQueryHandle> m_handles;
std::vector<VkQueryPool> m_pools;
void createQueryPool();
};
/**
* \brief Query pool
*
* Small wrapper class that manages query
* allocators for all supported query types,
*/
class DxvkGpuQueryPool : public RcObject {
public:
DxvkGpuQueryPool(
const Rc<vk::DeviceFn>& vkd);
~DxvkGpuQueryPool();
/**
* \brief Allocates a single query
*
* \param [in] type Query type
* \returns Handle to the allocated query
*/
DxvkGpuQueryHandle allocQuery(VkQueryType type);
private:
DxvkGpuQueryAllocator m_occlusion;
DxvkGpuQueryAllocator m_statistic;
DxvkGpuQueryAllocator m_timestamp;
DxvkGpuQueryAllocator m_xfbStream;
};
/**
* \brief Query manager
*
* Keeps track of enabled and disabled queries
* and assigns Vulkan queries to them as needed.
*/
class DxvkGpuQueryManager {
public:
DxvkGpuQueryManager(
const Rc<DxvkGpuQueryPool>& pool);
~DxvkGpuQueryManager();
/**
* \brief Enables a query
*
* This will also immediately begin the
* query in case the query type is active.
* \param [in] cmd Command list
* \param [in] query Query to allocate
*/
void enableQuery(
const Rc<DxvkCommandList>& cmd,
const Rc<DxvkGpuQuery>& query);
/**
* \brief Disables a query
*
* This will also immediately end the
* query in case the query type is active.
* \param [in] cmd Command list
* \param [in] query Query to allocate
*/
void disableQuery(
const Rc<DxvkCommandList>& cmd,
const Rc<DxvkGpuQuery>& query);
/**
* \brief Signals a time stamp query
*
* Timestamp queries are not scoped.
* \param [in] cmd Command list
* \param [in] query Query to allocate
*/
void writeTimestamp(
const Rc<DxvkCommandList>& cmd,
const Rc<DxvkGpuQuery>& query);
/**
* \brief Begins queries of a given type
*
* Makes a query type \e active. Begins
* all enabled queries of this type.
* \param [in] cmd Command list
* \param [in] type Query type
*/
void beginQueries(
const Rc<DxvkCommandList>& cmd,
VkQueryType type);
/**
* \brief Ends queries of a given type
*
* Makes a query type \e inactive. Ends
* all enabled queries of this type.
* \param [in] cmd Command list
* \param [in] type Query type
*/
void endQueries(
const Rc<DxvkCommandList>& cmd,
VkQueryType type);
private:
Rc<DxvkGpuQueryPool> m_pool;
uint32_t m_activeTypes;
std::vector<Rc<DxvkGpuQuery>> m_activeQueries;
void beginSingleQuery(
const Rc<DxvkCommandList>& cmd,
const Rc<DxvkGpuQuery>& query);
void endSingleQuery(
const Rc<DxvkCommandList>& cmd,
const Rc<DxvkGpuQuery>& query);
static uint32_t getQueryTypeBit(
VkQueryType type);
};
/**
* \brief Query tracker
*
* Returns queries to their allocators after
* the command buffer has finished executing.
*/
class DxvkGpuQueryTracker {
public:
DxvkGpuQueryTracker();
~DxvkGpuQueryTracker();
/**
* \param Tracks a query
* \param [in] handle Query handle
*/
void trackQuery(DxvkGpuQueryHandle handle);
/**
* \brief Recycles all tracked handles
*
* Releases all tracked query handles
* to their respective query allocator.
*/
void reset();
private:
std::vector<DxvkGpuQueryHandle> m_handles;
};
}

View File

@ -56,6 +56,7 @@ dxvk_src = files([
'dxvk_format.cpp',
'dxvk_framebuffer.cpp',
'dxvk_gpu_event.cpp',
'dxvk_gpu_query.cpp',
'dxvk_graphics.cpp',
'dxvk_image.cpp',
'dxvk_instance.cpp',