Vulkan: Implement GLsync and EGLSync fence syncs
That is required in GLES 3 for GLsync and EGL_KHR_fence_sync and
EGL_KHR_wait_sync (or EGL 1.5) for EGLSync.
The two constructs (GLsync and EGLSync) have similar semantics and share
the implementation on the Vulkan backend.
The implementation of a fence sync object is achieved through the
combined use of a vkEvent and the implicit vkFence inserted at the end
of every submission. Imagine the following command buffer:
glDraw : Draw
glCreateSync: Set Event <-- insertion of fence sync
glDraw : Draw
: Signal Fence <-- implicit fence at the end of submission
glFlush : Submit
Assume the serial S is associated to this submission. The following
hold:
- If event is set, the fence sync is signaled
- If S is already finished, the fence sync is signaled
- If client is waiting on the sync and S is not yet flushed, there will
be a deadlock (unless multi-threaded and another thread performs the
flush).
The event is used to implement server waits (glWaitSync), as vkEvent is
the only entity the GPU can signal and wait on within the command
buffer. The wait is inserted in the command graph without incurring a
flush, i.e. the wait can be within the same command buffer as event set.
The event however does not support CPU waits (glClientWaitSync).
vkFence is the only entity the CPU can wait on. For client wait
therefore, the following algorithm is used:
- If the event is already set, there's no wait -> already signaled
- If timeout is zero, there's no wait -> timeout expired
- If S is not flushed, flush it to ensure forward progress.
- Wait until S is finished -> condition satisfied / timeout expired.
Bug: angleproject:2466
Change-Id: I678995a6139dd9533fa8ad361a3d292b202c52a4
Reviewed-on: https://chromium-review.googlesource.com/c/1422552
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 4c85f98..734908d 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -53,9 +53,9 @@
// one for the vertex shader.
constexpr size_t kUniformBufferDescriptorsPerDescriptorSet = 2;
// Update the pipeline cache every this many swaps (if 60fps, this means every 10 minutes)
-static constexpr uint32_t kPipelineCacheVkUpdatePeriod = 10 * 60 * 60;
+constexpr uint32_t kPipelineCacheVkUpdatePeriod = 10 * 60 * 60;
// Wait a maximum of 10s. If that times out, we declare it a failure.
-static constexpr uint64_t kMaxFenceWaitTimeNs = 10'000'000'000llu;
+constexpr uint64_t kMaxFenceWaitTimeNs = 10'000'000'000llu;
bool ShouldEnableMockICD(const egl::AttributeMap &attribs)
{
@@ -1364,6 +1364,24 @@
angle::Result RendererVk::finishToSerial(vk::Context *context, Serial serial)
{
+ bool timedOut = false;
+ angle::Result result = finishToSerialOrTimeout(context, serial, kMaxFenceWaitTimeNs, &timedOut);
+
+ // Don't tolerate timeout. If such a large wait time results in timeout, something's wrong.
+ if (timedOut)
+ {
+ result = angle::Result::Stop;
+ }
+ return result;
+}
+
+angle::Result RendererVk::finishToSerialOrTimeout(vk::Context *context,
+ Serial serial,
+ uint64_t timeout,
+ bool *outTimedOut)
+{
+ *outTimedOut = false;
+
if (!isSerialInUse(serial) || mInFlightCommands.empty())
{
return angle::Result::Continue;
@@ -1383,7 +1401,16 @@
const CommandBatch &batch = mInFlightCommands[batchIndex];
// Wait for it finish
- ANGLE_VK_TRY(context, batch.fence.wait(mDevice, kMaxFenceWaitTimeNs));
+ VkResult status = batch.fence.wait(mDevice, kMaxFenceWaitTimeNs);
+
+ // If timed out, report it as such.
+ if (status == VK_TIMEOUT)
+ {
+ *outTimedOut = true;
+ return angle::Result::Continue;
+ }
+
+ ANGLE_VK_TRY(context, status);
// Clean up finished batches.
return checkCompletedCommands(context);
@@ -1785,7 +1812,7 @@
ANGLE_VK_TRY(context, commandBuffer.begin(beginInfo));
- commandBuffer.setEvent(gpuReady.get(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
+ commandBuffer.setEvent(gpuReady.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
commandBuffer.waitEvents(1, cpuReady.get().ptr(), VK_PIPELINE_STAGE_HOST_BIT,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, nullptr, 0, nullptr, 0,
nullptr);
@@ -1796,7 +1823,7 @@
timestampQuery.getQueryPool()->getHandle(),
timestampQuery.getQuery());
- commandBuffer.setEvent(gpuDone.get(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
+ commandBuffer.setEvent(gpuDone.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
ANGLE_VK_TRY(context, commandBuffer.end());