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 <private/EGL/display.h>
25 
26 #include "egl_cache.h"
27 #include "egl_object.h"
28 #include "egl_tls.h"
29 #include "egl_trace.h"
30 #include "Loader.h"
31 #include <cutils/properties.h>
32 
33 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
34 #include <configstore/Utils.h>
35 
36 using namespace android::hardware::configstore;
37 using namespace android::hardware::configstore::V1_0;
38 
39 // ----------------------------------------------------------------------------
40 namespace android {
41 // ----------------------------------------------------------------------------
42 
43 static char const * const sVendorString     = "Android";
44 static char const * const sVersionString    = "1.4 Android META-EGL";
45 static char const * const sClientApiString  = "OpenGL_ES";
46 
47 extern char const * const gBuiltinExtensionString;
48 extern char const * const gExtensionString;
49 
50 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
51 
52 // ----------------------------------------------------------------------------
53 
findExtension(const char * exts,const char * name,size_t nameLen)54 bool findExtension(const char* exts, const char* name, size_t nameLen) {
55     if (exts) {
56         if (!nameLen) {
57             nameLen = strlen(name);
58         }
59         for (const char* match = strstr(exts, name); match; match = strstr(match + nameLen, name)) {
60             if (match[nameLen] == '\0' || match[nameLen] == ' ') {
61                 return true;
62             }
63         }
64     }
65     return false;
66 }
67 
egl_get_init_count(EGLDisplay dpy)68 int egl_get_init_count(EGLDisplay dpy) {
69     egl_display_t* eglDisplay = egl_display_t::get(dpy);
70     return eglDisplay ? eglDisplay->getRefsCount() : 0;
71 }
72 
73 egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
74 
egl_display_t()75 egl_display_t::egl_display_t() :
76     magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0), eglIsInitialized(false) {
77 }
78 
~egl_display_t()79 egl_display_t::~egl_display_t() {
80     magic = 0;
81     egl_cache_t::get()->terminate();
82 }
83 
get(EGLDisplay dpy)84 egl_display_t* egl_display_t::get(EGLDisplay dpy) {
85     if (uintptr_t(dpy) == 0) {
86         return nullptr;
87     }
88 
89     uintptr_t index = uintptr_t(dpy)-1U;
90     if (index >= NUM_DISPLAYS || !sDisplay[index].isValid()) {
91         return nullptr;
92     }
93     return &sDisplay[index];
94 }
95 
addObject(egl_object_t * object)96 void egl_display_t::addObject(egl_object_t* object) {
97     std::lock_guard<std::mutex> _l(lock);
98     objects.insert(object);
99 }
100 
removeObject(egl_object_t * object)101 void egl_display_t::removeObject(egl_object_t* object) {
102     std::lock_guard<std::mutex> _l(lock);
103     objects.erase(object);
104 }
105 
getObject(egl_object_t * object) const106 bool egl_display_t::getObject(egl_object_t* object) const {
107     std::lock_guard<std::mutex> _l(lock);
108     if (objects.find(object) != objects.end()) {
109         if (object->getDisplay() == this) {
110             object->incRef();
111             return true;
112         }
113     }
114     return false;
115 }
116 
getFromNativeDisplay(EGLNativeDisplayType disp)117 EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
118     if (uintptr_t(disp) >= NUM_DISPLAYS)
119         return NULL;
120 
121     return sDisplay[uintptr_t(disp)].getDisplay(disp);
122 }
123 
getDisplay(EGLNativeDisplayType display)124 EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
125 
126     std::lock_guard<std::mutex> _l(lock);
127     ATRACE_CALL();
128 
129     // get our driver loader
130     Loader& loader(Loader::getInstance());
131 
132     egl_connection_t* const cnx = &gEGLImpl;
133     if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) {
134         EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
135         disp.dpy = dpy;
136         if (dpy == EGL_NO_DISPLAY) {
137             loader.close(cnx->dso);
138             cnx->dso = NULL;
139         }
140     }
141 
142     return EGLDisplay(uintptr_t(display) + 1U);
143 }
144 
initialize(EGLint * major,EGLint * minor)145 EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
146 
147     { // scope for refLock
148         std::unique_lock<std::mutex> _l(refLock);
149         refs++;
150         if (refs > 1) {
151             if (major != NULL)
152                 *major = VERSION_MAJOR;
153             if (minor != NULL)
154                 *minor = VERSION_MINOR;
155             while(!eglIsInitialized) {
156                 refCond.wait(_l);
157             }
158             return EGL_TRUE;
159         }
160         while(eglIsInitialized) {
161             refCond.wait(_l);
162         }
163     }
164 
165     { // scope for lock
166         std::lock_guard<std::mutex> _l(lock);
167 
168         setGLHooksThreadSpecific(&gHooksNoContext);
169 
170         // initialize each EGL and
171         // build our own extension string first, based on the extension we know
172         // and the extension supported by our client implementation
173 
174         egl_connection_t* const cnx = &gEGLImpl;
175         cnx->major = -1;
176         cnx->minor = -1;
177         if (cnx->dso) {
178             EGLDisplay idpy = disp.dpy;
179             if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
180                 //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p",
181                 //        idpy, cnx->major, cnx->minor, cnx);
182 
183                 // display is now initialized
184                 disp.state = egl_display_t::INITIALIZED;
185 
186                 // get the query-strings for this display for each implementation
187                 disp.queryString.vendor = cnx->egl.eglQueryString(idpy,
188                         EGL_VENDOR);
189                 disp.queryString.version = cnx->egl.eglQueryString(idpy,
190                         EGL_VERSION);
191                 disp.queryString.extensions = cnx->egl.eglQueryString(idpy,
192                         EGL_EXTENSIONS);
193                 disp.queryString.clientApi = cnx->egl.eglQueryString(idpy,
194                         EGL_CLIENT_APIS);
195 
196             } else {
197                 ALOGW("eglInitialize(%p) failed (%s)", idpy,
198                         egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
199             }
200         }
201 
202         // the query strings are per-display
203         mVendorString = sVendorString;
204         mVersionString = sVersionString;
205         mClientApiString = sClientApiString;
206 
207         mExtensionString = gBuiltinExtensionString;
208 
209         hasColorSpaceSupport = findExtension(disp.queryString.extensions, "EGL_KHR_gl_colorspace");
210 
211         // Note: CDD requires that devices supporting wide color and/or HDR color also support
212         // the EGL_KHR_gl_colorspace extension.
213         bool wideColorBoardConfig =
214                 getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(
215                         false);
216 
217         // Add wide-color extensions if device can support wide-color
218         if (wideColorBoardConfig && hasColorSpaceSupport) {
219             mExtensionString.append(
220                     "EGL_EXT_gl_colorspace_scrgb EGL_EXT_gl_colorspace_scrgb_linear "
221                     "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 ");
222         }
223 
224         bool hasHdrBoardConfig =
225                 getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
226 
227         if (hasHdrBoardConfig && hasColorSpaceSupport) {
228             // hasHDRBoardConfig indicates the system is capable of supporting HDR content.
229             // Typically that means there is an HDR capable display attached, but could be
230             // support for attaching an HDR display. In either case, advertise support for
231             // HDR color spaces.
232             mExtensionString.append(
233                     "EGL_EXT_gl_colorspace_bt2020_linear EGL_EXT_gl_colorspace_bt2020_pq ");
234         }
235 
236         char const* start = gExtensionString;
237         do {
238             // length of the extension name
239             size_t len = strcspn(start, " ");
240             if (len) {
241                 // NOTE: we could avoid the copy if we had strnstr.
242                 const std::string ext(start, len);
243                 // Temporary hack: Adreno 530 driver exposes this extension under the draft
244                 // KHR name, but during Khronos review it was decided to demote it to EXT.
245                 if (ext == "EGL_EXT_image_gl_colorspace" &&
246                     findExtension(disp.queryString.extensions, "EGL_KHR_image_gl_colorspace")) {
247                     mExtensionString.append("EGL_EXT_image_gl_colorspace ");
248                 }
249                 if (findExtension(disp.queryString.extensions, ext.c_str(), len)) {
250                     mExtensionString.append(ext + " ");
251                 }
252                 // advance to the next extension name, skipping the space.
253                 start += len;
254                 start += (*start == ' ') ? 1 : 0;
255             }
256         } while (*start != '\0');
257 
258         egl_cache_t::get()->initialize(this);
259 
260         char value[PROPERTY_VALUE_MAX];
261         property_get("debug.egl.finish", value, "0");
262         if (atoi(value)) {
263             finishOnSwap = true;
264         }
265 
266         property_get("debug.egl.traceGpuCompletion", value, "0");
267         if (atoi(value)) {
268             traceGpuCompletion = true;
269         }
270 
271         if (major != NULL)
272             *major = VERSION_MAJOR;
273         if (minor != NULL)
274             *minor = VERSION_MINOR;
275     }
276 
277     { // scope for refLock
278         std::unique_lock<std::mutex> _l(refLock);
279         eglIsInitialized = true;
280         refCond.notify_all();
281     }
282 
283     return EGL_TRUE;
284 }
285 
terminate()286 EGLBoolean egl_display_t::terminate() {
287 
288     { // scope for refLock
289         std::unique_lock<std::mutex> _rl(refLock);
290         if (refs == 0) {
291             /*
292              * From the EGL spec (3.2):
293              * "Termination of a display that has already been terminated,
294              *  (...), is allowed, but the only effect of such a call is
295              *  to return EGL_TRUE (...)
296              */
297             return EGL_TRUE;
298         }
299 
300         // this is specific to Android, display termination is ref-counted.
301         refs--;
302         if (refs > 0) {
303             return EGL_TRUE;
304         }
305     }
306 
307     EGLBoolean res = EGL_FALSE;
308 
309     { // scope for lock
310         std::lock_guard<std::mutex> _l(lock);
311 
312         egl_connection_t* const cnx = &gEGLImpl;
313         if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
314             if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
315                 ALOGW("eglTerminate(%p) failed (%s)", disp.dpy,
316                         egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
317             }
318             // REVISIT: it's unclear what to do if eglTerminate() fails
319             disp.state = egl_display_t::TERMINATED;
320             res = EGL_TRUE;
321         }
322 
323         // Reset the extension string since it will be regenerated if we get
324         // reinitialized.
325         mExtensionString.clear();
326 
327         // Mark all objects remaining in the list as terminated, unless
328         // there are no reference to them, it which case, we're free to
329         // delete them.
330         size_t count = objects.size();
331         ALOGW_IF(count, "eglTerminate() called w/ %zu objects remaining", count);
332         for (auto o : objects) {
333             o->destroy();
334         }
335 
336         // this marks all object handles are "terminated"
337         objects.clear();
338     }
339 
340     { // scope for refLock
341         std::unique_lock<std::mutex> _rl(refLock);
342         eglIsInitialized = false;
343         refCond.notify_all();
344     }
345 
346     return res;
347 }
348 
loseCurrent(egl_context_t * cur_c)349 void egl_display_t::loseCurrent(egl_context_t * cur_c)
350 {
351     if (cur_c) {
352         egl_display_t* display = cur_c->getDisplay();
353         if (display) {
354             display->loseCurrentImpl(cur_c);
355         }
356     }
357 }
358 
loseCurrentImpl(egl_context_t * cur_c)359 void egl_display_t::loseCurrentImpl(egl_context_t * cur_c)
360 {
361     // by construction, these are either 0 or valid (possibly terminated)
362     // it should be impossible for these to be invalid
363     ContextRef _cur_c(cur_c);
364     SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
365     SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
366 
367     { // scope for the lock
368         std::lock_guard<std::mutex> _l(lock);
369         cur_c->onLooseCurrent();
370 
371     }
372 
373     // This cannot be called with the lock held because it might end-up
374     // calling back into EGL (in particular when a surface is destroyed
375     // it calls ANativeWindow::disconnect
376     _cur_c.release();
377     _cur_r.release();
378     _cur_d.release();
379 }
380 
makeCurrent(egl_context_t * c,egl_context_t * cur_c,EGLSurface draw,EGLSurface read,EGLContext,EGLSurface impl_draw,EGLSurface impl_read,EGLContext impl_ctx)381 EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
382         EGLSurface draw, EGLSurface read, EGLContext /*ctx*/,
383         EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx)
384 {
385     EGLBoolean result;
386 
387     // by construction, these are either 0 or valid (possibly terminated)
388     // it should be impossible for these to be invalid
389     ContextRef _cur_c(cur_c);
390     SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
391     SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
392 
393     { // scope for the lock
394         std::lock_guard<std::mutex> _l(lock);
395         if (c) {
396             result = c->cnx->egl.eglMakeCurrent(
397                     disp.dpy, impl_draw, impl_read, impl_ctx);
398             if (result == EGL_TRUE) {
399                 c->onMakeCurrent(draw, read);
400             }
401         } else {
402             result = cur_c->cnx->egl.eglMakeCurrent(
403                     disp.dpy, impl_draw, impl_read, impl_ctx);
404             if (result == EGL_TRUE) {
405                 cur_c->onLooseCurrent();
406             }
407         }
408     }
409 
410     if (result == EGL_TRUE) {
411         // This cannot be called with the lock held because it might end-up
412         // calling back into EGL (in particular when a surface is destroyed
413         // it calls ANativeWindow::disconnect
414         _cur_c.release();
415         _cur_r.release();
416         _cur_d.release();
417     }
418 
419     return result;
420 }
421 
haveExtension(const char * name,size_t nameLen) const422 bool egl_display_t::haveExtension(const char* name, size_t nameLen) const {
423     if (!nameLen) {
424         nameLen = strlen(name);
425     }
426     return findExtension(mExtensionString.c_str(), name, nameLen);
427 }
428 
429 // ----------------------------------------------------------------------------
430 }; // namespace android
431 // ----------------------------------------------------------------------------
432