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