mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
vkGetQueryPoolResults may never return if VK_QUERY_RESULT_WAIT_BIT is set, and may return queries as not available when they should in fact be available. This would cause indefinite hangs, so instead we return fake data to query objects if retrieving query data fails.
126 lines
4.3 KiB
C++
126 lines
4.3 KiB
C++
#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();
|
|
|
|
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;
|
|
}
|
|
|
|
} |