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