• 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 // Map VkResult to GLenum
MapVkResultToGlenum(VkResult vkResult,angle::Result angleResult,void * outResult)72 void MapVkResultToGlenum(VkResult vkResult, angle::Result angleResult, void *outResult)
73 {
74     GLenum *glEnumOut = static_cast<GLenum *>(outResult);
75     ASSERT(glEnumOut);
76 
77     if (angleResult != angle::Result::Continue)
78     {
79         *glEnumOut = GL_WAIT_FAILED;
80         return;
81     }
82 
83     switch (vkResult)
84     {
85         case VK_EVENT_SET:
86             *glEnumOut = GL_ALREADY_SIGNALED;
87             break;
88         case VK_SUCCESS:
89             *glEnumOut = GL_CONDITION_SATISFIED;
90             break;
91         case VK_TIMEOUT:
92             *glEnumOut = GL_TIMEOUT_EXPIRED;
93             break;
94         default:
95             *glEnumOut = GL_WAIT_FAILED;
96             break;
97     }
98 }
99 
100 // Map VkResult to EGLint
MapVkResultToEglint(VkResult result,angle::Result angleResult,void * outResult)101 void MapVkResultToEglint(VkResult result, angle::Result angleResult, void *outResult)
102 {
103     EGLint *eglIntOut = static_cast<EGLint *>(outResult);
104     ASSERT(eglIntOut);
105 
106     if (angleResult != angle::Result::Continue)
107     {
108         *eglIntOut = EGL_FALSE;
109         return;
110     }
111 
112     switch (result)
113     {
114         case VK_EVENT_SET:
115             // fall through.  EGL doesn't differentiate between event being already set, or set
116             // before timeout.
117         case VK_SUCCESS:
118             *eglIntOut = EGL_CONDITION_SATISFIED_KHR;
119             break;
120         case VK_TIMEOUT:
121             *eglIntOut = EGL_TIMEOUT_EXPIRED_KHR;
122             break;
123         default:
124             *eglIntOut = EGL_FALSE;
125             break;
126     }
127 }
128 
129 }  // anonymous namespace
130 
131 namespace rx
132 {
133 namespace vk
134 {
SyncHelper()135 SyncHelper::SyncHelper() {}
136 
~SyncHelper()137 SyncHelper::~SyncHelper() {}
138 
releaseToRenderer(Renderer * renderer)139 void SyncHelper::releaseToRenderer(Renderer *renderer) {}
140 
initialize(ContextVk * contextVk,SyncFenceScope scope)141 angle::Result SyncHelper::initialize(ContextVk *contextVk, SyncFenceScope scope)
142 {
143     ASSERT(!mUse.valid());
144     return contextVk->onSyncObjectInit(this, scope);
145 }
146 
prepareForClientWait(Context * context,ContextVk * contextVk,bool flushCommands,uint64_t timeout,VkResult * resultOut)147 angle::Result SyncHelper::prepareForClientWait(Context *context,
148                                                ContextVk *contextVk,
149                                                bool flushCommands,
150                                                uint64_t timeout,
151                                                VkResult *resultOut)
152 {
153     // If the event is already set, don't wait
154     bool alreadySignaled = false;
155     ANGLE_TRY(getStatus(context, contextVk, &alreadySignaled));
156     if (alreadySignaled)
157     {
158         *resultOut = VK_EVENT_SET;
159         return angle::Result::Continue;
160     }
161 
162     // If timeout is zero, there's no need to wait, so return timeout already.
163     if (timeout == 0)
164     {
165         *resultOut = VK_TIMEOUT;
166         return angle::Result::Continue;
167     }
168 
169     // Submit commands if requested
170     if (flushCommands && contextVk)
171     {
172         ANGLE_TRY(contextVk->flushCommandsAndEndRenderPassIfDeferredSyncInit(
173             RenderPassClosureReason::SyncObjectClientWait));
174     }
175 
176     // Submit commands if it was deferred on the context that issued the sync object
177     ANGLE_TRY(submitSyncIfDeferred(contextVk, RenderPassClosureReason::SyncObjectClientWait));
178 
179     *resultOut = VK_INCOMPLETE;
180     return angle::Result::Continue;
181 }
182 
clientWait(Context * context,ContextVk * contextVk,bool flushCommands,uint64_t timeout,MapVkResultToApiType mappingFunction,void * resultOut)183 angle::Result SyncHelper::clientWait(Context *context,
184                                      ContextVk *contextVk,
185                                      bool flushCommands,
186                                      uint64_t timeout,
187                                      MapVkResultToApiType mappingFunction,
188                                      void *resultOut)
189 {
190     ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelper::clientWait");
191 
192     VkResult status = VK_INCOMPLETE;
193     ANGLE_TRY(prepareForClientWait(context, contextVk, flushCommands, timeout, &status));
194 
195     if (status != VK_INCOMPLETE)
196     {
197         mappingFunction(status, angle::Result::Continue, resultOut);
198         return angle::Result::Continue;
199     }
200 
201     Renderer *renderer = context->getRenderer();
202 
203     // If we need to perform a CPU wait don't set the resultOut parameter passed into the
204     // method, instead set the parameter passed into the unlocked tail call.
205     auto clientWaitUnlocked = [renderer, context, mappingFunction, use = mUse,
206                                timeout](void *resultOut) {
207         ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelper::clientWait block (unlocked)");
208 
209         VkResult status = VK_INCOMPLETE;
210         angle::Result angleResult =
211             renderer->waitForResourceUseToFinishWithUserTimeout(context, use, timeout, &status);
212         // Note: resultOut may be nullptr through the glFinishFenceNV path, which does not have a
213         // return value.
214         if (resultOut != nullptr)
215         {
216             mappingFunction(status, angleResult, resultOut);
217         }
218     };
219 
220     // Schedule the wait to be run at the tail of the current call.
221     egl::Display::GetCurrentThreadUnlockedTailCall()->add(clientWaitUnlocked);
222     return angle::Result::Continue;
223 }
224 
finish(ContextVk * contextVk)225 angle::Result SyncHelper::finish(ContextVk *contextVk)
226 {
227     GLenum result;
228     return clientWait(contextVk, contextVk, true, UINT64_MAX, MapVkResultToGlenum, &result);
229 }
230 
serverWait(ContextVk * contextVk)231 angle::Result SyncHelper::serverWait(ContextVk *contextVk)
232 {
233     // If already signaled, no need to wait
234     bool alreadySignaled = false;
235     ANGLE_TRY(getStatus(contextVk, contextVk, &alreadySignaled));
236     if (alreadySignaled)
237     {
238         return angle::Result::Continue;
239     }
240 
241     // Every resource already tracks its usage and issues the appropriate barriers, so there's
242     // really nothing to do here.  An execution barrier is issued to strictly satisfy what the
243     // application asked for.
244     vk::OutsideRenderPassCommandBuffer *commandBuffer;
245     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
246     commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
247                                    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 0,
248                                    nullptr);
249     return angle::Result::Continue;
250 }
251 
getStatus(Context * context,ContextVk * contextVk,bool * signaledOut)252 angle::Result SyncHelper::getStatus(Context *context, ContextVk *contextVk, bool *signaledOut)
253 {
254     // Submit commands if it was deferred on the context that issued the sync object
255     ANGLE_TRY(submitSyncIfDeferred(contextVk, RenderPassClosureReason::SyncObjectClientWait));
256     ASSERT(mUse.valid());
257     Renderer *renderer = context->getRenderer();
258     if (renderer->hasResourceUseFinished(mUse))
259     {
260         *signaledOut = true;
261     }
262     else
263     {
264         // Do immediate check in case it actually already finished.
265         ANGLE_TRY(renderer->checkCompletedCommands(context));
266         *signaledOut = renderer->hasResourceUseFinished(mUse);
267     }
268     return angle::Result::Continue;
269 }
270 
submitSyncIfDeferred(ContextVk * contextVk,RenderPassClosureReason reason)271 angle::Result SyncHelper::submitSyncIfDeferred(ContextVk *contextVk, RenderPassClosureReason reason)
272 {
273     if (contextVk == nullptr)
274     {
275         // This is EGLSync case. We always immediately call flushImpl.
276         return angle::Result::Continue;
277     }
278 
279     if (contextVk->getRenderer()->hasResourceUseSubmitted(mUse))
280     {
281         return angle::Result::Continue;
282     }
283 
284     // The submission of a sync object may be deferred to allow further optimizations to an open
285     // render pass before a submission happens for another reason.  If the sync object is being
286     // waited on by the current context, the application must have used GL_SYNC_FLUSH_COMMANDS_BIT.
287     // However, when waited on by other contexts, the application must have ensured the original
288     // context is flushed.  Due to deferred flushes, a glFlush is not sufficient to guarantee this.
289     //
290     // Deferring the submission is restricted to non-EGL sync objects, so it's sufficient to ensure
291     // that the contexts in the share group issue their deferred flushes.
292     for (auto context : contextVk->getShareGroup()->getContexts())
293     {
294         ContextVk *sharedContextVk = vk::GetImpl(context.second);
295         if (sharedContextVk->hasUnsubmittedUse(mUse))
296         {
297             ANGLE_TRY(sharedContextVk->flushCommandsAndEndRenderPassIfDeferredSyncInit(reason));
298             break;
299         }
300     }
301     // Note mUse could still be invalid here if it is inserted on a fresh created context, i.e.,
302     // fence is tracking nothing and is finished when inserted..
303     ASSERT(contextVk->getRenderer()->hasResourceUseSubmitted(mUse));
304 
305     return angle::Result::Continue;
306 }
307 
ExternalFence()308 ExternalFence::ExternalFence()
309     : mDevice(VK_NULL_HANDLE), mFenceFdStatus(VK_INCOMPLETE), mFenceFd(kInvalidFenceFd)
310 {}
311 
~ExternalFence()312 ExternalFence::~ExternalFence()
313 {
314     if (mDevice != VK_NULL_HANDLE)
315     {
316         mFence.destroy(mDevice);
317     }
318 
319     if (mFenceFd != kInvalidFenceFd)
320     {
321         close(mFenceFd);
322     }
323 }
324 
init(VkDevice device,const VkFenceCreateInfo & createInfo)325 VkResult ExternalFence::init(VkDevice device, const VkFenceCreateInfo &createInfo)
326 {
327     ASSERT(device != VK_NULL_HANDLE);
328     ASSERT(mFenceFdStatus == VK_INCOMPLETE && mFenceFd == kInvalidFenceFd);
329     ASSERT(mDevice == VK_NULL_HANDLE);
330     mDevice = device;
331     return mFence.init(device, createInfo);
332 }
333 
init(int fenceFd)334 void ExternalFence::init(int fenceFd)
335 {
336     ASSERT(fenceFd != kInvalidFenceFd);
337     ASSERT(mFenceFdStatus == VK_INCOMPLETE && mFenceFd == kInvalidFenceFd);
338     mFenceFdStatus = VK_SUCCESS;
339     mFenceFd       = fenceFd;
340 }
341 
getStatus(VkDevice device) const342 VkResult ExternalFence::getStatus(VkDevice device) const
343 {
344     if (mFenceFdStatus == VK_SUCCESS)
345     {
346         return SyncWaitFd(mFenceFd, 0, VK_NOT_READY);
347     }
348     return mFence.getStatus(device);
349 }
350 
wait(VkDevice device,uint64_t timeout) const351 VkResult ExternalFence::wait(VkDevice device, uint64_t timeout) const
352 {
353     if (mFenceFdStatus == VK_SUCCESS)
354     {
355         return SyncWaitFd(mFenceFd, timeout);
356     }
357     return mFence.wait(device, timeout);
358 }
359 
exportFd(VkDevice device,const VkFenceGetFdInfoKHR & fenceGetFdInfo)360 void ExternalFence::exportFd(VkDevice device, const VkFenceGetFdInfoKHR &fenceGetFdInfo)
361 {
362     ASSERT(mFenceFdStatus == VK_INCOMPLETE && mFenceFd == kInvalidFenceFd);
363     mFenceFdStatus = mFence.exportFd(device, fenceGetFdInfo, &mFenceFd);
364     ASSERT(mFenceFdStatus != VK_INCOMPLETE);
365 }
366 
SyncHelperNativeFence()367 SyncHelperNativeFence::SyncHelperNativeFence()
368 {
369     mExternalFence = std::make_shared<ExternalFence>();
370 }
371 
~SyncHelperNativeFence()372 SyncHelperNativeFence::~SyncHelperNativeFence() {}
373 
releaseToRenderer(Renderer * renderer)374 void SyncHelperNativeFence::releaseToRenderer(Renderer *renderer)
375 {
376     mExternalFence.reset();
377 }
378 
initializeWithFd(ContextVk * contextVk,int inFd)379 angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int inFd)
380 {
381     ASSERT(inFd >= kInvalidFenceFd);
382 
383     // If valid FD provided by application - import it to fence.
384     if (inFd > kInvalidFenceFd)
385     {
386         // File descriptor ownership: EGL_ANDROID_native_fence_sync
387         // Whenever a file descriptor is passed into or returned from an
388         // EGL call in this extension, ownership of that file descriptor is
389         // transferred. The recipient of the file descriptor must close it when it is
390         // no longer needed, and the provider of the file descriptor must dup it
391         // before providing it if they require continued use of the native fence.
392         mExternalFence->init(inFd);
393         return angle::Result::Continue;
394     }
395 
396     Renderer *renderer = contextVk->getRenderer();
397     VkDevice device    = renderer->getDevice();
398 
399     VkExportFenceCreateInfo exportCreateInfo = {};
400     exportCreateInfo.sType                   = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO;
401     exportCreateInfo.pNext                   = nullptr;
402     exportCreateInfo.handleTypes             = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR;
403 
404     // Create fenceInfo base.
405     VkFenceCreateInfo fenceCreateInfo = {};
406     fenceCreateInfo.sType             = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
407     fenceCreateInfo.flags             = 0;
408     fenceCreateInfo.pNext             = &exportCreateInfo;
409 
410     // Initialize/create a VkFence handle
411     ANGLE_VK_TRY(contextVk, mExternalFence->init(device, fenceCreateInfo));
412 
413     // invalid FD provided by application - create one with fence.
414     /*
415       Spec: "When a fence sync object is created or when an EGL native fence sync
416       object is created with the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute set to
417       EGL_NO_NATIVE_FENCE_FD_ANDROID, eglCreateSyncKHR also inserts a fence command
418       into the command stream of the bound client API's current context and associates it
419       with the newly created sync object.
420     */
421     // Flush current pending set of commands providing the fence...
422     ANGLE_TRY(contextVk->flushImpl(nullptr, &mExternalFence,
423                                    RenderPassClosureReason::SyncObjectWithFdInit));
424     QueueSerial submitSerial = contextVk->getLastSubmittedQueueSerial();
425 
426     // exportFd is exporting VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR type handle which
427     // obeys copy semantics. This means that the fence must already be signaled or the work to
428     // signal it is in the graphics pipeline at the time we export the fd. Thus we need to
429     // call waitForQueueSerialToBeSubmittedToDevice() here.
430     ANGLE_TRY(renderer->waitForQueueSerialToBeSubmittedToDevice(contextVk, submitSerial));
431 
432     ANGLE_VK_TRY(contextVk, mExternalFence->getFenceFdStatus());
433 
434     return angle::Result::Continue;
435 }
436 
prepareForClientWait(Context * context,ContextVk * contextVk,bool flushCommands,uint64_t timeout,VkResult * resultOut)437 angle::Result SyncHelperNativeFence::prepareForClientWait(Context *context,
438                                                           ContextVk *contextVk,
439                                                           bool flushCommands,
440                                                           uint64_t timeout,
441                                                           VkResult *resultOut)
442 {
443     // If already signaled, don't wait
444     bool alreadySignaled = false;
445     ANGLE_TRY(getStatus(context, contextVk, &alreadySignaled));
446     if (alreadySignaled)
447     {
448         *resultOut = VK_SUCCESS;
449         return angle::Result::Continue;
450     }
451 
452     // If timeout is zero, there's no need to wait, so return timeout already.
453     if (timeout == 0)
454     {
455         *resultOut = VK_TIMEOUT;
456         return angle::Result::Continue;
457     }
458 
459     if (flushCommands && contextVk)
460     {
461         ANGLE_TRY(
462             contextVk->flushImpl(nullptr, nullptr, RenderPassClosureReason::SyncObjectClientWait));
463     }
464 
465     *resultOut = VK_INCOMPLETE;
466     return angle::Result::Continue;
467 }
468 
clientWait(Context * context,ContextVk * contextVk,bool flushCommands,uint64_t timeout,MapVkResultToApiType mappingFunction,void * resultOut)469 angle::Result SyncHelperNativeFence::clientWait(Context *context,
470                                                 ContextVk *contextVk,
471                                                 bool flushCommands,
472                                                 uint64_t timeout,
473                                                 MapVkResultToApiType mappingFunction,
474                                                 void *resultOut)
475 {
476     ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelperNativeFence::clientWait");
477 
478     VkResult status = VK_INCOMPLETE;
479     ANGLE_TRY(prepareForClientWait(context, contextVk, flushCommands, timeout, &status));
480 
481     if (status != VK_INCOMPLETE)
482     {
483         mappingFunction(status, angle::Result::Continue, resultOut);
484         return angle::Result::Continue;
485     }
486 
487     Renderer *renderer = context->getRenderer();
488 
489     auto clientWaitUnlocked = [device = renderer->getDevice(), fence = mExternalFence,
490                                mappingFunction, timeout](void *resultOut) {
491         ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelperNativeFence::clientWait block (unlocked)");
492         ASSERT(resultOut);
493 
494         VkResult status = fence->wait(device, timeout);
495         mappingFunction(status, angle::Result::Continue, resultOut);
496     };
497 
498     egl::Display::GetCurrentThreadUnlockedTailCall()->add(clientWaitUnlocked);
499     return angle::Result::Continue;
500 }
501 
serverWait(ContextVk * contextVk)502 angle::Result SyncHelperNativeFence::serverWait(ContextVk *contextVk)
503 {
504     Renderer *renderer = contextVk->getRenderer();
505 
506     // If already signaled, no need to wait
507     bool alreadySignaled = false;
508     ANGLE_TRY(getStatus(contextVk, contextVk, &alreadySignaled));
509     if (alreadySignaled)
510     {
511         return angle::Result::Continue;
512     }
513 
514     VkDevice device = renderer->getDevice();
515     DeviceScoped<Semaphore> waitSemaphore(device);
516     // Wait semaphore for next vkQueueSubmit().
517     // Create a Semaphore with imported fenceFd.
518     ANGLE_VK_TRY(contextVk, waitSemaphore.get().init(device));
519 
520     VkImportSemaphoreFdInfoKHR importFdInfo = {};
521     importFdInfo.sType                      = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
522     importFdInfo.semaphore                  = waitSemaphore.get().getHandle();
523     importFdInfo.flags                      = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR;
524     importFdInfo.handleType                 = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR;
525     importFdInfo.fd                         = dup(mExternalFence->getFenceFd());
526     ANGLE_VK_TRY(contextVk, waitSemaphore.get().importFd(device, importFdInfo));
527 
528     // Add semaphore to next submit job.
529     contextVk->addWaitSemaphore(waitSemaphore.get().getHandle(),
530                                 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
531     contextVk->addGarbage(&waitSemaphore.get());  // This releases the handle.
532     return angle::Result::Continue;
533 }
534 
getStatus(Context * context,ContextVk * contextVk,bool * signaledOut)535 angle::Result SyncHelperNativeFence::getStatus(Context *context,
536                                                ContextVk *contextVk,
537                                                bool *signaledOut)
538 {
539     VkResult result = mExternalFence->getStatus(context->getDevice());
540     if (result != VK_NOT_READY)
541     {
542         ANGLE_VK_TRY(context, result);
543     }
544     *signaledOut = (result == VK_SUCCESS);
545     return angle::Result::Continue;
546 }
547 
dupNativeFenceFD(Context * context,int * fdOut) const548 angle::Result SyncHelperNativeFence::dupNativeFenceFD(Context *context, int *fdOut) const
549 {
550     if (mExternalFence->getFenceFd() == kInvalidFenceFd)
551     {
552         return angle::Result::Stop;
553     }
554 
555     *fdOut = dup(mExternalFence->getFenceFd());
556 
557     return angle::Result::Continue;
558 }
559 
560 }  // namespace vk
561 
SyncVk()562 SyncVk::SyncVk() : SyncImpl() {}
563 
~SyncVk()564 SyncVk::~SyncVk() {}
565 
onDestroy(const gl::Context * context)566 void SyncVk::onDestroy(const gl::Context *context)
567 {
568     mSyncHelper.releaseToRenderer(vk::GetImpl(context)->getRenderer());
569 }
570 
set(const gl::Context * context,GLenum condition,GLbitfield flags)571 angle::Result SyncVk::set(const gl::Context *context, GLenum condition, GLbitfield flags)
572 {
573     ASSERT(condition == GL_SYNC_GPU_COMMANDS_COMPLETE);
574     ASSERT(flags == 0);
575 
576     return mSyncHelper.initialize(vk::GetImpl(context), SyncFenceScope::CurrentContextToShareGroup);
577 }
578 
clientWait(const gl::Context * context,GLbitfield flags,GLuint64 timeout,GLenum * outResult)579 angle::Result SyncVk::clientWait(const gl::Context *context,
580                                  GLbitfield flags,
581                                  GLuint64 timeout,
582                                  GLenum *outResult)
583 {
584     ContextVk *contextVk = vk::GetImpl(context);
585 
586     ASSERT((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) == 0);
587 
588     bool flush = (flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0;
589 
590     return mSyncHelper.clientWait(contextVk, contextVk, flush, static_cast<uint64_t>(timeout),
591                                   MapVkResultToGlenum, outResult);
592 }
593 
serverWait(const gl::Context * context,GLbitfield flags,GLuint64 timeout)594 angle::Result SyncVk::serverWait(const gl::Context *context, GLbitfield flags, GLuint64 timeout)
595 {
596     ASSERT(flags == 0);
597     ASSERT(timeout == GL_TIMEOUT_IGNORED);
598 
599     ContextVk *contextVk = vk::GetImpl(context);
600     return mSyncHelper.serverWait(contextVk);
601 }
602 
getStatus(const gl::Context * context,GLint * outResult)603 angle::Result SyncVk::getStatus(const gl::Context *context, GLint *outResult)
604 {
605     ContextVk *contextVk = vk::GetImpl(context);
606     bool signaled        = false;
607     ANGLE_TRY(mSyncHelper.getStatus(contextVk, contextVk, &signaled));
608 
609     *outResult = signaled ? GL_SIGNALED : GL_UNSIGNALED;
610     return angle::Result::Continue;
611 }
612 
EGLSyncVk()613 EGLSyncVk::EGLSyncVk() : EGLSyncImpl(), mSyncHelper(nullptr) {}
614 
~EGLSyncVk()615 EGLSyncVk::~EGLSyncVk() {}
616 
onDestroy(const egl::Display * display)617 void EGLSyncVk::onDestroy(const egl::Display *display)
618 {
619     mSyncHelper->releaseToRenderer(vk::GetImpl(display)->getRenderer());
620 }
621 
initialize(const egl::Display * display,const gl::Context * context,EGLenum type,const egl::AttributeMap & attribs)622 egl::Error EGLSyncVk::initialize(const egl::Display *display,
623                                  const gl::Context *context,
624                                  EGLenum type,
625                                  const egl::AttributeMap &attribs)
626 {
627     ASSERT(context != nullptr);
628 
629     switch (type)
630     {
631         case EGL_SYNC_FENCE_KHR:
632         case EGL_SYNC_GLOBAL_FENCE_ANGLE:
633         {
634             vk::SyncHelper *syncHelper = new vk::SyncHelper();
635             mSyncHelper.reset(syncHelper);
636             const SyncFenceScope scope = type == EGL_SYNC_GLOBAL_FENCE_ANGLE
637                                              ? SyncFenceScope::AllContextsToAllContexts
638                                              : SyncFenceScope::CurrentContextToAllContexts;
639             if (syncHelper->initialize(vk::GetImpl(context), scope) == angle::Result::Stop)
640             {
641                 return egl::Error(EGL_BAD_ALLOC, "eglCreateSyncKHR failed to create sync object");
642             }
643             return egl::NoError();
644         }
645         case EGL_SYNC_NATIVE_FENCE_ANDROID:
646         {
647             vk::SyncHelperNativeFence *syncHelper = new vk::SyncHelperNativeFence();
648             mSyncHelper.reset(syncHelper);
649             EGLint nativeFenceFd =
650                 attribs.getAsInt(EGL_SYNC_NATIVE_FENCE_FD_ANDROID, EGL_NO_NATIVE_FENCE_FD_ANDROID);
651             return angle::ToEGL(syncHelper->initializeWithFd(vk::GetImpl(context), nativeFenceFd),
652                                 EGL_BAD_ALLOC);
653         }
654         default:
655             UNREACHABLE();
656             return egl::Error(EGL_BAD_ALLOC);
657     }
658 }
659 
clientWait(const egl::Display * display,const gl::Context * context,EGLint flags,EGLTime timeout,EGLint * outResult)660 egl::Error EGLSyncVk::clientWait(const egl::Display *display,
661                                  const gl::Context *context,
662                                  EGLint flags,
663                                  EGLTime timeout,
664                                  EGLint *outResult)
665 {
666     ASSERT((flags & ~EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) == 0);
667 
668     bool flush = (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) != 0;
669 
670     ContextVk *contextVk = context ? vk::GetImpl(context) : nullptr;
671     if (mSyncHelper->clientWait(vk::GetImpl(display), contextVk, flush,
672                                 static_cast<uint64_t>(timeout), MapVkResultToEglint,
673                                 outResult) == angle::Result::Stop)
674     {
675         return egl::Error(EGL_BAD_ALLOC);
676     }
677 
678     return egl::NoError();
679 }
680 
serverWait(const egl::Display * display,const gl::Context * context,EGLint flags)681 egl::Error EGLSyncVk::serverWait(const egl::Display *display,
682                                  const gl::Context *context,
683                                  EGLint flags)
684 {
685     // Server wait requires a valid bound context.
686     ASSERT(context);
687 
688     // No flags are currently implemented.
689     ASSERT(flags == 0);
690 
691     ContextVk *contextVk = vk::GetImpl(context);
692     return angle::ToEGL(mSyncHelper->serverWait(contextVk), EGL_BAD_ALLOC);
693 }
694 
getStatus(const egl::Display * display,EGLint * outStatus)695 egl::Error EGLSyncVk::getStatus(const egl::Display *display, EGLint *outStatus)
696 {
697     bool signaled = false;
698     if (mSyncHelper->getStatus(vk::GetImpl(display), nullptr, &signaled) == angle::Result::Stop)
699     {
700         return egl::Error(EGL_BAD_ALLOC);
701     }
702 
703     *outStatus = signaled ? EGL_SIGNALED_KHR : EGL_UNSIGNALED_KHR;
704     return egl::NoError();
705 }
706 
dupNativeFenceFD(const egl::Display * display,EGLint * fdOut) const707 egl::Error EGLSyncVk::dupNativeFenceFD(const egl::Display *display, EGLint *fdOut) const
708 {
709     return angle::ToEGL(mSyncHelper->dupNativeFenceFD(vk::GetImpl(display), fdOut),
710                         EGL_BAD_PARAMETER);
711 }
712 
713 }  // namespace rx
714