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