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