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