egl_display.cpp revision 28ef8d7911dbfd1bf8256fb43acba894d87fc07a
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), traceGpuCompletion(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 property_get("debug.egl.traceGpuCompletion", value, "0"); 243 if (atoi(value)) { 244 traceGpuCompletion = true; 245 } 246 247 refs++; 248 if (major != NULL) 249 *major = VERSION_MAJOR; 250 if (minor != NULL) 251 *minor = VERSION_MINOR; 252 return EGL_TRUE; 253} 254 255EGLBoolean egl_display_t::terminate() { 256 257 Mutex::Autolock _l(lock); 258 259 if (refs == 0) { 260 return setError(EGL_NOT_INITIALIZED, EGL_FALSE); 261 } 262 263 // this is specific to Android, display termination is ref-counted. 264 if (refs > 1) { 265 refs--; 266 return EGL_TRUE; 267 } 268 269 EGLBoolean res = EGL_FALSE; 270 egl_connection_t* const cnx = &gEGLImpl; 271 if (cnx->dso && disp.state == egl_display_t::INITIALIZED) { 272 if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) { 273 ALOGW("eglTerminate(%p) failed (%s)", disp.dpy, 274 egl_tls_t::egl_strerror(cnx->egl.eglGetError())); 275 } 276 // REVISIT: it's unclear what to do if eglTerminate() fails 277 disp.state = egl_display_t::TERMINATED; 278 res = EGL_TRUE; 279 } 280 281 // Mark all objects remaining in the list as terminated, unless 282 // there are no reference to them, it which case, we're free to 283 // delete them. 284 size_t count = objects.size(); 285 ALOGW_IF(count, "eglTerminate() called w/ %d objects remaining", count); 286 for (size_t i=0 ; i<count ; i++) { 287 egl_object_t* o = objects.itemAt(i); 288 o->destroy(); 289 } 290 291 // this marks all object handles are "terminated" 292 objects.clear(); 293 294 refs--; 295 return res; 296} 297 298void egl_display_t::loseCurrent(egl_context_t * cur_c) 299{ 300 if (cur_c) { 301 egl_display_t* display = cur_c->getDisplay(); 302 if (display) { 303 display->loseCurrentImpl(cur_c); 304 } 305 } 306} 307 308void egl_display_t::loseCurrentImpl(egl_context_t * cur_c) 309{ 310 // by construction, these are either 0 or valid (possibly terminated) 311 // it should be impossible for these to be invalid 312 ContextRef _cur_c(cur_c); 313 SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL); 314 SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL); 315 316 { // scope for the lock 317 Mutex::Autolock _l(lock); 318 cur_c->onLooseCurrent(); 319 320 } 321 322 // This cannot be called with the lock held because it might end-up 323 // calling back into EGL (in particular when a surface is destroyed 324 // it calls ANativeWindow::disconnect 325 _cur_c.release(); 326 _cur_r.release(); 327 _cur_d.release(); 328} 329 330EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c, 331 EGLSurface draw, EGLSurface read, EGLContext ctx, 332 EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx) 333{ 334 EGLBoolean result; 335 336 // by construction, these are either 0 or valid (possibly terminated) 337 // it should be impossible for these to be invalid 338 ContextRef _cur_c(cur_c); 339 SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL); 340 SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL); 341 342 { // scope for the lock 343 Mutex::Autolock _l(lock); 344 if (c) { 345 result = c->cnx->egl.eglMakeCurrent( 346 disp.dpy, impl_draw, impl_read, impl_ctx); 347 if (result == EGL_TRUE) { 348 c->onMakeCurrent(draw, read); 349 } 350 } else { 351 result = cur_c->cnx->egl.eglMakeCurrent( 352 disp.dpy, impl_draw, impl_read, impl_ctx); 353 if (result == EGL_TRUE) { 354 cur_c->onLooseCurrent(); 355 } 356 } 357 } 358 359 if (result == EGL_TRUE) { 360 // This cannot be called with the lock held because it might end-up 361 // calling back into EGL (in particular when a surface is destroyed 362 // it calls ANativeWindow::disconnect 363 _cur_c.release(); 364 _cur_r.release(); 365 _cur_d.release(); 366 } 367 368 return result; 369} 370 371// ---------------------------------------------------------------------------- 372}; // namespace android 373// ---------------------------------------------------------------------------- 374