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