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