]> git.cworth.org Git - apitrace/blob - glretrace.py
Allow to snapshot and compare simultanously.
[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 bool __wait = false;
166
167 const char *__compare_prefix = "";
168 const char *__snapshot_prefix = "";
169
170
171 static void
172 checkGlError(void) {
173     if (insideGlBeginEnd) {
174         return;
175     }
176
177     GLenum error = glGetError();
178     if (error == GL_NO_ERROR) {
179         return;
180     }
181
182     std::cerr << "warning: glGetError() = ";
183     switch (error) {
184     case GL_INVALID_ENUM:
185         std::cerr << "GL_INVALID_ENUM";
186         break;
187     case GL_INVALID_VALUE:
188         std::cerr << "GL_INVALID_VALUE";
189         break;
190     case GL_INVALID_OPERATION:
191         std::cerr << "GL_INVALID_OPERATION";
192         break;
193     case GL_STACK_OVERFLOW:
194         std::cerr << "GL_STACK_OVERFLOW";
195         break;
196     case GL_STACK_UNDERFLOW:
197         std::cerr << "GL_STACK_UNDERFLOW";
198         break;
199     case GL_OUT_OF_MEMORY:
200         std::cerr << "GL_OUT_OF_MEMORY";
201         break;
202     case GL_INVALID_FRAMEBUFFER_OPERATION:
203         std::cerr << "GL_INVALID_FRAMEBUFFER_OPERATION";
204         break;
205     case GL_TABLE_TOO_LARGE:
206         std::cerr << "GL_TABLE_TOO_LARGE";
207         break;
208     default:
209         std::cerr << error;
210         break;
211     }
212     std::cerr << "\n";
213 }
214 '''
215     api = glapi.glapi
216     retracer = GlRetracer()
217     retracer.retrace_api(glapi.glapi)
218     print r'''
219
220 static Trace::Parser parser;
221
222 static void display_noop(void) {
223 }
224
225 #include "image.hpp"
226
227 static void frame_complete(void) {
228     ++__frame;
229     
230     if (!__reshape_window && (__snapshot_prefix || __compare_prefix)) {
231         Image::Image *ref = NULL;
232         if (__compare_prefix) {
233             char filename[PATH_MAX];
234             snprintf(filename, sizeof filename, "%s%04u.png", __compare_prefix, __frame);
235             ref = Image::readPNG(filename);
236             if (!ref) {
237                 return;
238             }
239             if (verbosity)
240                 std::cout << "Read " << filename << "\n";
241         }
242         
243         Image::Image src(__window_width, __window_height, true);
244         glReadPixels(0, 0, __window_width, __window_height, GL_RGBA, GL_UNSIGNED_BYTE, src.pixels);
245
246         if (__snapshot_prefix) {
247             char filename[PATH_MAX];
248             snprintf(filename, sizeof filename, "%s%04u.png", __snapshot_prefix, __frame);
249             if (src.writePNG(filename) && verbosity) {
250                 std::cout << "Wrote " << filename << "\n";
251             }
252         }
253
254         if (ref) {
255             std::cout << "Frame " << __frame << " average precision of " << src.compare(*ref) << " bits\n";
256             delete ref;
257         }
258     }
259
260 }
261
262 static void display(void) {
263     Trace::Call *call;
264
265     while ((call = parser.parse_call())) {
266         const std::string &name = call->name();
267
268         if ((name[0] == 'w' && name[1] == 'g' && name[2] == 'l') ||
269             (name[0] == 'g' && name[1] == 'l' && name[2] == 'X')) {
270             // XXX: We ignore the majority of the OS-specific calls for now
271             if (name == "glXSwapBuffers" ||
272                 name == "wglSwapBuffers") {
273                 if (double_buffer)
274                     glutSwapBuffers();
275                 else
276                     glFlush();
277                 frame_complete();
278                 return;
279             } else {
280                 continue;
281             }
282         }
283
284         if (name == "glFlush") {
285             glFlush();
286             if (!double_buffer) {
287                 frame_complete();
288             }
289         }
290         
291         retrace_call(*call);
292     }
293
294     // Reached the end of trace
295     glFlush();
296
297     long long endTime = OS::GetTime();
298     float timeInterval = (endTime - __startTime) * 1.0E-6;
299
300     std::cout << 
301         "Rendered " << __frame << " frames"
302         " in " <<  timeInterval << " secs,"
303         " average of " << (__frame/timeInterval) << " fps\n";
304
305     if (__wait) {
306         glutDisplayFunc(&display_noop);
307         glutIdleFunc(NULL);
308     } else {
309         exit(0);
310     }
311 }
312
313 static void idle(void) {
314     if (__reshape_window) {
315         // XXX: doesn't quite work
316         glutReshapeWindow(__window_width, __window_height);
317         __reshape_window = false;
318     }
319     glutPostRedisplay();
320 }
321
322 static void usage(void) {
323     std::cout << 
324         "Usage: glretrace [OPTION] TRACE\n"
325         "Replay TRACE.\n"
326         "\n"
327         "  -c PREFIX    compare against snapshots\n"
328         "  -db          use a double buffer visual\n"
329         "  -s PREFIX    take snapshots\n"
330         "  -v           verbose output\n";
331 }
332
333 int main(int argc, char **argv)
334 {
335
336     int i;
337     for (i = 1; i < argc; ++i) {
338         const char *arg = argv[i];
339
340         if (arg[0] != '-') {
341             break;
342         }
343
344         if (!strcmp(arg, "--")) {
345             break;
346         } else if (!strcmp(arg, "-c")) {
347             __compare_prefix = argv[++i];
348         } else if (!strcmp(arg, "-db")) {
349             double_buffer = true;
350         } else if (!strcmp(arg, "--help")) {
351             usage();
352             return 0;
353         } else if (!strcmp(arg, "-p")) {
354         } else if (!strcmp(arg, "-s")) {
355             __snapshot_prefix = argv[++i];
356         } else if (!strcmp(arg, "-v")) {
357             ++verbosity;
358         } else if (!strcmp(arg, "-w")) {
359             __wait = true;
360         } else {
361             std::cerr << "error: unknown option " << arg << "\n";
362             usage();
363             return 1;
364         }
365     }
366
367     glutInit(&argc, argv);
368     glutInitWindowPosition(0, 0);
369     glutInitWindowSize(__window_width, __window_height);
370     glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | (double_buffer ? GLUT_DOUBLE : GLUT_SINGLE));
371     glutCreateWindow(argv[0]);
372
373     glutDisplayFunc(&display);
374     glutIdleFunc(&idle);
375
376     for (GLuint h = 0; h < 1024; ++h) {
377         __list_map[h] = h;
378     }
379
380     for ( ; i < argc; ++i) {
381         if (parser.open(argv[i])) {
382             __startTime = OS::GetTime();
383             glutMainLoop();
384             parser.close();
385         }
386     }
387
388     return 0;
389 }
390
391 '''