// // Copyright 2019 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // SyncEGL.cpp: Implements the rx::SyncEGL class. #include "libANGLE/renderer/gl/egl/SyncEGL.h" #include "libANGLE/AttributeMap.h" #include "libANGLE/Display.h" #include "libANGLE/renderer/gl/egl/FunctionsEGL.h" namespace rx { SyncEGL::SyncEGL(const FunctionsEGL *egl) : mEGL(egl), mSync(EGL_NO_SYNC_KHR) {} SyncEGL::~SyncEGL() { ASSERT(mSync == EGL_NO_SYNC_KHR); } void SyncEGL::onDestroy(const egl::Display *display) { if (mSync != EGL_NO_SYNC_KHR) { egl::Display::GetCurrentThreadUnlockedTailCall()->add( [egl = mEGL, sync = mSync](void *resultOut) { EGLBoolean result = egl->destroySyncKHR(sync); if (resultOut) { // It's possible for resultOut to be null if this sync is being destructed as // part of display destruction. *static_cast(resultOut) = result; } }); mSync = EGL_NO_SYNC_KHR; } } egl::Error SyncEGL::initialize(const egl::Display *display, const gl::Context *context, EGLenum type, const egl::AttributeMap &attribs) { ASSERT(type == EGL_SYNC_FENCE_KHR || type == EGL_SYNC_NATIVE_FENCE_ANDROID); constexpr size_t kAttribVectorSize = 3; angle::FixedVector nativeAttribs; if (type == EGL_SYNC_NATIVE_FENCE_ANDROID) { EGLint fenceFd = attribs.getAsInt(EGL_SYNC_NATIVE_FENCE_FD_ANDROID, EGL_NO_NATIVE_FENCE_FD_ANDROID); nativeAttribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID); nativeAttribs.push_back(fenceFd); } nativeAttribs.push_back(EGL_NONE); egl::Display::GetCurrentThreadUnlockedTailCall()->add( [egl = mEGL, &sync = mSync, type, attribs = nativeAttribs](void *resultOut) { sync = egl->createSyncKHR(type, attribs.data()); // If sync creation failed, force the return value of eglCreateSync to EGL_NO_SYNC. This // won't delete this sync object but a driver error is unexpected at this point. if (sync == EGL_NO_SYNC_KHR) { ERR() << "eglCreateSync failed with " << gl::FmtHex(egl->getError()); *static_cast(resultOut) = EGL_NO_SYNC_KHR; } }); return egl::NoError(); } egl::Error SyncEGL::clientWait(const egl::Display *display, const gl::Context *context, EGLint flags, EGLTime timeout, EGLint *outResult) { ASSERT(mSync != EGL_NO_SYNC_KHR); // If we need to perform a CPU wait don't set the resultOut parameter passed into the // method, instead set the parameter passed into the unlocked tail call. egl::Display::GetCurrentThreadUnlockedTailCall()->add( [egl = mEGL, sync = mSync, flags, timeout](void *resultOut) { *static_cast(resultOut) = egl->clientWaitSyncKHR(sync, flags, timeout); }); return egl::NoError(); } egl::Error SyncEGL::serverWait(const egl::Display *display, const gl::Context *context, EGLint flags) { ASSERT(mSync != EGL_NO_SYNC_KHR); egl::Display::GetCurrentThreadUnlockedTailCall()->add( [egl = mEGL, sync = mSync, flags](void *resultOut) { *static_cast(resultOut) = egl->waitSyncKHR(sync, flags); }); return egl::NoError(); } egl::Error SyncEGL::getStatus(const egl::Display *display, EGLint *outStatus) { ASSERT(mSync != EGL_NO_SYNC_KHR); EGLBoolean result = mEGL->getSyncAttribKHR(mSync, EGL_SYNC_STATUS_KHR, outStatus); if (result == EGL_FALSE) { return egl::Error(mEGL->getError(), "eglGetSyncAttribKHR with EGL_SYNC_STATUS_KHR failed"); } return egl::NoError(); } egl::Error SyncEGL::dupNativeFenceFD(const egl::Display *display, EGLint *result) const { ASSERT(mSync != EGL_NO_SYNC_KHR); *result = mEGL->dupNativeFenceFDANDROID(mSync); if (*result == EGL_NO_NATIVE_FENCE_FD_ANDROID) { return egl::Error(mEGL->getError(), "eglDupNativeFenceFDANDROID failed"); } return egl::NoError(); } } // namespace rx