]> git.cworth.org Git - apitrace/blobdiff - wrappers/glxtrace.py
cli: Fix invalid option message.
[apitrace] / wrappers / glxtrace.py
index 8c18e0bdf62bee57f30709926ce572931c936690..e9c43a9c65132e69ad0f34cb7697616b2a4f1a5e 100644 (file)
@@ -29,8 +29,7 @@
 
 
 from gltrace import GlTracer
-from dispatch import function_pointer_type, function_pointer_value
-from specs.stdapi import API
+from specs.stdapi import Module, API
 from specs.glapi import glapi
 from specs.glxapi import glxapi
 
@@ -41,11 +40,119 @@ class GlxTracer(GlTracer):
         # The symbols visible in libGL.so can vary, so expose them all
         return True
 
-    def wrapRet(self, function, instance):
-        GlTracer.wrapRet(self, function, instance)
-
-        if function.name in ("glXGetProcAddress", "glXGetProcAddressARB"):
-            print '    %s = __unwrap_proc_addr(procName, %s);' % (instance, instance)
+    getProcAddressFunctionNames = [
+        "glXGetProcAddress",
+        "glXGetProcAddressARB",
+    ]
+
+    createContextFunctionNames = [
+        'glXCreateContext',
+        'glXCreateContextAttribsARB',
+        'glXCreateContextWithConfigSGIX',
+        'glXCreateNewContext',
+    ]
+
+    destroyContextFunctionNames = [
+        'glXDestroyContext',
+    ]
+
+    makeCurrentFunctionNames = [
+        'glXMakeCurrent',
+        'glXMakeContextCurrent',
+        'glXMakeCurrentReadSGI',
+    ]
+
+    def traceFunctionImplBody(self, function):
+        if function.name in self.destroyContextFunctionNames:
+            print '    gltrace::releaseContext((uintptr_t)ctx);'
+
+        GlTracer.traceFunctionImplBody(self, function)
+
+        if function.name in self.createContextFunctionNames:
+            print '    if (_result != NULL)'
+            print '        gltrace::createContext((uintptr_t)_result);'
+
+        if function.name in self.makeCurrentFunctionNames:
+            print '    if (_result) {'
+            print '        if (ctx != NULL)'
+            print '            gltrace::setContext((uintptr_t)ctx);'
+            print '        else'
+            print '            gltrace::clearContext();'
+            print '    }'
+
+        if function.name == 'glXBindTexImageEXT':
+            # FIXME: glXBindTexImageEXT gets called frequently, so we should
+            # avoid recording the same data over and over again somehow, e.g.:
+            # - get the pixels before and after glXBindTexImageEXT, and only
+            #   emit emitFakeTexture2D when it changes
+            # - keep a global hash of the pixels
+            # FIXME: Handle mipmaps
+            print r'''
+                unsigned glx_target = 0;
+                _glXQueryDrawable(display, drawable, GLX_TEXTURE_TARGET_EXT, &glx_target);
+                GLenum target;
+                switch (glx_target) {
+                // FIXME
+                //case GLX_TEXTURE_1D_EXT:
+                //    target = GL_TEXTURE_1D;
+                //    break;
+                case GLX_TEXTURE_2D_EXT:
+                    target = GL_TEXTURE_2D;
+                    break;
+                case GLX_TEXTURE_RECTANGLE_EXT:
+                    target = GL_TEXTURE_RECTANGLE;
+                    break;
+                default:
+                    os::log("apitrace: warning: %s: unsupported GLX_TEXTURE_TARGET_EXT 0x%u\n", __FUNCTION__, glx_target);
+                    target = GL_NONE;
+                    break;
+                }
+                GLint level = 0;
+                GLint internalformat = GL_NONE;
+                _glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
+                // XXX: GL_TEXTURE_INTERNAL_FORMAT cannot be trusted on NVIDIA
+                // -- it sometimes returns GL_BGRA, even though GL_BGR/BGRA is
+                // not a valid internal format.
+                switch (internalformat) {
+                case GL_BGR:
+                    internalformat = GL_RGB;
+                    break;
+                case GL_BGRA:
+                    internalformat = GL_RGBA;
+                    break;
+                }
+                GLint width = 0;
+                _glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
+                GLint height = 0;
+                _glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
+                GLint border = 0;
+                // XXX: We always use GL_RGBA format to read the pixels because:
+                // - some implementations (Mesa) seem to return bogus results
+                //   for GLX_TEXTURE_FORMAT_EXT
+                // - hardware usually stores GL_RGB with 32bpp, so it should be
+                //   faster to read/write
+                // - it is more robust against GL_(UN)PACK_ALIGNMENT state
+                //   changes
+                // The drawback is that traces will be slightly bigger.
+                GLenum format = GL_RGBA;
+                GLenum type = GL_UNSIGNED_BYTE;
+                if (target && internalformat && height && width) {
+                    // FIXME: This assumes (UN)PACK state (in particular
+                    // GL_(UN)PACK_ROW_LENGTH) is set to its defaults. We
+                    // really should temporarily reset the state here (and emit
+                    // according fake calls) to cope when its not. At very
+                    // least we need a heads up warning that this will cause
+                    // problems.
+                    GLint alignment = 4;
+                    GLint row_stride = _align(width * 4, alignment);
+                    GLvoid * pixels = malloc(height * row_stride);
+                    _glGetTexImage(target, level, format, type, pixels);
+            '''
+            self.emitFakeTexture2D()
+            print r'''
+                    free(pixels);
+                }
+            '''
 
 
 if __name__ == '__main__':
