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