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