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