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