diff options
author | José Fonseca <jose.r.fonseca@gmail.com> | 2011-06-13 10:18:31 +0100 |
---|---|---|
committer | José Fonseca <jose.r.fonseca@gmail.com> | 2011-06-13 10:18:31 +0100 |
commit | d46b8d338220dd9935f25651c75046b9081b758a (patch) | |
tree | 062e989da13ceea2463cc5312ba2511813b1a355 /glsnapshot.cpp | |
parent | c7b1c2a58055b6a95393b6abff9d2a45d700c27c (diff) |
Ability to take snapshots while tracing.
Mostly for purposes of validating the trace/retrace process.
Diffstat (limited to 'glsnapshot.cpp')
-rw-r--r-- | glsnapshot.cpp | 193 |
1 files changed, 193 insertions, 0 deletions
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 <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 */ |