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/CommandGraph.h b/src/libANGLE/renderer/vulkan/CommandGraph.h
index 1314da5..14cf9c9 100644
--- a/src/libANGLE/renderer/vulkan/CommandGraph.h
+++ b/src/libANGLE/renderer/vulkan/CommandGraph.h
@@ -30,6 +30,7 @@
Framebuffer,
Image,
Query,
+ FenceSync,
};
// Certain functionality cannot be put in secondary command buffers, so they are special-cased in
@@ -40,6 +41,8 @@
BeginQuery,
EndQuery,
WriteTimestamp,
+ SetFenceSync,
+ WaitFenceSync,
};
// Receives notifications when a command buffer is no longer able to record. Can be used with
@@ -127,6 +130,7 @@
CommandGraphNodeFunction getFunction() const { return mFunction; }
void setQueryPool(const QueryPool *queryPool, uint32_t queryIndex);
+ void setFenceSync(const vk::Event &event);
ANGLE_INLINE void addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess)
{
@@ -168,8 +172,11 @@
CommandBuffer mInsideRenderPassCommands;
// Special-function additional data:
+ // Queries:
VkQueryPool mQueryPool;
uint32_t mQueryIndex;
+ // GLsync and EGLSync:
+ VkEvent mFenceSyncEvent;
// Parents are commands that must be submitted before 'this' CommandNode can be submitted.
std::vector<CommandGraphNode *> mParents;
@@ -359,6 +366,9 @@
void beginQuery(const QueryPool *queryPool, uint32_t queryIndex);
void endQuery(const QueryPool *queryPool, uint32_t queryIndex);
void writeTimestamp(const QueryPool *queryPool, uint32_t queryIndex);
+ // GLsync and EGLSync:
+ void setFenceSync(const vk::Event &event);
+ void waitFenceSync(const vk::Event &event);
private:
CommandGraphNode *allocateBarrierNode(CommandGraphResourceType resourceType,