From d46b8d338220dd9935f25651c75046b9081b758a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Mon, 13 Jun 2011 10:18:31 +0100 Subject: [PATCH] Ability to take snapshots while tracing. Mostly for purposes of validating the trace/retrace process. --- CMakeLists.txt | 11 ++- glsnapshot.cpp | 193 +++++++++++++++++++++++++++++++++++++++++++++++++ glsnapshot.hpp | 49 +++++++++++++ glxtrace.py | 18 +++++ 4 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 glsnapshot.cpp create mode 100644 glsnapshot.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7da18a7..cd32044 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 index 0000000..98a11fb --- /dev/null +++ b/glsnapshot.cpp @@ -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 +#include + +#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 index 0000000..745ef9a --- /dev/null +++ b/glsnapshot.hpp @@ -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_ */ diff --git a/glxtrace.py b/glxtrace.py index 2a49d25..7511f0a 100644 --- a/glxtrace.py +++ b/glxtrace.py @@ -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 -- 2.43.0