summaryrefslogtreecommitdiff
path: root/glsnapshot.cpp
diff options
context:
space:
mode:
authorJosé Fonseca <jose.r.fonseca@gmail.com>2011-06-13 10:18:31 +0100
committerJosé Fonseca <jose.r.fonseca@gmail.com>2011-06-13 10:18:31 +0100
commitd46b8d338220dd9935f25651c75046b9081b758a (patch)
tree062e989da13ceea2463cc5312ba2511813b1a355 /glsnapshot.cpp
parentc7b1c2a58055b6a95393b6abff9d2a45d700c27c (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.cpp193
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 */