]> git.cworth.org Git - apitrace/blob - glsnapshot.cpp
Add a few comments/links to Cocoa development resources.
[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 #if !defined(_WIN32) && !defined(__APPLE__)
36
37
38 #include <X11/Xproto.h>
39
40
41 static int
42 errorHandler(Display *display, XErrorEvent *event)
43 {
44     if (event->error_code == BadDrawable &&
45         event->request_code == X_GetGeometry) {
46         return 0;
47     }
48
49     char error_text[512];
50     XGetErrorText(display, event->error_code, error_text, sizeof error_text);
51     fprintf(stderr, "X Error of failed request:  %s\n", error_text);
52
53     return 0;
54 }
55
56
57 #endif /* !_WIN32 && !__APPLE__ */
58
59
60 namespace glsnapshot {
61
62
63 /**
64  * Get the contents of the current drawable into an image.
65  */
66 static Image::Image *
67 getDrawableImage(void) {
68 #if defined(_WIN32)
69
70     HDC hDC = __wglGetCurrentDC();
71     if (!hDC) {
72         return false;
73     }
74
75     HWND hWnd = WindowFromDC(hDC);
76     RECT rect;
77
78     if (!GetClientRect(hWnd, &rect)) {
79        return false;
80     }
81
82     int width  = rect.right  - rect.left;
83     int height = rect.bottom - rect.top;
84
85     // TODO: http://msdn.microsoft.com/en-us/library/dd183402
86
87     return NULL;
88
89 #elif defined(__APPLE__)
90
91     // TODO
92     return NULL;
93
94 #else
95
96     Display *display;
97     Drawable drawable;
98     Window root;
99     int x, y;
100     unsigned int w, h, bw, depth;
101
102     __glFinish();
103     __glXWaitGL();
104
105     display = __glXGetCurrentDisplay();
106     if (!display) {
107         return false;
108     }
109
110     drawable = __glXGetCurrentDrawable();
111     if (drawable == None) {
112         return false;
113     }
114
115     /*
116      * XXX: This does not work for drawables created with glXCreateWindow
117      */
118
119     int (*oldErrorHandler)(Display *, XErrorEvent *);
120     Status status;
121
122     oldErrorHandler = XSetErrorHandler(errorHandler);
123     status = XGetGeometry(display, drawable, &root, &x, &y, &w, &h, &bw, &depth);
124     XSetErrorHandler(oldErrorHandler);
125     if (!status) {
126         return false;
127     }
128
129     XImage *ximage;
130
131     ximage = XGetImage(display, drawable, 0, 0, w, h, AllPlanes, ZPixmap);
132     if (!ximage) {
133         return NULL;
134     }
135
136     Image::Image *image = NULL;
137
138     if (ximage->depth          == 24 &&
139         ximage->bits_per_pixel == 32 &&
140         ximage->red_mask       == 0x00ff0000 &&
141         ximage->green_mask     == 0x0000ff00 &&
142         ximage->blue_mask      == 0x000000ff) {
143
144         image = new Image::Image(w, h, 4);
145
146         if (image) {
147             const uint32_t *src = (const uint32_t *)ximage->data;
148             uint32_t *dst = (uint32_t*) image->start();
149             for (unsigned y = 0; y < h; ++y) {
150                 for (unsigned x = 0; x < w; ++x) {
151                     uint32_t bgra = src[x];
152                     uint32_t rgba = (bgra & 0xff00ff00)
153                                   | ((bgra >> 16) & 0xff)
154                                   | ((bgra & 0xff) << 16);
155                     dst[x] = rgba;
156                 }
157
158                 src += ximage->bytes_per_line / sizeof *src;
159                 dst += image->stride() / sizeof *src;
160             }
161         }
162     } else {
163         OS::DebugMessage("apitrace: unexpected XImage: "
164                          "bits_per_pixel = %i, "
165                          "depth = %i, "
166                          "red_mask = 0x%08lx, "
167                          "green_mask = 0x%08lx, "
168                          "blue_mask = 0x%08lx\n",
169                          ximage->bits_per_pixel,
170                          ximage->depth,
171                          ximage->red_mask,
172                          ximage->green_mask,
173                          ximage->blue_mask);
174     }
175
176     XDestroyImage(ximage);
177
178     return image;
179 #endif
180 }
181
182
183 // Prefix of the snapshot images to take, if not NULL.
184 static const char *snapshot_prefix = NULL;
185
186 // Maximum number of frames to trace.
187 static unsigned max_frames = ~0;
188
189 // Current frame number.
190 static unsigned frame_no = 0;
191
192
193 void snapshot(unsigned call_no) {
194
195     if (frame_no == 0) {
196         const char *max_frames_str = getenv("TRACE_FRAMES");
197         if (max_frames_str) {
198             max_frames = atoi(max_frames_str);
199         }
200         snapshot_prefix = getenv("TRACE_SNAPSHOT");
201     }
202
203     ++frame_no;
204
205     if (snapshot_prefix) {
206         Image::Image *src = getDrawableImage();
207         if (src) {
208             char filename[PATH_MAX];
209             snprintf(filename, sizeof filename, "%s%010u.png", snapshot_prefix, call_no);
210             if (src->writePNG(filename)) {
211                 OS::DebugMessage("apitrace: wrote %s\n", filename);
212             }
213
214             delete src;
215         }
216     }
217
218     if (frame_no >= max_frames) {
219         exit(0);
220     }
221 }
222
223
224 } /* namespace glsnapshot */