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)