OSDN Git Service

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