]> git.cworth.org Git - apitrace/commitdiff
Ability to take snapshots while tracing.
authorJosé Fonseca <jose.r.fonseca@gmail.com>
Mon, 13 Jun 2011 09:18:31 +0000 (10:18 +0100)
committerJosé Fonseca <jose.r.fonseca@gmail.com>
Mon, 13 Jun 2011 09:18:31 +0000 (10:18 +0100)
Mostly for purposes of validating the trace/retrace process.

CMakeLists.txt
glsnapshot.cpp [new file with mode: 0644]
glsnapshot.hpp [new file with mode: 0644]
glxtrace.py

index 7da18a7ab5dfbb71a94b8b03d681aa10040b479c..cd320440e8092d1244817a1476d436e63c9df9a9 100755 (executable)
@@ -283,7 +283,14 @@ else ()
         DEPENDS glxtrace.py gltrace.py trace.py glxapi.py glapi.py glparams.py gltypes.py stdapi.py
     )
 
-    add_library (glxtrace SHARED glxtrace.cpp trace_writer.cpp os_posix.cpp ${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp)
+    add_library (glxtrace SHARED
+        ${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp
+        glxtrace.cpp
+        glsnapshot.cpp
+        trace_writer.cpp
+        image.cpp
+        os_posix.cpp
+    )
 
     set_target_properties (glxtrace PROPERTIES
         # avoid the default "lib" prefix
@@ -296,7 +303,7 @@ else ()
         LINK_FLAGS "-Wl,-Bsymbolic -Wl,-Bsymbolic-functions"
     )
 
-    target_link_libraries (glxtrace dl)
+    target_link_libraries (glxtrace dl ${X11_X11_LIB})
     
     install (TARGETS glxtrace LIBRARY DESTINATION lib)
 endif ()
diff --git a/glsnapshot.cpp b/glsnapshot.cpp
new file mode 100644 (file)
index 0000000..98a11fb
--- /dev/null
@@ -0,0 +1,193 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "image.hpp"
+#include "glproc.hpp"
+#include "glsize.hpp"
+
+
+namespace glsnapshot {
+
+
+/**
+ * Get the contents of the current drawable into an image.
+ */
+static Image::Image *
+getDrawableImage(void) {
+#if defined(_WIN32)
+
+    HDC hDC = __wglGetCurrentDC();
+    if (!hDC) {
+        return false;
+    }
+
+    HWND hWnd = WindowFromDC(hDC);
+    RECT rect;
+
+    if (!GetClientRect(hWnd, &rect)) {
+       return false;
+    }
+
+    int width  = rect.right  - rect.left;
+    int height = rect.bottom - rect.top;
+
+    // TODO: http://msdn.microsoft.com/en-us/library/dd183402
+
+    return NULL;
+
+#elif defined(__APPLE__)
+
+    // TODO
+    return NULL;
+
+#else
+
+    Display *display;
+    Drawable drawable;
+    Window root;
+    int x, y;
+    unsigned int w, h, bw, depth;
+
+    __glFinish();
+    __glXWaitGL();
+
+    display = __glXGetCurrentDisplay();
+    if (!display) {
+        return false;
+    }
+
+    drawable = __glXGetCurrentDrawable();
+    if (drawable == None) {
+        return false;
+    }
+
+    /*
+     * XXX: This does not work for drawables created with glXCreateWindow
+     */
+
+    if (!XGetGeometry(display, drawable, &root, &x, &y, &w, &h, &bw, &depth)) {
+        return false;
+    }
+
+    XImage *ximage;
+
+    ximage = XGetImage(display, drawable, 0, 0, w, h, AllPlanes, ZPixmap);
+    if (!ximage) {
+        return NULL;
+    }
+
+    Image::Image *image = NULL;
+
+    if (ximage->depth          == 24 &&
+        ximage->bits_per_pixel == 32 &&
+        ximage->red_mask       == 0x00ff0000 &&
+        ximage->green_mask     == 0x0000ff00 &&
+        ximage->blue_mask      == 0x000000ff) {
+
+        image = new Image::Image(w, h, 4);
+
+        if (image) {
+            const uint32_t *src = (const uint32_t *)ximage->data;
+            uint32_t *dst = (uint32_t*) image->start();
+            for (int y = 0; y < h; ++y) {
+                for (int x = 0; x < w; ++x) {
+                    uint32_t bgra = src[x];
+                    uint32_t rgba = (bgra & 0xff00ff00)
+                                  | ((bgra >> 16) & 0xff)
+                                  | ((bgra & 0xff) << 16);
+                    dst[x] = rgba;
+                }
+
+                src += ximage->bytes_per_line / sizeof *src;
+                dst += image->stride() / sizeof *src;
+            }
+        }
+    } else {
+        OS::DebugMessage("apitrace: unexpected XImage: "
+                         "bits_per_pixel = %i, "
+                         "depth = %i, "
+                         "red_mask = 0x%08lx, "
+                         "green_mask = 0x%08lx, "
+                         "blue_mask = 0x%08lx\n",
+                         ximage->bits_per_pixel,
+                         ximage->depth,
+                         ximage->red_mask,
+                         ximage->green_mask,
+                         ximage->blue_mask);
+    }
+
+    XDestroyImage(ximage);
+
+    return image;
+#endif
+}
+
+
+// Prefix of the snapshot images to take, if not NULL.
+static const char *snapshot_prefix = NULL;
+
+// Maximum number of frames to trace.
+static unsigned max_frames = ~0;
+
+// Current frame number.
+static unsigned frame_no = 0;
+
+
+void snapshot(unsigned call_no) {
+
+    if (frame_no == 0) {
+        const char *max_frames_str = getenv("TRACE_FRAMES");
+        if (max_frames_str) {
+            max_frames = atoi(max_frames_str);
+        }
+        snapshot_prefix = getenv("TRACE_SNAPSHOT");
+    }
+
+    ++frame_no;
+
+    if (snapshot_prefix) {
+        Image::Image *src = getDrawableImage();
+        if (src) {
+            char filename[PATH_MAX];
+            snprintf(filename, sizeof filename, "%s%010u.png", snapshot_prefix, call_no);
+            if (src->writePNG(filename)) {
+                OS::DebugMessage("apitrace: wrote %s\n", filename);
+            }
+
+            delete src;
+        }
+    }
+
+    if (frame_no >= max_frames) {
+        exit(0);
+    }
+}
+
+
+} /* namespace glsnapshot */
diff --git a/glsnapshot.hpp b/glsnapshot.hpp
new file mode 100644 (file)
index 0000000..745ef9a
--- /dev/null
@@ -0,0 +1,49 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _GLSNAPSHOT_HPP_
+#define _GLSNAPSHOT_HPP_
+
+
+class JSONWriter;
+
+
+namespace Image {
+    class Image;
+}
+
+
+namespace glsnapshot {
+
+
+Image::Image *
+getDrawableImage(void);
+
+void snapshot(unsigned call_no);
+
+} /* namespace glsnapshot */
+
+
+#endif /* _GLSNAPSHOT_HPP_ */
index 2a49d25fcf0c18310ba3123c768ae7261425d2d6..7511f0a392ac7afc53acaa6a758c5cbc63b72c62 100644 (file)
@@ -41,6 +41,23 @@ class GlxTracer(GlTracer):
         # The symbols visible in libGL.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 == 'glXSwapBuffers':
+            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 '        }'
+            print '    }'
+
     def wrap_ret(self, function, instance):
         GlTracer.wrap_ret(self, function, instance)
 
@@ -66,6 +83,7 @@ if __name__ == '__main__':
     print
     print '#include "glproc.hpp"'
     print '#include "glsize.hpp"'
+    print '#include "glsnapshot.hpp"'
     print
     print 'static __GLXextFuncPtr __unwrap_proc_addr(const GLubyte * procName, __GLXextFuncPtr procPtr);'
     print