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