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