diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 9e9d7156..dd55780a 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -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, diff --git a/src/dxvk/dxvk_query_pool.cpp b/src/dxvk/dxvk_query_pool.cpp index ac4f5e66..b0a5972c 100644 --- a/src/dxvk/dxvk_query_pool.cpp +++ b/src/dxvk/dxvk_query_pool.cpp @@ -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 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; diff --git a/src/dxvk/dxvk_queue.cpp b/src/dxvk/dxvk_queue.cpp index b1497ce2..8ab6f8ca 100644 --- a/src/dxvk/dxvk_queue.cpp +++ b/src/dxvk/dxvk_queue.cpp @@ -55,7 +55,8 @@ namespace dxvk { m_condOnTake.notify_one(); if (entry.fence != nullptr) { - entry.fence->wait(std::numeric_limits::max()); + while (!entry.fence->wait(1'000'000'000ull)) + continue; entry.cmdList->writeQueryData(); entry.cmdList->signalEvents();