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/log.h> 31#include "ServerConnection.h" 32#include "ThreadInfo.h" 33#include <pthread.h> 34#include "gl_wrapper_context.h" 35#include "gl2_wrapper_context.h" 36 37#define GLES_EMUL_TARGETS_FILE "/system/etc/gles_emul.cfg" 38// implementation libraries; 39#define GLESv1_enc_LIB "/system/lib/libGLESv1_enc.so" 40#define GLESv2_enc_LIB "/system/lib/libGLESv2_enc.so" 41#define GLES_android_LIB "/system/lib/egl/libGLES_android.so" 42// driver libraries; 43#define GLESv1_DRIVER "/system/lib/egl/libGLESv1_CM_emul.so" 44#define GLESv2_DRIVER "/system/lib/egl/libGLESv2_emul.so" 45 46 47static struct egl_dispatch *s_dispatch = NULL; 48pthread_once_t dispatchTablesInitialized = PTHREAD_ONCE_INIT; 49 50static bool s_needEncode = false; 51 52static gl_wrapper_context_t *g_gl_dispatch = NULL; 53static gl2_wrapper_context_t *g_gl2_dispatch = NULL; 54 55template <class T> 56int initApi(const char *driverLibName, const char *implLibName, T **dispatchTable, T *(*accessor)()) 57{ 58 void *driverLib = dlopen(driverLibName, RTLD_NOW | RTLD_LOCAL); 59 if (driverLib == NULL) { 60 ALOGE("failed to load %s : %s\n", driverLibName, dlerror()); 61 return -1; 62 } 63 64 typedef T *(*createFcn_t)(void *, T *(*accessor)()); 65 createFcn_t createFcn; 66 createFcn = (createFcn_t) dlsym(driverLib, "createFromLib"); 67 if (createFcn == NULL) { 68 ALOGE("failed to load createFromLib constructor function\n"); 69 return -1; 70 } 71 72 void *implLib = dlopen(implLibName, RTLD_NOW | RTLD_LOCAL); 73 if (implLib == NULL) { 74 ALOGE("couldn't open %s", implLibName); 75 return -2; 76 } 77 *dispatchTable = createFcn(implLib, accessor); 78 if (*dispatchTable == NULL) { 79 return -3; 80 } 81 82 // XXX - we do close the impl library since it doesn't have data, as far as we concern. 83 dlclose(implLib); 84 85 // XXX - we do not dlclose the driver library, so its not initialized when 86 // later loaded by android - is this required? 87 ALOGD("loading %s into %s complete\n", implLibName, driverLibName); 88 return 0; 89 90} 91 92static gl_wrapper_context_t *getGLContext() 93{ 94 return g_gl_dispatch; 95} 96 97static gl2_wrapper_context_t *getGL2Context() 98{ 99 return g_gl2_dispatch; 100} 101 102const char *getProcName() 103{ 104 static constexpr size_t kMaxProcessNameLength = 100; 105 static const char procname[kMaxProcessNameLength]{0}; 106 107 int rc = pthread_getname_np(pthread_self(), procname, kMaxProcessNameLength); 108 109 if (rc == 0) { 110 return procname; 111 } 112 113 return nullptr; 114} 115 116 117 118bool isNeedEncode() 119{ 120 const char *procname = getProcName(); 121 if (procname == NULL) return false; 122 ALOGD("isNeedEncode? for %s\n", procname); 123 // check on our whitelist 124 FILE *fp = fopen(GLES_EMUL_TARGETS_FILE, "rt"); 125 if (fp == NULL) { 126 ALOGE("couldn't open %s\n", GLES_EMUL_TARGETS_FILE); 127 return false; 128 } 129 130 char line[100]; 131 bool found = false; 132 size_t procnameLen = strlen(procname); 133 134 while (fgets(line, sizeof(line), fp) != NULL) { 135 if (strlen(line) >= procnameLen && 136 !strncmp(procname, line, procnameLen)) { 137 char c = line[procnameLen]; 138 if (c == '\0' || c == ' ' || c == '\t' || c == '\n') { 139 found = true; 140 ALOGD("should use encoder for %s\n", procname); 141 break; 142 } 143 } 144 } 145 fclose(fp); 146 return found; 147} 148 149void initDispatchTables() 150{ 151 // 152 // Load our back-end implementation of EGL/GLES 153 // 154 ALOGD("Loading egl dispatch for %s\n", getProcName()); 155 156 void *gles_android = dlopen("/system/lib/egl/libGLES_android.so", RTLD_NOW | RTLD_LOCAL); 157 if (!gles_android) { 158 fprintf(stderr,"FATAL ERROR: Could not load libGLES_android lib\n"); 159 exit(-1); 160 } 161 162 // 163 // Load back-end EGL implementation library 164 // 165 s_dispatch = create_egl_dispatch( gles_android ); 166 if (!s_dispatch) { 167 fprintf(stderr,"FATAL ERROR: Could not create egl dispatch\n"); 168 exit(-1); 169 } 170 171 // 172 // initialize gles 173 // 174 s_needEncode = isNeedEncode(); 175 void *gles_encoder = NULL; 176 if (s_needEncode) { 177 // initialize a connection to the server, and the GLESv1/v2 encoders; 178 ServerConnection * connection = ServerConnection::s_getServerConnection(); 179 if (connection == NULL) { 180 ALOGE("couldn't create server connection\n"); 181 s_needEncode = false; 182 } 183 } 184 185 // init dispatch tabels for GLESv1 & GLESv2 186 if (s_needEncode) { 187 // XXX - we do not check the retrun value because there isn't much we can do here on failure. 188 189 if (initApi<gl_wrapper_context_t>(GLESv1_DRIVER, GLESv1_enc_LIB, &g_gl_dispatch, getGLContext) < 0) { 190 // fallback to android on faluire 191 s_needEncode = false; 192 } else { 193 initApi<gl2_wrapper_context_t>(GLESv2_DRIVER, GLESv2_enc_LIB, &g_gl2_dispatch, getGL2Context); 194 } 195 } 196 197 if (!s_needEncode) { 198 ALOGD("Initializing native opengl for %s\n", getProcName()); 199 initApi<gl_wrapper_context_t>(GLESv1_DRIVER, GLES_android_LIB, &g_gl_dispatch, getGLContext); 200 // try to initialize gl2 from GLES, though its probably going to fail 201 initApi<gl2_wrapper_context_t>(GLESv2_DRIVER, GLES_android_LIB, &g_gl2_dispatch, getGL2Context); 202 } 203} 204 205static struct egl_dispatch *getDispatch() 206{ 207 pthread_once(&dispatchTablesInitialized, initDispatchTables); 208 return s_dispatch; 209} 210 211__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) 212{ 213 214 // search in EGL function table 215 for (int i=0; i<egl_num_funcs; i++) { 216 if (!strcmp(egl_funcs_by_name[i].name, procname)) { 217 return (__eglMustCastToProperFunctionPointerType)egl_funcs_by_name[i].proc; 218 } 219 } 220 221 // we do not support eglGetProcAddress for GLESv1 & GLESv2. The loader 222 // should be able to find this function through dynamic loading. 223 return NULL; 224} 225 226//////////////// Path through functions ////////// 227 228EGLint eglGetError() 229{ 230 return getDispatch()->eglGetError(); 231} 232 233EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) 234{ 235 return getDispatch()->eglGetDisplay(display_id); 236} 237 238EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) 239{ 240 return getDispatch()->eglInitialize(dpy, major, minor); 241} 242 243EGLBoolean eglTerminate(EGLDisplay dpy) 244{ 245 return getDispatch()->eglTerminate(dpy); 246} 247 248const char* eglQueryString(EGLDisplay dpy, EGLint name) 249{ 250 return getDispatch()->eglQueryString(dpy, name); 251} 252 253EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) 254{ 255 return getDispatch()->eglGetConfigs(dpy, configs, config_size, num_config); 256} 257 258static EGLint * filter_es2_bit(const EGLint *attrib_list, bool *isES2) 259{ 260 if (attrib_list == NULL) { 261 if (isES2 != NULL) *isES2 = false; 262 return NULL; 263 } 264 265 EGLint *attribs = NULL; 266 int nAttribs = 0; 267 while(attrib_list[nAttribs] != EGL_NONE) nAttribs++; 268 nAttribs++; 269 270 attribs = new EGLint[nAttribs]; 271 memcpy(attribs, attrib_list, nAttribs * sizeof(EGLint)); 272 if (isES2 != NULL) *isES2 = false; 273 274 // scan the attribute list for ES2 request and replace with ES1. 275 for (int i = 0; i < nAttribs; i++) { 276 if (attribs[i] == EGL_RENDERABLE_TYPE) { 277 if (attribs[i + 1] & EGL_OPENGL_ES2_BIT) { 278 attribs[i + 1] &= ~EGL_OPENGL_ES2_BIT; 279 attribs[i + 1] |= EGL_OPENGL_ES_BIT; 280 ALOGD("removing ES2 bit 0x%x\n", attribs[i + 1]); 281 if (isES2 != NULL) *isES2 = true; 282 } 283 } 284 } 285 return attribs; 286} 287 288EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) 289{ 290 EGLBoolean res; 291 if (s_needEncode) { 292 EGLint *attribs = filter_es2_bit(attrib_list, NULL); 293 res = getDispatch()->eglChooseConfig(dpy, 294 attribs, 295 configs, 296 config_size, 297 num_config); 298 ALOGD("eglChooseConfig: %d configs found\n", *num_config); 299 if (*num_config == 0 && attribs != NULL) { 300 ALOGD("requested attributes:\n"); 301 for (int i = 0; attribs[i] != EGL_NONE; i++) { 302 ALOGD("%d: 0x%x\n", i, attribs[i]); 303 } 304 } 305 306 delete attribs; 307 } else { 308 res = getDispatch()->eglChooseConfig(dpy, attrib_list, configs, config_size, num_config); 309 } 310 return res; 311} 312 313EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) 314{ 315 if (s_needEncode && attribute == EGL_RENDERABLE_TYPE) { 316 *value = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT; 317 return EGL_TRUE; 318 } else { 319 return getDispatch()->eglGetConfigAttrib(dpy, config, attribute, value); 320 } 321} 322 323EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) 324{ 325 EGLSurface surface = getDispatch()->eglCreateWindowSurface(dpy, config, win, attrib_list); 326 if (surface != EGL_NO_SURFACE) { 327 ServerConnection *server; 328 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) { 329 server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface); 330 } 331 } 332 return surface; 333} 334 335EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) 336{ 337 EGLSurface surface = getDispatch()->eglCreatePbufferSurface(dpy, config, attrib_list); 338 if (surface != EGL_NO_SURFACE) { 339 ServerConnection *server; 340 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) { 341 server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface); 342 } 343 } 344 return surface; 345} 346 347EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) 348{ 349 EGLSurface surface = getDispatch()->eglCreatePixmapSurface(dpy, config, pixmap, attrib_list); 350 if (surface != EGL_NO_SURFACE) { 351 ServerConnection *server; 352 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) { 353 server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface); 354 } 355 } 356 return surface; 357} 358 359EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) 360{ 361 EGLBoolean res = getDispatch()->eglDestroySurface(dpy, surface); 362 if (res && surface != EGL_NO_SURFACE) { 363 ServerConnection *server; 364 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) { 365 server->utEnc()->destroySurface(server->utEnc(), getpid(), (uint32_t)surface); 366 } 367 } 368 return res; 369} 370 371EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) 372{ 373 EGLBoolean res = getDispatch()->eglQuerySurface(dpy, surface, attribute, value); 374 if (res && attribute == EGL_RENDERABLE_TYPE) { 375 *value |= EGL_OPENGL_ES2_BIT; 376 } 377 return res; 378} 379 380EGLBoolean eglBindAPI(EGLenum api) 381{ 382 return getDispatch()->eglBindAPI(api); 383} 384 385EGLenum eglQueryAPI() 386{ 387 return getDispatch()->eglQueryAPI(); 388} 389 390EGLBoolean eglWaitClient() 391{ 392 return getDispatch()->eglWaitClient(); 393} 394 395EGLBoolean eglReleaseThread() 396{ 397 return getDispatch()->eglReleaseThread(); 398} 399 400EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) 401{ 402 return getDispatch()->eglCreatePbufferFromClientBuffer(dpy, buftype, buffer, config, attrib_list); 403} 404 405EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) 406{ 407 return getDispatch()->eglSurfaceAttrib(dpy, surface, attribute, value); 408} 409 410EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) 411{ 412 return getDispatch()->eglBindTexImage(dpy, surface, buffer); 413} 414 415EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) 416{ 417 return getDispatch()->eglReleaseTexImage(dpy, surface, buffer); 418} 419 420EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) 421{ 422 return getDispatch()->eglSwapInterval(dpy, interval); 423} 424 425EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) 426{ 427 428 EGLContext share = share_context; 429 if (share) share = ((EGLWrapperContext *)share_context)->aglContext; 430 431 // check if are ES2, and convert it to ES1. 432 int nAttribs = 0; 433 if (attrib_list != NULL) { 434 while(attrib_list[nAttribs] != EGL_NONE) { 435 nAttribs++; 436 } 437 nAttribs++; 438 } 439 440 EGLint *attrib = NULL; 441 if (nAttribs > 0) { 442 attrib = new EGLint[nAttribs]; 443 memcpy(attrib, attrib_list, nAttribs * sizeof(EGLint)); 444 } 445 446 int version = 1; 447 for (int i = 0; i < nAttribs; i++) { 448 if (attrib[i] == EGL_CONTEXT_CLIENT_VERSION && 449 attrib[i + 1] == 2) { 450 version = 2; 451 attrib[i + 1] = 1; // replace to version 1 452 } 453 } 454 455 EGLContext ctx = getDispatch()->eglCreateContext(dpy, config, share, attrib); 456 delete[] attrib; 457 EGLWrapperContext *wctx = new EGLWrapperContext(ctx, version); 458 if (ctx != EGL_NO_CONTEXT) { 459 ServerConnection *server; 460 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) { 461 wctx->clientState = new GLClientState(); 462 server->utEnc()->createContext(server->utEnc(), getpid(), 463 (uint32_t)wctx, 464 (uint32_t)(share_context == EGL_NO_CONTEXT ? 0 : share_context), wctx->version); 465 } 466 } 467 return (EGLContext)wctx; 468} 469 470EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) 471{ 472 EGLWrapperContext *wctx = (EGLWrapperContext *)ctx; 473 EGLBoolean res = EGL_FALSE; 474 475 if (ctx && ctx != EGL_NO_CONTEXT) { 476 res = getDispatch()->eglDestroyContext(dpy, wctx->aglContext); 477 if (res) { 478 EGLThreadInfo *ti = getEGLThreadInfo(); 479 ServerConnection *server; 480 if (s_needEncode && (server = ServerConnection::s_getServerConnection())) { 481 server->utEnc()->destroyContext(ti->serverConn->utEnc(), getpid(), (uint32_t)ctx); 482 } 483 if (ti->currentContext == wctx) ti->currentContext = NULL; 484 delete wctx; 485 } 486 } 487 488 return res; 489} 490 491EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) 492{ 493 EGLWrapperContext *wctx = (EGLWrapperContext *)ctx; 494 EGLContext aglContext = (ctx == EGL_NO_CONTEXT ? EGL_NO_CONTEXT : wctx->aglContext); 495 EGLThreadInfo *ti = getEGLThreadInfo(); 496 EGLBoolean res = getDispatch()->eglMakeCurrent(dpy, draw, read, aglContext); 497 if (res ) { 498 // NOTE - we do get a pointer to the server connection, (rather then using ti->serverConn) 499 // for cases that this is the first egl call of the current thread. 500 501 ServerConnection *server; 502 if (s_needEncode && (server = ServerConnection::s_getServerConnection())) { 503 server->utEnc()->makeCurrentContext(server->utEnc(), getpid(), 504 (uint32_t) (draw == EGL_NO_SURFACE ? 0 : draw), 505 (uint32_t) (read == EGL_NO_SURFACE ? 0 : read), 506 (uint32_t) (ctx == EGL_NO_CONTEXT ? 0 : ctx)); 507 server->glEncoder()->setClientState( wctx ? wctx->clientState : NULL ); 508 server->gl2Encoder()->setClientState( wctx ? wctx->clientState : NULL ); 509 } 510 511 // set current context in our thread info 512 ti->currentContext = wctx; 513 } 514 return res; 515 516} 517 518EGLContext eglGetCurrentContext() 519{ 520 EGLThreadInfo *ti = getEGLThreadInfo(); 521 return (ti->currentContext ? ti->currentContext : EGL_NO_CONTEXT); 522} 523 524EGLSurface eglGetCurrentSurface(EGLint readdraw) 525{ 526 return getDispatch()->eglGetCurrentSurface(readdraw); 527} 528 529EGLDisplay eglGetCurrentDisplay() 530{ 531 return getDispatch()->eglGetCurrentDisplay(); 532} 533 534EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) 535{ 536 EGLWrapperContext *wctx = (EGLWrapperContext *)ctx; 537 if (wctx) { 538 if (attribute == EGL_CONTEXT_CLIENT_VERSION) { 539 *value = wctx->version; 540 return EGL_TRUE; 541 } else { 542 return getDispatch()->eglQueryContext(dpy, wctx->aglContext, attribute, value); 543 } 544 } 545 else { 546 return EGL_BAD_CONTEXT; 547 } 548} 549 550EGLBoolean eglWaitGL() 551{ 552 return getDispatch()->eglWaitGL(); 553} 554 555EGLBoolean eglWaitNative(EGLint engine) 556{ 557 return getDispatch()->eglWaitNative(engine); 558} 559 560EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) 561{ 562 ServerConnection *server; 563 if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) { 564 server->utEnc()->swapBuffers(server->utEnc(), getpid(), (uint32_t)surface); 565 server->glEncoder()->flush(); 566 server->gl2Encoder()->flush(); 567 return 1; 568 } 569 return getDispatch()->eglSwapBuffers(dpy, surface); 570} 571 572EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) 573{ 574 return getDispatch()->eglCopyBuffers(dpy, surface, target); 575} 576 577EGLBoolean eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list) 578{ 579 return getDispatch()->eglLockSurfaceKHR(display, surface, attrib_list); 580} 581 582EGLBoolean eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface) 583{ 584 return getDispatch()->eglUnlockSurfaceKHR(display, surface); 585} 586 587EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) 588{ 589 EGLWrapperContext *wctx = (EGLWrapperContext *)ctx; 590 EGLContext aglContext = (wctx ? wctx->aglContext : EGL_NO_CONTEXT); 591 return getDispatch()->eglCreateImageKHR(dpy, aglContext, target, buffer, attrib_list); 592} 593 594EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) 595{ 596 return getDispatch()->eglDestroyImageKHR(dpy, image); 597} 598 599EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) 600{ 601 return getDispatch()->eglCreateSyncKHR(dpy, type, attrib_list); 602} 603 604EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) 605{ 606 return getDispatch()->eglDestroySyncKHR(dpy, sync); 607} 608 609EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) 610{ 611 return getDispatch()->eglClientWaitSyncKHR(dpy, sync, flags, timeout); 612} 613 614EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) 615{ 616 return getDispatch()->eglSignalSyncKHR(dpy, sync, mode); 617} 618 619EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) 620{ 621 return getDispatch()->eglGetSyncAttribKHR(dpy, sync, attribute, value); 622} 623 624EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height) 625{ 626 return getDispatch()->eglSetSwapRectangleANDROID(dpy, draw, left, top, width, height); 627} 628