blob: 6b6f8cf410fcf8451051bb81fd25c206d4476873 [file] [log] [blame]
Mathias Agopian518ec112011-05-13 16:21:08 -07001/*
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
Mathias Agopian4b9511c2011-11-13 23:52:47 -080017#include <string.h>
18
Jamie Gennisaca51c02011-11-03 17:42:43 -070019#include "egl_cache.h"
Mathias Agopian518ec112011-05-13 16:21:08 -070020#include "egl_display.h"
21#include "egl_object.h"
22#include "egl_tls.h"
23#include "egl_impl.h"
24#include "Loader.h"
Mathias Agopian7db993a2012-03-25 00:49:46 -070025#include <cutils/properties.h>
Mathias Agopian518ec112011-05-13 16:21:08 -070026
27// ----------------------------------------------------------------------------
28namespace android {
29// ----------------------------------------------------------------------------
30
Mathias Agopian4b9511c2011-11-13 23:52:47 -080031static char const * const sVendorString = "Android";
32static char const * const sVersionString = "1.4 Android META-EGL";
33static char const * const sClientApiString = "OpenGL ES";
34
35// this is the list of EGL extensions that are exposed to applications
36// some of them are mandatory because used by the ANDROID system.
37//
38// mandatory extensions are required per the CDD and not explicitly
39// checked during EGL initialization. the system *assumes* these extensions
40// are present. the system may not function properly if some mandatory
41// extensions are missing.
42//
43// NOTE: sExtensionString MUST be have a single space as the last character.
44//
45static char const * const sExtensionString =
46 "EGL_KHR_image " // mandatory
47 "EGL_KHR_image_base " // mandatory
48 "EGL_KHR_image_pixmap "
49 "EGL_KHR_gl_texture_2D_image "
50 "EGL_KHR_gl_texture_cubemap_image "
51 "EGL_KHR_gl_renderbuffer_image "
52 "EGL_KHR_fence_sync "
53 "EGL_NV_system_time "
54 "EGL_ANDROID_image_native_buffer " // mandatory
55 ;
56
57// extensions not exposed to applications but used by the ANDROID system
58// "EGL_ANDROID_recordable " // mandatory
59// "EGL_ANDROID_blob_cache " // strongly recommended
60
Mathias Agopian518ec112011-05-13 16:21:08 -070061extern void initEglTraceLevel();
Siva Velusamyb13c78f2012-03-09 14:51:28 -080062extern void initEglDebugLevel();
Mathias Agopian518ec112011-05-13 16:21:08 -070063extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
64
Mathias Agopian518ec112011-05-13 16:21:08 -070065// ----------------------------------------------------------------------------
66
67egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
68
69egl_display_t::egl_display_t() :
Jamie Gennis28ef8d72012-04-05 20:34:54 -070070 magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0) {
Mathias Agopian518ec112011-05-13 16:21:08 -070071}
72
73egl_display_t::~egl_display_t() {
74 magic = 0;
Jamie Gennis76601082011-11-06 14:14:33 -080075 egl_cache_t::get()->terminate();
Mathias Agopian518ec112011-05-13 16:21:08 -070076}
77
78egl_display_t* egl_display_t::get(EGLDisplay dpy) {
79 uintptr_t index = uintptr_t(dpy)-1U;
80 return (index >= NUM_DISPLAYS) ? NULL : &sDisplay[index];
81}
82
83void egl_display_t::addObject(egl_object_t* object) {
84 Mutex::Autolock _l(lock);
85 objects.add(object);
86}
87
Mathias Agopian5b287a62011-05-16 18:58:55 -070088void egl_display_t::removeObject(egl_object_t* object) {
89 Mutex::Autolock _l(lock);
90 objects.remove(object);
91}
92
Mathias Agopianf0480de2011-11-13 20:50:07 -080093bool egl_display_t::getObject(egl_object_t* object) const {
Mathias Agopian518ec112011-05-13 16:21:08 -070094 Mutex::Autolock _l(lock);
95 if (objects.indexOf(object) >= 0) {
Mathias Agopianf0480de2011-11-13 20:50:07 -080096 if (object->getDisplay() == this) {
97 object->incRef();
98 return true;
99 }
Mathias Agopian518ec112011-05-13 16:21:08 -0700100 }
101 return false;
102}
103
Mathias Agopian518ec112011-05-13 16:21:08 -0700104EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
105 if (uintptr_t(disp) >= NUM_DISPLAYS)
106 return NULL;
107
108 return sDisplay[uintptr_t(disp)].getDisplay(disp);
109}
110
111EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
112
113 Mutex::Autolock _l(lock);
114
115 // get our driver loader
116 Loader& loader(Loader::getInstance());
117
Mathias Agopianada798b2012-02-13 17:09:30 -0800118 egl_connection_t* const cnx = &gEGLImpl;
119 if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) {
120 EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
121 disp.dpy = dpy;
122 if (dpy == EGL_NO_DISPLAY) {
123 loader.close(cnx->dso);
124 cnx->dso = NULL;
Mathias Agopian518ec112011-05-13 16:21:08 -0700125 }
126 }
127
128 return EGLDisplay(uintptr_t(display) + 1U);
129}
130
131EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
132
133 Mutex::Autolock _l(lock);
134
135 if (refs > 0) {
136 if (major != NULL)
137 *major = VERSION_MAJOR;
138 if (minor != NULL)
139 *minor = VERSION_MINOR;
140 refs++;
141 return EGL_TRUE;
142 }
143
144#if EGL_TRACE
145
146 // Called both at early_init time and at this time. (Early_init is pre-zygote, so
147 // the information from that call may be stale.)
148 initEglTraceLevel();
Siva Velusamyb13c78f2012-03-09 14:51:28 -0800149 initEglDebugLevel();
Mathias Agopian518ec112011-05-13 16:21:08 -0700150
151#endif
152
153 setGLHooksThreadSpecific(&gHooksNoContext);
154
155 // initialize each EGL and
156 // build our own extension string first, based on the extension we know
157 // and the extension supported by our client implementation
Mathias Agopianada798b2012-02-13 17:09:30 -0800158
159 egl_connection_t* const cnx = &gEGLImpl;
160 cnx->major = -1;
161 cnx->minor = -1;
162 if (cnx->dso) {
Mathias Agopian518ec112011-05-13 16:21:08 -0700163
164#if defined(ADRENO130)
165#warning "Adreno-130 eglInitialize() workaround"
166 /*
167 * The ADRENO 130 driver returns a different EGLDisplay each time
168 * eglGetDisplay() is called, but also makes the EGLDisplay invalid
169 * after eglTerminate() has been called, so that eglInitialize()
170 * cannot be called again. Therefore, we need to make sure to call
171 * eglGetDisplay() before calling eglInitialize();
172 */
173 if (i == IMPL_HARDWARE) {
Mathias Agopianada798b2012-02-13 17:09:30 -0800174 disp[i].dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
Mathias Agopian518ec112011-05-13 16:21:08 -0700175 }
176#endif
177
Mathias Agopianada798b2012-02-13 17:09:30 -0800178 EGLDisplay idpy = disp.dpy;
Mathias Agopian518ec112011-05-13 16:21:08 -0700179 if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
Mathias Agopianada798b2012-02-13 17:09:30 -0800180 //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p",
181 // idpy, cnx->major, cnx->minor, cnx);
Mathias Agopian518ec112011-05-13 16:21:08 -0700182
183 // display is now initialized
Mathias Agopianada798b2012-02-13 17:09:30 -0800184 disp.state = egl_display_t::INITIALIZED;
Mathias Agopian518ec112011-05-13 16:21:08 -0700185
186 // get the query-strings for this display for each implementation
Mathias Agopianada798b2012-02-13 17:09:30 -0800187 disp.queryString.vendor = cnx->egl.eglQueryString(idpy,
Mathias Agopian518ec112011-05-13 16:21:08 -0700188 EGL_VENDOR);
Mathias Agopianada798b2012-02-13 17:09:30 -0800189 disp.queryString.version = cnx->egl.eglQueryString(idpy,
Mathias Agopian518ec112011-05-13 16:21:08 -0700190 EGL_VERSION);
Mathias Agopianada798b2012-02-13 17:09:30 -0800191 disp.queryString.extensions = cnx->egl.eglQueryString(idpy,
Mathias Agopian518ec112011-05-13 16:21:08 -0700192 EGL_EXTENSIONS);
Mathias Agopianada798b2012-02-13 17:09:30 -0800193 disp.queryString.clientApi = cnx->egl.eglQueryString(idpy,
Mathias Agopian518ec112011-05-13 16:21:08 -0700194 EGL_CLIENT_APIS);
195
196 } else {
Mathias Agopianada798b2012-02-13 17:09:30 -0800197 ALOGW("eglInitialize(%p) failed (%s)", idpy,
Mathias Agopian518ec112011-05-13 16:21:08 -0700198 egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
199 }
200 }
201
Mathias Agopian4b9511c2011-11-13 23:52:47 -0800202 // the query strings are per-display
203 mVendorString.setTo(sVendorString);
204 mVersionString.setTo(sVersionString);
205 mClientApiString.setTo(sClientApiString);
206
Mathias Agopian7773c432012-02-13 20:06:08 -0800207 // we only add extensions that exist in the implementation
Mathias Agopian4b9511c2011-11-13 23:52:47 -0800208 char const* start = sExtensionString;
209 char const* end;
210 do {
211 // find the space separating this extension for the next one
212 end = strchr(start, ' ');
213 if (end) {
214 // length of the extension string
215 const size_t len = end - start;
Mathias Agopianf3ae82d2011-11-16 16:49:25 -0800216 if (len) {
217 // NOTE: we could avoid the copy if we had strnstr.
218 const String8 ext(start, len);
Mathias Agopianada798b2012-02-13 17:09:30 -0800219 // now look for this extension
220 if (disp.queryString.extensions) {
221 // if we find it, add this extension string to our list
222 // (and don't forget the space)
223 const char* match = strstr(disp.queryString.extensions, ext.string());
224 if (match && (match[len] == ' ' || match[len] == 0)) {
225 mExtensionString.append(start, len+1);
Mathias Agopianf3ae82d2011-11-16 16:49:25 -0800226 }
Mathias Agopian4b9511c2011-11-13 23:52:47 -0800227 }
228 }
229 // process the next extension string, and skip the space.
230 start = end + 1;
231 }
232 } while (end);
233
Jamie Gennisaca51c02011-11-03 17:42:43 -0700234 egl_cache_t::get()->initialize(this);
235
Mathias Agopian7db993a2012-03-25 00:49:46 -0700236 char value[PROPERTY_VALUE_MAX];
237 property_get("debug.egl.finish", value, "0");
238 if (atoi(value)) {
239 finishOnSwap = true;
240 }
241
Jamie Gennis28ef8d72012-04-05 20:34:54 -0700242 property_get("debug.egl.traceGpuCompletion", value, "0");
243 if (atoi(value)) {
244 traceGpuCompletion = true;
245 }
246
Mathias Agopian7773c432012-02-13 20:06:08 -0800247 refs++;
248 if (major != NULL)
249 *major = VERSION_MAJOR;
250 if (minor != NULL)
251 *minor = VERSION_MINOR;
252 return EGL_TRUE;
Mathias Agopian518ec112011-05-13 16:21:08 -0700253}
254
255EGLBoolean egl_display_t::terminate() {
256
257 Mutex::Autolock _l(lock);
258
259 if (refs == 0) {
260 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
261 }
262
263 // this is specific to Android, display termination is ref-counted.
264 if (refs > 1) {
265 refs--;
266 return EGL_TRUE;
267 }
268
269 EGLBoolean res = EGL_FALSE;
Mathias Agopianada798b2012-02-13 17:09:30 -0800270 egl_connection_t* const cnx = &gEGLImpl;
271 if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
272 if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
273 ALOGW("eglTerminate(%p) failed (%s)", disp.dpy,
274 egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
Mathias Agopian518ec112011-05-13 16:21:08 -0700275 }
Mathias Agopianada798b2012-02-13 17:09:30 -0800276 // REVISIT: it's unclear what to do if eglTerminate() fails
Mathias Agopianada798b2012-02-13 17:09:30 -0800277 disp.state = egl_display_t::TERMINATED;
Mathias Agopianada798b2012-02-13 17:09:30 -0800278 res = EGL_TRUE;
Mathias Agopian518ec112011-05-13 16:21:08 -0700279 }
280
Mathias Agopian5b287a62011-05-16 18:58:55 -0700281 // Mark all objects remaining in the list as terminated, unless
282 // there are no reference to them, it which case, we're free to
283 // delete them.
284 size_t count = objects.size();
Steve Block32397c12012-01-05 23:22:43 +0000285 ALOGW_IF(count, "eglTerminate() called w/ %d objects remaining", count);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700286 for (size_t i=0 ; i<count ; i++) {
287 egl_object_t* o = objects.itemAt(i);
288 o->destroy();
289 }
290
291 // this marks all object handles are "terminated"
292 objects.clear();
Mathias Agopian518ec112011-05-13 16:21:08 -0700293
294 refs--;
Mathias Agopian518ec112011-05-13 16:21:08 -0700295 return res;
296}
297
Mathias Agopianfb87e542012-01-30 18:20:52 -0800298void egl_display_t::loseCurrent(egl_context_t * cur_c)
299{
300 if (cur_c) {
Mathias Agopiana4b2c042012-02-03 15:24:51 -0800301 egl_display_t* display = cur_c->getDisplay();
302 if (display) {
303 display->loseCurrentImpl(cur_c);
304 }
305 }
306}
Mathias Agopianfb87e542012-01-30 18:20:52 -0800307
Mathias Agopiana4b2c042012-02-03 15:24:51 -0800308void egl_display_t::loseCurrentImpl(egl_context_t * cur_c)
309{
310 // by construction, these are either 0 or valid (possibly terminated)
311 // it should be impossible for these to be invalid
312 ContextRef _cur_c(cur_c);
313 SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
314 SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
Mathias Agopianfb87e542012-01-30 18:20:52 -0800315
Mathias Agopiana4b2c042012-02-03 15:24:51 -0800316 { // scope for the lock
317 Mutex::Autolock _l(lock);
Mathias Agopianfb87e542012-01-30 18:20:52 -0800318 cur_c->onLooseCurrent();
319
Mathias Agopianfb87e542012-01-30 18:20:52 -0800320 }
Mathias Agopiana4b2c042012-02-03 15:24:51 -0800321
322 // This cannot be called with the lock held because it might end-up
323 // calling back into EGL (in particular when a surface is destroyed
324 // it calls ANativeWindow::disconnect
325 _cur_c.release();
326 _cur_r.release();
327 _cur_d.release();
Mathias Agopianfb87e542012-01-30 18:20:52 -0800328}
329
330EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
331 EGLSurface draw, EGLSurface read, EGLContext ctx,
332 EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx)
333{
Mathias Agopianfb87e542012-01-30 18:20:52 -0800334 EGLBoolean result;
Mathias Agopiana4b2c042012-02-03 15:24:51 -0800335
336 // by construction, these are either 0 or valid (possibly terminated)
337 // it should be impossible for these to be invalid
338 ContextRef _cur_c(cur_c);
339 SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
340 SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
341
342 { // scope for the lock
343 Mutex::Autolock _l(lock);
Mathias Agopianfb87e542012-01-30 18:20:52 -0800344 if (c) {
Mathias Agopiana4b2c042012-02-03 15:24:51 -0800345 result = c->cnx->egl.eglMakeCurrent(
Mathias Agopianada798b2012-02-13 17:09:30 -0800346 disp.dpy, impl_draw, impl_read, impl_ctx);
Mathias Agopiana4b2c042012-02-03 15:24:51 -0800347 if (result == EGL_TRUE) {
348 c->onMakeCurrent(draw, read);
349 }
350 } else {
351 result = cur_c->cnx->egl.eglMakeCurrent(
Mathias Agopianada798b2012-02-13 17:09:30 -0800352 disp.dpy, impl_draw, impl_read, impl_ctx);
Mathias Agopiana4b2c042012-02-03 15:24:51 -0800353 if (result == EGL_TRUE) {
354 cur_c->onLooseCurrent();
355 }
Mathias Agopianfb87e542012-01-30 18:20:52 -0800356 }
357 }
Mathias Agopiana4b2c042012-02-03 15:24:51 -0800358
359 if (result == EGL_TRUE) {
360 // This cannot be called with the lock held because it might end-up
361 // calling back into EGL (in particular when a surface is destroyed
362 // it calls ANativeWindow::disconnect
363 _cur_c.release();
364 _cur_r.release();
365 _cur_d.release();
366 }
367
Mathias Agopianfb87e542012-01-30 18:20:52 -0800368 return result;
369}
Mathias Agopian518ec112011-05-13 16:21:08 -0700370
371// ----------------------------------------------------------------------------
372}; // namespace android
373// ----------------------------------------------------------------------------