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