egl_display.cpp revision ecc0c9aa412aaf463d91bedcf53f881536a6d560
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// ---------------------------------------------------------------------------- 31namespace android { 32// ---------------------------------------------------------------------------- 33 34static char const * const sVendorString = "Android"; 35static char const * const sVersionString = "1.4 Android META-EGL"; 36static char const * const sClientApiString = "OpenGL_ES"; 37 38extern char const * const gBuiltinExtensionString; 39extern char const * const gExtensionString; 40 41extern void setGLHooksThreadSpecific(gl_hooks_t const *value); 42 43// ---------------------------------------------------------------------------- 44 45static bool findExtension(const char* exts, const char* name, size_t nameLen) { 46 if (exts) { 47 const char* match = strstr(exts, name); 48 if (match && (match[nameLen] == '\0' || match[nameLen] == ' ')) { 49 return true; 50 } 51 } 52 return false; 53} 54 55egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS]; 56 57egl_display_t::egl_display_t() : 58 magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0), eglIsInitialized(false) { 59} 60 61egl_display_t::~egl_display_t() { 62 magic = 0; 63 egl_cache_t::get()->terminate(); 64} 65 66egl_display_t* egl_display_t::get(EGLDisplay dpy) { 67 uintptr_t index = uintptr_t(dpy)-1U; 68 return (index >= NUM_DISPLAYS) ? NULL : &sDisplay[index]; 69} 70 71void egl_display_t::addObject(egl_object_t* object) { 72 Mutex::Autolock _l(lock); 73 objects.add(object); 74} 75 76void egl_display_t::removeObject(egl_object_t* object) { 77 Mutex::Autolock _l(lock); 78 objects.remove(object); 79} 80 81bool egl_display_t::getObject(egl_object_t* object) const { 82 Mutex::Autolock _l(lock); 83 if (objects.indexOf(object) >= 0) { 84 if (object->getDisplay() == this) { 85 object->incRef(); 86 return true; 87 } 88 } 89 return false; 90} 91 92EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) { 93 if (uintptr_t(disp) >= NUM_DISPLAYS) 94 return NULL; 95 96 return sDisplay[uintptr_t(disp)].getDisplay(disp); 97} 98 99EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) { 100 101 Mutex::Autolock _l(lock); 102 103 // get our driver loader 104 Loader& loader(Loader::getInstance()); 105 106 egl_connection_t* const cnx = &gEGLImpl; 107 if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) { 108 EGLDisplay dpy = cnx->egl.eglGetDisplay(display); 109 disp.dpy = dpy; 110 if (dpy == EGL_NO_DISPLAY) { 111 loader.close(cnx->dso); 112 cnx->dso = NULL; 113 } 114 } 115 116 return EGLDisplay(uintptr_t(display) + 1U); 117} 118 119EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { 120 121 { 122 Mutex::Autolock _rf(refLock); 123 124 refs++; 125 if (refs > 1) { 126 if (major != NULL) 127 *major = VERSION_MAJOR; 128 if (minor != NULL) 129 *minor = VERSION_MINOR; 130 while(!eglIsInitialized) refCond.wait(refLock); 131 return EGL_TRUE; 132 } 133 134 while(eglIsInitialized) refCond.wait(refLock); 135 } 136 137 { 138 Mutex::Autolock _l(lock); 139 140 setGLHooksThreadSpecific(&gHooksNoContext); 141 142 // initialize each EGL and 143 // build our own extension string first, based on the extension we know 144 // and the extension supported by our client implementation 145 146 egl_connection_t* const cnx = &gEGLImpl; 147 cnx->major = -1; 148 cnx->minor = -1; 149 if (cnx->dso) { 150 EGLDisplay idpy = disp.dpy; 151 if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) { 152 //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p", 153 // idpy, cnx->major, cnx->minor, cnx); 154 155 // display is now initialized 156 disp.state = egl_display_t::INITIALIZED; 157 158 // get the query-strings for this display for each implementation 159 disp.queryString.vendor = cnx->egl.eglQueryString(idpy, 160 EGL_VENDOR); 161 disp.queryString.version = cnx->egl.eglQueryString(idpy, 162 EGL_VERSION); 163 disp.queryString.extensions = cnx->egl.eglQueryString(idpy, 164 EGL_EXTENSIONS); 165 disp.queryString.clientApi = cnx->egl.eglQueryString(idpy, 166 EGL_CLIENT_APIS); 167 168 } else { 169 ALOGW("eglInitialize(%p) failed (%s)", idpy, 170 egl_tls_t::egl_strerror(cnx->egl.eglGetError())); 171 } 172 } 173 174 // the query strings are per-display 175 mVendorString.setTo(sVendorString); 176 mVersionString.setTo(sVersionString); 177 mClientApiString.setTo(sClientApiString); 178 179 mExtensionString.setTo(gBuiltinExtensionString); 180 char const* start = gExtensionString; 181 do { 182 // length of the extension name 183 size_t len = strcspn(start, " "); 184 if (len) { 185 // NOTE: we could avoid the copy if we had strnstr. 186 const String8 ext(start, len); 187 if (findExtension(disp.queryString.extensions, ext.string(), 188 len)) { 189 mExtensionString.append(ext + " "); 190 } 191 // advance to the next extension name, skipping the space. 192 start += len; 193 start += (*start == ' ') ? 1 : 0; 194 } 195 } while (*start != '\0'); 196 197 egl_cache_t::get()->initialize(this); 198 199 char value[PROPERTY_VALUE_MAX]; 200 property_get("debug.egl.finish", value, "0"); 201 if (atoi(value)) { 202 finishOnSwap = true; 203 } 204 205 property_get("debug.egl.traceGpuCompletion", value, "0"); 206 if (atoi(value)) { 207 traceGpuCompletion = true; 208 } 209 210 if (major != NULL) 211 *major = VERSION_MAJOR; 212 if (minor != NULL) 213 *minor = VERSION_MINOR; 214 215 mHibernation.setDisplayValid(true); 216 } 217 218 { 219 Mutex::Autolock _rf(refLock); 220 eglIsInitialized = true; 221 refCond.broadcast(); 222 } 223 224 return EGL_TRUE; 225} 226 227EGLBoolean egl_display_t::terminate() { 228 229 { 230 Mutex::Autolock _rl(refLock); 231 if (refs == 0) { 232 /* 233 * From the EGL spec (3.2): 234 * "Termination of a display that has already been terminated, 235 * (...), is allowed, but the only effect of such a call is 236 * to return EGL_TRUE (...) 237 */ 238 return EGL_TRUE; 239 } 240 241 // this is specific to Android, display termination is ref-counted. 242 refs--; 243 if (refs > 0) { 244 return EGL_TRUE; 245 } 246 } 247 248 EGLBoolean res = EGL_FALSE; 249 250 { 251 Mutex::Autolock _l(lock); 252 253 egl_connection_t* const cnx = &gEGLImpl; 254 if (cnx->dso && disp.state == egl_display_t::INITIALIZED) { 255 if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) { 256 ALOGW("eglTerminate(%p) failed (%s)", disp.dpy, 257 egl_tls_t::egl_strerror(cnx->egl.eglGetError())); 258 } 259 // REVISIT: it's unclear what to do if eglTerminate() fails 260 disp.state = egl_display_t::TERMINATED; 261 res = EGL_TRUE; 262 } 263 264 mHibernation.setDisplayValid(false); 265 266 // Reset the extension string since it will be regenerated if we get 267 // reinitialized. 268 mExtensionString.setTo(""); 269 270 // Mark all objects remaining in the list as terminated, unless 271 // there are no reference to them, it which case, we're free to 272 // delete them. 273 size_t count = objects.size(); 274 ALOGW_IF(count, "eglTerminate() called w/ %d objects remaining", count); 275 for (size_t i=0 ; i<count ; i++) { 276 egl_object_t* o = objects.itemAt(i); 277 o->destroy(); 278 } 279 280 // this marks all object handles are "terminated" 281 objects.clear(); 282 } 283 284 { 285 Mutex::Autolock _rl(refLock); 286 eglIsInitialized = false; 287 refCond.broadcast(); 288 } 289 290 return res; 291} 292 293void 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 303void 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 325EGLBoolean 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 370bool egl_display_t::haveExtension(const char* name, size_t nameLen) const { 371 if (!nameLen) { 372 nameLen = strlen(name); 373 } 374 return findExtension(mExtensionString.string(), name, nameLen); 375} 376 377// ---------------------------------------------------------------------------- 378 379bool egl_display_t::HibernationMachine::incWakeCount(WakeRefStrength strength) { 380 Mutex::Autolock _l(mLock); 381 ALOGE_IF(mWakeCount < 0 || mWakeCount == INT32_MAX, 382 "Invalid WakeCount (%d) on enter\n", mWakeCount); 383 384 mWakeCount++; 385 if (strength == STRONG) 386 mAttemptHibernation = false; 387 388 if (CC_UNLIKELY(mHibernating)) { 389 ALOGV("Awakening\n"); 390 egl_connection_t* const cnx = &gEGLImpl; 391 392 // These conditions should be guaranteed before entering hibernation; 393 // we don't want to get into a state where we can't wake up. 394 ALOGD_IF(!mDpyValid || !cnx->egl.eglAwakenProcessIMG, 395 "Invalid hibernation state, unable to awaken\n"); 396 397 if (!cnx->egl.eglAwakenProcessIMG()) { 398 ALOGE("Failed to awaken EGL implementation\n"); 399 return false; 400 } 401 mHibernating = false; 402 } 403 return true; 404} 405 406void egl_display_t::HibernationMachine::decWakeCount(WakeRefStrength strength) { 407 Mutex::Autolock _l(mLock); 408 ALOGE_IF(mWakeCount <= 0, "Invalid WakeCount (%d) on leave\n", mWakeCount); 409 410 mWakeCount--; 411 if (strength == STRONG) 412 mAttemptHibernation = true; 413 414 if (mWakeCount == 0 && CC_UNLIKELY(mAttemptHibernation)) { 415 egl_connection_t* const cnx = &gEGLImpl; 416 mAttemptHibernation = false; 417 if (mAllowHibernation && mDpyValid && 418 cnx->egl.eglHibernateProcessIMG && 419 cnx->egl.eglAwakenProcessIMG) { 420 ALOGV("Hibernating\n"); 421 if (!cnx->egl.eglHibernateProcessIMG()) { 422 ALOGE("Failed to hibernate EGL implementation\n"); 423 return; 424 } 425 mHibernating = true; 426 } 427 } 428} 429 430void egl_display_t::HibernationMachine::setDisplayValid(bool valid) { 431 Mutex::Autolock _l(mLock); 432 mDpyValid = valid; 433} 434 435// ---------------------------------------------------------------------------- 436}; // namespace android 437// ---------------------------------------------------------------------------- 438