OSDN Git Service

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