]> git.cworth.org Git - apitrace/blob - glretrace.py
Don't wait for a keypress by default.
[apitrace] / glretrace.py
1 ##########################################################################
2 #
3 # Copyright 2010 VMware, Inc.
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 """GL retracer generator."""
28
29
30 import stdapi
31 import glapi
32 from retrace import Retracer
33
34
35 class GlRetracer(Retracer):
36
37     def retrace_function(self, function):
38         Retracer.retrace_function(self, function)
39
40     draw_array_function_names = set([
41         "glDrawArrays",
42         "glDrawArraysEXT",
43         "glDrawArraysIndirect",
44         "glDrawArraysInstanced",
45         "glDrawArraysInstancedARB",
46         "glDrawArraysInstancedEXT",
47         "glDrawMeshArraysSUN",
48         "glMultiDrawArrays",
49         "glMultiDrawArraysEXT",
50         "glMultiModeDrawArraysIBM",
51     ])
52
53     draw_elements_function_names = set([
54         "glDrawElements",
55         "glDrawElementsBaseVertex",
56         "glDrawElementsIndirect",
57         "glDrawElementsInstanced",
58         "glDrawElementsInstancedARB",
59         "glDrawElementsInstancedBaseVertex",
60         "glDrawElementsInstancedEXT",
61         "glDrawRangeElements",
62         "glDrawRangeElementsBaseVertex",
63         "glDrawRangeElementsEXT",
64         "glMultiDrawElements",
65         "glMultiDrawElementsBaseVertex",
66         "glMultiDrawElementsEXT",
67         "glMultiModeDrawElementsIBM",
68     ])
69
70     def call_function(self, function):
71         if (function.name in self.draw_array_function_names or 
72             function.name in self.draw_elements_function_names):
73             print '    GLint __array_buffer = 0;'
74             print '    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
75             print '    if (!__array_buffer) {'
76             self.fail_function(function)
77             print '    }'
78
79         if function.name in self.draw_elements_function_names:
80             print '    GLint __element_array_buffer = 0;'
81             print '    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
82             print '    if (!__element_array_buffer) {'
83             self.fail_function(function)
84             print '    }'
85
86         if function.name == "glViewport":
87             print '    if (x + width > __window_width) {'
88             print '        __window_width = x + width;'
89             print '        __reshape_window = true;'
90             print '    }'
91             print '    if (y + height > __window_height) {'
92             print '        __window_height = y + height;'
93             print '        __reshape_window = true;'
94             print '    }'
95
96         if function.name == "glEnd":
97             print '    insideGlBeginEnd = false;'
98         
99         Retracer.call_function(self, function)
100
101         if function.name == "glBegin":
102             print '    insideGlBeginEnd = true;'
103         else:
104             # glGetError is not allowed inside glBegin/glEnd
105             print '    checkGlError();'
106
107     pointer_function_names = set([
108         "glColorPointer",
109         "glColorPointerEXT",
110         "glEdgeFlagPointer",
111         "glEdgeFlagPointerEXT",
112         "glFogCoordPointer",
113         "glFogCoordPointerEXT",
114         "glIndexPointer",
115         "glIndexPointerEXT",
116         "glMatrixIndexPointerARB",
117         "glNormalPointer",
118         "glNormalPointerEXT",
119         "glSecondaryColorPointer",
120         "glSecondaryColorPointerEXT",
121         "glTexCoordPointer",
122         "glTexCoordPointerEXT",
123         "glVertexAttribLPointer",
124         "glVertexAttribPointer",
125         "glVertexAttribPointerARB",
126         "glVertexAttribPointerNV",
127         "glVertexPointer",
128         "glVertexPointerEXT",
129     ])
130
131     def extract_arg(self, function, arg, arg_type, lvalue, rvalue):
132         if (function.name in self.pointer_function_names and arg.name == 'pointer' or
133             function.name in self.draw_elements_function_names and arg.name == 'indices'):
134             print '    if (dynamic_cast<Trace::Null *>(&%s)) {' % rvalue
135             print '        %s = 0;' % (lvalue)
136             print '    } else {'
137             print '        %s = (%s)(uintptr_t)(%s);' % (lvalue, arg_type, rvalue)
138             print '    }'
139             return
140
141         if function.name.startswith('glUniform') and function.args[0].name == arg.name == 'location':
142             print '    GLint program = -1;'
143             print '    glGetIntegerv(GL_CURRENT_PROGRAM, &program);'
144
145         Retracer.extract_arg(self, function, arg, arg_type, lvalue, rvalue)
146
147
148 if __name__ == '__main__':
149     print r'''
150 #include <string.h>
151 #include <stdio.h>
152 #include <iostream>
153
154 #include "glproc.hpp"
155 #include <GL/glut.h>
156
157 static bool double_buffer = false;
158 static bool insideGlBeginEnd = false;
159
160 static int __window_width = 256, __window_height = 256;
161 bool __reshape_window = false;
162
163 unsigned __frame = 0;
164 long long __startTime = 0;
165 static enum {
166     MODE_DISPLAY = 0,
167     MODE_SNAPSHOT,
168     MODE_COMPARE,
169 } __mode = MODE_DISPLAY;
170 bool __wait = false;
171
172 const char *__snapshot_prefix = "";
173
174
175 static void
176 checkGlError(void) {
177     if (insideGlBeginEnd) {
178         return;
179     }
180
181     GLenum error = glGetError();
182     if (error == GL_NO_ERROR) {
183         return;
184     }
185
186     std::cerr << "warning: glGetError() = ";
187     switch (error) {
188     case GL_INVALID_ENUM:
189         std::cerr << "GL_INVALID_ENUM";
190         break;
191     case GL_INVALID_VALUE:
192         std::cerr << "GL_INVALID_VALUE";
193         break;
194     case GL_INVALID_OPERATION:
195         std::cerr << "GL_INVALID_OPERATION";
196         break;
197     case GL_STACK_OVERFLOW:
198         std::cerr << "GL_STACK_OVERFLOW";
199         break;
200     case GL_STACK_UNDERFLOW:
201         std::cerr << "GL_STACK_UNDERFLOW";
202         break;
203     case GL_OUT_OF_MEMORY:
204         std::cerr << "GL_OUT_OF_MEMORY";
205         break;
206     case GL_INVALID_FRAMEBUFFER_OPERATION:
207         std::cerr << "GL_INVALID_FRAMEBUFFER_OPERATION";
208         break;
209     case GL_TABLE_TOO_LARGE:
210         std::cerr << "GL_TABLE_TOO_LARGE";
211         break;
212     default:
213         std::cerr << error;
214         break;
215     }
216     std::cerr << "\n";
217 }
218 '''
219     api = glapi.glapi
220     retracer = GlRetracer()
221     retracer.retrace_api(glapi.glapi)
222     print r'''
223
224 static Trace::Parser parser;
225
226 static void display_noop(void) {
227 }
228
229 #include "image.hpp"
230
231 static void frame_complete(void) {
232     ++__frame;
233     
234     if (!__reshape_window && (__mode == MODE_SNAPSHOT || __mode == MODE_COMPARE)) {
235         char filename[PATH_MAX];
236
237         snprintf(filename, sizeof filename, "%s%04u.png", __snapshot_prefix, __frame);
238         
239         Image::Image *ref = NULL;
240         if (__mode == MODE_COMPARE) {
241             ref = Image::readPNG(filename);
242             if (!ref) {
243                 return;
244             }
245             if (verbosity)
246                 std::cout << "Read " << filename << "\n";
247         }
248         
249         Image::Image src(__window_width, __window_height, true);
250         glReadPixels(0, 0, __window_width, __window_height, GL_RGBA, GL_UNSIGNED_BYTE, src.pixels);
251
252         if (__mode == MODE_SNAPSHOT) {
253             if (src.writePNG(filename) && verbosity) {
254                 std::cout << "Wrote " << filename << "\n";
255             }
256         }
257
258         if (__mode == MODE_COMPARE) {
259             std::cout << "Frame " << __frame << " average precision of " << src.compare(*ref) << " bits\n";
260             delete ref;
261         }
262     }
263
264 }
265
266 static void display(void) {
267     Trace::Call *call;
268
269     while ((call = parser.parse_call())) {
270         const std::string &name = call->name();
271
272         if ((name[0] == 'w' && name[1] == 'g' && name[2] == 'l') ||
273             (name[0] == 'g' && name[1] == 'l' && name[2] == 'X')) {
274             // XXX: We ignore the majority of the OS-specific calls for now
275             if (name == "glXSwapBuffers" ||
276                 name == "wglSwapBuffers") {
277                 if (double_buffer)
278                     glutSwapBuffers();
279                 else
280                     glFlush();
281                 frame_complete();
282                 return;
283             } else {
284                 continue;
285             }
286         }
287
288         if (name == "glFlush") {
289             glFlush();
290             if (!double_buffer) {
291                 frame_complete();
292             }
293         }
294         
295         retrace_call(*call);
296     }
297
298     // Reached the end of trace
299     glFlush();
300
301     long long endTime = OS::GetTime();
302     float timeInterval = (endTime - __startTime) * 1.0E-6;
303
304     std::cout << 
305         "Rendered " << __frame << " frames"
306         " in " <<  timeInterval << " secs,"
307         " average of " << (__frame/timeInterval) << " fps\n";
308
309     if (__wait) {
310         glutDisplayFunc(&display_noop);
311         glutIdleFunc(NULL);
312     } else {
313         exit(0);
314     }
315 }
316
317 static void idle(void) {
318     if (__reshape_window) {
319         // XXX: doesn't quite work
320         glutReshapeWindow(__window_width, __window_height);
321         __reshape_window = false;
322     }
323     glutPostRedisplay();
324 }
325
326 static void usage(void) {
327     std::cout << 
328         "Usage: glretrace [OPTION] TRACE\n"
329         "Replay TRACE.\n"
330         "\n"
331         "  -c           compare against snapshots\n"
332         "  -db          use a double buffer visual\n"
333         "  -p PREFIX    snapshot prefix\n"
334         "  -s           take snapshots\n"
335         "  -v           verbose output\n";
336 }
337
338 int main(int argc, char **argv)
339 {
340
341     int i;
342     for (i = 1; i < argc; ++i) {
343         const char *arg = argv[i];
344
345         if (arg[0] != '-') {
346             break;
347         }
348
349         if (!strcmp(arg, "--")) {
350             break;
351         } else if (!strcmp(arg, "-c")) {
352             __mode = MODE_COMPARE;
353         } else if (!strcmp(arg, "-db")) {
354             double_buffer = true;
355         } else if (!strcmp(arg, "--help")) {
356             usage();
357             return 0;
358         } else if (!strcmp(arg, "-p")) {
359             __snapshot_prefix = argv[++i];
360         } else if (!strcmp(arg, "-s")) {
361             __mode = MODE_SNAPSHOT;
362         } else if (!strcmp(arg, "-v")) {
363             ++verbosity;
364         } else if (!strcmp(arg, "-w")) {
365             __wait = true;
366         } else {
367             std::cerr << "error: unknown option " << arg << "\n";
368             usage();
369             return 1;
370         }
371     }
372
373     glutInit(&argc, argv);
374     glutInitWindowPosition(0, 0);
375     glutInitWindowSize(__window_width, __window_height);
376     glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | (double_buffer ? GLUT_DOUBLE : GLUT_SINGLE));
377     glutCreateWindow(argv[0]);
378
379     glutDisplayFunc(&display);
380     glutIdleFunc(&idle);
381
382     for (GLuint h = 0; h < 1024; ++h) {
383         __list_map[h] = h;
384     }
385
386     for ( ; i < argc; ++i) {
387         if (parser.open(argv[i])) {
388             __startTime = OS::GetTime();
389             glutMainLoop();
390             parser.close();
391         }
392     }
393
394     return 0;
395 }
396
397 '''