X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=wrappers%2Fglxtrace.py;h=568eb1a129ad3db1d8d38e806c87abbe1efddd68;hb=72d2ba9c2b5ba2e2516c0959bf66eafd7b054892;hp=8c18e0bdf62bee57f30709926ce572931c936690;hpb=452d3256a3ba7f249222ef857d69c8caaaa753f3;p=apitrace diff --git a/wrappers/glxtrace.py b/wrappers/glxtrace.py index 8c18e0b..568eb1a 100644 --- a/wrappers/glxtrace.py +++ b/wrappers/glxtrace.py @@ -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,9 +160,6 @@ if __name__ == '__main__': print '#include ' print '#include ' print - print '#ifndef _GNU_SOURCE' - print '#define _GNU_SOURCE // for dladdr' - print '#endif' print '#include ' print print '#include "trace_writer_local.hpp"' @@ -67,43 +171,28 @@ if __name__ == '__main__': 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 + tracer.traceApi(api) + print r''' /* * Invoke the true dlopen() function. */ -static void *__dlopen(const char *filename, int flag) +static void *_dlopen(const char *filename, int flag) { - typedef void * (*PFNDLOPEN)(const char *, int); - static PFNDLOPEN dlopen_ptr = NULL; + typedef void * (*PFN_DLOPEN)(const char *, int); + static PFN_DLOPEN dlopen_ptr = NULL; if (!dlopen_ptr) { - dlopen_ptr = (PFNDLOPEN)dlsym(RTLD_NEXT, "dlopen"); + dlopen_ptr = (PFN_DLOPEN)dlsym(RTLD_NEXT, "dlopen"); if (!dlopen_ptr) { os::log("apitrace: error: dlsym(RTLD_NEXT, \"dlopen\") failed\n"); return NULL; @@ -125,7 +214,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 +228,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"); }