egl_display.cpp revision 7db993a98b9239bd4e384cc4aa128262fe3cf52c
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#include <cutils/properties.h> 26 27// ---------------------------------------------------------------------------- 28namespace android { 29// ---------------------------------------------------------------------------- 30 31static 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 61extern void initEglTraceLevel(); 62extern void initEglDebugLevel(); 63extern void setGLHooksThreadSpecific(gl_hooks_t const *value); 64 65// ---------------------------------------------------------------------------- 66 67egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS]; 68 69egl_display_t::egl_display_t() : 70 magic('_dpy'), finishOnSwap(false), refs(0) { 71} 72 73egl_display_t::~egl_display_t() { 74 magic = 0; 75 egl_cache_t::get()->terminate(); 76} 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 88void egl_display_t::removeObject(egl_object_t* object) { 89 Mutex::Autolock _l(lock); 90 objects.remove(object); 91} 92 93bool egl_display_t::getObject(egl_object_t* object) const { 94 Mutex::Autolock _l(lock); 95 if (objects.indexOf(object) >= 0) { 96 if (object->getDisplay() == this) { 97 object->incRef(); 98 return true; 99 } 100 } 101 return false; 102} 103 104EGLDisplay 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 118 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; 125 } 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(); 149 initEglDebugLevel(); 150 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 158 159 egl_connection_t* const cnx = &gEGLImpl; 160 cnx->major = -1; 161 cnx->minor = -1; 162 if (cnx->dso) { 163 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) { 174 disp[i].dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); 175 } 176#endif 177 178 EGLDisplay idpy = disp.dpy; 179 if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) { 180 //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p", 181 // idpy, cnx->major, cnx->minor, cnx); 182 183 // display is now initialized 184 disp.state = egl_display_t::INITIALIZED; 185 186 // get the query-strings for this display for each implementation 187 disp.queryString.vendor = cnx->egl.eglQueryString(idpy, 188 EGL_VENDOR); 189 disp.queryString.version = cnx->egl.eglQueryString(idpy, 190 EGL_VERSION); 191 disp.queryString.extensions = cnx->egl.eglQueryString(idpy, 192 EGL_EXTENSIONS); 193 disp.queryString.clientApi = cnx->egl.eglQueryString(idpy, 194 EGL_CLIENT_APIS); 195 196 } else { 197 ALOGW("eglInitialize(%p) failed (%s)", idpy, 198 egl_tls_t::egl_strerror(cnx->egl.eglGetError())); 199 } 200 } 201 202 // the query strings are per-display 203 mVendorString.setTo(sVendorString); 204 mVersionString.setTo(sVersionString); 205 mClientApiString.setTo(sClientApiString); 206 207 // we only add extensions that exist in the implementation 208 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; 216 if (len) { 217 // NOTE: we could avoid the copy if we had strnstr. 218 const String8 ext(start, len); 219 // 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); 226 } 227 } 228 } 229 // process the next extension string, and skip the space. 230 start = end + 1; 231 } 232 } while (end); 233 234 egl_cache_t::get()->initialize(this); 235 236 char value[PROPERTY_VALUE_MAX]; 237 property_get("debug.egl.finish", value, "0"); 238 if (atoi(value)) { 239 finishOnSwap = true; 240 } 241 242 refs++; 243 if (major != NULL) 244 *major = VERSION_MAJOR; 245 if (minor != NULL) 246 *minor = VERSION_MINOR; 247 return EGL_TRUE; 248} 249 250EGLBoolean egl_display_t::terminate() { 251 252 Mutex::Autolock _l(lock); 253 254 if (refs == 0) { 255 return setError(EGL_NOT_INITIALIZED, EGL_FALSE); 256 } 257 258 // this is specific to Android, display termination is ref-counted. 259 if (refs > 1) { 260 refs--; 261 return EGL_TRUE; 262 } 263 264 EGLBoolean res = EGL_FALSE; 265 egl_connection_t* const cnx = &gEGLImpl; 266 if (cnx->dso && disp.state == egl_display_t::INITIALIZED) { 267 if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) { 268 ALOGW("eglTerminate(%p) failed (%s)", disp.dpy, 269 egl_tls_t::egl_strerror(cnx->egl.eglGetError())); 270 } 271 // REVISIT: it's unclear what to do if eglTerminate() fails 272 disp.state = egl_display_t::TERMINATED; 273 res = EGL_TRUE; 274 } 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 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 } 345 } else { 346 result = cur_c->cnx->egl.eglMakeCurrent( 347 disp.dpy, impl_draw, impl_read, impl_ctx); 348 if (result == EGL_TRUE) { 349 cur_c->onLooseCurrent(); 350 } 351 } 352 } 353 354 if (result == EGL_TRUE) { 355 // This cannot be called with the lock held because it might end-up 356 // calling back into EGL (in particular when a surface is destroyed 357 // it calls ANativeWindow::disconnect 358 _cur_c.release(); 359 _cur_r.release(); 360 _cur_d.release(); 361 } 362 363 return result; 364} 365 366// ---------------------------------------------------------------------------- 367}; // namespace android 368// ---------------------------------------------------------------------------- 369