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