Home | History | Annotate | Download | only in EGL
      1 /*
      2  ** Copyright 2007, The Android Open Source Project
      3  **
      4  ** Licensed under the Apache License, Version 2.0 (the "License");
      5  ** you may not use this file except in compliance with the License.
      6  ** You may obtain a copy of the License at
      7  **
      8  **     http://www.apache.org/licenses/LICENSE-2.0
      9  **
     10  ** Unless required by applicable law or agreed to in writing, software
     11  ** distributed under the License is distributed on an "AS IS" BASIS,
     12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  ** See the License for the specific language governing permissions and
     14  ** limitations under the License.
     15  */
     16 
     17 #define __STDC_LIMIT_MACROS 1
     18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
     19 
     20 #include "egl_display.h"
     21 
     22 #include "../egl_impl.h"
     23 
     24 #include <EGL/eglext_angle.h>
     25 #include <private/EGL/display.h>
     26 
     27 #include <cutils/properties.h>
     28 #include "Loader.h"
     29 #include "egl_angle_platform.h"
     30 #include "egl_cache.h"
     31 #include "egl_object.h"
     32 #include "egl_tls.h"
     33 
     34 #include <android/dlext.h>
     35 #include <dlfcn.h>
     36 #include <graphicsenv/GraphicsEnv.h>
     37 
     38 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
     39 #include <configstore/Utils.h>
     40 
     41 using namespace android::hardware::configstore;
     42 using namespace android::hardware::configstore::V1_0;
     43 
     44 // ----------------------------------------------------------------------------
     45 namespace android {
     46 // ----------------------------------------------------------------------------
     47 
     48 static char const * const sVendorString     = "Android";
     49 static char const* const sVersionString14 = "1.4 Android META-EGL";
     50 static char const* const sVersionString15 = "1.5 Android META-EGL";
     51 static char const * const sClientApiString  = "OpenGL_ES";
     52 
     53 extern char const * const gBuiltinExtensionString;
     54 extern char const * const gExtensionString;
     55 
     56 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
     57 
     58 // ----------------------------------------------------------------------------
     59 
     60 bool findExtension(const char* exts, const char* name, size_t nameLen) {
     61     if (exts) {
     62         if (!nameLen) {
     63             nameLen = strlen(name);
     64         }
     65         for (const char* match = strstr(exts, name); match; match = strstr(match + nameLen, name)) {
     66             if (match[nameLen] == '\0' || match[nameLen] == ' ') {
     67                 return true;
     68             }
     69         }
     70     }
     71     return false;
     72 }
     73 
     74 bool needsAndroidPEglMitigation() {
     75     static const int32_t vndk_version = property_get_int32("ro.vndk.version", -1);
     76     return vndk_version <= 28;
     77 }
     78 
     79 int egl_get_init_count(EGLDisplay dpy) {
     80     egl_display_t* eglDisplay = egl_display_t::get(dpy);
     81     return eglDisplay ? eglDisplay->getRefsCount() : 0;
     82 }
     83 
     84 egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
     85 
     86 egl_display_t::egl_display_t() :
     87     magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0), eglIsInitialized(false) {
     88 }
     89 
     90 egl_display_t::~egl_display_t() {
     91     magic = 0;
     92     egl_cache_t::get()->terminate();
     93 }
     94 
     95 egl_display_t* egl_display_t::get(EGLDisplay dpy) {
     96     if (uintptr_t(dpy) == 0) {
     97         return nullptr;
     98     }
     99 
    100     uintptr_t index = uintptr_t(dpy)-1U;
    101     if (index >= NUM_DISPLAYS || !sDisplay[index].isValid()) {
    102         return nullptr;
    103     }
    104     return &sDisplay[index];
    105 }
    106 
    107 void egl_display_t::addObject(egl_object_t* object) {
    108     std::lock_guard<std::mutex> _l(lock);
    109     objects.insert(object);
    110 }
    111 
    112 void egl_display_t::removeObject(egl_object_t* object) {
    113     std::lock_guard<std::mutex> _l(lock);
    114     objects.erase(object);
    115 }
    116 
    117 bool egl_display_t::getObject(egl_object_t* object) const {
    118     std::lock_guard<std::mutex> _l(lock);
    119     if (objects.find(object) != objects.end()) {
    120         if (object->getDisplay() == this) {
    121             object->incRef();
    122             return true;
    123         }
    124     }
    125     return false;
    126 }
    127 
    128 EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp,
    129                                                const EGLAttrib* attrib_list) {
    130     if (uintptr_t(disp) >= NUM_DISPLAYS)
    131         return nullptr;
    132 
    133     return sDisplay[uintptr_t(disp)].getPlatformDisplay(disp, attrib_list);
    134 }
    135 
    136 static bool addAnglePlatformAttributes(egl_connection_t* const cnx,
    137                                        std::vector<EGLAttrib>& attrs) {
    138     intptr_t vendorEGL = (intptr_t)cnx->vendorEGL;
    139 
    140     attrs.reserve(4 * 2);
    141 
    142     attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
    143     attrs.push_back(cnx->angleBackend);
    144 
    145     switch (cnx->angleBackend) {
    146         case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
    147             ALOGV("%s: Requesting Vulkan ANGLE back-end", __FUNCTION__);
    148             char prop[PROPERTY_VALUE_MAX];
    149             property_get("debug.angle.validation", prop, "0");
    150             attrs.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
    151             attrs.push_back(atoi(prop));
    152             break;
    153         case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
    154             ALOGV("%s: Requesting Default ANGLE back-end", __FUNCTION__);
    155             break;
    156         case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
    157             ALOGV("%s: Requesting OpenGL ES ANGLE back-end", __FUNCTION__);
    158             // NOTE: This is only valid if the backend is OpenGL
    159             attrs.push_back(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE);
    160             attrs.push_back(vendorEGL);
    161             break;
    162         default:
    163             ALOGV("%s: Requesting Unknown (%d) ANGLE back-end", __FUNCTION__, cnx->angleBackend);
    164             break;
    165     }
    166     attrs.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
    167     attrs.push_back(EGL_FALSE);
    168 
    169     return true;
    170 }
    171 
    172 static EGLDisplay getPlatformDisplayAngle(EGLNativeDisplayType display, egl_connection_t* const cnx,
    173                                           const EGLAttrib* attrib_list, EGLint* error) {
    174     EGLDisplay dpy = EGL_NO_DISPLAY;
    175     *error = EGL_NONE;
    176 
    177     if (cnx->egl.eglGetPlatformDisplay) {
    178         std::vector<EGLAttrib> attrs;
    179         if (attrib_list) {
    180             for (const EGLAttrib* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
    181                 attrs.push_back(attr[0]);
    182                 attrs.push_back(attr[1]);
    183             }
    184         }
    185 
    186         if (!addAnglePlatformAttributes(cnx, attrs)) {
    187             ALOGE("eglGetDisplay(%p) failed: Mismatch display request", display);
    188             *error = EGL_BAD_PARAMETER;
    189             return EGL_NO_DISPLAY;
    190         }
    191         attrs.push_back(EGL_NONE);
    192 
    193         dpy = cnx->egl.eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
    194                                              reinterpret_cast<void*>(EGL_DEFAULT_DISPLAY),
    195                                              attrs.data());
    196         if (dpy == EGL_NO_DISPLAY) {
    197             ALOGE("eglGetPlatformDisplay failed!");
    198         } else {
    199             if (!angle::initializeAnglePlatform(dpy)) {
    200                 ALOGE("initializeAnglePlatform failed!");
    201             }
    202         }
    203     } else {
    204         ALOGE("eglGetDisplay(%p) failed: Unable to look up eglGetPlatformDisplay from ANGLE",
    205               display);
    206     }
    207 
    208     return dpy;
    209 }
    210 
    211 EGLDisplay egl_display_t::getPlatformDisplay(EGLNativeDisplayType display,
    212                                              const EGLAttrib* attrib_list) {
    213     std::lock_guard<std::mutex> _l(lock);
    214     ATRACE_CALL();
    215 
    216     // get our driver loader
    217     Loader& loader(Loader::getInstance());
    218 
    219     egl_connection_t* const cnx = &gEGLImpl;
    220     if (cnx->dso) {
    221         EGLDisplay dpy = EGL_NO_DISPLAY;
    222 
    223         if (cnx->useAngle) {
    224             EGLint error;
    225             dpy = getPlatformDisplayAngle(display, cnx, attrib_list, &error);
    226             if (error != EGL_NONE) {
    227                 return setError(error, dpy);
    228             }
    229         }
    230         if (dpy == EGL_NO_DISPLAY) {
    231             // NOTE: eglGetPlatformDisplay with a empty attribute list
    232             // behaves the same as eglGetDisplay
    233             if (cnx->egl.eglGetPlatformDisplay) {
    234                 dpy = cnx->egl.eglGetPlatformDisplay(EGL_PLATFORM_ANDROID_KHR, display,
    235                                                      attrib_list);
    236             }
    237 
    238             // It is possible that eglGetPlatformDisplay does not have a
    239             // working implementation for Android platform; in that case,
    240             // one last fallback to eglGetDisplay
    241             if(dpy == EGL_NO_DISPLAY) {
    242                 if (attrib_list) {
    243                     ALOGW("getPlatformDisplay: unexpected attribute list, attributes ignored");
    244                 }
    245                 dpy = cnx->egl.eglGetDisplay(display);
    246             }
    247         }
    248 
    249         disp.dpy = dpy;
    250         if (dpy == EGL_NO_DISPLAY) {
    251             loader.close(cnx);
    252         }
    253     }
    254 
    255     return EGLDisplay(uintptr_t(display) + 1U);
    256 }
    257 
    258 EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
    259 
    260     { // scope for refLock
    261         std::unique_lock<std::mutex> _l(refLock);
    262         refs++;
    263         if (refs > 1) {
    264             // We don't know what to report until we know what the
    265             // driver supports. Make sure we are initialized before
    266             // returning the version info.
    267             while(!eglIsInitialized) {
    268                 refCond.wait(_l);
    269             }
    270             egl_connection_t* const cnx = &gEGLImpl;
    271 
    272             // TODO: If device doesn't provide 1.4 or 1.5 then we'll be
    273             // changing the behavior from the past where we always advertise
    274             // version 1.4. May need to check that revision is valid
    275             // before using cnx->major & cnx->minor
    276             if (major != nullptr) *major = cnx->major;
    277             if (minor != nullptr) *minor = cnx->minor;
    278             return EGL_TRUE;
    279         }
    280         while(eglIsInitialized) {
    281             refCond.wait(_l);
    282         }
    283     }
    284 
    285     { // scope for lock
    286         std::lock_guard<std::mutex> _l(lock);
    287 
    288         setGLHooksThreadSpecific(&gHooksNoContext);
    289 
    290         // initialize each EGL and
    291         // build our own extension string first, based on the extension we know
    292         // and the extension supported by our client implementation
    293 
    294         egl_connection_t* const cnx = &gEGLImpl;
    295         cnx->major = -1;
    296         cnx->minor = -1;
    297         if (cnx->dso) {
    298             EGLDisplay idpy = disp.dpy;
    299             if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
    300                 //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p",
    301                 //        idpy, cnx->major, cnx->minor, cnx);
    302 
    303                 // display is now initialized
    304                 disp.state = egl_display_t::INITIALIZED;
    305 
    306                 // get the query-strings for this display for each implementation
    307                 disp.queryString.vendor = cnx->egl.eglQueryString(idpy,
    308                         EGL_VENDOR);
    309                 disp.queryString.version = cnx->egl.eglQueryString(idpy,
    310                         EGL_VERSION);
    311                 disp.queryString.extensions = cnx->egl.eglQueryString(idpy,
    312                         EGL_EXTENSIONS);
    313                 disp.queryString.clientApi = cnx->egl.eglQueryString(idpy,
    314                         EGL_CLIENT_APIS);
    315 
    316             } else {
    317                 ALOGW("eglInitialize(%p) failed (%s)", idpy,
    318                         egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
    319             }
    320         }
    321 
    322         if (cnx->minor == 5) {
    323             // full list in egl_entries.in
    324             if (!cnx->egl.eglCreateImage ||
    325                 !cnx->egl.eglDestroyImage ||
    326                 !cnx->egl.eglGetPlatformDisplay ||
    327                 !cnx->egl.eglCreatePlatformWindowSurface ||
    328                 !cnx->egl.eglCreatePlatformPixmapSurface ||
    329                 !cnx->egl.eglCreateSync ||
    330                 !cnx->egl.eglDestroySync ||
    331                 !cnx->egl.eglClientWaitSync ||
    332                 !cnx->egl.eglGetSyncAttrib ||
    333                 !cnx->egl.eglWaitSync) {
    334                 ALOGE("Driver indicates EGL 1.5 support, but does not have "
    335                       "a critical API");
    336                 cnx->minor = 4;
    337             }
    338         }
    339 
    340         // the query strings are per-display
    341         mVendorString = sVendorString;
    342         mVersionString.clear();
    343         cnx->driverVersion = EGL_MAKE_VERSION(1, 4, 0);
    344         mVersionString = sVersionString14;
    345         if ((cnx->major == 1) && (cnx->minor == 5)) {
    346             mVersionString = sVersionString15;
    347             cnx->driverVersion = EGL_MAKE_VERSION(1, 5, 0);
    348         }
    349         if (mVersionString.empty()) {
    350             ALOGW("Unexpected driver version: %d.%d, want 1.4 or 1.5", cnx->major, cnx->minor);
    351             mVersionString = sVersionString14;
    352         }
    353         mClientApiString = sClientApiString;
    354 
    355         mExtensionString = gBuiltinExtensionString;
    356 
    357         hasColorSpaceSupport = findExtension(disp.queryString.extensions, "EGL_KHR_gl_colorspace");
    358 
    359         // Note: CDD requires that devices supporting wide color and/or HDR color also support
    360         // the EGL_KHR_gl_colorspace extension.
    361         bool wideColorBoardConfig =
    362                 getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(
    363                         false);
    364 
    365         // Add wide-color extensions if device can support wide-color
    366         if (wideColorBoardConfig && hasColorSpaceSupport) {
    367             mExtensionString.append(
    368                     "EGL_EXT_gl_colorspace_scrgb EGL_EXT_gl_colorspace_scrgb_linear "
    369                     "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 "
    370                     "EGL_EXT_gl_colorspace_display_p3_passthrough ");
    371         }
    372 
    373         bool hasHdrBoardConfig =
    374                 getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
    375 
    376         if (hasHdrBoardConfig && hasColorSpaceSupport) {
    377             // hasHDRBoardConfig indicates the system is capable of supporting HDR content.
    378             // Typically that means there is an HDR capable display attached, but could be
    379             // support for attaching an HDR display. In either case, advertise support for
    380             // HDR color spaces.
    381             mExtensionString.append(
    382                     "EGL_EXT_gl_colorspace_bt2020_linear EGL_EXT_gl_colorspace_bt2020_pq ");
    383         }
    384 
    385         char const* start = gExtensionString;
    386         do {
    387             // length of the extension name
    388             size_t len = strcspn(start, " ");
    389             if (len) {
    390                 // NOTE: we could avoid the copy if we had strnstr.
    391                 const std::string ext(start, len);
    392                 // Mitigation for Android P vendor partitions: Adreno 530 driver shipped on
    393                 // some Android P vendor partitions this extension under the draft KHR name,
    394                 // but during Khronos review it was decided to demote it to EXT.
    395                 if (needsAndroidPEglMitigation() && ext == "EGL_EXT_image_gl_colorspace" &&
    396                     findExtension(disp.queryString.extensions, "EGL_KHR_image_gl_colorspace")) {
    397                     mExtensionString.append("EGL_EXT_image_gl_colorspace ");
    398                 }
    399                 if (findExtension(disp.queryString.extensions, ext.c_str(), len)) {
    400                     mExtensionString.append(ext + " ");
    401                 }
    402                 // advance to the next extension name, skipping the space.
    403                 start += len;
    404                 start += (*start == ' ') ? 1 : 0;
    405             }
    406         } while (*start != '\0');
    407 
    408         egl_cache_t::get()->initialize(this);
    409 
    410         char value[PROPERTY_VALUE_MAX];
    411         property_get("debug.egl.finish", value, "0");
    412         if (atoi(value)) {
    413             finishOnSwap = true;
    414         }
    415 
    416         property_get("debug.egl.traceGpuCompletion", value, "0");
    417         if (atoi(value)) {
    418             traceGpuCompletion = true;
    419         }
    420 
    421         // TODO: If device doesn't provide 1.4 or 1.5 then we'll be
    422         // changing the behavior from the past where we always advertise
    423         // version 1.4. May need to check that revision is valid
    424         // before using cnx->major & cnx->minor
    425         if (major != nullptr) *major = cnx->major;
    426         if (minor != nullptr) *minor = cnx->minor;
    427     }
    428 
    429     { // scope for refLock
    430         std::unique_lock<std::mutex> _l(refLock);
    431         eglIsInitialized = true;
    432         refCond.notify_all();
    433     }
    434 
    435     return EGL_TRUE;
    436 }
    437 
    438 EGLBoolean egl_display_t::terminate() {
    439 
    440     { // scope for refLock
    441         std::unique_lock<std::mutex> _rl(refLock);
    442         if (refs == 0) {
    443             /*
    444              * From the EGL spec (3.2):
    445              * "Termination of a display that has already been terminated,
    446              *  (...), is allowed, but the only effect of such a call is
    447              *  to return EGL_TRUE (...)
    448              */
    449             return EGL_TRUE;
    450         }
    451 
    452         // this is specific to Android, display termination is ref-counted.
    453         refs--;
    454         if (refs > 0) {
    455             return EGL_TRUE;
    456         }
    457     }
    458 
    459     EGLBoolean res = EGL_FALSE;
    460 
    461     { // scope for lock
    462         std::lock_guard<std::mutex> _l(lock);
    463 
    464         egl_connection_t* const cnx = &gEGLImpl;
    465         if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
    466             // If we're using ANGLE reset any custom DisplayPlatform
    467             if (cnx->useAngle) {
    468                 angle::resetAnglePlatform(disp.dpy);
    469             }
    470             if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
    471                 ALOGW("eglTerminate(%p) failed (%s)", disp.dpy,
    472                         egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
    473             }
    474             // REVISIT: it's unclear what to do if eglTerminate() fails
    475             disp.state = egl_display_t::TERMINATED;
    476             res = EGL_TRUE;
    477         }
    478 
    479         // Reset the extension string since it will be regenerated if we get
    480         // reinitialized.
    481         mExtensionString.clear();
    482 
    483         // Mark all objects remaining in the list as terminated, unless
    484         // there are no reference to them, it which case, we're free to
    485         // delete them.
    486         size_t count = objects.size();
    487         ALOGW_IF(count, "eglTerminate() called w/ %zu objects remaining", count);
    488         for (auto o : objects) {
    489             o->destroy();
    490         }
    491 
    492         // this marks all object handles are "terminated"
    493         objects.clear();
    494     }
    495 
    496     { // scope for refLock
    497         std::unique_lock<std::mutex> _rl(refLock);
    498         eglIsInitialized = false;
    499         refCond.notify_all();
    500     }
    501 
    502     return res;
    503 }
    504 
    505 void egl_display_t::loseCurrent(egl_context_t * cur_c)
    506 {
    507     if (cur_c) {
    508         egl_display_t* display = cur_c->getDisplay();
    509         if (display) {
    510             display->loseCurrentImpl(cur_c);
    511         }
    512     }
    513 }
    514 
    515 void egl_display_t::loseCurrentImpl(egl_context_t * cur_c)
    516 {
    517     // by construction, these are either 0 or valid (possibly terminated)
    518     // it should be impossible for these to be invalid
    519     ContextRef _cur_c(cur_c);
    520     SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : nullptr);
    521     SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : nullptr);
    522 
    523     { // scope for the lock
    524         std::lock_guard<std::mutex> _l(lock);
    525         cur_c->onLooseCurrent();
    526 
    527     }
    528 
    529     // This cannot be called with the lock held because it might end-up
    530     // calling back into EGL (in particular when a surface is destroyed
    531     // it calls ANativeWindow::disconnect
    532     _cur_c.release();
    533     _cur_r.release();
    534     _cur_d.release();
    535 }
    536 
    537 EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
    538         EGLSurface draw, EGLSurface read, EGLContext /*ctx*/,
    539         EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx)
    540 {
    541     EGLBoolean result;
    542 
    543     // by construction, these are either 0 or valid (possibly terminated)
    544     // it should be impossible for these to be invalid
    545     ContextRef _cur_c(cur_c);
    546     SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : nullptr);
    547     SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : nullptr);
    548 
    549     { // scope for the lock
    550         std::lock_guard<std::mutex> _l(lock);
    551         if (c) {
    552             result = c->cnx->egl.eglMakeCurrent(
    553                     disp.dpy, impl_draw, impl_read, impl_ctx);
    554             if (result == EGL_TRUE) {
    555                 c->onMakeCurrent(draw, read);
    556             }
    557         } else {
    558             result = cur_c->cnx->egl.eglMakeCurrent(
    559                     disp.dpy, impl_draw, impl_read, impl_ctx);
    560             if (result == EGL_TRUE) {
    561                 cur_c->onLooseCurrent();
    562             }
    563         }
    564     }
    565 
    566     if (result == EGL_TRUE) {
    567         // This cannot be called with the lock held because it might end-up
    568         // calling back into EGL (in particular when a surface is destroyed
    569         // it calls ANativeWindow::disconnect
    570         _cur_c.release();
    571         _cur_r.release();
    572         _cur_d.release();
    573     }
    574 
    575     return result;
    576 }
    577 
    578 bool egl_display_t::haveExtension(const char* name, size_t nameLen) const {
    579     if (!nameLen) {
    580         nameLen = strlen(name);
    581     }
    582     return findExtension(mExtensionString.c_str(), name, nameLen);
    583 }
    584 
    585 // ----------------------------------------------------------------------------
    586 }; // namespace android
    587 // ----------------------------------------------------------------------------
    588