egl.cpp revision a4205ba264bd96ddf44429de7973291ce437249e
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 17// 18// WARNING -------------------------- WARNING 19// This code meant to be used for testing purposes only. It is not production 20// level quality. 21// Use on your own risk !! 22// 23 24#include <stdio.h> 25#include <stdlib.h> 26#include <string.h> 27#include <dlfcn.h> 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" 34#include <pthread.h> 35 36 37#define GLES_EMUL_TARGETS_FILE "/system/etc/gles_emul.cfg" 38 39static struct egl_dispatch *s_dispatch = NULL; 40pthread_once_t dispatchTablesInitialized = PTHREAD_ONCE_INIT; 41 42static bool s_needEncode = false; 43 44extern void init_gles(void *gles_android); 45extern __eglMustCastToProperFunctionPointerType gles_getProcAddress(const char *procname); 46 47 48const char *getProcName() 49{ 50 static const char *procname = NULL; 51 52 if (procname == NULL) { 53 const char *str = get_process_name(); 54 if (strcmp(str, "unknown") != 0) { 55 procname = str; 56 } else { 57 // we need to obtain our process name from the command line; 58 FILE *fp = fopen("/proc/self/cmdline", "rt"); 59 if (fp == NULL) { 60 LOGE("couldn't open /proc/self/cmdline\n"); 61 return NULL; 62 } 63 64 char line[1000]; 65 if (fgets(line, sizeof(line), fp) == NULL) { 66 LOGE("couldn't read the self cmdline from \n"); 67 fclose(fp); 68 return NULL; 69 } 70 fclose(fp); 71 72 if (line[0] == '\0') { 73 LOGE("cmdline is empty\n"); 74 return NULL; 75 } 76 77 //obtain the basename; 78 line[sizeof(line) - 1] = '\0'; 79 char *p = line; 80 while (*p != '\0' && 81 *p != '\t' && 82 *p != ' ' && 83 *p != '\n') { 84 p++; 85 } 86 87 *p = '\0'; p--; 88 while (p > line && *p != '/') p--; 89 if (*p == '/') p++; 90 procname = strdup(p); 91 } 92 } 93 LOGD("getProcessName: %s\n", procname == NULL ? "NULL": procname); 94 95 return procname; 96} 97 98 99 100bool isNeedEncode() 101{ 102 const char *procname = getProcName(); 103 if (procname == NULL) return false; 104 LOGD("isNeedEncode? for %s\n", procname); 105 // check on our whitelist 106 FILE *fp = fopen(GLES_EMUL_TARGETS_FILE, "rt"); 107 if (fp == NULL) { 108 LOGE("couldn't open %s\n", GLES_EMUL_TARGETS_FILE); 109 return false; 110 } 111 112 char line[100]; 113 bool found = false; 114 size_t procnameLen = strlen(procname); 115 116 while (fgets(line, sizeof(line), fp) != NULL) { 117 if (strlen(line) >= procnameLen && 118 !strncmp(procname, line, procnameLen)) { 119 char c = line[procnameLen]; 120 if (c == '\0' || c == ' ' || c == '\t' || c == '\n') { 121 found = true; 122 LOGD("should use encoder for %s\n", procname); 123 break; 124 } 125 } 126 } 127 fclose(fp); 128 return found; 129} 130 131void initDispatchTables() 132{ 133 // 134 // Load our back-end implementation of EGL/GLES 135 // 136 LOGD("Loading egl dispatch for %s\n", getProcName()); 137 138 void *gles_android = dlopen("/system/lib/egl/libGLES_android.so", RTLD_NOW | RTLD_LOCAL); 139 if (!gles_android) { 140 fprintf(stderr,"FATAL ERROR: Could not load libGLES_android lib\n"); 141 exit(-1); 142 } 143 144 // 145 // Load back-end EGL implementation library 146 // 147 s_dispatch = create_egl_dispatch( gles_android ); 148 if (!s_dispatch) { 149 fprintf(stderr,"FATAL ERROR: Could not create egl dispatch\n"); 150 exit(-1); 151 } 152 153 // 154 // initialize gles 155 // 156 s_needEncode = isNeedEncode(); 157 void *gles_encoder = NULL; 158 if (s_needEncode) { 159 ServerConnection * connection = ServerConnection::s_getServerConnection(); 160 if (connection == NULL) { 161 LOGE("couldn't create server connection\n"); 162 s_needEncode = false; 163 } else { 164 LOGD("Created server connection for %s\n", getProcName()); 165 gles_encoder = dlopen("/system/lib/libGLESv1_enc.so", RTLD_NOW); 166 if (gles_encoder == NULL) { 167 LOGE("couldn't open libGLESv1_enc.so... aborting connection"); 168 delete connection; 169 s_needEncode = false; 170 } 171 } 172 } 173 174 if (s_needEncode && gles_encoder) { 175 init_gles(gles_encoder); 176 } else { 177 LOGD("Initializing native opengl for %s\n", getProcName()); 178 init_gles(gles_android); 179 } 180} 181 182static struct egl_dispatch *getDispatch() 183{ 184 pthread_once(&dispatchTablesInitialized, initDispatchTables); 185 return s_dispatch; 186} 187 188__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) 189{ 190 191 // search in EGL function table 192 for (int i=0; i<egl_num_funcs; i++) { 193 if (!strcmp(egl_funcs_by_name[i].name, procname)) { 194 return (__eglMustCastToProperFunctionPointerType)egl_funcs_by_name[i].proc; 195 } 196 } 197 198 // search in GLES function table 199 __eglMustCastToProperFunctionPointerType f = gles_getProcAddress(procname); 200 if (f != NULL) { 201 return f; 202 } 203 204 // should probably fail - search in back-end anyway. 205 return getDispatch()->eglGetProcAddress(procname); 206} 207 208//////////////// Path through functions ////////// 209 210EGLint eglGetError() 211{ 212 return getDispatch()->eglGetError(); 213} 214 215EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) 216{ 217 return getDispatch()->eglGetDisplay(display_id); 218} 219 220EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) 221{ 222 return getDispatch()->eglInitialize(dpy, major, minor); 223} 224 225EGLBoolean eglTerminate(EGLDisplay dpy) 226{ 227 return getDispatch()->eglTerminate(dpy); 228} 229 230const char* eglQueryString(EGLDisplay dpy, EGLint name) 231{ 232 return getDispatch()->eglQueryString(dpy, name); 233} 234 235EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) 236{ 237 return getDispatch()->eglGetConfigs(dpy, configs, config_size, num_config); 238} 239 240EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) 241{ 242 return getDispatch()->eglChooseConfig(dpy, attrib_list, configs, config_size, num_config); 243} 244 245EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) 246{ 247 return getDispatch()->eglGetConfigAttrib(dpy, config, attribute, value); 248} 249 250EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) 251{ 252 EGLSurface surface = getDispatch()->eglCreateWindowSurface(dpy, config, win, attrib_list); 253 if (surface != EGL_NO_SURFACE) { 254 ServerConnection *server; 255 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) { 256 server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface); 257 } 258 } 259 return surface; 260} 261 262EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) 263{ 264 EGLSurface surface = getDispatch()->eglCreatePbufferSurface(dpy, config, attrib_list); 265 if (surface != EGL_NO_SURFACE) { 266 ServerConnection *server; 267 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) { 268 server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface); 269 } 270 } 271 return surface; 272} 273 274EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) 275{ 276 EGLSurface surface = getDispatch()->eglCreatePixmapSurface(dpy, config, pixmap, attrib_list); 277 if (surface != EGL_NO_SURFACE) { 278 ServerConnection *server; 279 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) { 280 server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface); 281 } 282 } 283 return surface; 284} 285 286EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) 287{ 288 EGLBoolean res = getDispatch()->eglDestroySurface(dpy, surface); 289 if (res && surface != EGL_NO_SURFACE) { 290 ServerConnection *server; 291 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) { 292 server->utEnc()->destroySurface(server->utEnc(), getpid(), (uint32_t)surface); 293 } 294 } 295 return res; 296} 297 298EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) 299{ 300 return getDispatch()->eglQuerySurface(dpy, surface, attribute, value); 301} 302 303EGLBoolean eglBindAPI(EGLenum api) 304{ 305 return getDispatch()->eglBindAPI(api); 306} 307 308EGLenum eglQueryAPI() 309{ 310 return getDispatch()->eglQueryAPI(); 311} 312 313EGLBoolean eglWaitClient() 314{ 315 return getDispatch()->eglWaitClient(); 316} 317 318EGLBoolean eglReleaseThread() 319{ 320 return getDispatch()->eglReleaseThread(); 321} 322 323EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) 324{ 325 return getDispatch()->eglCreatePbufferFromClientBuffer(dpy, buftype, buffer, config, attrib_list); 326} 327 328EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) 329{ 330 return getDispatch()->eglSurfaceAttrib(dpy, surface, attribute, value); 331} 332 333EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) 334{ 335 return getDispatch()->eglBindTexImage(dpy, surface, buffer); 336} 337 338EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) 339{ 340 return getDispatch()->eglReleaseTexImage(dpy, surface, buffer); 341} 342 343EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) 344{ 345 return getDispatch()->eglSwapInterval(dpy, interval); 346} 347 348EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) 349{ 350 EGLContext share = share_context; 351 if (share) share = ((EGLWrapperContext *)share_context)->aglContext; 352 353 EGLContext ctx = getDispatch()->eglCreateContext(dpy, config, share, attrib_list); 354 EGLWrapperContext *wctx = new EGLWrapperContext(ctx); 355 if (ctx != EGL_NO_CONTEXT) { 356 ServerConnection *server; 357 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) { 358 wctx->clientState = new GLClientState(); 359 server->utEnc()->createContext(server->utEnc(), getpid(), 360 (uint32_t)wctx, 361 (uint32_t)(share_context == EGL_NO_CONTEXT ? 0 : share_context)); 362 } 363 } 364 return (EGLContext)wctx; 365} 366 367EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) 368{ 369 EGLWrapperContext *wctx = (EGLWrapperContext *)ctx; 370 EGLBoolean res = EGL_FALSE; 371 372 if (ctx && ctx != EGL_NO_CONTEXT) { 373 res = getDispatch()->eglDestroyContext(dpy, wctx->aglContext); 374 if (res) { 375 EGLThreadInfo *ti = getEGLThreadInfo(); 376 if (s_needEncode && ti->serverConn) { 377 ti->serverConn->utEnc()->destroyContext(ti->serverConn->utEnc(), getpid(), (uint32_t)ctx); 378 } 379 if (ti->currentContext == wctx) ti->currentContext = NULL; 380 delete wctx; 381 } 382 } 383 384 return res; 385} 386 387EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) 388{ 389 EGLWrapperContext *wctx = (EGLWrapperContext *)ctx; 390 EGLContext aglContext = (ctx == EGL_NO_CONTEXT ? EGL_NO_CONTEXT : wctx->aglContext); 391 EGLThreadInfo *ti = getEGLThreadInfo(); 392 EGLBoolean res = getDispatch()->eglMakeCurrent(dpy, draw, read, aglContext); 393 if (res ) { 394 ServerConnection *server; 395 if (s_needEncode && ti->serverConn) { 396 ti->serverConn->utEnc()->makeCurrentContext(ti->serverConn->utEnc(), getpid(), 397 (uint32_t) (draw == EGL_NO_SURFACE ? 0 : draw), 398 (uint32_t) (read == EGL_NO_SURFACE ? 0 : read), 399 (uint32_t) (ctx == EGL_NO_CONTEXT ? 0 : ctx)); 400 ti->serverConn->glEncoder()->setClientState( wctx ? wctx->clientState : NULL ); 401 } 402 403 // set current context in our thread info 404 ti->currentContext = wctx; 405 } 406 return res; 407 408} 409 410EGLContext eglGetCurrentContext() 411{ 412 EGLThreadInfo *ti = getEGLThreadInfo(); 413 return (ti->currentContext ? ti->currentContext : EGL_NO_CONTEXT); 414} 415 416EGLSurface eglGetCurrentSurface(EGLint readdraw) 417{ 418 return getDispatch()->eglGetCurrentSurface(readdraw); 419} 420 421EGLDisplay eglGetCurrentDisplay() 422{ 423 return getDispatch()->eglGetCurrentDisplay(); 424} 425 426EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) 427{ 428 EGLWrapperContext *wctx = (EGLWrapperContext *)ctx; 429 if (wctx) { 430 return getDispatch()->eglQueryContext(dpy, wctx->aglContext, attribute, value); 431 } 432 else { 433 return EGL_BAD_CONTEXT; 434 } 435} 436 437EGLBoolean eglWaitGL() 438{ 439 return getDispatch()->eglWaitGL(); 440} 441 442EGLBoolean eglWaitNative(EGLint engine) 443{ 444 return getDispatch()->eglWaitNative(engine); 445} 446 447EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) 448{ 449 ServerConnection *server; 450 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) { 451 server->utEnc()->swapBuffers(server->utEnc(), getpid(), (uint32_t)surface); 452 server->glEncoder()->flush(); 453 return 1; 454 } 455 return getDispatch()->eglSwapBuffers(dpy, surface); 456} 457 458EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) 459{ 460 return getDispatch()->eglCopyBuffers(dpy, surface, target); 461} 462 463EGLBoolean eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list) 464{ 465 return getDispatch()->eglLockSurfaceKHR(display, surface, attrib_list); 466} 467 468EGLBoolean eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface) 469{ 470 return getDispatch()->eglUnlockSurfaceKHR(display, surface); 471} 472 473EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) 474{ 475 EGLWrapperContext *wctx = (EGLWrapperContext *)ctx; 476 EGLContext aglContext = (wctx ? wctx->aglContext : EGL_NO_CONTEXT); 477 return getDispatch()->eglCreateImageKHR(dpy, aglContext, target, buffer, attrib_list); 478} 479 480EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) 481{ 482 return getDispatch()->eglDestroyImageKHR(dpy, image); 483} 484 485EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) 486{ 487 return getDispatch()->eglCreateSyncKHR(dpy, type, attrib_list); 488} 489 490EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) 491{ 492 return getDispatch()->eglDestroySyncKHR(dpy, sync); 493} 494 495EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) 496{ 497 return getDispatch()->eglClientWaitSyncKHR(dpy, sync, flags, timeout); 498} 499 500EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) 501{ 502 return getDispatch()->eglSignalSyncKHR(dpy, sync, mode); 503} 504 505EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) 506{ 507 return getDispatch()->eglGetSyncAttribKHR(dpy, sync, attribute, value); 508} 509 510EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height) 511{ 512 return getDispatch()->eglSetSwapRectangleANDROID(dpy, draw, left, top, width, height); 513} 514