@@ -53,65 +160,26 @@ if __name__ == '__main__':
     print '#include <stdlib.h>'
     print '#include <string.h>'
     print
-    print '#ifndef _GNU_SOURCE'
-    print '#define _GNU_SOURCE // for dladdr'
-    print '#endif'
-    print '#include <dlfcn.h>'
-    print
     print '#include "trace_writer_local.hpp"'
     print
     print '// To validate our prototypes'
     print '#define GL_GLEXT_PROTOTYPES'
     print '#define GLX_GLXEXT_PROTOTYPES'
     print
+    print '#include "dlopen.hpp"'
     print '#include "glproc.hpp"'
     print '#include "glsize.hpp"'
     print
-    print 'static __GLXextFuncPtr __unwrap_proc_addr(const GLubyte * procName, __GLXextFuncPtr procPtr);'
-    print
 
+    module = Module()
+    module.mergeModule(glxapi)
+    module.mergeModule(glapi)
     api = API()
-    api.addApi(glxapi)
-    api.addApi(glapi)
+    api.addModule(module)
     tracer = GlxTracer()
-    tracer.trace_api(api)
-
-    print 'static __GLXextFuncPtr __unwrap_proc_addr(const GLubyte * procName, __GLXextFuncPtr procPtr) {'
-    print '    if (!procPtr) {'
-    print '        return procPtr;'
-    print '    }'
-    for f in api.functions:
-        ptype = function_pointer_type(f)
-        pvalue = function_pointer_value(f)
-        print '    if (strcmp("%s", (const char *)procName) == 0) {' % f.name
-        print '        %s = (%s)procPtr;' % (pvalue, ptype)
-        print '        return (__GLXextFuncPtr)&%s;' % (f.name,)
-        print '    }'
-    print '    os::log("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);'
-    print '    return procPtr;'
-    print '}'
-    print
-    print r'''
-
-
-/*
- * Invoke the true dlopen() function.
- */
-static void *__dlopen(const char *filename, int flag)
-{
-    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;
-        }
-    }
+    tracer.traceApi(api)
 
-    return dlopen_ptr(filename, flag);
-}
+    print r'''
 
 
 /*
@@ -125,7 +193,7 @@ void * dlopen(const char *filename, int flag)
 {
     void *handle;
 
-    handle = __dlopen(filename, flag);
+    handle = _dlopen(filename, flag);
 
     const char * libgl_filename = getenv("TRACE_LIBGL");
 
@@ -139,14 +207,14 @@ void * dlopen(const char *filename, int flag)
             strcmp(filename, "libGL.so.1") == 0) {
 
             // Use the true libGL.so handle instead of RTLD_NEXT from now on
-            __libGlHandle = handle;
+            _libGlHandle = handle;
 
             // Get the file path for our shared object, and use it instead
             static int dummy = 0xdeedbeef;
             Dl_info info;
             if (dladdr(&dummy, &info)) {
                 os::log("apitrace: redirecting dlopen(\"%s\", 0x%x)\n", filename, flag);
-                handle = __dlopen(info.dli_fname, flag);
+                handle = _dlopen(info.dli_fname, flag);
             } else {
                 os::log("apitrace: warning: dladdr() failed\n");
             }