[dxvk] Accumulate query data into query object

And do so when adding additional query handles, in order
to avoid allocating queries indefinitely if End is never
called, which Halo:MCC supposedly does.

Co-authored-by: Sam Edwards <CFSworks@gmail.com>
This commit is contained in:
Philip Rebohle 2023-03-02 21:12:24 +01:00 committed by Philip Rebohle
parent e430ff5cfd
commit 7f21a6c491
3 changed files with 77 additions and 32 deletions

View File

@ -28,7 +28,7 @@ namespace dxvk {
}
DxvkGpuQueryStatus DxvkGpuQuery::getData(DxvkQueryData& queryData) const {
DxvkGpuQueryStatus DxvkGpuQuery::getData(DxvkQueryData& queryData) {
queryData = DxvkQueryData();
// Callers must ensure that no begin call is pending when
@ -37,21 +37,21 @@ namespace dxvk {
if (!m_ended.load(std::memory_order_acquire))
return DxvkGpuQueryStatus::Invalid;
// Get query data from all associated handles
DxvkGpuQueryStatus status = DxvkGpuQueryStatus::Available;
for (size_t i = 0; i < m_handles.size()
&& status == DxvkGpuQueryStatus::Available; i++)
status = getDataForHandle(queryData, m_handles[i]);
// Accumulate query data from all available queries
DxvkGpuQueryStatus status = this->accumulateQueryData();
// 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))
&& (m_queryData.occlusion.samplesPassed))
status = DxvkGpuQueryStatus::Available;
// Write back accumulated query data if the result is useful
if (status == DxvkGpuQueryStatus::Available)
queryData = m_queryData;
return status;
}
@ -61,10 +61,15 @@ namespace dxvk {
// only the false->true transition is defined.
m_ended.store(false, std::memory_order_relaxed);
// Ideally we should have no queries left at this point,
// if we do, lifetime-track them with the command list.
for (size_t i = 0; i < m_handles.size(); i++)
cmd->trackGpuQuery(m_handles[i]);
m_handles.clear();
// Reset accumulated query data
m_queryData = DxvkQueryData();
}
@ -75,14 +80,18 @@ namespace dxvk {
void DxvkGpuQuery::addQueryHandle(const DxvkGpuQueryHandle& handle) {
// Already accumulate available queries here in case
// we already allocated a large number of queries
if (m_handles.size() >= m_handles.MinCapacity)
this->accumulateQueryData();
m_handles.push_back(handle);
}
DxvkGpuQueryStatus DxvkGpuQuery::getDataForHandle(
DxvkQueryData& queryData,
const DxvkGpuQueryHandle& handle) const {
DxvkQueryData tmpData;
DxvkGpuQueryStatus DxvkGpuQuery::accumulateQueryDataForHandle(
const DxvkGpuQueryHandle& handle) {
DxvkQueryData tmpData = { };
// Try to copy query data to temporary structure
VkResult result = m_vkd->vkGetQueryPoolResults(m_vkd->device(),
@ -98,30 +107,30 @@ namespace dxvk {
// Add numbers to the destination structure
switch (m_type) {
case VK_QUERY_TYPE_OCCLUSION:
queryData.occlusion.samplesPassed += tmpData.occlusion.samplesPassed;
m_queryData.occlusion.samplesPassed += tmpData.occlusion.samplesPassed;
break;
case VK_QUERY_TYPE_TIMESTAMP:
queryData.timestamp.time = tmpData.timestamp.time;
m_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;
m_queryData.statistic.iaVertices += tmpData.statistic.iaVertices;
m_queryData.statistic.iaPrimitives += tmpData.statistic.iaPrimitives;
m_queryData.statistic.vsInvocations += tmpData.statistic.vsInvocations;
m_queryData.statistic.gsInvocations += tmpData.statistic.gsInvocations;
m_queryData.statistic.gsPrimitives += tmpData.statistic.gsPrimitives;
m_queryData.statistic.clipInvocations += tmpData.statistic.clipInvocations;
m_queryData.statistic.clipPrimitives += tmpData.statistic.clipPrimitives;
m_queryData.statistic.fsInvocations += tmpData.statistic.fsInvocations;
m_queryData.statistic.tcsPatches += tmpData.statistic.tcsPatches;
m_queryData.statistic.tesInvocations += tmpData.statistic.tesInvocations;
m_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;
m_queryData.xfbStream.primitivesWritten += tmpData.xfbStream.primitivesWritten;
m_queryData.xfbStream.primitivesNeeded += tmpData.xfbStream.primitivesNeeded;
break;
default:
@ -131,6 +140,37 @@ namespace dxvk {
return DxvkGpuQueryStatus::Available;
}
DxvkGpuQueryStatus DxvkGpuQuery::accumulateQueryData() {
DxvkGpuQueryStatus status = DxvkGpuQueryStatus::Available;
// Process available queries and return them to the
// allocator if possible. This may help reduce the
// number of Vulkan queries in flight.
size_t queriesAvailable = 0;
while (queriesAvailable < m_handles.size()) {
status = this->accumulateQueryDataForHandle(m_handles[queriesAvailable]);
if (status != DxvkGpuQueryStatus::Available)
break;
queriesAvailable += 1;
}
if (queriesAvailable) {
for (size_t i = 0; i < queriesAvailable; i++)
m_handles[i].allocator->freeQuery(m_handles[i]);
for (size_t i = queriesAvailable; i < m_handles.size(); i++)
m_handles[i - queriesAvailable] = m_handles[i];
m_handles.resize(m_handles.size() - queriesAvailable);
}
return status;
}

View File

@ -188,7 +188,7 @@ namespace dxvk {
* \returns Current query status
*/
DxvkGpuQueryStatus getData(
DxvkQueryData& queryData) const;
DxvkQueryData& queryData);
/**
* \brief Begins query
@ -230,11 +230,14 @@ namespace dxvk {
uint32_t m_index;
std::atomic<bool> m_ended;
DxvkQueryData m_queryData = { };
small_vector<DxvkGpuQueryHandle, 8> m_handles;
DxvkGpuQueryStatus getDataForHandle(
DxvkQueryData& queryData,
const DxvkGpuQueryHandle& handle) const;
DxvkGpuQueryStatus accumulateQueryDataForHandle(
const DxvkGpuQueryHandle& handle);
DxvkGpuQueryStatus accumulateQueryData();
};

View File

@ -9,6 +9,8 @@ namespace dxvk {
using storage = std::aligned_storage_t<sizeof(T), alignof(T)>;
public:
constexpr static size_t MinCapacity = N;
small_vector() { }
small_vector (const small_vector&) = delete;