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