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