Say which way an abandoned occlusion query was failing

Upstream now bounds this wait itself: warn at one second, abandon at
three and use whatever the query holds. That replaces the fatal timeout
this commit previously carried, and it is the better answer -- the throw
could end a session over a driver that was merely slow, at worst wrong
culling for a frame was the actual cost. What remains here is the part
the bound does not cover:

- On abandonment, ask the driver once more directly with
  VK_QUERY_RESULT_WITH_AVAILABILITY_BIT and log which way it is
  stalling: VK_NOT_READY, or VK_SUCCESS with the availability word still
  clear. The two are indistinguishable through poke_query and need
  different conversations with whoever maintains the driver.

- Leave the loop when emulation is aborting. A driver that never answers
  must not also wedge the exit path, and the value is irrelevant once
  the session is going away.

Found chasing a Skate 3 freeze on an Adreno 830, where stevenmxz's gen8
driver builds accept occlusion queries and never complete them; the
system driver completes them in microseconds.
This commit is contained in:
Zulux91
2026-08-11 19:59:51 -05:00
parent 8772786f9a
commit 8fed09d40e
+20 -1
View File
@@ -196,6 +196,14 @@ namespace vk
for (u32 spins = 0; !query_info.ready; spins++)
{
// Emulation is going away; a driver that never answers must not also wedge
// the exit path. The value is irrelevant once we are aborting.
if (thread_ctrl::state() == thread_state::aborting)
{
rsx_log.warning("Occlusion query %u abandoned: emulation is shutting down.", index);
break;
}
if ((spins & 0xffff) == 0xffff)
{
const auto waited = std::chrono::steady_clock::now() - wait_started;
@@ -208,7 +216,18 @@ namespace vk
if (waited > std::chrono::seconds(3))
{
rsx_log.error("Occlusion query %u never completed; abandoning the wait and using result=%u.", index, query_info.data);
// Ask once more directly before giving up, to record WHICH way the
// driver is stalling: VK_NOT_READY, or VK_SUCCESS with the
// availability word still clear. The two are indistinguishable
// through poke_query and need different conversations with whoever
// maintains the driver.
u32 probe[2] = { 0, 0 };
const VkResult status = vkGetQueryPoolResults(*owner, *query_info.pool, index, 1, 8, probe, 8,
result_flags | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT);
rsx_log.error("Occlusion query %u never completed (last VkResult %d, result %u, availability %u); "
"abandoning the wait and using result=%u.",
index, static_cast<int>(status), probe[0], probe[1], query_info.data);
query_info.ready = true;
break;
}