2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 // WARNING -------------------------- WARNING
19 // This code meant to be used for testing purposes only. It is not production
21 // Use on your own risk !!
28 #include "egl_dispatch.h"
29 #include "egl_ftable.h"
30 #include <cutils/process_name.h>
31 #include <cutils/log.h>
32 #include "ServerConnection.h"
33 #include "ThreadInfo.h"
35 #include "gl_wrapper_context.h"
36 #include "gl2_wrapper_context.h"
38 #define GLES_EMUL_TARGETS_FILE "/system/etc/gles_emul.cfg"
39 // implementation libraries;
40 #define GLESv1_enc_LIB "/system/lib/libGLESv1_enc.so"
41 #define GLESv2_enc_LIB "/system/lib/libGLESv2_enc.so"
42 #define GLES_android_LIB "/system/lib/egl/libGLES_android.so"
44 #define GLESv1_DRIVER "/system/lib/egl/libGLESv1_CM_emul.so"
45 #define GLESv2_DRIVER "/system/lib/egl/libGLESv2_emul.so"
48 static struct egl_dispatch *s_dispatch = NULL;
49 pthread_once_t dispatchTablesInitialized = PTHREAD_ONCE_INIT;
51 static bool s_needEncode = false;
53 static gl_wrapper_context_t *g_gl_dispatch = NULL;
54 static gl2_wrapper_context_t *g_gl2_dispatch = NULL;
57 int initApi(const char *driverLibName, const char *implLibName, T **dispatchTable, T *(*accessor)())
59 void *driverLib = dlopen(driverLibName, RTLD_NOW | RTLD_LOCAL);
60 if (driverLib == NULL) {
61 ALOGE("failed to load %s : %s\n", driverLibName, dlerror());
65 typedef T *(*createFcn_t)(void *, T *(*accessor)());
66 createFcn_t createFcn;
67 createFcn = (createFcn_t) dlsym(driverLib, "createFromLib");
68 if (createFcn == NULL) {
69 ALOGE("failed to load createFromLib constructor function\n");
73 void *implLib = dlopen(implLibName, RTLD_NOW | RTLD_LOCAL);
74 if (implLib == NULL) {
75 ALOGE("couldn't open %s", implLibName);
78 *dispatchTable = createFcn(implLib, accessor);
79 if (*dispatchTable == NULL) {
83 // XXX - we do close the impl library since it doesn't have data, as far as we concern.
86 // XXX - we do not dlclose the driver library, so its not initialized when
87 // later loaded by android - is this required?
88 ALOGD("loading %s into %s complete\n", implLibName, driverLibName);
93 static gl_wrapper_context_t *getGLContext()
98 static gl2_wrapper_context_t *getGL2Context()
100 return g_gl2_dispatch;
103 const char *getProcName()
105 static const char *procname = NULL;
107 if (procname == NULL) {
108 const char *str = get_process_name();
109 if (strcmp(str, "unknown") != 0) {
112 // we need to obtain our process name from the command line;
113 FILE *fp = fopen("/proc/self/cmdline", "rt");
115 ALOGE("couldn't open /proc/self/cmdline\n");
120 if (fgets(line, sizeof(line), fp) == NULL) {
121 ALOGE("couldn't read the self cmdline from \n");
127 if (line[0] == '\0') {
128 ALOGE("cmdline is empty\n");
132 //obtain the basename;
133 line[sizeof(line) - 1] = '\0';
143 while (p > line && *p != '/') p--;
145 procname = strdup(p);
156 const char *procname = getProcName();
157 if (procname == NULL) return false;
158 ALOGD("isNeedEncode? for %s\n", procname);
159 // check on our whitelist
160 FILE *fp = fopen(GLES_EMUL_TARGETS_FILE, "rt");
162 ALOGE("couldn't open %s\n", GLES_EMUL_TARGETS_FILE);
168 size_t procnameLen = strlen(procname);
170 while (fgets(line, sizeof(line), fp) != NULL) {
171 if (strlen(line) >= procnameLen &&
172 !strncmp(procname, line, procnameLen)) {
173 char c = line[procnameLen];
174 if (c == '\0' || c == ' ' || c == '\t' || c == '\n') {
176 ALOGD("should use encoder for %s\n", procname);
185 void initDispatchTables()
188 // Load our back-end implementation of EGL/GLES
190 ALOGD("Loading egl dispatch for %s\n", getProcName());
192 void *gles_android = dlopen("/system/lib/egl/libGLES_android.so", RTLD_NOW | RTLD_LOCAL);
194 fprintf(stderr,"FATAL ERROR: Could not load libGLES_android lib\n");
199 // Load back-end EGL implementation library
201 s_dispatch = create_egl_dispatch( gles_android );
203 fprintf(stderr,"FATAL ERROR: Could not create egl dispatch\n");
210 s_needEncode = isNeedEncode();
211 void *gles_encoder = NULL;
213 // initialize a connection to the server, and the GLESv1/v2 encoders;
214 ServerConnection * connection = ServerConnection::s_getServerConnection();
215 if (connection == NULL) {
216 ALOGE("couldn't create server connection\n");
217 s_needEncode = false;
221 // init dispatch tabels for GLESv1 & GLESv2
223 // XXX - we do not check the retrun value because there isn't much we can do here on failure.
225 if (initApi<gl_wrapper_context_t>(GLESv1_DRIVER, GLESv1_enc_LIB, &g_gl_dispatch, getGLContext) < 0) {
226 // fallback to android on faluire
227 s_needEncode = false;
229 initApi<gl2_wrapper_context_t>(GLESv2_DRIVER, GLESv2_enc_LIB, &g_gl2_dispatch, getGL2Context);
234 ALOGD("Initializing native opengl for %s\n", getProcName());
235 initApi<gl_wrapper_context_t>(GLESv1_DRIVER, GLES_android_LIB, &g_gl_dispatch, getGLContext);
236 // try to initialize gl2 from GLES, though its probably going to fail
237 initApi<gl2_wrapper_context_t>(GLESv2_DRIVER, GLES_android_LIB, &g_gl2_dispatch, getGL2Context);
241 static struct egl_dispatch *getDispatch()
243 pthread_once(&dispatchTablesInitialized, initDispatchTables);
247 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
250 // search in EGL function table
251 for (int i=0; i<egl_num_funcs; i++) {
252 if (!strcmp(egl_funcs_by_name[i].name, procname)) {
253 return (__eglMustCastToProperFunctionPointerType)egl_funcs_by_name[i].proc;
257 // we do not support eglGetProcAddress for GLESv1 & GLESv2. The loader
258 // should be able to find this function through dynamic loading.
262 //////////////// Path through functions //////////
266 return getDispatch()->eglGetError();
269 EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id)
271 return getDispatch()->eglGetDisplay(display_id);
274 EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
276 return getDispatch()->eglInitialize(dpy, major, minor);
279 EGLBoolean eglTerminate(EGLDisplay dpy)
281 return getDispatch()->eglTerminate(dpy);
284 const char* eglQueryString(EGLDisplay dpy, EGLint name)
286 return getDispatch()->eglQueryString(dpy, name);
289 EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
291 return getDispatch()->eglGetConfigs(dpy, configs, config_size, num_config);
294 static EGLint * filter_es2_bit(const EGLint *attrib_list, bool *isES2)
296 if (attrib_list == NULL) {
297 if (isES2 != NULL) *isES2 = false;
301 EGLint *attribs = NULL;
303 while(attrib_list[nAttribs] != EGL_NONE) nAttribs++;
306 attribs = new EGLint[nAttribs];
307 memcpy(attribs, attrib_list, nAttribs * sizeof(EGLint));
308 if (isES2 != NULL) *isES2 = false;
310 // scan the attribute list for ES2 request and replace with ES1.
311 for (int i = 0; i < nAttribs; i++) {
312 if (attribs[i] == EGL_RENDERABLE_TYPE) {
313 if (attribs[i + 1] & EGL_OPENGL_ES2_BIT) {
314 attribs[i + 1] &= ~EGL_OPENGL_ES2_BIT;
315 attribs[i + 1] |= EGL_OPENGL_ES_BIT;
316 ALOGD("removing ES2 bit 0x%x\n", attribs[i + 1]);
317 if (isES2 != NULL) *isES2 = true;
324 EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
328 EGLint *attribs = filter_es2_bit(attrib_list, NULL);
329 res = getDispatch()->eglChooseConfig(dpy,
334 ALOGD("eglChooseConfig: %d configs found\n", *num_config);
335 if (*num_config == 0 && attribs != NULL) {
336 ALOGD("requested attributes:\n");
337 for (int i = 0; attribs[i] != EGL_NONE; i++) {
338 ALOGD("%d: 0x%x\n", i, attribs[i]);
344 res = getDispatch()->eglChooseConfig(dpy, attrib_list, configs, config_size, num_config);
349 EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
351 if (s_needEncode && attribute == EGL_RENDERABLE_TYPE) {
352 *value = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT;
355 return getDispatch()->eglGetConfigAttrib(dpy, config, attribute, value);
359 EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
361 EGLSurface surface = getDispatch()->eglCreateWindowSurface(dpy, config, win, attrib_list);
362 if (surface != EGL_NO_SURFACE) {
363 ServerConnection *server;
364 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
365 server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface);
371 EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
373 EGLSurface surface = getDispatch()->eglCreatePbufferSurface(dpy, config, attrib_list);
374 if (surface != EGL_NO_SURFACE) {
375 ServerConnection *server;
376 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
377 server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface);
383 EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
385 EGLSurface surface = getDispatch()->eglCreatePixmapSurface(dpy, config, pixmap, attrib_list);
386 if (surface != EGL_NO_SURFACE) {
387 ServerConnection *server;
388 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
389 server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface);
395 EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
397 EGLBoolean res = getDispatch()->eglDestroySurface(dpy, surface);
398 if (res && surface != EGL_NO_SURFACE) {
399 ServerConnection *server;
400 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
401 server->utEnc()->destroySurface(server->utEnc(), getpid(), (uint32_t)surface);
407 EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value)
409 EGLBoolean res = getDispatch()->eglQuerySurface(dpy, surface, attribute, value);
410 if (res && attribute == EGL_RENDERABLE_TYPE) {
411 *value |= EGL_OPENGL_ES2_BIT;
416 EGLBoolean eglBindAPI(EGLenum api)
418 return getDispatch()->eglBindAPI(api);
421 EGLenum eglQueryAPI()
423 return getDispatch()->eglQueryAPI();
426 EGLBoolean eglWaitClient()
428 return getDispatch()->eglWaitClient();
431 EGLBoolean eglReleaseThread()
433 return getDispatch()->eglReleaseThread();
436 EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
438 return getDispatch()->eglCreatePbufferFromClientBuffer(dpy, buftype, buffer, config, attrib_list);
441 EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
443 return getDispatch()->eglSurfaceAttrib(dpy, surface, attribute, value);
446 EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
448 return getDispatch()->eglBindTexImage(dpy, surface, buffer);
451 EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
453 return getDispatch()->eglReleaseTexImage(dpy, surface, buffer);
456 EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
458 return getDispatch()->eglSwapInterval(dpy, interval);
461 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
464 EGLContext share = share_context;
465 if (share) share = ((EGLWrapperContext *)share_context)->aglContext;
467 // check if are ES2, and convert it to ES1.
469 if (attrib_list != NULL) {
470 while(attrib_list[nAttribs] != EGL_NONE) {
476 EGLint *attrib = NULL;
478 attrib = new EGLint[nAttribs];
479 memcpy(attrib, attrib_list, nAttribs * sizeof(EGLint));
483 for (int i = 0; i < nAttribs; i++) {
484 if (attrib[i] == EGL_CONTEXT_CLIENT_VERSION &&
485 attrib[i + 1] == 2) {
487 attrib[i + 1] = 1; // replace to version 1
491 EGLContext ctx = getDispatch()->eglCreateContext(dpy, config, share, attrib);
493 EGLWrapperContext *wctx = new EGLWrapperContext(ctx, version);
494 if (ctx != EGL_NO_CONTEXT) {
495 ServerConnection *server;
496 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
497 wctx->clientState = new GLClientState();
498 server->utEnc()->createContext(server->utEnc(), getpid(),
500 (uint32_t)(share_context == EGL_NO_CONTEXT ? 0 : share_context), wctx->version);
503 return (EGLContext)wctx;
506 EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
508 EGLWrapperContext *wctx = (EGLWrapperContext *)ctx;
509 EGLBoolean res = EGL_FALSE;
511 if (ctx && ctx != EGL_NO_CONTEXT) {
512 res = getDispatch()->eglDestroyContext(dpy, wctx->aglContext);
514 EGLThreadInfo *ti = getEGLThreadInfo();
515 ServerConnection *server;
516 if (s_needEncode && (server = ServerConnection::s_getServerConnection())) {
517 server->utEnc()->destroyContext(ti->serverConn->utEnc(), getpid(), (uint32_t)ctx);
519 if (ti->currentContext == wctx) ti->currentContext = NULL;
527 EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
529 EGLWrapperContext *wctx = (EGLWrapperContext *)ctx;
530 EGLContext aglContext = (ctx == EGL_NO_CONTEXT ? EGL_NO_CONTEXT : wctx->aglContext);
531 EGLThreadInfo *ti = getEGLThreadInfo();
532 EGLBoolean res = getDispatch()->eglMakeCurrent(dpy, draw, read, aglContext);
534 // NOTE - we do get a pointer to the server connection, (rather then using ti->serverConn)
535 // for cases that this is the first egl call of the current thread.
537 ServerConnection *server;
538 if (s_needEncode && (server = ServerConnection::s_getServerConnection())) {
539 server->utEnc()->makeCurrentContext(server->utEnc(), getpid(),
540 (uint32_t) (draw == EGL_NO_SURFACE ? 0 : draw),
541 (uint32_t) (read == EGL_NO_SURFACE ? 0 : read),
542 (uint32_t) (ctx == EGL_NO_CONTEXT ? 0 : ctx));
543 server->glEncoder()->setClientState( wctx ? wctx->clientState : NULL );
544 server->gl2Encoder()->setClientState( wctx ? wctx->clientState : NULL );
547 // set current context in our thread info
548 ti->currentContext = wctx;
554 EGLContext eglGetCurrentContext()
556 EGLThreadInfo *ti = getEGLThreadInfo();
557 return (ti->currentContext ? ti->currentContext : EGL_NO_CONTEXT);
560 EGLSurface eglGetCurrentSurface(EGLint readdraw)
562 return getDispatch()->eglGetCurrentSurface(readdraw);
565 EGLDisplay eglGetCurrentDisplay()
567 return getDispatch()->eglGetCurrentDisplay();
570 EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
572 EGLWrapperContext *wctx = (EGLWrapperContext *)ctx;
574 if (attribute == EGL_CONTEXT_CLIENT_VERSION) {
575 *value = wctx->version;
578 return getDispatch()->eglQueryContext(dpy, wctx->aglContext, attribute, value);
582 return EGL_BAD_CONTEXT;
586 EGLBoolean eglWaitGL()
588 return getDispatch()->eglWaitGL();
591 EGLBoolean eglWaitNative(EGLint engine)
593 return getDispatch()->eglWaitNative(engine);
596 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
598 ServerConnection *server;
599 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
600 server->utEnc()->swapBuffers(server->utEnc(), getpid(), (uint32_t)surface);
601 server->glEncoder()->flush();
602 server->gl2Encoder()->flush();
605 return getDispatch()->eglSwapBuffers(dpy, surface);
608 EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
610 return getDispatch()->eglCopyBuffers(dpy, surface, target);
613 EGLBoolean eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list)
615 return getDispatch()->eglLockSurfaceKHR(display, surface, attrib_list);
618 EGLBoolean eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface)
620 return getDispatch()->eglUnlockSurfaceKHR(display, surface);
623 EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
625 EGLWrapperContext *wctx = (EGLWrapperContext *)ctx;
626 EGLContext aglContext = (wctx ? wctx->aglContext : EGL_NO_CONTEXT);
627 return getDispatch()->eglCreateImageKHR(dpy, aglContext, target, buffer, attrib_list);
630 EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
632 return getDispatch()->eglDestroyImageKHR(dpy, image);
635 EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
637 return getDispatch()->eglCreateSyncKHR(dpy, type, attrib_list);
640 EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
642 return getDispatch()->eglDestroySyncKHR(dpy, sync);
645 EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
647 return getDispatch()->eglClientWaitSyncKHR(dpy, sync, flags, timeout);
650 EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode)
652 return getDispatch()->eglSignalSyncKHR(dpy, sync, mode);
655 EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
657 return getDispatch()->eglGetSyncAttribKHR(dpy, sync, attribute, value);
660 EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height)
662 return getDispatch()->eglSetSwapRectangleANDROID(dpy, draw, left, top, width, height);