• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
findExtension(const char * exts,const char * name,size_t nameLen)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 
needsAndroidPEglMitigation()74 bool needsAndroidPEglMitigation() {
75     static const int32_t vndk_version = property_get_int32("ro.vndk.version", -1);
76     return vndk_version <= 28;
77 }
78 
egl_get_init_count(EGLDisplay dpy)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 
egl_display_t()86 egl_display_t::egl_display_t() :
87     magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0), eglIsInitialized(false) {
88 }
89 
~egl_display_t()90 egl_display_t::~egl_display_t() {
91     magic = 0;
92     egl_cache_t::get()->terminate();
93 }
94 
get(EGLDisplay dpy)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 
addObject(egl_object_t * object)107 void egl_display_t::addObject(egl_object_t* object) {
108     std::lock_guard<std::mutex> _l(lock);
109     objects.insert(object);
110 }
111 
removeObject(egl_object_t * object)112 void egl_display_t::removeObject(egl_object_t* object) {
113     std::lock_guard<std::mutex> _l(lock);
114     objects.erase(object);
115 }
116 
getObject(egl_object_t * object) const117 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 
getFromNativeDisplay(EGLNativeDisplayType disp,const EGLAttrib * attrib_list)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 
addAnglePlatformAttributes(egl_connection_t * const cnx,std::vector<EGLAttrib> & attrs)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 
getPlatformDisplayAngle(EGLNativeDisplayType display,egl_connection_t * const cnx,const EGLAttrib * attrib_list,EGLint * error)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 
getPlatformDisplay(EGLNativeDisplayType display,const EGLAttrib * attrib_list)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 
initialize(EGLint * major,EGLint * minor)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 
terminate()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 
loseCurrent(egl_context_t * cur_c)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 
loseCurrentImpl(egl_context_t * cur_c)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 
makeCurrent(egl_context_t * c,egl_context_t * cur_c,EGLSurface draw,EGLSurface read,EGLContext,EGLSurface impl_draw,EGLSurface impl_read,EGLContext impl_ctx)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 
haveExtension(const char * name,size_t nameLen) const578 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