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