]> git.cworth.org Git - apitrace/blobdiff - egltrace.py
Don't abuse NotImplementedError.
[apitrace] / egltrace.py
index 64e51910300782c4e4d08e7360585b1f7d17ebf1..5d5c7593a9f51b8663b901e9fe969786d7fa2115 100644 (file)
 from specs.stdapi import API
 from specs.glapi import glapi
 from specs.eglapi import eglapi
+from specs.glesapi import glesapi
 from gltrace import GlTracer
 from dispatch import function_pointer_type, function_pointer_value
 
 
 class EglTracer(GlTracer):
 
-    def is_public_function(self, function):
+    def isFunctionPublic(self, function):
         # The symbols visible in libEGL.so can vary, so expose them all
         return True
 
-    def trace_function_impl_body(self, function):
-        GlTracer.trace_function_impl_body(self, function)
-
-        # Take snapshots
-        if function.name == 'eglSwapBuffers':
-            print '    glsnapshot::snapshot(__call);'
-        if function.name in ('glFinish', 'glFlush'):
-            print '    GLint __draw_framebuffer = 0;'
-            print '    __glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &__draw_framebuffer);'
-            print '    if (__draw_framebuffer == 0) {'
-            print '        GLint __draw_buffer = GL_NONE;'
-            print '        __glGetIntegerv(GL_DRAW_BUFFER, &__draw_buffer);'
-            print '        if (__draw_buffer == GL_FRONT) {'
-            print '             glsnapshot::snapshot(__call);'
-            print '        }'
+    def traceFunctionImplBody(self, function):
+        GlTracer.traceFunctionImplBody(self, function)
+
+        if function.name == 'eglMakeCurrent':
+            print '    // update the profile'
+            print '    if (ctx != EGL_NO_CONTEXT) {'
+            print '        EGLint api = EGL_OPENGL_ES_API, version = 1;'
+            print '        gltrace::Context *tr = gltrace::getContext();'
+            print '        __eglQueryContext(dpy, ctx, EGL_CONTEXT_CLIENT_TYPE, &api);'
+            print '        __eglQueryContext(dpy, ctx, EGL_CONTEXT_CLIENT_VERSION, &version);'
+            print '        if (api == EGL_OPENGL_API)'
+            print '            tr->profile = gltrace::PROFILE_COMPAT;'
+            print '        else if (version == 1)'
+            print '            tr->profile = gltrace::PROFILE_ES1;'
+            print '        else'
+            print '            tr->profile = gltrace::PROFILE_ES2;'
             print '    }'
 
-    def wrap_ret(self, function, instance):
-        GlTracer.wrap_ret(self, function, instance)
+    def wrapRet(self, function, instance):
+        GlTracer.wrapRet(self, function, instance)
 
         if function.name == "eglGetProcAddress":
             print '    %s = __unwrap_proc_addr(procname, %s);' % (instance, instance)
@@ -74,7 +76,7 @@ if __name__ == '__main__':
     print '#include <string.h>'
     print '#include <dlfcn.h>'
     print
-    print '#include "trace_writer.hpp"'
+    print '#include "trace_writer_local.hpp"'
     print
     print '// To validate our prototypes'
     print '#define GL_GLEXT_PROTOTYPES'
@@ -82,14 +84,14 @@ if __name__ == '__main__':
     print
     print '#include "glproc.hpp"'
     print '#include "glsize.hpp"'
-    print '#include "glsnapshot.hpp"'
     print
     print 'static __eglMustCastToProperFunctionPointerType __unwrap_proc_addr(const char * procname, __eglMustCastToProperFunctionPointerType procPtr);'
     print
 
     api = API()
-    api.add_api(eglapi)
-    api.add_api(glapi)
+    api.addApi(eglapi)
+    api.addApi(glapi)
+    api.addApi(glesapi)
     tracer = EglTracer()
     tracer.trace_api(api)
 
@@ -110,28 +112,88 @@ if __name__ == '__main__':
     print
     print r'''
 
+
+/*
+ * Android does not support LD_PRELOAD.
+ */
+#if !defined(ANDROID)
+
+
 /*
- * Lookup a EGL or GLES symbol
+ * Invoke the true dlopen() function.
  */
-void * __libegl_sym(const char *symbol, bool pub)
+static void *__dlopen(const char *filename, int flag)
 {
-    void *proc;
-
-    /*
-     * Public symbols are EGL core functions and those defined in dekstop GL
-     * ABI.  Troubles come from the latter.
-     */
-    if (pub) {
-        proc = dlsym(RTLD_NEXT, symbol);
-        if (!proc && symbol[0] == 'g' && symbol[1] == 'l')
-            proc = (void *) __eglGetProcAddress(symbol);
+    typedef void * (*PFNDLOPEN)(const char *, int);
+    static PFNDLOPEN dlopen_ptr = NULL;
+
+    if (!dlopen_ptr) {
+        dlopen_ptr = (PFNDLOPEN)dlsym(RTLD_NEXT, "dlopen");
+        if (!dlopen_ptr) {
+            os::log("apitrace: error: dlsym(RTLD_NEXT, \"dlopen\") failed\n");
+            return NULL;
+        }
     }
-    else {
-        proc = (void *) __eglGetProcAddress(symbol);
-        if (!proc && symbol[0] == 'g' && symbol[1] == 'l')
-            proc = dlsym(RTLD_NEXT, symbol);
+
+    return dlopen_ptr(filename, flag);
+}
+
+
+/*
+ * Several applications, such as Quake3, use dlopen("libGL.so.1"), but
+ * LD_PRELOAD does not intercept symbols obtained via dlopen/dlsym, therefore
+ * we need to intercept the dlopen() call here, and redirect to our wrapper
+ * shared object.
+ */
+extern "C" PUBLIC
+void * dlopen(const char *filename, int flag)
+{
+    bool intercept = false;
+
+    if (filename) {
+        intercept =
+            strcmp(filename, "libEGL.so") == 0 ||
+            strcmp(filename, "libEGL.so.1") == 0 ||
+            strcmp(filename, "libGLESv1_CM.so") == 0 ||
+            strcmp(filename, "libGLESv1_CM.so.1") == 0 ||
+            strcmp(filename, "libGLESv2.so") == 0 ||
+            strcmp(filename, "libGLESv2.so.2") == 0 ||
+            strcmp(filename, "libGL.so") == 0 ||
+            strcmp(filename, "libGL.so.1") == 0;
+
+        if (intercept) {
+            os::log("apitrace: redirecting dlopen(\"%s\", 0x%x)\n", filename, flag);
+
+            /* The current dispatch implementation relies on core entry-points to be globally available, so force this.
+             *
+             * TODO: A better approach would be note down the entry points here and
+             * use them latter. Another alternative would be to reopen the library
+             * with RTLD_NOLOAD | RTLD_GLOBAL.
+             */
+            flag &= ~RTLD_LOCAL;
+            flag |= RTLD_GLOBAL;
+        }
     }
 
-    return proc;
+    void *handle = __dlopen(filename, flag);
+
+    if (intercept) {
+        // Get the file path for our shared object, and use it instead
+        static int dummy = 0xdeedbeef;
+        Dl_info info;
+        if (dladdr(&dummy, &info)) {
+            handle = __dlopen(info.dli_fname, flag);
+        } else {
+            os::log("apitrace: warning: dladdr() failed\n");
+        }
+    }
+
+    return handle;
 }
+
+
+#endif /* !ANDROID */
+
+
+
 '''