mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-20 19:54:19 +01:00
[d3d11] Use new query implementation
This commit is contained in:
parent
e5441e841f
commit
412d79c8c1
@ -249,13 +249,10 @@ namespace dxvk {
|
||||
return;
|
||||
|
||||
Com<D3D11Query> queryPtr = static_cast<D3D11Query*>(pAsync);
|
||||
|
||||
if (queryPtr->HasBeginEnabled()) {
|
||||
uint32_t revision = queryPtr->Reset();
|
||||
EmitCs([revision, queryPtr] (DxvkContext* ctx) {
|
||||
queryPtr->Begin(ctx, revision);
|
||||
});
|
||||
}
|
||||
|
||||
EmitCs([queryPtr] (DxvkContext* ctx) {
|
||||
queryPtr->Begin(ctx);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -267,16 +264,9 @@ namespace dxvk {
|
||||
|
||||
Com<D3D11Query> queryPtr = static_cast<D3D11Query*>(pAsync);
|
||||
|
||||
if (queryPtr->HasBeginEnabled()) {
|
||||
EmitCs([queryPtr] (DxvkContext* ctx) {
|
||||
queryPtr->End(ctx);
|
||||
});
|
||||
} else {
|
||||
uint32_t revision = queryPtr->Reset();
|
||||
EmitCs([revision, queryPtr] (DxvkContext* ctx) {
|
||||
queryPtr->Signal(ctx, revision);
|
||||
});
|
||||
}
|
||||
EmitCs([queryPtr] (DxvkContext* ctx) {
|
||||
queryPtr->End(ctx);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,27 +16,27 @@ namespace dxvk {
|
||||
break;
|
||||
|
||||
case D3D11_QUERY_OCCLUSION:
|
||||
m_query = new DxvkQuery(
|
||||
m_query = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_OCCLUSION,
|
||||
VK_QUERY_CONTROL_PRECISE_BIT);
|
||||
VK_QUERY_CONTROL_PRECISE_BIT, 0);
|
||||
break;
|
||||
|
||||
case D3D11_QUERY_OCCLUSION_PREDICATE:
|
||||
m_query = new DxvkQuery(
|
||||
VK_QUERY_TYPE_OCCLUSION, 0);
|
||||
m_query = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_OCCLUSION, 0, 0);
|
||||
break;
|
||||
|
||||
case D3D11_QUERY_TIMESTAMP:
|
||||
m_query = new DxvkQuery(
|
||||
VK_QUERY_TYPE_TIMESTAMP, 0);
|
||||
m_query = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_TIMESTAMP, 0, 0);
|
||||
break;
|
||||
|
||||
case D3D11_QUERY_TIMESTAMP_DISJOINT:
|
||||
break;
|
||||
|
||||
case D3D11_QUERY_PIPELINE_STATISTICS:
|
||||
m_query = new DxvkQuery(
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS, 0);
|
||||
m_query = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS, 0, 0);
|
||||
break;
|
||||
|
||||
case D3D11_QUERY_SO_STATISTICS:
|
||||
@ -46,25 +46,25 @@ namespace dxvk {
|
||||
// FIXME it is technically incorrect to map
|
||||
// SO_OVERFLOW_PREDICATE to the first stream,
|
||||
// but this is good enough for D3D10 behaviour
|
||||
m_query = new DxvkQuery(
|
||||
m_query = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 0);
|
||||
break;
|
||||
|
||||
case D3D11_QUERY_SO_STATISTICS_STREAM1:
|
||||
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1:
|
||||
m_query = new DxvkQuery(
|
||||
m_query = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 1);
|
||||
break;
|
||||
|
||||
case D3D11_QUERY_SO_STATISTICS_STREAM2:
|
||||
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2:
|
||||
m_query = new DxvkQuery(
|
||||
m_query = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 2);
|
||||
break;
|
||||
|
||||
case D3D11_QUERY_SO_STATISTICS_STREAM3:
|
||||
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3:
|
||||
m_query = new DxvkQuery(
|
||||
m_query = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 3);
|
||||
break;
|
||||
|
||||
@ -169,51 +169,34 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
uint32_t D3D11Query::Reset() {
|
||||
if (m_query != nullptr)
|
||||
return m_query->reset();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool D3D11Query::HasBeginEnabled() const {
|
||||
return m_desc.Query != D3D11_QUERY_EVENT
|
||||
&& m_desc.Query != D3D11_QUERY_TIMESTAMP;
|
||||
}
|
||||
|
||||
|
||||
void D3D11Query::Begin(DxvkContext* ctx, uint32_t revision) {
|
||||
m_revision = revision;
|
||||
|
||||
if (m_query != nullptr) {
|
||||
DxvkQueryRevision rev = { m_query, revision };
|
||||
ctx->beginQuery(rev);
|
||||
void D3D11Query::Begin(DxvkContext* ctx) {
|
||||
switch (m_desc.Query) {
|
||||
case D3D11_QUERY_EVENT:
|
||||
case D3D11_QUERY_TIMESTAMP:
|
||||
case D3D11_QUERY_TIMESTAMP_DISJOINT:
|
||||
break;
|
||||
|
||||
default:
|
||||
ctx->beginQuery(m_query);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11Query::End(DxvkContext* ctx) {
|
||||
if (m_query != nullptr) {
|
||||
DxvkQueryRevision rev = { m_query, m_revision };
|
||||
ctx->endQuery(rev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D11Query::Signal(DxvkContext* ctx, uint32_t revision) {
|
||||
switch (m_desc.Query) {
|
||||
case D3D11_QUERY_EVENT: {
|
||||
case D3D11_QUERY_EVENT:
|
||||
ctx->signalGpuEvent(m_event);
|
||||
} break;
|
||||
break;
|
||||
|
||||
case D3D11_QUERY_TIMESTAMP: {
|
||||
DxvkQueryRevision rev = { m_query, revision };
|
||||
ctx->writeTimestamp(rev);
|
||||
} break;
|
||||
case D3D11_QUERY_TIMESTAMP:
|
||||
ctx->writeTimestamp(m_query);
|
||||
break;
|
||||
|
||||
case D3D11_QUERY_TIMESTAMP_DISJOINT:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
ctx->endQuery(m_query);
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,10 +212,6 @@ namespace dxvk {
|
||||
|
||||
bool signaled = status == DxvkGpuEventStatus::Signaled;
|
||||
|
||||
// FIXME remove once query refactor is done
|
||||
if (m_event->isInUse())
|
||||
signaled = false;
|
||||
|
||||
if (pData != nullptr)
|
||||
*static_cast<BOOL*>(pData) = signaled;
|
||||
|
||||
@ -241,12 +220,13 @@ namespace dxvk {
|
||||
DxvkQueryData queryData = {};
|
||||
|
||||
if (m_query != nullptr) {
|
||||
DxvkQueryStatus status = m_query->getData(queryData);
|
||||
DxvkGpuQueryStatus status = m_query->getData(queryData);
|
||||
|
||||
if (status == DxvkQueryStatus::Created)
|
||||
if (status == DxvkGpuQueryStatus::Invalid
|
||||
|| status == DxvkGpuQueryStatus::Failed)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
if (status != DxvkQueryStatus::Available)
|
||||
if (status == DxvkGpuQueryStatus::Pending)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../dxvk/dxvk_gpu_event.h"
|
||||
#include "../dxvk/dxvk_query.h"
|
||||
#include "../dxvk/dxvk_gpu_query.h"
|
||||
|
||||
#include "../d3d10/d3d10_query.h"
|
||||
|
||||
@ -31,16 +31,10 @@ namespace dxvk {
|
||||
void STDMETHODCALLTYPE GetDesc(
|
||||
D3D11_QUERY_DESC *pDesc) final;
|
||||
|
||||
uint32_t Reset();
|
||||
|
||||
bool HasBeginEnabled() const;
|
||||
|
||||
void Begin(DxvkContext* ctx, uint32_t revision);
|
||||
void Begin(DxvkContext* ctx);
|
||||
|
||||
void End(DxvkContext* ctx);
|
||||
|
||||
void Signal(DxvkContext* ctx, uint32_t revision);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetData(
|
||||
void* pData,
|
||||
UINT GetDataFlags);
|
||||
@ -54,7 +48,7 @@ namespace dxvk {
|
||||
D3D11Device* const m_device;
|
||||
D3D11_QUERY_DESC m_desc;
|
||||
|
||||
Rc<DxvkQuery> m_query = nullptr;
|
||||
Rc<DxvkGpuQuery> m_query = nullptr;
|
||||
Rc<DxvkGpuEvent> m_event = nullptr;
|
||||
|
||||
uint32_t m_revision = 0;
|
||||
|
@ -127,7 +127,6 @@ namespace dxvk {
|
||||
m_gpuQueryTracker.reset();
|
||||
m_gpuEventTracker.reset();
|
||||
m_eventTracker.reset();
|
||||
m_queryTracker.reset();
|
||||
m_stagingAlloc.reset();
|
||||
m_descriptorPoolTracker.reset();
|
||||
m_resources.reset();
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "dxvk_lifetime.h"
|
||||
#include "dxvk_limits.h"
|
||||
#include "dxvk_pipelayout.h"
|
||||
#include "dxvk_query_tracker.h"
|
||||
#include "dxvk_staging.h"
|
||||
#include "dxvk_stats.h"
|
||||
|
||||
@ -136,18 +135,6 @@ namespace dxvk {
|
||||
m_resources.trackResource(std::move(rc));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Adds a query range to track
|
||||
*
|
||||
* Query data will be retrieved and written back to
|
||||
* the query objects after the command buffer has
|
||||
* finished executing on the GPU.
|
||||
* \param [in] queries The query range
|
||||
*/
|
||||
void trackQueryRange(DxvkQueryRange&& queries) {
|
||||
m_queryTracker.trackQueryRange(std::move(queries));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Adds an event revision to track
|
||||
*
|
||||
@ -198,17 +185,6 @@ namespace dxvk {
|
||||
m_eventTracker.signalEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Writes back query results
|
||||
*
|
||||
* Writes back query data to all queries tracked by the
|
||||
* query range tracker. Call this after synchronizing
|
||||
* with a fence for this command list.
|
||||
*/
|
||||
void writeQueryData() {
|
||||
m_queryTracker.writeQueryData();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Resets the command list
|
||||
*
|
||||
@ -707,7 +683,6 @@ namespace dxvk {
|
||||
DxvkLifetimeTracker m_resources;
|
||||
DxvkDescriptorPoolTracker m_descriptorPoolTracker;
|
||||
DxvkStagingAlloc m_stagingAlloc;
|
||||
DxvkQueryTracker m_queryTracker;
|
||||
DxvkEventTracker m_eventTracker;
|
||||
DxvkGpuEventTracker m_gpuEventTracker;
|
||||
DxvkGpuQueryTracker m_gpuQueryTracker;
|
||||
|
@ -24,7 +24,6 @@ namespace dxvk {
|
||||
m_metaMipGen (metaMipGenObjects),
|
||||
m_metaPack (metaPackObjects),
|
||||
m_metaResolve (metaResolveObjects),
|
||||
m_queries (device->vkd()),
|
||||
m_queryManager(gpuQueryPool) {
|
||||
|
||||
}
|
||||
@ -68,8 +67,6 @@ namespace dxvk {
|
||||
Rc<DxvkCommandList> DxvkContext::endRecording() {
|
||||
this->spillRenderPass();
|
||||
|
||||
m_queries.trackQueryPools(m_cmd);
|
||||
|
||||
m_barriers.recordCommands(m_cmd);
|
||||
|
||||
m_cmd->endRecording();
|
||||
@ -88,18 +85,6 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::beginQuery(const DxvkQueryRevision& query) {
|
||||
query.query->beginRecording(query.revision);
|
||||
m_queries.enableQuery(m_cmd, query);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::endQuery(const DxvkQueryRevision& query) {
|
||||
m_queries.disableQuery(m_cmd, query);
|
||||
query.query->endRecording(query.revision);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::beginQuery(const Rc<DxvkGpuQuery>& query) {
|
||||
m_queryManager.enableQuery(m_cmd, query);
|
||||
}
|
||||
@ -1123,17 +1108,11 @@ namespace dxvk {
|
||||
if (this->validateComputeState()) {
|
||||
this->commitComputeInitBarriers();
|
||||
|
||||
m_queries.beginQueries(m_cmd,
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS);
|
||||
|
||||
m_queryManager.beginQueries(m_cmd,
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS);
|
||||
|
||||
m_cmd->cmdDispatch(x, y, z);
|
||||
|
||||
m_queries.endQueries(m_cmd,
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS);
|
||||
|
||||
m_queryManager.endQueries(m_cmd,
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS);
|
||||
|
||||
@ -1157,9 +1136,6 @@ namespace dxvk {
|
||||
if (this->validateComputeState()) {
|
||||
this->commitComputeInitBarriers();
|
||||
|
||||
m_queries.beginQueries(m_cmd,
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS);
|
||||
|
||||
m_queryManager.beginQueries(m_cmd,
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS);
|
||||
|
||||
@ -1167,9 +1143,6 @@ namespace dxvk {
|
||||
bufferSlice.handle,
|
||||
bufferSlice.offset);
|
||||
|
||||
m_queries.endQueries(m_cmd,
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS);
|
||||
|
||||
m_queryManager.endQueries(m_cmd,
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS);
|
||||
|
||||
@ -1803,17 +1776,6 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::writeTimestamp(const DxvkQueryRevision& query) {
|
||||
DxvkQueryHandle handle = m_queries.allocQuery(m_cmd, query);
|
||||
|
||||
m_cmd->cmdWriteTimestamp(
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
handle.queryPool, handle.queryId);
|
||||
|
||||
query.query->endRecording(query.revision);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::writeTimestamp(const Rc<DxvkGpuQuery>& query) {
|
||||
m_queryManager.writeTimestamp(m_cmd, query);
|
||||
}
|
||||
@ -2464,9 +2426,6 @@ namespace dxvk {
|
||||
m_state.om.renderPassOps);
|
||||
|
||||
// Begin occlusion queries
|
||||
m_queries.beginQueries(m_cmd, VK_QUERY_TYPE_OCCLUSION);
|
||||
m_queries.beginQueries(m_cmd, VK_QUERY_TYPE_PIPELINE_STATISTICS);
|
||||
|
||||
m_queryManager.beginQueries(m_cmd, VK_QUERY_TYPE_OCCLUSION);
|
||||
m_queryManager.beginQueries(m_cmd, VK_QUERY_TYPE_PIPELINE_STATISTICS);
|
||||
}
|
||||
@ -2482,9 +2441,6 @@ namespace dxvk {
|
||||
|
||||
this->pauseTransformFeedback();
|
||||
|
||||
m_queries.endQueries(m_cmd, VK_QUERY_TYPE_OCCLUSION);
|
||||
m_queries.endQueries(m_cmd, VK_QUERY_TYPE_PIPELINE_STATISTICS);
|
||||
|
||||
m_queryManager.endQueries(m_cmd, VK_QUERY_TYPE_OCCLUSION);
|
||||
m_queryManager.endQueries(m_cmd, VK_QUERY_TYPE_PIPELINE_STATISTICS);
|
||||
|
||||
@ -2675,9 +2631,6 @@ namespace dxvk {
|
||||
m_cmd->cmdBeginTransformFeedback(
|
||||
0, MaxNumXfbBuffers, ctrBuffers, ctrOffsets);
|
||||
|
||||
m_queries.beginQueries(m_cmd,
|
||||
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT);
|
||||
|
||||
m_queryManager.beginQueries(m_cmd,
|
||||
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT);
|
||||
}
|
||||
@ -2701,9 +2654,6 @@ namespace dxvk {
|
||||
m_cmd->trackResource(m_state.xfb.counters[i].buffer());
|
||||
}
|
||||
|
||||
m_queries.endQueries(m_cmd,
|
||||
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT);
|
||||
|
||||
m_queryManager.endQueries(m_cmd,
|
||||
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT);
|
||||
|
||||
|
@ -15,9 +15,6 @@
|
||||
#include "dxvk_meta_resolve.h"
|
||||
#include "dxvk_pipecache.h"
|
||||
#include "dxvk_pipemanager.h"
|
||||
#include "dxvk_query.h"
|
||||
#include "dxvk_query_manager.h"
|
||||
#include "dxvk_query_pool.h"
|
||||
#include "dxvk_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
@ -81,9 +78,6 @@ namespace dxvk {
|
||||
* \brief Begins generating query data
|
||||
* \param [in] query The query to end
|
||||
*/
|
||||
void beginQuery(
|
||||
const DxvkQueryRevision& query);
|
||||
|
||||
void beginQuery(
|
||||
const Rc<DxvkGpuQuery>& query);
|
||||
|
||||
@ -91,9 +85,6 @@ namespace dxvk {
|
||||
* \brief Ends generating query data
|
||||
* \param [in] query The query to end
|
||||
*/
|
||||
void endQuery(
|
||||
const DxvkQueryRevision& query);
|
||||
|
||||
void endQuery(
|
||||
const Rc<DxvkGpuQuery>& query);
|
||||
|
||||
@ -792,9 +783,6 @@ namespace dxvk {
|
||||
* \brief Writes to a timestamp query
|
||||
* \param [in] query The timestamp query
|
||||
*/
|
||||
void writeTimestamp(
|
||||
const DxvkQueryRevision& query);
|
||||
|
||||
void writeTimestamp(
|
||||
const Rc<DxvkGpuQuery>& query);
|
||||
|
||||
@ -819,9 +807,8 @@ namespace dxvk {
|
||||
DxvkBarrierSet m_transitions;
|
||||
DxvkBarrierControlFlags m_barrierControl;
|
||||
|
||||
DxvkQueryManager m_queries;
|
||||
DxvkGpuQueryManager m_queryManager;
|
||||
|
||||
|
||||
VkPipeline m_gpActivePipeline = VK_NULL_HANDLE;
|
||||
VkPipeline m_cpActivePipeline = VK_NULL_HANDLE;
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "dxvk_pipecache.h"
|
||||
#include "dxvk_pipemanager.h"
|
||||
#include "dxvk_queue.h"
|
||||
#include "dxvk_query_pool.h"
|
||||
#include "dxvk_recycler.h"
|
||||
#include "dxvk_renderpass.h"
|
||||
#include "dxvk_sampler.h"
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "dxvk_query.h"
|
||||
#include "dxvk_resource.h"
|
||||
|
||||
namespace dxvk {
|
||||
@ -27,6 +26,72 @@ namespace dxvk {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \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 Transform feedback stream query
|
||||
*
|
||||
* Stores the number of primitives written to the
|
||||
* buffer, as well as the number of primitives
|
||||
* generated. The latter can be used to check for
|
||||
* overflow.
|
||||
*/
|
||||
struct DxvkQueryXfbStreamData {
|
||||
uint64_t primitivesWritten;
|
||||
uint64_t primitivesNeeded;
|
||||
};
|
||||
|
||||
/**
|
||||
* \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;
|
||||
DxvkQueryXfbStreamData xfbStream;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Query handle
|
||||
*
|
||||
|
@ -1,129 +0,0 @@
|
||||
#include "dxvk_query.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkQuery::DxvkQuery(
|
||||
VkQueryType type,
|
||||
VkQueryControlFlags flags,
|
||||
uint32_t index)
|
||||
: m_type (type),
|
||||
m_flags (flags),
|
||||
m_index (index) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
DxvkQuery::~DxvkQuery() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool DxvkQuery::isIndexed() const {
|
||||
return m_type == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxvkQuery::reset() {
|
||||
std::unique_lock<sync::TicketLock> 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<sync::TicketLock> lock(m_mutex);
|
||||
|
||||
if (m_status == DxvkQueryStatus::Available)
|
||||
data = m_data;
|
||||
|
||||
return m_status;
|
||||
}
|
||||
|
||||
|
||||
DxvkQueryHandle DxvkQuery::getHandle() {
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
|
||||
void DxvkQuery::beginRecording(uint32_t revision) {
|
||||
std::unique_lock<sync::TicketLock> lock(m_mutex);
|
||||
|
||||
if (m_revision == revision)
|
||||
m_status = DxvkQueryStatus::Active;
|
||||
}
|
||||
|
||||
|
||||
void DxvkQuery::endRecording(uint32_t revision) {
|
||||
std::unique_lock<sync::TicketLock> lock(m_mutex);
|
||||
|
||||
if (m_revision == revision) {
|
||||
m_status = m_queryIndex < m_queryCount
|
||||
? DxvkQueryStatus::Pending
|
||||
: DxvkQueryStatus::Available;
|
||||
m_handle = DxvkQueryHandle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkQuery::associateQuery(uint32_t revision, DxvkQueryHandle handle) {
|
||||
std::unique_lock<sync::TicketLock> lock(m_mutex);
|
||||
|
||||
if (m_revision == revision)
|
||||
m_queryCount += 1;
|
||||
|
||||
// Assign the handle either way as this
|
||||
// will be used by the DXVK context.
|
||||
m_handle = handle;
|
||||
}
|
||||
|
||||
|
||||
void DxvkQuery::updateData(
|
||||
uint32_t revision,
|
||||
const DxvkQueryData& data) {
|
||||
std::unique_lock<sync::TicketLock> 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;
|
||||
|
||||
case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT:
|
||||
m_data.xfbStream.primitivesWritten += data.xfbStream.primitivesWritten;
|
||||
m_data.xfbStream.primitivesNeeded += data.xfbStream.primitivesNeeded;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,250 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "dxvk_limits.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Query status
|
||||
*
|
||||
* Allows the application to query
|
||||
* the current status of the query.
|
||||
*/
|
||||
enum class DxvkQueryStatus : uint32_t {
|
||||
Created = 0, ///< Query was just created
|
||||
Reset = 1, ///< Query is reset
|
||||
Active = 2, ///< Query is being recorded
|
||||
Pending = 3, ///< Query has been recorded
|
||||
Available = 4, ///< 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 Transform feedback stream query
|
||||
*
|
||||
* Stores the number of primitives written to the
|
||||
* buffer, as well as the number of primitives
|
||||
* generated. The latter can be used to check for
|
||||
* overflow.
|
||||
*/
|
||||
struct DxvkQueryXfbStreamData {
|
||||
uint64_t primitivesWritten;
|
||||
uint64_t primitivesNeeded;
|
||||
};
|
||||
|
||||
/**
|
||||
* \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;
|
||||
DxvkQueryXfbStreamData xfbStream;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Query entry
|
||||
*
|
||||
* Stores the pool handle and the
|
||||
* index of a single Vulkan query.
|
||||
*/
|
||||
struct DxvkQueryHandle {
|
||||
VkQueryPool queryPool = VK_NULL_HANDLE;
|
||||
uint32_t queryId = 0;
|
||||
VkQueryControlFlags flags = 0;
|
||||
uint32_t index = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \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(
|
||||
VkQueryType type,
|
||||
VkQueryControlFlags flags,
|
||||
uint32_t index = ~0u);
|
||||
~DxvkQuery();
|
||||
|
||||
/**
|
||||
* \brief Query type
|
||||
* \returns Query type
|
||||
*/
|
||||
VkQueryType type() const {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Query control flags
|
||||
*
|
||||
* Flags that will be applied when
|
||||
* calling \c vkCmdBeginQuery.
|
||||
* \returns Query control flags
|
||||
*/
|
||||
VkQueryControlFlags flags() const {
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Query type index
|
||||
*
|
||||
* The query type index. Will be undefined if the
|
||||
* query type is not indexed. Not to be confused
|
||||
* with the query index within the query pool.
|
||||
* \returns Query type index
|
||||
*/
|
||||
uint32_t index() const {
|
||||
return m_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether the query type is indexed
|
||||
* \returns \c true if the query type is indexed
|
||||
*/
|
||||
bool isIndexed() const;
|
||||
|
||||
/**
|
||||
* \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
|
||||
*/
|
||||
uint32_t reset();
|
||||
|
||||
/**
|
||||
* \brief Retrieves query data
|
||||
*
|
||||
* \param [out] data Query data
|
||||
* \returns Query status
|
||||
*/
|
||||
DxvkQueryStatus getData(
|
||||
DxvkQueryData& data);
|
||||
|
||||
/**
|
||||
* \brief Gets current query handle
|
||||
* \returns The current query handle
|
||||
*/
|
||||
DxvkQueryHandle getHandle();
|
||||
|
||||
/**
|
||||
* \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
|
||||
* \param [in] handle The query handle
|
||||
*/
|
||||
void associateQuery(
|
||||
uint32_t revision,
|
||||
DxvkQueryHandle handle);
|
||||
|
||||
/**
|
||||
* \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:
|
||||
|
||||
const VkQueryType m_type;
|
||||
const VkQueryControlFlags m_flags;
|
||||
const uint32_t m_index;
|
||||
|
||||
sync::TicketLock m_mutex;
|
||||
|
||||
DxvkQueryStatus m_status = DxvkQueryStatus::Created;
|
||||
DxvkQueryData m_data = {};
|
||||
DxvkQueryHandle m_handle;
|
||||
|
||||
uint32_t m_queryIndex = 0;
|
||||
uint32_t m_queryCount = 0;
|
||||
uint64_t m_revision = 0;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Query revision
|
||||
*
|
||||
* Stores the query object and the
|
||||
* version ID for query operations.
|
||||
*/
|
||||
struct DxvkQueryRevision {
|
||||
Rc<DxvkQuery> query;
|
||||
uint32_t revision;
|
||||
};
|
||||
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
#include "dxvk_query_manager.h"
|
||||
#include "dxvk_query_pool.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkQueryManager::DxvkQueryManager(const Rc<vk::DeviceFn>& vkd)
|
||||
: m_vkd(vkd) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
DxvkQueryManager::~DxvkQueryManager() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
DxvkQueryHandle DxvkQueryManager::allocQuery(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
const DxvkQueryRevision& query) {
|
||||
const VkQueryType queryType = query.query->type();
|
||||
|
||||
DxvkQueryHandle queryHandle = DxvkQueryHandle();
|
||||
Rc<DxvkQueryPool>& queryPool = this->getQueryPool(queryType);
|
||||
|
||||
if (queryPool != nullptr)
|
||||
queryHandle = queryPool->allocQuery(query);
|
||||
|
||||
if (queryHandle.queryPool == VK_NULL_HANDLE) {
|
||||
if (queryPool != nullptr)
|
||||
this->trackQueryPool(cmd, queryPool);
|
||||
|
||||
queryPool = new DxvkQueryPool(m_vkd, queryType, MaxNumQueryCountPerPool);
|
||||
queryPool->reset(cmd);
|
||||
|
||||
queryHandle = queryPool->allocQuery(query);
|
||||
}
|
||||
|
||||
return queryHandle;
|
||||
}
|
||||
|
||||
|
||||
void DxvkQueryManager::enableQuery(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
const DxvkQueryRevision& query) {
|
||||
m_activeQueries.push_back(query);
|
||||
|
||||
if (m_activeTypes & getDxvkQueryTypeBit(query.query->type()))
|
||||
this->beginVulkanQuery(cmd, query);
|
||||
}
|
||||
|
||||
|
||||
void DxvkQueryManager::disableQuery(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
const DxvkQueryRevision& query) {
|
||||
auto iter = m_activeQueries.begin();
|
||||
|
||||
while (iter != m_activeQueries.end()) {
|
||||
if (iter->query == query.query
|
||||
&& iter->revision == query.revision)
|
||||
break;
|
||||
|
||||
iter++;
|
||||
}
|
||||
|
||||
if (iter != m_activeQueries.end()) {
|
||||
if (m_activeTypes & getDxvkQueryTypeBit(iter->query->type()))
|
||||
this->endVulkanQuery(cmd, query);
|
||||
|
||||
m_activeQueries.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkQueryManager::beginQueries(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
VkQueryType type) {
|
||||
m_activeTypes |= getDxvkQueryTypeBit(type);
|
||||
|
||||
for (const DxvkQueryRevision& query : m_activeQueries) {
|
||||
if (type == query.query->type())
|
||||
this->beginVulkanQuery(cmd, query);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkQueryManager::endQueries(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
VkQueryType type) {
|
||||
m_activeTypes &= ~getDxvkQueryTypeBit(type);
|
||||
|
||||
for (const DxvkQueryRevision& query : m_activeQueries) {
|
||||
if (type == query.query->type())
|
||||
this->endVulkanQuery(cmd, query);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkQueryManager::trackQueryPools(const Rc<DxvkCommandList>& cmd) {
|
||||
this->trackQueryPool(cmd, m_occlusion);
|
||||
this->trackQueryPool(cmd, m_pipeStats);
|
||||
this->trackQueryPool(cmd, m_timestamp);
|
||||
this->trackQueryPool(cmd, m_xfbStream);
|
||||
}
|
||||
|
||||
|
||||
void DxvkQueryManager::trackQueryPool(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
const Rc<DxvkQueryPool>& pool) {
|
||||
if (pool != nullptr) {
|
||||
DxvkQueryRange range = pool->getActiveQueryRange();
|
||||
|
||||
if (range.queryCount > 0)
|
||||
cmd->trackQueryRange(std::move(range));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkQueryManager::beginVulkanQuery(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
const DxvkQueryRevision& query) {
|
||||
DxvkQueryHandle handle = this->allocQuery(cmd, query);
|
||||
|
||||
if (query.query->isIndexed()) {
|
||||
cmd->cmdBeginQueryIndexed(
|
||||
handle.queryPool,
|
||||
handle.queryId,
|
||||
handle.flags,
|
||||
handle.index);
|
||||
} else {
|
||||
cmd->cmdBeginQuery(
|
||||
handle.queryPool,
|
||||
handle.queryId,
|
||||
handle.flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkQueryManager::endVulkanQuery(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
const DxvkQueryRevision& query) {
|
||||
DxvkQueryHandle handle = query.query->getHandle();
|
||||
|
||||
if (query.query->isIndexed()) {
|
||||
cmd->cmdEndQueryIndexed(
|
||||
handle.queryPool,
|
||||
handle.queryId,
|
||||
handle.index);
|
||||
} else {
|
||||
cmd->cmdEndQuery(
|
||||
handle.queryPool,
|
||||
handle.queryId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkQueryPool>& DxvkQueryManager::getQueryPool(VkQueryType type) {
|
||||
switch (type) {
|
||||
case VK_QUERY_TYPE_OCCLUSION:
|
||||
return m_occlusion;
|
||||
|
||||
case VK_QUERY_TYPE_PIPELINE_STATISTICS:
|
||||
return m_pipeStats;
|
||||
|
||||
case VK_QUERY_TYPE_TIMESTAMP:
|
||||
return m_timestamp;
|
||||
|
||||
case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT:
|
||||
return m_xfbStream;
|
||||
|
||||
default:
|
||||
throw DxvkError("DXVK: Invalid query type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxvkQueryManager::getDxvkQueryTypeBit(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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "dxvk_cmdlist.h"
|
||||
#include "dxvk_query.h"
|
||||
#include "dxvk_query_pool.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Query manager
|
||||
*
|
||||
* Manages Vulkan query pools
|
||||
* and the current query state.
|
||||
*/
|
||||
class DxvkQueryManager {
|
||||
|
||||
public:
|
||||
|
||||
DxvkQueryManager(const Rc<vk::DeviceFn>& vkd);
|
||||
~DxvkQueryManager();
|
||||
|
||||
/**
|
||||
* \brief Allocates a Vulkan query
|
||||
*
|
||||
* Creates a query pool of the correct type if
|
||||
* necessary, and allocates one query from it.
|
||||
* \param [in] cmd The context's command list
|
||||
* \param [in] query The DXVK query revision
|
||||
* \returns Allocated query handle
|
||||
*/
|
||||
DxvkQueryHandle allocQuery(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
const DxvkQueryRevision& query);
|
||||
|
||||
/**
|
||||
* \brief Enables a query
|
||||
*
|
||||
* Starts tracking a query. Depending on the
|
||||
* query type, unterlying Vulkan queries will
|
||||
* begin and end on render pass boundaries.
|
||||
* \param [in] cmd The context's command list
|
||||
* \param [in] query The query to enable
|
||||
*/
|
||||
void enableQuery(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
const DxvkQueryRevision& query);
|
||||
|
||||
/**
|
||||
* \brief Disables a query
|
||||
*
|
||||
* Ends the query if it is currently active,
|
||||
* and stops tracking any further state changes.
|
||||
* \param [in] cmd The context's command list
|
||||
* \param [in] query The query to enable
|
||||
*/
|
||||
void disableQuery(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
const DxvkQueryRevision& query);
|
||||
|
||||
/**
|
||||
* \brief Begins active queries
|
||||
*
|
||||
* Creates a Vulkan query for each enabled
|
||||
* query of the given types and begins them.
|
||||
* \param [in] cmd The context's command list
|
||||
* \param [in] types Query types to begin
|
||||
*/
|
||||
void beginQueries(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
VkQueryType type);
|
||||
|
||||
/**
|
||||
* \brief Ends active queries
|
||||
*
|
||||
* Ends active queries of the given types.
|
||||
* \param [in] cmd The context's command list
|
||||
* \param [in] types Query types to begin
|
||||
*/
|
||||
void endQueries(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
VkQueryType type);
|
||||
|
||||
/**
|
||||
* \brief Tracks query pools
|
||||
*
|
||||
* Adds all current non-empty query pools to
|
||||
* the query tracker of the given command list.
|
||||
* \param [in] cmd The context's command list
|
||||
*/
|
||||
void trackQueryPools(
|
||||
const Rc<DxvkCommandList>& cmd);
|
||||
|
||||
private:
|
||||
|
||||
const Rc<vk::DeviceFn> m_vkd;
|
||||
|
||||
uint32_t m_activeTypes = 0;
|
||||
|
||||
Rc<DxvkQueryPool> m_occlusion;
|
||||
Rc<DxvkQueryPool> m_pipeStats;
|
||||
Rc<DxvkQueryPool> m_timestamp;
|
||||
Rc<DxvkQueryPool> m_xfbStream;
|
||||
|
||||
std::vector<DxvkQueryRevision> m_activeQueries;
|
||||
|
||||
void trackQueryPool(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
const Rc<DxvkQueryPool>& pool);
|
||||
|
||||
void beginVulkanQuery(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
const DxvkQueryRevision& query);
|
||||
|
||||
void endVulkanQuery(
|
||||
const Rc<DxvkCommandList>& cmd,
|
||||
const DxvkQueryRevision& query);
|
||||
|
||||
Rc<DxvkQueryPool>& getQueryPool(
|
||||
VkQueryType type);
|
||||
|
||||
static uint32_t getDxvkQueryTypeBit(
|
||||
VkQueryType type);
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
#include "dxvk_cmdlist.h"
|
||||
#include "dxvk_query_pool.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkQueryPool::DxvkQueryPool(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
VkQueryType queryType,
|
||||
uint32_t queryCount)
|
||||
: m_vkd(vkd), m_queryCount(queryCount), m_queryType(queryType) {
|
||||
m_queries.resize(queryCount);
|
||||
|
||||
VkQueryPoolCreateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.queryType = queryType;
|
||||
info.queryCount = queryCount;
|
||||
info.pipelineStatistics = 0;
|
||||
|
||||
if (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;
|
||||
}
|
||||
|
||||
if (m_vkd->vkCreateQueryPool(m_vkd->device(), &info, nullptr, &m_queryPool) != VK_SUCCESS)
|
||||
Logger::err("DxvkQueryPool: Failed to create query pool");
|
||||
}
|
||||
|
||||
|
||||
DxvkQueryPool::~DxvkQueryPool() {
|
||||
m_vkd->vkDestroyQueryPool(
|
||||
m_vkd->device(), m_queryPool, nullptr);
|
||||
}
|
||||
|
||||
|
||||
DxvkQueryHandle DxvkQueryPool::allocQuery(const DxvkQueryRevision& query) {
|
||||
const uint32_t queryIndex = m_queryRangeOffset + m_queryRangeLength;
|
||||
|
||||
if (queryIndex >= m_queryCount)
|
||||
return DxvkQueryHandle();
|
||||
|
||||
DxvkQueryHandle result;
|
||||
result.queryPool = m_queryPool;
|
||||
result.queryId = queryIndex;
|
||||
result.flags = query.query->flags();
|
||||
result.index = query.query->index();
|
||||
|
||||
query.query->associateQuery(query.revision, result);
|
||||
m_queries.at(queryIndex) = query;
|
||||
|
||||
m_queryRangeLength += 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
VkResult DxvkQueryPool::getData(
|
||||
uint32_t queryIndex,
|
||||
uint32_t queryCount) {
|
||||
std::array<DxvkQueryData, MaxNumQueryCountPerPool> results;
|
||||
|
||||
// We cannot use VK_QUERY_RESULT_WAIT_BIT here since that
|
||||
// may stall the calling thread indefinitely. Instead, we
|
||||
// just assume that all queries should be available after
|
||||
// waiting for the fence that protects the command buffer.
|
||||
const VkResult status = m_vkd->vkGetQueryPoolResults(
|
||||
m_vkd->device(), m_queryPool, queryIndex, queryCount,
|
||||
sizeof(DxvkQueryData) * queryCount, results.data(),
|
||||
sizeof(DxvkQueryData), VK_QUERY_RESULT_64_BIT);
|
||||
|
||||
if (status != VK_SUCCESS) {
|
||||
Logger::warn(str::format(
|
||||
"DxvkQueryPool: Failed to get query data for ", queryIndex,
|
||||
":", queryCount, " with: ", status));
|
||||
|
||||
// If retrieving query data failed, we need to fake query
|
||||
// data. In case of occlusion queries, we should return a
|
||||
// non-zero value for samples passed, so that games do not
|
||||
// accidentally omit certain geometry because of this.
|
||||
for (uint32_t i = 0; i < queryCount; i++) {
|
||||
results[i] = DxvkQueryData();
|
||||
|
||||
if (m_queryType == VK_QUERY_TYPE_OCCLUSION)
|
||||
results[i].occlusion.samplesPassed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Forward query data to the query objects
|
||||
for (uint32_t i = 0; i < queryCount; i++) {
|
||||
const DxvkQueryRevision& query = m_queries.at(queryIndex + i);
|
||||
query.query->updateData(query.revision, results[i]);
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void DxvkQueryPool::reset(const Rc<DxvkCommandList>& cmd) {
|
||||
cmd->cmdResetQueryPool(m_queryPool, 0, m_queryCount);
|
||||
|
||||
m_queryRangeOffset = 0;
|
||||
m_queryRangeLength = 0;
|
||||
}
|
||||
|
||||
|
||||
DxvkQueryRange DxvkQueryPool::getActiveQueryRange() {
|
||||
DxvkQueryRange result;
|
||||
result.queryPool = this;
|
||||
result.queryIndex = m_queryRangeOffset;
|
||||
result.queryCount = m_queryRangeLength;
|
||||
|
||||
m_queryRangeOffset += m_queryRangeLength;
|
||||
m_queryRangeLength = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "dxvk_query.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class DxvkCommandList;
|
||||
class DxvkQueryPool;
|
||||
|
||||
/**
|
||||
* \brief Query range
|
||||
*
|
||||
* Stores an index of a query in a query pool,
|
||||
* and the number of queries to track.
|
||||
*/
|
||||
struct DxvkQueryRange {
|
||||
Rc<DxvkQueryPool> queryPool;
|
||||
|
||||
uint32_t queryIndex = 0;
|
||||
uint32_t queryCount = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \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>& vkd,
|
||||
VkQueryType queryType,
|
||||
uint32_t queryCount);
|
||||
|
||||
~DxvkQueryPool();
|
||||
|
||||
/**
|
||||
* \brief Query pool handle
|
||||
* \returns Query pool handle
|
||||
*/
|
||||
VkQueryPool handle() const {
|
||||
return m_queryPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocates a Vulkan query
|
||||
*
|
||||
* \param [in] revision Query revision
|
||||
* \returns The query ID and pool handle
|
||||
*/
|
||||
DxvkQueryHandle allocQuery(
|
||||
const DxvkQueryRevision& revision);
|
||||
|
||||
/**
|
||||
* \brief Writes back data for a range of queries
|
||||
*
|
||||
* \param [in] queryIndex First query in the range
|
||||
* \param [in] queryCount Number of queries
|
||||
* \returns Query result status
|
||||
*/
|
||||
VkResult getData(
|
||||
uint32_t queryIndex,
|
||||
uint32_t queryCount);
|
||||
|
||||
/**
|
||||
* \brief Resets query pool
|
||||
*
|
||||
* Resets the Vulkan query pool itself, as
|
||||
* well as the the internal query allocator.
|
||||
* \param [in] cmd Command list
|
||||
*/
|
||||
void reset(
|
||||
const Rc<DxvkCommandList>& cmd);
|
||||
|
||||
/**
|
||||
* \brief Retrieves active query range
|
||||
*
|
||||
* This will also move the beginning of the
|
||||
* new active query range to the end of the
|
||||
* current active query range.
|
||||
* \returns Active query range
|
||||
*/
|
||||
DxvkQueryRange getActiveQueryRange();
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
|
||||
uint32_t m_queryCount;
|
||||
VkQueryType m_queryType;
|
||||
VkQueryPool m_queryPool = VK_NULL_HANDLE;
|
||||
|
||||
std::vector<DxvkQueryRevision> m_queries;
|
||||
|
||||
uint32_t m_queryRangeOffset = 0;
|
||||
uint32_t m_queryRangeLength = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
#include "dxvk_query_tracker.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkQueryTracker:: DxvkQueryTracker() { }
|
||||
DxvkQueryTracker::~DxvkQueryTracker() { }
|
||||
|
||||
|
||||
void DxvkQueryTracker::trackQueryRange(DxvkQueryRange&& queryRange) {
|
||||
m_queries.push_back(std::move(queryRange));
|
||||
}
|
||||
|
||||
|
||||
void DxvkQueryTracker::writeQueryData() {
|
||||
for (const DxvkQueryRange& curr : m_queries)
|
||||
curr.queryPool->getData(curr.queryIndex, curr.queryCount);
|
||||
}
|
||||
|
||||
|
||||
void DxvkQueryTracker::reset() {
|
||||
m_queries.clear();
|
||||
}
|
||||
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_query_pool.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Query tracker
|
||||
*/
|
||||
class DxvkQueryTracker {
|
||||
|
||||
public:
|
||||
|
||||
DxvkQueryTracker();
|
||||
~DxvkQueryTracker();
|
||||
|
||||
/**
|
||||
* \brief Adds a query range to track
|
||||
* \param [in] queryRange The query range
|
||||
*/
|
||||
void trackQueryRange(DxvkQueryRange&& queryRange);
|
||||
|
||||
/**
|
||||
* \brief Fetches query data
|
||||
*
|
||||
* Retrieves query data from the query pools
|
||||
* and writes it back to the query objects.
|
||||
*/
|
||||
void writeQueryData();
|
||||
|
||||
/**
|
||||
* \brief Resets query tracker
|
||||
*
|
||||
* Releases all query ranges from the tracker.
|
||||
* Call this after writing back the query data.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
private:
|
||||
|
||||
std::vector<DxvkQueryRange> m_queries;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -58,7 +58,6 @@ namespace dxvk {
|
||||
VkResult status = cmdList->synchronize();
|
||||
|
||||
if (status == VK_SUCCESS) {
|
||||
cmdList->writeQueryData();
|
||||
cmdList->signalEvents();
|
||||
cmdList->reset();
|
||||
|
||||
|
@ -73,10 +73,6 @@ dxvk_src = files([
|
||||
'dxvk_pipecache.cpp',
|
||||
'dxvk_pipelayout.cpp',
|
||||
'dxvk_pipemanager.cpp',
|
||||
'dxvk_query.cpp',
|
||||
'dxvk_query_pool.cpp',
|
||||
'dxvk_query_manager.cpp',
|
||||
'dxvk_query_tracker.cpp',
|
||||
'dxvk_queue.cpp',
|
||||
'dxvk_renderpass.cpp',
|
||||
'dxvk_resource.cpp',
|
||||
|
Loading…
x
Reference in New Issue
Block a user