mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-20 19:54:19 +01:00
[dxvk] Implemented new workaround for query-related lockups
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.
This commit is contained in:
parent
a5706254d5
commit
bdfbd3e81c
@ -70,9 +70,6 @@ namespace dxvk {
|
||||
void DxvkContext::beginQuery(const DxvkQueryRevision& query) {
|
||||
DxvkQueryHandle handle = this->allocQuery(query);
|
||||
|
||||
if (query.query->type() == VK_QUERY_TYPE_OCCLUSION)
|
||||
this->renderPassBegin();
|
||||
|
||||
m_cmd->cmdBeginQuery(
|
||||
handle.queryPool,
|
||||
handle.queryId,
|
||||
|
@ -15,7 +15,7 @@ namespace dxvk {
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.queryType = queryType;
|
||||
info.queryCount = MaxNumQueryCountPerPool;
|
||||
info.queryCount = queryCount;
|
||||
info.pipelineStatistics = 0;
|
||||
|
||||
if (queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
|
||||
@ -47,20 +47,19 @@ namespace dxvk {
|
||||
DxvkQueryHandle DxvkQueryPool::allocQuery(const DxvkQueryRevision& query) {
|
||||
const uint32_t queryIndex = m_queryRangeOffset + m_queryRangeLength;
|
||||
|
||||
if (queryIndex < m_queryCount) {
|
||||
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;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -69,18 +68,36 @@ namespace dxvk {
|
||||
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) * MaxNumQueryCountPerPool,
|
||||
results.data(), sizeof(DxvkQueryData),
|
||||
VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
|
||||
sizeof(DxvkQueryData) * queryCount, results.data(),
|
||||
sizeof(DxvkQueryData), VK_QUERY_RESULT_64_BIT);
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
return status;
|
||||
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.at(i));
|
||||
query.query->updateData(query.revision, results[i]);
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
@ -55,7 +55,8 @@ namespace dxvk {
|
||||
m_condOnTake.notify_one();
|
||||
|
||||
if (entry.fence != nullptr) {
|
||||
entry.fence->wait(std::numeric_limits<uint64_t>::max());
|
||||
while (!entry.fence->wait(1'000'000'000ull))
|
||||
continue;
|
||||
|
||||
entry.cmdList->writeQueryData();
|
||||
entry.cmdList->signalEvents();
|
||||
|
Loading…
x
Reference in New Issue
Block a user