]> git.cworth.org Git - apitrace/blob - glsnapshot.cpp
Ability to take snapshots while tracing.
[apitrace] / glsnapshot.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 #include <assert.h>
28 #include <stdint.h>
29
30 #include "image.hpp"
31 #include "glproc.hpp"
32 #include "glsize.hpp"
33
34
35 namespace glsnapshot {
36
37
38 /**
39  * Get the contents of the current drawable into an image.
40  */
41 static Image::Image *
42 getDrawableImage(void) {
43 #if defined(_WIN32)
44
45     HDC hDC = __wglGetCurrentDC();
46     if (!hDC) {
47         return false;
48     }
49
50     HWND hWnd = WindowFromDC(hDC);
51     RECT rect;
52
53     if (!GetClientRect(hWnd, &rect)) {
54        return false;
55     }
56
57     int width  = rect.right  - rect.left;
58     int height = rect.bottom - rect.top;
59
60     // TODO: http://msdn.microsoft.com/en-us/library/dd183402
61
62     return NULL;
63
64 #elif defined(__APPLE__)
65
66     // TODO
67     return NULL;
68
69 #else
70
71     Display *display;
72     Drawable drawable;
73     Window root;
74     int x, y;
75     unsigned int w, h, bw, depth;
76
77     __glFinish();
78     __glXWaitGL();
79
80     display = __glXGetCurrentDisplay();
81     if (!display) {
82         return false;
83     }
84
85     drawable = __glXGetCurrentDrawable();
86     if (drawable == None) {
87         return false;
88     }
89
90     /*
91      * XXX: This does not work for drawables created with glXCreateWindow
92      */
93
94     if (!XGetGeometry(display, drawable, &root, &x, &y, &w, &h, &bw, &depth)) {
95         return false;
96     }
97
98     XImage *ximage;
99
100     ximage = XGetImage(display, drawable, 0, 0, w, h, AllPlanes, ZPixmap);
101     if (!ximage) {
102         return NULL;
103     }
104
105     Image::Image *image = NULL;
106
107     if (ximage->depth          == 24 &&
108         ximage->bits_per_pixel == 32 &&
109         ximage->red_mask       == 0x00ff0000 &&
110         ximage->green_mask     == 0x0000ff00 &&
111         ximage->blue_mask      == 0x000000ff) {
112
113         image = new Image::Image(w, h, 4);
114
115         if (image) {
116             const uint32_t *src = (const uint32_t *)ximage->data;
117             uint32_t *dst = (uint32_t*) image->start();
118             for (int y = 0; y < h; ++y) {
119                 for (int x = 0; x < w; ++x) {
120                     uint32_t bgra = src[x];
121                     uint32_t rgba = (bgra & 0xff00ff00)
122                                   | ((bgra >> 16) & 0xff)
123                                   | ((bgra & 0xff) << 16);
124                     dst[x] = rgba;
125                 }
126
127                 src += ximage->bytes_per_line / sizeof *src;
128                 dst += image->stride() / sizeof *src;
129             }
130         }
131     } else {
132         OS::DebugMessage("apitrace: unexpected XImage: "
133                          "bits_per_pixel = %i, "
134                          "depth = %i, "
135                          "red_mask = 0x%08lx, "
136                          "green_mask = 0x%08lx, "
137                          "blue_mask = 0x%08lx\n",
138                          ximage->bits_per_pixel,
139                          ximage->depth,
140                          ximage->red_mask,
141                          ximage->green_mask,
142                          ximage->blue_mask);
143     }
144
145     XDestroyImage(ximage);
146
147     return image;
148 #endif
149 }
150
151
152 // Prefix of the snapshot images to take, if not NULL.
153 static const char *snapshot_prefix = NULL;
154
155 // Maximum number of frames to trace.
156 static unsigned max_frames = ~0;
157
158 // Current frame number.
159 static unsigned frame_no = 0;
160
161
162 void snapshot(unsigned call_no) {
163
164     if (frame_no == 0) {
165         const char *max_frames_str = getenv("TRACE_FRAMES");
166         if (max_frames_str) {
167             max_frames = atoi(max_frames_str);
168         }
169         snapshot_prefix = getenv("TRACE_SNAPSHOT");
170     }
171
172     ++frame_no;
173
174     if (snapshot_prefix) {
175         Image::Image *src = getDrawableImage();
176         if (src) {
177             char filename[PATH_MAX];
178             snprintf(filename, sizeof filename, "%s%010u.png", snapshot_prefix, call_no);
179             if (src->writePNG(filename)) {
180                 OS::DebugMessage("apitrace: wrote %s\n", filename);
181             }
182
183             delete src;
184         }
185     }
186
187     if (frame_no >= max_frames) {
188         exit(0);
189     }
190 }
191
192
193 } /* namespace glsnapshot */