1 /* 2 * Copyright (C) 2011 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 #include "eglDisplay.h" 17 #include "HostConnection.h" 18 #include <dlfcn.h> 19 20 #include <string> 21 22 static const int systemEGLVersionMajor = 1; 23 static const int systemEGLVersionMinor = 4; 24 static const char systemEGLVendor[] = "Google Android emulator"; 25 26 // list of extensions supported by this EGL implementation 27 // NOTE that each extension name should be suffixed with space 28 static const char systemStaticEGLExtensions[] = 29 "EGL_ANDROID_image_native_buffer " 30 "EGL_KHR_fence_sync " 31 "EGL_KHR_image_base " 32 "EGL_KHR_gl_texture_2d_image "; 33 34 // extensions to add dynamically depending on host-side support 35 static const char kDynamicEGLExtNativeSync[] = "EGL_ANDROID_native_fence_sync "; 36 37 static void *s_gles_lib = NULL; 38 static void *s_gles2_lib = NULL; 39 40 // The following function will be called when we (libEGL) 41 // gets unloaded 42 // At this point we want to unload the gles libraries we 43 // might have loaded during initialization 44 static void __attribute__ ((destructor)) do_on_unload(void) 45 { 46 if (s_gles_lib) { 47 dlclose(s_gles_lib); 48 } 49 50 if (s_gles2_lib) { 51 dlclose(s_gles2_lib); 52 } 53 } 54 55 eglDisplay::eglDisplay() : 56 m_initialized(false), 57 m_major(0), 58 m_minor(0), 59 m_hostRendererVersion(0), 60 m_numConfigs(0), 61 m_numConfigAttribs(0), 62 m_attribs(DefaultKeyedVector<EGLint, EGLint>(ATTRIBUTE_NONE)), 63 m_configs(NULL), 64 m_gles_iface(NULL), 65 m_gles2_iface(NULL), 66 m_versionString(NULL), 67 m_vendorString(NULL), 68 m_extensionString(NULL) 69 { 70 pthread_mutex_init(&m_lock, NULL); 71 pthread_mutex_init(&m_ctxLock, NULL); 72 pthread_mutex_init(&m_surfaceLock, NULL); 73 } 74 75 eglDisplay::~eglDisplay() 76 { 77 terminate(); 78 pthread_mutex_destroy(&m_lock); 79 pthread_mutex_destroy(&m_ctxLock); 80 pthread_mutex_destroy(&m_surfaceLock); 81 } 82 83 bool eglDisplay::initialize(EGLClient_eglInterface *eglIface) 84 { 85 pthread_mutex_lock(&m_lock); 86 if (!m_initialized) { 87 88 // 89 // load GLES client API 90 // 91 #if __LP64__ 92 m_gles_iface = loadGLESClientAPI("/system/lib64/egl/libGLESv1_CM_emulation.so", 93 eglIface, 94 &s_gles_lib); 95 #else 96 m_gles_iface = loadGLESClientAPI("/system/lib/egl/libGLESv1_CM_emulation.so", 97 eglIface, 98 &s_gles_lib); 99 #endif 100 if (!m_gles_iface) { 101 pthread_mutex_unlock(&m_lock); 102 ALOGE("Failed to load gles1 iface"); 103 return false; 104 } 105 106 #ifdef WITH_GLES2 107 #if __LP64__ 108 m_gles2_iface = loadGLESClientAPI("/system/lib64/egl/libGLESv2_emulation.so", 109 eglIface, 110 &s_gles2_lib); 111 #else 112 m_gles2_iface = loadGLESClientAPI("/system/lib/egl/libGLESv2_emulation.so", 113 eglIface, 114 &s_gles2_lib); 115 #endif 116 // Note that if loading gles2 failed, we can still run with no 117 // GLES2 support, having GLES2 is not mandatory. 118 #endif 119 120 // 121 // establish connection with the host 122 // 123 HostConnection *hcon = HostConnection::get(); 124 if (!hcon) { 125 pthread_mutex_unlock(&m_lock); 126 ALOGE("Failed to establish connection with the host\n"); 127 return false; 128 } 129 hcon->setGrallocOnly(false); 130 131 // 132 // get renderControl encoder instance 133 // 134 renderControl_encoder_context_t *rcEnc = hcon->rcEncoder(); 135 if (!rcEnc) { 136 pthread_mutex_unlock(&m_lock); 137 ALOGE("Failed to get renderControl encoder instance"); 138 return false; 139 } 140 141 // 142 // Query host reneder and EGL version 143 // 144 m_hostRendererVersion = rcEnc->rcGetRendererVersion(rcEnc); 145 EGLint status = rcEnc->rcGetEGLVersion(rcEnc, &m_major, &m_minor); 146 if (status != EGL_TRUE) { 147 // host EGL initialization failed !! 148 pthread_mutex_unlock(&m_lock); 149 return false; 150 } 151 152 // 153 // Take minimum version beween what we support and what the host support 154 // 155 if (m_major > systemEGLVersionMajor) { 156 m_major = systemEGLVersionMajor; 157 m_minor = systemEGLVersionMinor; 158 } 159 else if (m_major == systemEGLVersionMajor && 160 m_minor > systemEGLVersionMinor) { 161 m_minor = systemEGLVersionMinor; 162 } 163 164 // 165 // Query the host for the set of configs 166 // 167 m_numConfigs = rcEnc->rcGetNumConfigs(rcEnc, (uint32_t*)&m_numConfigAttribs); 168 if (m_numConfigs <= 0 || m_numConfigAttribs <= 0) { 169 // just sanity check - should never happen 170 pthread_mutex_unlock(&m_lock); 171 return false; 172 } 173 174 uint32_t nInts = m_numConfigAttribs * (m_numConfigs + 1); 175 EGLint tmp_buf[nInts]; 176 m_configs = new EGLint[nInts-m_numConfigAttribs]; 177 if (!m_configs) { 178 pthread_mutex_unlock(&m_lock); 179 return false; 180 } 181 182 //EGLint n = rcEnc->rcGetConfigs(rcEnc, nInts*sizeof(EGLint), m_configs); 183 EGLint n = rcEnc->rcGetConfigs(rcEnc, nInts*sizeof(EGLint), (GLuint*)tmp_buf); 184 if (n != m_numConfigs) { 185 pthread_mutex_unlock(&m_lock); 186 return false; 187 } 188 189 //Fill the attributes vector. 190 //The first m_numConfigAttribs values of tmp_buf are the actual attributes enums. 191 for (int i=0; i<m_numConfigAttribs; i++) { 192 m_attribs.add(tmp_buf[i], i); 193 } 194 195 //Copy the actual configs data to m_configs 196 memcpy(m_configs, tmp_buf + m_numConfigAttribs, m_numConfigs*m_numConfigAttribs*sizeof(EGLint)); 197 198 m_initialized = true; 199 } 200 pthread_mutex_unlock(&m_lock); 201 202 processConfigs(); 203 204 return true; 205 } 206 207 void eglDisplay::processConfigs() 208 { 209 for (intptr_t i=0; i<m_numConfigs; i++) { 210 EGLConfig config = (EGLConfig)i; 211 //Setup the EGL_NATIVE_VISUAL_ID attribute 212 PixelFormat format; 213 if (getConfigNativePixelFormat(config, &format)) { 214 setConfigAttrib(config, EGL_NATIVE_VISUAL_ID, format); 215 } 216 } 217 } 218 219 void eglDisplay::terminate() 220 { 221 pthread_mutex_lock(&m_lock); 222 if (m_initialized) { 223 // Cannot use the for loop in the following code because 224 // eglDestroyContext may erase elements. 225 EGLContextSet::iterator ctxIte = m_contexts.begin(); 226 while (ctxIte != m_contexts.end()) { 227 EGLContextSet::iterator ctxToDelete = ctxIte; 228 ctxIte ++; 229 eglDestroyContext(static_cast<EGLDisplay>(this), *ctxToDelete); 230 } 231 EGLSurfaceSet::iterator surfaceIte = m_surfaces.begin(); 232 while (surfaceIte != m_surfaces.end()) { 233 EGLSurfaceSet::iterator surfaceToDelete = surfaceIte; 234 surfaceIte ++; 235 eglDestroySurface(static_cast<EGLDisplay>(this), *surfaceToDelete); 236 } 237 m_initialized = false; 238 delete [] m_configs; 239 m_configs = NULL; 240 241 if (m_versionString) { 242 free(m_versionString); 243 m_versionString = NULL; 244 } 245 if (m_vendorString) { 246 free(m_vendorString); 247 m_vendorString = NULL; 248 } 249 if (m_extensionString) { 250 free(m_extensionString); 251 m_extensionString = NULL; 252 } 253 } 254 pthread_mutex_unlock(&m_lock); 255 } 256 257 EGLClient_glesInterface *eglDisplay::loadGLESClientAPI(const char *libName, 258 EGLClient_eglInterface *eglIface, 259 void **libHandle) 260 { 261 void *lib = dlopen(libName, RTLD_NOW); 262 if (!lib) { 263 ALOGE("Failed to dlopen %s", libName); 264 return NULL; 265 } 266 267 init_emul_gles_t init_gles_func = (init_emul_gles_t)dlsym(lib,"init_emul_gles"); 268 if (!init_gles_func) { 269 ALOGE("Failed to find init_emul_gles"); 270 dlclose((void*)lib); 271 return NULL; 272 } 273 274 *libHandle = lib; 275 return (*init_gles_func)(eglIface); 276 } 277 278 static char *queryHostEGLString(EGLint name) 279 { 280 HostConnection *hcon = HostConnection::get(); 281 if (hcon) { 282 renderControl_encoder_context_t *rcEnc = hcon->rcEncoder(); 283 if (rcEnc) { 284 int n = rcEnc->rcQueryEGLString(rcEnc, name, NULL, 0); 285 if (n < 0) { 286 // allocate space for the string. 287 char *str = (char *)malloc(-n); 288 n = rcEnc->rcQueryEGLString(rcEnc, name, str, -n); 289 if (n > 0) { 290 return str; 291 } 292 293 free(str); 294 } 295 } 296 } 297 298 return NULL; 299 } 300 301 static bool findExtInList(const char* token, int tokenlen, const char* list) 302 { 303 const char* p = list; 304 while (*p != '\0') { 305 const char* q = strchr(p, ' '); 306 if (q == NULL) { 307 /* should not happen, list must be space-terminated */ 308 break; 309 } 310 if (tokenlen == (q - p) && !memcmp(token, p, tokenlen)) { 311 return true; /* found it */ 312 } 313 p = q+1; 314 } 315 return false; /* not found */ 316 } 317 318 static char *buildExtensionString() 319 { 320 //Query host extension string 321 char *hostExt = queryHostEGLString(EGL_EXTENSIONS); 322 if (!hostExt || (hostExt[1] == '\0')) { 323 // no extensions on host - only static extension list supported 324 return strdup(systemStaticEGLExtensions); 325 } 326 327 int n = strlen(hostExt); 328 if (n > 0) { 329 char *initialEGLExts; 330 char *finalEGLExts; 331 332 HostConnection *hcon = HostConnection::get(); 333 // If we got here, we must have succeeded in queryHostEGLString 334 // and we thus should have a valid connection 335 assert(hcon); 336 337 asprintf(&initialEGLExts,"%s%s", systemStaticEGLExtensions, hostExt); 338 339 std::string dynamicEGLExtensions; 340 341 if (hcon->rcEncoder()->hasNativeSync() && 342 !strstr(initialEGLExts, kDynamicEGLExtNativeSync)) { 343 dynamicEGLExtensions += kDynamicEGLExtNativeSync; 344 } 345 346 asprintf(&finalEGLExts, "%s%s", initialEGLExts, dynamicEGLExtensions.c_str()); 347 348 free((char*)hostExt); 349 return finalEGLExts; 350 } 351 else { 352 free((char*)hostExt); 353 return strdup(systemStaticEGLExtensions); 354 } 355 } 356 357 const char *eglDisplay::queryString(EGLint name) 358 { 359 if (name == EGL_CLIENT_APIS) { 360 return "OpenGL_ES"; 361 } 362 else if (name == EGL_VERSION) { 363 pthread_mutex_lock(&m_lock); 364 if (m_versionString) { 365 pthread_mutex_unlock(&m_lock); 366 return m_versionString; 367 } 368 369 // build version string 370 asprintf(&m_versionString, "%d.%d", m_major, m_minor); 371 pthread_mutex_unlock(&m_lock); 372 373 return m_versionString; 374 } 375 else if (name == EGL_VENDOR) { 376 pthread_mutex_lock(&m_lock); 377 if (m_vendorString) { 378 pthread_mutex_unlock(&m_lock); 379 return m_vendorString; 380 } 381 382 // build vendor string 383 const char *hostVendor = queryHostEGLString(EGL_VENDOR); 384 385 if (hostVendor) { 386 asprintf(&m_vendorString, "%s Host: %s", 387 systemEGLVendor, hostVendor); 388 free((char*)hostVendor); 389 } 390 else { 391 m_vendorString = (char *)systemEGLVendor; 392 } 393 pthread_mutex_unlock(&m_lock); 394 395 return m_vendorString; 396 } 397 else if (name == EGL_EXTENSIONS) { 398 pthread_mutex_lock(&m_lock); 399 if (m_extensionString) { 400 pthread_mutex_unlock(&m_lock); 401 return m_extensionString; 402 } 403 404 // build extension string 405 m_extensionString = buildExtensionString(); 406 pthread_mutex_unlock(&m_lock); 407 408 return m_extensionString; 409 } 410 else { 411 ALOGE("[%s] Unknown name %d\n", __FUNCTION__, name); 412 return NULL; 413 } 414 } 415 416 /* To get the value of attribute <a> of config <c> use the following formula: 417 * value = *(m_configs + (int)c*m_numConfigAttribs + a); 418 */ 419 EGLBoolean eglDisplay::getAttribValue(EGLConfig config, EGLint attribIdx, EGLint * value) 420 { 421 if (attribIdx == ATTRIBUTE_NONE) 422 { 423 ALOGE("[%s] Bad attribute idx\n", __FUNCTION__); 424 return EGL_FALSE; 425 } 426 *value = *(m_configs + (intptr_t)config*m_numConfigAttribs + attribIdx); 427 return EGL_TRUE; 428 } 429 430 EGLBoolean eglDisplay::getConfigAttrib(EGLConfig config, EGLint attrib, EGLint * value) 431 { 432 //Though it seems that valueFor() is thread-safe, we don't take chanses 433 pthread_mutex_lock(&m_lock); 434 EGLBoolean ret = getAttribValue(config, m_attribs.valueFor(attrib), value); 435 pthread_mutex_unlock(&m_lock); 436 return ret; 437 } 438 439 void eglDisplay::dumpConfig(EGLConfig config) 440 { 441 EGLint value = 0; 442 DBG("^^^^^^^^^^ dumpConfig %d ^^^^^^^^^^^^^^^^^^", (int)config); 443 for (int i=0; i<m_numConfigAttribs; i++) { 444 getAttribValue(config, i, &value); 445 DBG("{%d}[%d] %d\n", (int)config, i, value); 446 } 447 } 448 449 /* To set the value of attribute <a> of config <c> use the following formula: 450 * *(m_configs + (int)c*m_numConfigAttribs + a) = value; 451 */ 452 EGLBoolean eglDisplay::setAttribValue(EGLConfig config, EGLint attribIdx, EGLint value) 453 { 454 if (attribIdx == ATTRIBUTE_NONE) 455 { 456 ALOGE("[%s] Bad attribute idx\n", __FUNCTION__); 457 return EGL_FALSE; 458 } 459 *(m_configs + (intptr_t)config*m_numConfigAttribs + attribIdx) = value; 460 return EGL_TRUE; 461 } 462 463 EGLBoolean eglDisplay::setConfigAttrib(EGLConfig config, EGLint attrib, EGLint value) 464 { 465 //Though it seems that valueFor() is thread-safe, we don't take chanses 466 pthread_mutex_lock(&m_lock); 467 EGLBoolean ret = setAttribValue(config, m_attribs.valueFor(attrib), value); 468 pthread_mutex_unlock(&m_lock); 469 return ret; 470 } 471 472 473 EGLBoolean eglDisplay::getConfigNativePixelFormat(EGLConfig config, PixelFormat * format) 474 { 475 EGLint redSize, blueSize, greenSize, alphaSize; 476 477 if ( !(getAttribValue(config, m_attribs.valueFor(EGL_RED_SIZE), &redSize) && 478 getAttribValue(config, m_attribs.valueFor(EGL_BLUE_SIZE), &blueSize) && 479 getAttribValue(config, m_attribs.valueFor(EGL_GREEN_SIZE), &greenSize) && 480 getAttribValue(config, m_attribs.valueFor(EGL_ALPHA_SIZE), &alphaSize)) ) 481 { 482 ALOGE("Couldn't find value for one of the pixel format attributes"); 483 return EGL_FALSE; 484 } 485 486 //calculate the GL internal format 487 if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==8)) *format = PIXEL_FORMAT_RGBA_8888; //XXX: BGR? 488 else if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==0)) *format = PIXEL_FORMAT_RGBX_8888; //XXX or PIXEL_FORMAT_RGB_888 489 else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = PIXEL_FORMAT_RGB_565; 490 else if ((redSize==5)&&(greenSize==5)&&(blueSize==5)&&(alphaSize==1)) *format = PIXEL_FORMAT_RGBA_5551; 491 else if ((redSize==4)&&(greenSize==4)&&(blueSize==4)&&(alphaSize==4)) *format = PIXEL_FORMAT_RGBA_4444; 492 else { 493 return EGL_FALSE; 494 } 495 return EGL_TRUE; 496 } 497 EGLBoolean eglDisplay::getConfigGLPixelFormat(EGLConfig config, GLenum * format) 498 { 499 EGLint redSize, blueSize, greenSize, alphaSize; 500 501 if ( !(getAttribValue(config, m_attribs.valueFor(EGL_RED_SIZE), &redSize) && 502 getAttribValue(config, m_attribs.valueFor(EGL_BLUE_SIZE), &blueSize) && 503 getAttribValue(config, m_attribs.valueFor(EGL_GREEN_SIZE), &greenSize) && 504 getAttribValue(config, m_attribs.valueFor(EGL_ALPHA_SIZE), &alphaSize)) ) 505 { 506 ALOGE("Couldn't find value for one of the pixel format attributes"); 507 return EGL_FALSE; 508 } 509 510 //calculate the GL internal format 511 if ((redSize == greenSize) && (redSize == blueSize) && 512 ((redSize == 8) || (redSize == 16) || (redSize == 32))) 513 { 514 if (alphaSize == 0) *format = GL_RGB; 515 else *format = GL_RGBA; 516 } 517 else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = GL_RGB565_OES; 518 else if ((redSize==5)&&(greenSize==5)&&(blueSize==5)&&(alphaSize==1)) *format = GL_RGB5_A1_OES; 519 else if ((redSize==4)&&(greenSize==4)&&(blueSize==4)&&(alphaSize==4)) *format = GL_RGBA4_OES; 520 else return EGL_FALSE; 521 522 return EGL_TRUE; 523 } 524 525 void eglDisplay::onCreateContext(EGLContext ctx) { 526 pthread_mutex_lock(&m_ctxLock); 527 m_contexts.insert(ctx); 528 pthread_mutex_unlock(&m_ctxLock); 529 } 530 531 void eglDisplay::onCreateSurface(EGLSurface surface) { 532 pthread_mutex_lock(&m_surfaceLock); 533 m_surfaces.insert(surface); 534 pthread_mutex_unlock(&m_surfaceLock); 535 } 536 537 void eglDisplay::onDestroyContext(EGLContext ctx) { 538 pthread_mutex_lock(&m_ctxLock); 539 m_contexts.erase(ctx); 540 pthread_mutex_unlock(&m_ctxLock); 541 } 542 543 void eglDisplay::onDestroySurface(EGLSurface surface) { 544 pthread_mutex_lock(&m_surfaceLock); 545 m_surfaces.erase(surface); 546 pthread_mutex_unlock(&m_surfaceLock); 547 } 548 549