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