egl_display.cpp revision b13c78f8520ef5a96effdee977bbacb881236c66
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#include <string.h> 18 19#include "egl_cache.h" 20#include "egl_display.h" 21#include "egl_object.h" 22#include "egl_tls.h" 23#include "egl_impl.h" 24#include "Loader.h" 25 26// ---------------------------------------------------------------------------- 27namespace android { 28// ---------------------------------------------------------------------------- 29 30static char const * const sVendorString = "Android"; 31static char const * const sVersionString = "1.4 Android META-EGL"; 32static char const * const sClientApiString = "OpenGL ES"; 33 34// this is the list of EGL extensions that are exposed to applications 35// some of them are mandatory because used by the ANDROID system. 36// 37// mandatory extensions are required per the CDD and not explicitly 38// checked during EGL initialization. the system *assumes* these extensions 39// are present. the system may not function properly if some mandatory 40// extensions are missing. 41// 42// NOTE: sExtensionString MUST be have a single space as the last character. 43// 44static char const * const sExtensionString = 45 "EGL_KHR_image " // mandatory 46 "EGL_KHR_image_base " // mandatory 47 "EGL_KHR_image_pixmap " 48 "EGL_KHR_gl_texture_2D_image " 49 "EGL_KHR_gl_texture_cubemap_image " 50 "EGL_KHR_gl_renderbuffer_image " 51 "EGL_KHR_fence_sync " 52 "EGL_NV_system_time " 53 "EGL_ANDROID_image_native_buffer " // mandatory 54 ; 55 56// extensions not exposed to applications but used by the ANDROID system 57// "EGL_ANDROID_recordable " // mandatory 58// "EGL_ANDROID_blob_cache " // strongly recommended 59 60extern void initEglTraceLevel(); 61extern void initEglDebugLevel(); 62extern void setGLHooksThreadSpecific(gl_hooks_t const *value); 63 64// ---------------------------------------------------------------------------- 65 66egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS]; 67 68egl_display_t::egl_display_t() : 69 magic('_dpy'), refs(0) { 70} 71 72egl_display_t::~egl_display_t() { 73 magic = 0; 74 egl_cache_t::get()->terminate(); 75} 76 77egl_display_t* egl_display_t::get(EGLDisplay dpy) { 78 uintptr_t index = uintptr_t(dpy)-1U; 79 return (index >= NUM_DISPLAYS) ? NULL : &sDisplay[index]; 80} 81 82void egl_display_t::addObject(egl_object_t* object) { 83 Mutex::Autolock _l(lock); 84 objects.add(object); 85} 86 87void egl_display_t::removeObject(egl_object_t* object) { 88 Mutex::Autolock _l(lock); 89 objects.remove(object); 90} 91 92bool egl_display_t::getObject(egl_object_t* object) const { 93 Mutex::Autolock _l(lock); 94 if (objects.indexOf(object) >= 0) { 95 if (object->getDisplay() == this) { 96 object->incRef(); 97 return true; 98 } 99 } 100 return false; 101} 102 103EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) { 104 if (uintptr_t(disp) >= NUM_DISPLAYS) 105 return NULL; 106 107 return sDisplay[uintptr_t(disp)].getDisplay(disp); 108} 109 110EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) { 111 112 Mutex::Autolock _l(lock); 113 114 // get our driver loader 115 Loader& loader(Loader::getInstance()); 116 117 egl_connection_t* const cnx = &gEGLImpl; 118 if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) { 119 EGLDisplay dpy = cnx->egl.eglGetDisplay(display); 120 disp.dpy = dpy; 121 if (dpy == EGL_NO_DISPLAY) { 122 loader.close(cnx->dso); 123 cnx->dso = NULL; 124 } 125 } 126 127 return EGLDisplay(uintptr_t(display) + 1U); 128} 129 130EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { 131 132 Mutex::Autolock _l(lock); 133 134 if (refs > 0) { 135 if (major != NULL) 136 *major = VERSION_MAJOR; 137 if (minor != NULL) 138 *minor = VERSION_MINOR; 139 refs++; 140 return EGL_TRUE; 141 } 142 143#if EGL_TRACE 144 145 // Called both at early_init time and at this time. (Early_init is pre-zygote, so 146 // the information from that call may be stale.) 147 initEglTraceLevel(); 148 initEglDebugLevel(); 149 150#endif 151 152 setGLHooksThreadSpecific(&gHooksNoContext); 153 154 // initialize each EGL and 155 // build our own extension string first, based on the extension we know 156 // and the extension supported by our client implementation 157 158 egl_connection_t* const cnx = &gEGLImpl; 159 cnx->major = -1; 160 cnx->minor = -1; 161 if (cnx->dso) { 162 163#if defined(ADRENO130) 164#warning "Adreno-130 eglInitialize() workaround" 165 /* 166 * The ADRENO 130 driver returns a different EGLDisplay each time 167 * eglGetDisplay() is called, but also makes the EGLDisplay invalid 168 * after eglTerminate() has been called, so that eglInitialize() 169 * cannot be called again. Therefore, we need to make sure to call 170 * eglGetDisplay() before calling eglInitialize(); 171 */ 172 if (i == IMPL_HARDWARE) { 173 disp[i].dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); 174 } 175#endif 176 177 EGLDisplay idpy = disp.dpy; 178 if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) { 179 //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p", 180 // idpy, cnx->major, cnx->minor, cnx); 181 182 // display is now initialized 183 disp.state = egl_display_t::INITIALIZED; 184 185 // get the query-strings for this display for each implementation 186 disp.queryString.vendor = cnx->egl.eglQueryString(idpy, 187 EGL_VENDOR); 188 disp.queryString.version = cnx->egl.eglQueryString(idpy, 189 EGL_VERSION); 190 disp.queryString.extensions = cnx->egl.eglQueryString(idpy, 191 EGL_EXTENSIONS); 192 disp.queryString.clientApi = cnx->egl.eglQueryString(idpy, 193 EGL_CLIENT_APIS); 194 195 } else { 196 ALOGW("eglInitialize(%p) failed (%s)", idpy, 197 egl_tls_t::egl_strerror(cnx->egl.eglGetError())); 198 } 199 } 200 201 // the query strings are per-display 202 mVendorString.setTo(sVendorString); 203 mVersionString.setTo(sVersionString); 204 mClientApiString.setTo(sClientApiString); 205 206 // we only add extensions that exist in the implementation 207 char const* start = sExtensionString; 208 char const* end; 209 do { 210 // find the space separating this extension for the next one 211 end = strchr(start, ' '); 212 if (end) { 213 // length of the extension string 214 const size_t len = end - start; 215 if (len) { 216 // NOTE: we could avoid the copy if we had strnstr. 217 const String8 ext(start, len); 218 // now look for this extension 219 if (disp.queryString.extensions) { 220 // if we find it, add this extension string to our list 221 // (and don't forget the space) 222 const char* match = strstr(disp.queryString.extensions, ext.string()); 223 if (match && (match[len] == ' ' || match[len] == 0)) { 224 mExtensionString.append(start, len+1); 225 } 226 } 227 } 228 // process the next extension string, and skip the space. 229 start = end + 1; 230 } 231 } while (end); 232 233 egl_cache_t::get()->initialize(this); 234 235 refs++; 236 if (major != NULL) 237 *major = VERSION_MAJOR; 238 if (minor != NULL) 239 *minor = VERSION_MINOR; 240 return EGL_TRUE; 241} 242 243EGLBoolean egl_display_t::terminate() { 244 245 Mutex::Autolock _l(lock); 246 247 if (refs == 0) { 248 return setError(EGL_NOT_INITIALIZED, EGL_FALSE); 249 } 250 251 // this is specific to Android, display termination is ref-counted. 252 if (refs > 1) { 253 refs--; 254 return EGL_TRUE; 255 } 256 257 EGLBoolean res = EGL_FALSE; 258 egl_connection_t* const cnx = &gEGLImpl; 259 if (cnx->dso && disp.state == egl_display_t::INITIALIZED) { 260 if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) { 261 ALOGW("eglTerminate(%p) failed (%s)", disp.dpy, 262 egl_tls_t::egl_strerror(cnx->egl.eglGetError())); 263 } 264 // REVISIT: it's unclear what to do if eglTerminate() fails 265 disp.state = egl_display_t::TERMINATED; 266 res = EGL_TRUE; 267 } 268 269 // Mark all objects remaining in the list as terminated, unless 270 // there are no reference to them, it which case, we're free to 271 // delete them. 272 size_t count = objects.size(); 273 ALOGW_IF(count, "eglTerminate() called w/ %d objects remaining", count); 274 for (size_t i=0 ; i<count ; i++) { 275 egl_object_t* o = objects.itemAt(i); 276 o->destroy(); 277 } 278 279 // this marks all object handles are "terminated" 280 objects.clear(); 281 282 refs--; 283 return res; 284} 285 286void egl_display_t::loseCurrent(egl_context_t * cur_c) 287{ 288 if (cur_c) { 289 egl_display_t* display = cur_c->getDisplay(); 290 if (display) { 291 display->loseCurrentImpl(cur_c); 292 } 293 } 294} 295 296void egl_display_t::loseCurrentImpl(egl_context_t * cur_c) 297{ 298 // by construction, these are either 0 or valid (possibly terminated) 299 // it should be impossible for these to be invalid 300 ContextRef _cur_c(cur_c); 301 SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL); 302 SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL); 303 304 { // scope for the lock 305 Mutex::Autolock _l(lock); 306 cur_c->onLooseCurrent(); 307 308 } 309 310 // This cannot be called with the lock held because it might end-up 311 // calling back into EGL (in particular when a surface is destroyed 312 // it calls ANativeWindow::disconnect 313 _cur_c.release(); 314 _cur_r.release(); 315 _cur_d.release(); 316} 317 318EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c, 319 EGLSurface draw, EGLSurface read, EGLContext ctx, 320 EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx) 321{ 322 EGLBoolean result; 323 324 // by construction, these are either 0 or valid (possibly terminated) 325 // it should be impossible for these to be invalid 326 ContextRef _cur_c(cur_c); 327 SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL); 328 SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL); 329 330 { // scope for the lock 331 Mutex::Autolock _l(lock); 332 if (c) { 333 result = c->cnx->egl.eglMakeCurrent( 334 disp.dpy, impl_draw, impl_read, impl_ctx); 335 if (result == EGL_TRUE) { 336 c->onMakeCurrent(draw, read); 337 } 338 } else { 339 result = cur_c->cnx->egl.eglMakeCurrent( 340 disp.dpy, impl_draw, impl_read, impl_ctx); 341 if (result == EGL_TRUE) { 342 cur_c->onLooseCurrent(); 343 } 344 } 345 } 346 347 if (result == EGL_TRUE) { 348 // This cannot be called with the lock held because it might end-up 349 // calling back into EGL (in particular when a surface is destroyed 350 // it calls ANativeWindow::disconnect 351 _cur_c.release(); 352 _cur_r.release(); 353 _cur_d.release(); 354 } 355 356 return result; 357} 358 359// ---------------------------------------------------------------------------- 360}; // namespace android 361// ---------------------------------------------------------------------------- 362