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