• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // SyncVk.cpp:
7 //    Implements the class methods for SyncVk.
8 //
9 
10 #include "libANGLE/renderer/vulkan/SyncVk.h"
11 
12 #include "common/debug.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Display.h"
15 #include "libANGLE/renderer/vulkan/ContextVk.h"
16 #include "libANGLE/renderer/vulkan/DisplayVk.h"
17 
18 #if !defined(ANGLE_PLATFORM_WINDOWS)
19 #    include <poll.h>
20 #    include <unistd.h>
21 #else
22 #    include <io.h>
23 #endif
24 
25 namespace
26 {
27 // Wait for file descriptor to be signaled
SyncWaitFd(int fd,uint64_t timeoutNs,VkResult timeoutResult=VK_TIMEOUT)28 VkResult SyncWaitFd(int fd, uint64_t timeoutNs, VkResult timeoutResult = VK_TIMEOUT)
29 {
30 #if !defined(ANGLE_PLATFORM_WINDOWS)
31     struct pollfd fds;
32     int ret;
33 
34     // Convert nanoseconds to milliseconds
35     int timeoutMs = static_cast<int>(timeoutNs / 1000000);
36     // If timeoutNs was non-zero but less than one millisecond, make it a millisecond.
37     if (timeoutNs > 0 && timeoutNs < 1000000)
38     {
39         timeoutMs = 1;
40     }
41 
42     ASSERT(fd >= 0);
43 
44     fds.fd     = fd;
45     fds.events = POLLIN;
46 
47     do
48     {
49         ret = poll(&fds, 1, timeoutMs);
50         if (ret > 0)
51         {
52             if (fds.revents & (POLLERR | POLLNVAL))
53             {
54                 return VK_ERROR_UNKNOWN;
55             }
56             return VK_SUCCESS;
57         }
58         else if (ret == 0)
59         {
60             return timeoutResult;
61         }
62     } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
63 
64     return VK_ERROR_UNKNOWN;
65 #else
66     UNREACHABLE();
67     return VK_ERROR_UNKNOWN;
68 #endif
69 }
70 
71 }  // anonymous namespace
72 
73 namespace rx
74 {
75 namespace vk
76 {
SyncHelper()77 SyncHelper::SyncHelper() {}
78 
~SyncHelper()79 SyncHelper::~SyncHelper() {}
80 
releaseToRenderer(RendererVk * renderer)81 void SyncHelper::releaseToRenderer(RendererVk *renderer) {}
82 
initialize(ContextVk * contextVk,bool isEGLSyncObject)83 angle::Result SyncHelper::initialize(ContextVk *contextVk, bool isEGLSyncObject)
84 {
85     ASSERT(!mUse.valid());
86     return contextVk->onSyncObjectInit(this, isEGLSyncObject);
87 }
88 
clientWait(Context * context,ContextVk * contextVk,bool flushCommands,uint64_t timeout,VkResult * outResult)89 angle::Result SyncHelper::clientWait(Context *context,
90                                      ContextVk *contextVk,
91                                      bool flushCommands,
92                                      uint64_t timeout,
93                                      VkResult *outResult)
94 {
95     RendererVk *renderer = context->getRenderer();
96 
97     // If the event is already set, don't wait
98     bool alreadySignaled = false;
99     ANGLE_TRY(getStatus(context, contextVk, &alreadySignaled));
100     if (alreadySignaled)
101     {
102         *outResult = VK_EVENT_SET;
103         return angle::Result::Continue;
104     }
105 
106     // If timeout is zero, there's no need to wait, so return timeout already.
107     if (timeout == 0)
108     {
109         *outResult = VK_TIMEOUT;
110         return angle::Result::Continue;
111     }
112 
113     // Submit commands if requested
114     if (flushCommands && contextVk)
115     {
116         ANGLE_TRY(contextVk->flushCommandsAndEndRenderPassIfDeferredSyncInit(
117             RenderPassClosureReason::SyncObjectClientWait));
118     }
119     // Submit commands if it was deferred on the context that issued the sync object
120     ANGLE_TRY(submitSyncIfDeferred(contextVk, RenderPassClosureReason::SyncObjectClientWait));
121 
122     VkResult status = VK_SUCCESS;
123     ANGLE_TRY(renderer->waitForResourceUseToFinishWithUserTimeout(context, mUse, timeout, &status));
124 
125     // Check for errors, but don't consider timeout as such.
126     if (status != VK_TIMEOUT)
127     {
128         ANGLE_VK_TRY(context, status);
129     }
130 
131     *outResult = status;
132     return angle::Result::Continue;
133 }
134 
serverWait(ContextVk * contextVk)135 angle::Result SyncHelper::serverWait(ContextVk *contextVk)
136 {
137     // If already signaled, no need to wait
138     bool alreadySignaled = false;
139     ANGLE_TRY(getStatus(contextVk, contextVk, &alreadySignaled));
140     if (alreadySignaled)
141     {
142         return angle::Result::Continue;
143     }
144 
145     // Every resource already tracks its usage and issues the appropriate barriers, so there's
146     // really nothing to do here.  An execution barrier is issued to strictly satisfy what the
147     // application asked for.
148     vk::OutsideRenderPassCommandBuffer *commandBuffer;
149     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
150     commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
151                                    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 0,
152                                    nullptr);
153     return angle::Result::Continue;
154 }
155 
getStatus(Context * context,ContextVk * contextVk,bool * signaledOut)156 angle::Result SyncHelper::getStatus(Context *context, ContextVk *contextVk, bool *signaledOut)
157 {
158     // Submit commands if it was deferred on the context that issued the sync object
159     ANGLE_TRY(submitSyncIfDeferred(contextVk, RenderPassClosureReason::SyncObjectClientWait));
160     ASSERT(mUse.valid());
161     RendererVk *renderer = context->getRenderer();
162     if (renderer->hasResourceUseFinished(mUse))
163     {
164         *signaledOut = true;
165     }
166     else
167     {
168         // Do immediate check in case it actually already finished.
169         ANGLE_TRY(renderer->checkCompletedCommands(context));
170         *signaledOut = renderer->hasResourceUseFinished(mUse);
171     }
172     return angle::Result::Continue;
173 }
174 
submitSyncIfDeferred(ContextVk * contextVk,RenderPassClosureReason reason)175 angle::Result SyncHelper::submitSyncIfDeferred(ContextVk *contextVk, RenderPassClosureReason reason)
176 {
177     if (contextVk == nullptr)
178     {
179         // This is EGLSync case. We always immediately call flushImpl.
180         return angle::Result::Continue;
181     }
182 
183     if (contextVk->getRenderer()->hasResourceUseSubmitted(mUse))
184     {
185         return angle::Result::Continue;
186     }
187 
188     // The submission of a sync object may be deferred to allow further optimizations to an open
189     // render pass before a submission happens for another reason.  If the sync object is being
190     // waited on by the current context, the application must have used GL_SYNC_FLUSH_COMMANDS_BIT.
191     // However, when waited on by other contexts, the application must have ensured the original
192     // context is flushed.  Due to the deferFlushUntilEndRenderPass feature, a glFlush is not
193     // sufficient to guarantee this.
194     //
195     // Deferring the submission is restricted to non-EGL sync objects, so it's sufficient to ensure
196     // that the contexts in the share group issue their deferred flushes.
197     for (auto context : contextVk->getShareGroup()->getContexts())
198     {
199         ContextVk *sharedContextVk = vk::GetImpl(context.second);
200         if (sharedContextVk->hasUnsubmittedUse(mUse))
201         {
202             ANGLE_TRY(sharedContextVk->flushCommandsAndEndRenderPassIfDeferredSyncInit(reason));
203             break;
204         }
205     }
206     // Note mUse could still be invalid here if it is inserted on a fresh created context, i.e.,
207     // fence is tracking nothing and is finished when inserted..
208     ASSERT(contextVk->getRenderer()->hasResourceUseSubmitted(mUse));
209 
210     return angle::Result::Continue;
211 }
212 
ExternalFence()213 ExternalFence::ExternalFence()
214     : mDevice(VK_NULL_HANDLE), mFenceFdStatus(VK_INCOMPLETE), mFenceFd(kInvalidFenceFd)
215 {}
216 
~ExternalFence()217 ExternalFence::~ExternalFence()
218 {
219     if (mDevice != VK_NULL_HANDLE)
220     {
221         mFence.destroy(mDevice);
222     }
223 
224     if (mFenceFd != kInvalidFenceFd)
225     {
226         close(mFenceFd);
227     }
228 }
229 
init(VkDevice device,const VkFenceCreateInfo & createInfo)230 VkResult ExternalFence::init(VkDevice device, const VkFenceCreateInfo &createInfo)
231 {
232     ASSERT(device != VK_NULL_HANDLE);
233     ASSERT(mFenceFdStatus == VK_INCOMPLETE && mFenceFd == kInvalidFenceFd);
234     ASSERT(mDevice == VK_NULL_HANDLE);
235     mDevice = device;
236     return mFence.init(device, createInfo);
237 }
238 
init(int fenceFd)239 void ExternalFence::init(int fenceFd)
240 {
241     ASSERT(fenceFd != kInvalidFenceFd);
242     ASSERT(mFenceFdStatus == VK_INCOMPLETE && mFenceFd == kInvalidFenceFd);
243     mFenceFdStatus = VK_SUCCESS;
244     mFenceFd       = fenceFd;
245 }
246 
getStatus(VkDevice device) const247 VkResult ExternalFence::getStatus(VkDevice device) const
248 {
249     if (mFenceFdStatus == VK_SUCCESS)
250     {
251         return SyncWaitFd(mFenceFd, 0, VK_NOT_READY);
252     }
253     return mFence.getStatus(device);
254 }
255 
wait(VkDevice device,uint64_t timeout) const256 VkResult ExternalFence::wait(VkDevice device, uint64_t timeout) const
257 {
258     if (mFenceFdStatus == VK_SUCCESS)
259     {
260         return SyncWaitFd(mFenceFd, timeout);
261     }
262     return mFence.wait(device, timeout);
263 }
264 
exportFd(VkDevice device,const VkFenceGetFdInfoKHR & fenceGetFdInfo)265 void ExternalFence::exportFd(VkDevice device, const VkFenceGetFdInfoKHR &fenceGetFdInfo)
266 {
267     ASSERT(mFenceFdStatus == VK_INCOMPLETE && mFenceFd == kInvalidFenceFd);
268     mFenceFdStatus = mFence.exportFd(device, fenceGetFdInfo, &mFenceFd);
269     ASSERT(mFenceFdStatus != VK_INCOMPLETE);
270 }
271 
SyncHelperNativeFence()272 SyncHelperNativeFence::SyncHelperNativeFence()
273 {
274     mExternalFence = std::make_shared<ExternalFence>();
275 }
276 
~SyncHelperNativeFence()277 SyncHelperNativeFence::~SyncHelperNativeFence() {}
278 
releaseToRenderer(RendererVk * renderer)279 void SyncHelperNativeFence::releaseToRenderer(RendererVk *renderer)
280 {
281     mExternalFence.reset();
282 }
283 
initializeWithFd(ContextVk * contextVk,int inFd)284 angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int inFd)
285 {
286     ASSERT(inFd >= kInvalidFenceFd);
287 
288     // If valid FD provided by application - import it to fence.
289     if (inFd > kInvalidFenceFd)
290     {
291         // File descriptor ownership: EGL_ANDROID_native_fence_sync
292         // Whenever a file descriptor is passed into or returned from an
293         // EGL call in this extension, ownership of that file descriptor is
294         // transferred. The recipient of the file descriptor must close it when it is
295         // no longer needed, and the provider of the file descriptor must dup it
296         // before providing it if they require continued use of the native fence.
297         mExternalFence->init(inFd);
298         return angle::Result::Continue;
299     }
300 
301     RendererVk *renderer = contextVk->getRenderer();
302     VkDevice device      = renderer->getDevice();
303 
304     VkExportFenceCreateInfo exportCreateInfo = {};
305     exportCreateInfo.sType                   = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO;
306     exportCreateInfo.pNext                   = nullptr;
307     exportCreateInfo.handleTypes             = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR;
308 
309     // Create fenceInfo base.
310     VkFenceCreateInfo fenceCreateInfo = {};
311     fenceCreateInfo.sType             = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
312     fenceCreateInfo.flags             = 0;
313     fenceCreateInfo.pNext             = &exportCreateInfo;
314 
315     // Initialize/create a VkFence handle
316     ANGLE_VK_TRY(contextVk, mExternalFence->init(device, fenceCreateInfo));
317 
318     // invalid FD provided by application - create one with fence.
319     /*
320       Spec: "When a fence sync object is created or when an EGL native fence sync
321       object is created with the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute set to
322       EGL_NO_NATIVE_FENCE_FD_ANDROID, eglCreateSyncKHR also inserts a fence command
323       into the command stream of the bound client API's current context and associates it
324       with the newly created sync object.
325     */
326     // Flush current pending set of commands providing the fence...
327     ANGLE_TRY(contextVk->flushImpl(nullptr, &mExternalFence,
328                                    RenderPassClosureReason::SyncObjectWithFdInit));
329     QueueSerial submitSerial = contextVk->getLastSubmittedQueueSerial();
330 
331     // exportFd is exporting VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR type handle which
332     // obeys copy semantics. This means that the fence must already be signaled or the work to
333     // signal it is in the graphics pipeline at the time we export the fd. Thus we need to
334     // call waitForQueueSerialToBeSubmittedToDevice() here.
335     ANGLE_TRY(renderer->waitForQueueSerialToBeSubmittedToDevice(contextVk, submitSerial));
336 
337     ANGLE_VK_TRY(contextVk, mExternalFence->getFenceFdStatus());
338 
339     return angle::Result::Continue;
340 }
341 
clientWait(Context * context,ContextVk * contextVk,bool flushCommands,uint64_t timeout,VkResult * outResult)342 angle::Result SyncHelperNativeFence::clientWait(Context *context,
343                                                 ContextVk *contextVk,
344                                                 bool flushCommands,
345                                                 uint64_t timeout,
346                                                 VkResult *outResult)
347 {
348     RendererVk *renderer = context->getRenderer();
349 
350     // If already signaled, don't wait
351     bool alreadySignaled = false;
352     ANGLE_TRY(getStatus(context, contextVk, &alreadySignaled));
353     if (alreadySignaled)
354     {
355         *outResult = VK_SUCCESS;
356         return angle::Result::Continue;
357     }
358 
359     // If timeout is zero, there's no need to wait, so return timeout already.
360     if (timeout == 0)
361     {
362         *outResult = VK_TIMEOUT;
363         return angle::Result::Continue;
364     }
365 
366     if (flushCommands && contextVk)
367     {
368         ANGLE_TRY(
369             contextVk->flushImpl(nullptr, nullptr, RenderPassClosureReason::SyncObjectClientWait));
370     }
371 
372     VkResult status = mExternalFence->wait(renderer->getDevice(), timeout);
373     if (status != VK_TIMEOUT)
374     {
375         ANGLE_VK_TRY(contextVk, status);
376     }
377 
378     *outResult = status;
379     return angle::Result::Continue;
380 }
381 
serverWait(ContextVk * contextVk)382 angle::Result SyncHelperNativeFence::serverWait(ContextVk *contextVk)
383 {
384     RendererVk *renderer = contextVk->getRenderer();
385 
386     // If already signaled, no need to wait
387     bool alreadySignaled = false;
388     ANGLE_TRY(getStatus(contextVk, contextVk, &alreadySignaled));
389     if (alreadySignaled)
390     {
391         return angle::Result::Continue;
392     }
393 
394     VkDevice device = renderer->getDevice();
395     DeviceScoped<Semaphore> waitSemaphore(device);
396     // Wait semaphore for next vkQueueSubmit().
397     // Create a Semaphore with imported fenceFd.
398     ANGLE_VK_TRY(contextVk, waitSemaphore.get().init(device));
399 
400     VkImportSemaphoreFdInfoKHR importFdInfo = {};
401     importFdInfo.sType                      = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
402     importFdInfo.semaphore                  = waitSemaphore.get().getHandle();
403     importFdInfo.flags                      = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR;
404     importFdInfo.handleType                 = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR;
405     importFdInfo.fd                         = dup(mExternalFence->getFenceFd());
406     ANGLE_VK_TRY(contextVk, waitSemaphore.get().importFd(device, importFdInfo));
407 
408     // Add semaphore to next submit job.
409     contextVk->addWaitSemaphore(waitSemaphore.get().getHandle(),
410                                 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
411     contextVk->addGarbage(&waitSemaphore.get());  // This releases the handle.
412     return angle::Result::Continue;
413 }
414 
getStatus(Context * context,ContextVk * contextVk,bool * signaledOut)415 angle::Result SyncHelperNativeFence::getStatus(Context *context,
416                                                ContextVk *contextVk,
417                                                bool *signaledOut)
418 {
419     VkResult result = mExternalFence->getStatus(context->getDevice());
420     if (result != VK_NOT_READY)
421     {
422         ANGLE_VK_TRY(context, result);
423     }
424     *signaledOut = (result == VK_SUCCESS);
425     return angle::Result::Continue;
426 }
427 
dupNativeFenceFD(Context * context,int * fdOut) const428 angle::Result SyncHelperNativeFence::dupNativeFenceFD(Context *context, int *fdOut) const
429 {
430     if (mExternalFence->getFenceFd() == kInvalidFenceFd)
431     {
432         return angle::Result::Stop;
433     }
434 
435     *fdOut = dup(mExternalFence->getFenceFd());
436 
437     return angle::Result::Continue;
438 }
439 
440 }  // namespace vk
441 
SyncVk()442 SyncVk::SyncVk() : SyncImpl() {}
443 
~SyncVk()444 SyncVk::~SyncVk() {}
445 
onDestroy(const gl::Context * context)446 void SyncVk::onDestroy(const gl::Context *context)
447 {
448     mSyncHelper.releaseToRenderer(vk::GetImpl(context)->getRenderer());
449 }
450 
set(const gl::Context * context,GLenum condition,GLbitfield flags)451 angle::Result SyncVk::set(const gl::Context *context, GLenum condition, GLbitfield flags)
452 {
453     ASSERT(condition == GL_SYNC_GPU_COMMANDS_COMPLETE);
454     ASSERT(flags == 0);
455 
456     return mSyncHelper.initialize(vk::GetImpl(context), false);
457 }
458 
clientWait(const gl::Context * context,GLbitfield flags,GLuint64 timeout,GLenum * outResult)459 angle::Result SyncVk::clientWait(const gl::Context *context,
460                                  GLbitfield flags,
461                                  GLuint64 timeout,
462                                  GLenum *outResult)
463 {
464     ContextVk *contextVk = vk::GetImpl(context);
465 
466     ASSERT((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) == 0);
467 
468     bool flush = (flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0;
469     VkResult result;
470 
471     ANGLE_TRY(mSyncHelper.clientWait(contextVk, contextVk, flush, static_cast<uint64_t>(timeout),
472                                      &result));
473 
474     switch (result)
475     {
476         case VK_EVENT_SET:
477             *outResult = GL_ALREADY_SIGNALED;
478             return angle::Result::Continue;
479 
480         case VK_SUCCESS:
481             *outResult = GL_CONDITION_SATISFIED;
482             return angle::Result::Continue;
483 
484         case VK_TIMEOUT:
485             *outResult = GL_TIMEOUT_EXPIRED;
486             return angle::Result::Incomplete;
487 
488         default:
489             UNREACHABLE();
490             *outResult = GL_WAIT_FAILED;
491             return angle::Result::Stop;
492     }
493 }
494 
serverWait(const gl::Context * context,GLbitfield flags,GLuint64 timeout)495 angle::Result SyncVk::serverWait(const gl::Context *context, GLbitfield flags, GLuint64 timeout)
496 {
497     ASSERT(flags == 0);
498     ASSERT(timeout == GL_TIMEOUT_IGNORED);
499 
500     ContextVk *contextVk = vk::GetImpl(context);
501     return mSyncHelper.serverWait(contextVk);
502 }
503 
getStatus(const gl::Context * context,GLint * outResult)504 angle::Result SyncVk::getStatus(const gl::Context *context, GLint *outResult)
505 {
506     ContextVk *contextVk = vk::GetImpl(context);
507     bool signaled        = false;
508     ANGLE_TRY(mSyncHelper.getStatus(contextVk, contextVk, &signaled));
509 
510     *outResult = signaled ? GL_SIGNALED : GL_UNSIGNALED;
511     return angle::Result::Continue;
512 }
513 
EGLSyncVk(const egl::AttributeMap & attribs)514 EGLSyncVk::EGLSyncVk(const egl::AttributeMap &attribs)
515     : EGLSyncImpl(),
516       mSyncHelper(nullptr),
517       mNativeFenceFD(
518           attribs.getAsInt(EGL_SYNC_NATIVE_FENCE_FD_ANDROID, EGL_NO_NATIVE_FENCE_FD_ANDROID))
519 {}
520 
~EGLSyncVk()521 EGLSyncVk::~EGLSyncVk()
522 {
523     SafeDelete(mSyncHelper);
524 }
525 
onDestroy(const egl::Display * display)526 void EGLSyncVk::onDestroy(const egl::Display *display)
527 {
528     mSyncHelper->releaseToRenderer(vk::GetImpl(display)->getRenderer());
529 }
530 
initialize(const egl::Display * display,const gl::Context * context,EGLenum type)531 egl::Error EGLSyncVk::initialize(const egl::Display *display,
532                                  const gl::Context *context,
533                                  EGLenum type)
534 {
535     ASSERT(context != nullptr);
536     mType = type;
537 
538     switch (type)
539     {
540         case EGL_SYNC_FENCE_KHR:
541         {
542             vk::SyncHelper *syncHelper = new vk::SyncHelper();
543             mSyncHelper                = syncHelper;
544             if (syncHelper->initialize(vk::GetImpl(context), true) == angle::Result::Stop)
545             {
546                 return egl::Error(EGL_BAD_ALLOC, "eglCreateSyncKHR failed to create sync object");
547             }
548             return egl::NoError();
549         }
550         case EGL_SYNC_NATIVE_FENCE_ANDROID:
551         {
552             vk::SyncHelperNativeFence *syncHelper = new vk::SyncHelperNativeFence();
553             mSyncHelper                           = syncHelper;
554             return angle::ToEGL(syncHelper->initializeWithFd(vk::GetImpl(context), mNativeFenceFD),
555                                 EGL_BAD_ALLOC);
556         }
557         default:
558             UNREACHABLE();
559             return egl::Error(EGL_BAD_ALLOC);
560     }
561 }
562 
clientWait(const egl::Display * display,const gl::Context * context,EGLint flags,EGLTime timeout,EGLint * outResult)563 egl::Error EGLSyncVk::clientWait(const egl::Display *display,
564                                  const gl::Context *context,
565                                  EGLint flags,
566                                  EGLTime timeout,
567                                  EGLint *outResult)
568 {
569     ASSERT((flags & ~EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) == 0);
570 
571     bool flush = (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) != 0;
572     VkResult result;
573 
574     ContextVk *contextVk = context ? vk::GetImpl(context) : nullptr;
575     if (mSyncHelper->clientWait(vk::GetImpl(display), contextVk, flush,
576                                 static_cast<uint64_t>(timeout), &result) == angle::Result::Stop)
577     {
578         return egl::Error(EGL_BAD_ALLOC);
579     }
580 
581     switch (result)
582     {
583         case VK_EVENT_SET:
584             // fall through.  EGL doesn't differentiate between event being already set, or set
585             // before timeout.
586         case VK_SUCCESS:
587             *outResult = EGL_CONDITION_SATISFIED_KHR;
588             return egl::NoError();
589 
590         case VK_TIMEOUT:
591             *outResult = EGL_TIMEOUT_EXPIRED_KHR;
592             return egl::NoError();
593 
594         default:
595             UNREACHABLE();
596             *outResult = EGL_FALSE;
597             return egl::Error(EGL_BAD_ALLOC);
598     }
599 }
600 
serverWait(const egl::Display * display,const gl::Context * context,EGLint flags)601 egl::Error EGLSyncVk::serverWait(const egl::Display *display,
602                                  const gl::Context *context,
603                                  EGLint flags)
604 {
605     // Server wait requires a valid bound context.
606     ASSERT(context);
607 
608     // No flags are currently implemented.
609     ASSERT(flags == 0);
610 
611     ContextVk *contextVk = vk::GetImpl(context);
612     return angle::ToEGL(mSyncHelper->serverWait(contextVk), EGL_BAD_ALLOC);
613 }
614 
getStatus(const egl::Display * display,EGLint * outStatus)615 egl::Error EGLSyncVk::getStatus(const egl::Display *display, EGLint *outStatus)
616 {
617     bool signaled = false;
618     if (mSyncHelper->getStatus(vk::GetImpl(display), nullptr, &signaled) == angle::Result::Stop)
619     {
620         return egl::Error(EGL_BAD_ALLOC);
621     }
622 
623     *outStatus = signaled ? EGL_SIGNALED_KHR : EGL_UNSIGNALED_KHR;
624     return egl::NoError();
625 }
626 
dupNativeFenceFD(const egl::Display * display,EGLint * fdOut) const627 egl::Error EGLSyncVk::dupNativeFenceFD(const egl::Display *display, EGLint *fdOut) const
628 {
629     switch (mType)
630     {
631         case EGL_SYNC_NATIVE_FENCE_ANDROID:
632             return angle::ToEGL(mSyncHelper->dupNativeFenceFD(vk::GetImpl(display), fdOut),
633                                 EGL_BAD_PARAMETER);
634         default:
635             return egl::EglBadDisplay();
636     }
637 }
638 
639 }  // namespace rx
640