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