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