Vulkan: fix glGetQueryObject not flushing
glGetQueryObject* requires forward progress in the queue regardless of
whether we are waiting on the result or busy-looping over whether the
results are available. This commit calls flush() if the query has
pending work.
Additionally, this fixes a race condition where glGetQueryObject* may be
accessing a query whose corresponding batch has been submitted but not
yet executed. In such a case, the GPU may not have already reset the
query, so we have to wait on the fence of that batch to make sure the
query results are reliably available.
Bug: angleproject:2855
Change-Id: I977909c6526c0778a13722a8b8b73e54ad0202f6
Reviewed-on: https://chromium-review.googlesource.com/c/1279125
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index bdd8ac7..e14b877 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -881,17 +881,17 @@
mGarbage.clear();
}
-angle::Result RendererVk::checkInFlightCommands(vk::Context *context)
+angle::Result RendererVk::checkCompletedCommands(vk::Context *context)
{
int finishedCount = 0;
for (CommandBatch &batch : mInFlightCommands)
{
- VkResult result = batch.fence.getStatus(mDevice);
- if (result == VK_NOT_READY)
+ angle::Result result = batch.fence.getStatus(context);
+ ANGLE_TRY(result);
+ if (result == angle::Result::Incomplete())
break;
- ANGLE_VK_TRY(context, result);
ASSERT(batch.serial > mLastCompletedQueueSerial);
mLastCompletedQueueSerial = batch.serial;
@@ -949,7 +949,7 @@
// TODO(jmadill): Overflow check.
mCurrentQueueSerial = mQueueSerialFactory.generate();
- ANGLE_TRY(checkInFlightCommands(context));
+ ANGLE_TRY(checkCompletedCommands(context));
// Simply null out the command buffer here - it was allocated using the command pool.
commandBuffer.releaseHandle();
@@ -971,6 +971,40 @@
return serial > mLastCompletedQueueSerial;
}
+angle::Result RendererVk::finishToSerial(vk::Context *context, Serial serial)
+{
+ if (!isSerialInUse(serial) || mInFlightCommands.empty())
+ {
+ return angle::Result::Continue();
+ }
+
+ // Find the first batch with serial equal to or bigger than given serial (note that
+ // the batch serials are unique, otherwise upper-bound would have been necessary).
+ size_t batchIndex = mInFlightCommands.size() - 1;
+ for (size_t i = 0; i < mInFlightCommands.size(); ++i)
+ {
+ if (mInFlightCommands[i].serial >= serial)
+ {
+ batchIndex = i;
+ break;
+ }
+ }
+ const CommandBatch &batch = mInFlightCommands[batchIndex];
+
+ // Wait for it finish
+ constexpr uint64_t kMaxFenceWaitTimeNs = 10'000'000'000llu;
+ angle::Result result = batch.fence.wait(context, kMaxFenceWaitTimeNs);
+ if (result == angle::Result::Incomplete())
+ {
+ // Wait a maximum of 10s. If that times out, we declare it a failure.
+ result = angle::Result::Stop();
+ }
+ ANGLE_TRY(result);
+
+ // Clean up finished batches.
+ return checkCompletedCommands(context);
+}
+
angle::Result RendererVk::getCompatibleRenderPass(vk::Context *context,
const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut)