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