blob: c516c16f153c25f1db9c10140606b772dd87039f [file] [log] [blame]
José Fonseca7e329022010-11-19 17:05:18 +00001##########################################################################
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
José Fonseca4a826ed2010-11-30 16:58:22 +000027"""GL retracer generator."""
28
29
José Fonseca9796b842010-11-25 11:44:50 +000030import stdapi
José Fonseca8fbdd3a2010-11-23 20:55:07 +000031import glapi
José Fonsecadacd8dd2010-11-25 17:50:26 +000032from retrace import Retracer
José Fonseca7e329022010-11-19 17:05:18 +000033
34
José Fonsecadacd8dd2010-11-25 17:50:26 +000035class GlRetracer(Retracer):
José Fonsecac9edb832010-11-20 09:03:10 +000036
José Fonseca3d245f42010-11-28 00:08:23 +000037 def retrace_function(self, function):
38 Retracer.retrace_function(self, function)
39
José Fonseca8caf2c82010-11-30 12:09:12 +000040 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
José Fonsecafa15d332010-11-25 20:22:39 +000070 def call_function(self, function):
José Fonseca8caf2c82010-11-30 12:09:12 +000071 if (function.name in self.draw_array_function_names or
72 function.name in self.draw_elements_function_names):
José Fonsecafa15d332010-11-25 20:22:39 +000073 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
José Fonseca8caf2c82010-11-30 12:09:12 +000079 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
José Fonsecacdb574a2010-11-29 12:23:35 +000086 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
José Fonseca3d245f42010-11-28 00:08:23 +000096 if function.name == "glEnd":
97 print ' insideGlBeginEnd = false;'
José Fonsecacdb574a2010-11-29 12:23:35 +000098
José Fonsecafa15d332010-11-25 20:22:39 +000099 Retracer.call_function(self, function)
José Fonsecacdb574a2010-11-29 12:23:35 +0000100
José Fonseca3d245f42010-11-28 00:08:23 +0000101 if function.name == "glBegin":
102 print ' insideGlBeginEnd = true;'
103 else:
104 # glGetError is not allowed inside glBegin/glEnd
105 print ' checkGlError();'
106
José Fonseca8caf2c82010-11-30 12:09:12 +0000107 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 ])
José Fonsecafa15d332010-11-25 20:22:39 +0000130
José Fonsecadacd8dd2010-11-25 17:50:26 +0000131 def extract_arg(self, function, arg, arg_type, lvalue, rvalue):
José Fonseca8caf2c82010-11-30 12:09:12 +0000132 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'):
José Fonseca8a844ae2010-12-06 18:50:52 +0000134 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
José Fonsecadacd8dd2010-11-25 17:50:26 +0000140
José Fonseca8a844ae2010-12-06 18:50:52 +0000141 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)
José Fonsecae6a50bd2010-11-24 10:12:22 +0000146
147
José Fonseca7e329022010-11-19 17:05:18 +0000148if __name__ == '__main__':
José Fonseca796a3042010-11-29 14:21:06 +0000149 print r'''
José Fonsecadf66a902010-11-29 13:24:20 +0000150#include <string.h>
José Fonsecae0081492010-12-04 13:24:17 +0000151#include <stdio.h>
José Fonsecadf66a902010-11-29 13:24:20 +0000152#include <iostream>
153
154#include "glproc.hpp"
155#include <GL/glut.h>
156
157static bool double_buffer = false;
158static bool insideGlBeginEnd = false;
159
160static int __window_width = 256, __window_height = 256;
161bool __reshape_window = false;
162
163unsigned __frame = 0;
164long long __startTime = 0;
José Fonseca077142e2010-12-12 11:13:33 +0000165static enum {
166 MODE_DISPLAY = 0,
167 MODE_SCREENSHOT,
168 MODE_COMPARE,
169} __mode = MODE_DISPLAY;
José Fonseca796a3042010-11-29 14:21:06 +0000170
José Fonsecadf66a902010-11-29 13:24:20 +0000171
José Fonseca3d245f42010-11-28 00:08:23 +0000172static void
173checkGlError(void) {
174 if (insideGlBeginEnd) {
175 return;
176 }
177
178 GLenum error = glGetError();
179 if (error == GL_NO_ERROR) {
180 return;
181 }
182
183 std::cerr << "warning: glGetError() = ";
184 switch (error) {
185 case GL_INVALID_ENUM:
186 std::cerr << "GL_INVALID_ENUM";
187 break;
188 case GL_INVALID_VALUE:
189 std::cerr << "GL_INVALID_VALUE";
190 break;
191 case GL_INVALID_OPERATION:
192 std::cerr << "GL_INVALID_OPERATION";
193 break;
194 case GL_STACK_OVERFLOW:
195 std::cerr << "GL_STACK_OVERFLOW";
196 break;
197 case GL_STACK_UNDERFLOW:
198 std::cerr << "GL_STACK_UNDERFLOW";
199 break;
200 case GL_OUT_OF_MEMORY:
201 std::cerr << "GL_OUT_OF_MEMORY";
202 break;
203 case GL_INVALID_FRAMEBUFFER_OPERATION:
204 std::cerr << "GL_INVALID_FRAMEBUFFER_OPERATION";
205 break;
206 case GL_TABLE_TOO_LARGE:
207 std::cerr << "GL_TABLE_TOO_LARGE";
208 break;
209 default:
210 std::cerr << error;
211 break;
212 }
José Fonseca796a3042010-11-29 14:21:06 +0000213 std::cerr << "\n";
José Fonseca3d245f42010-11-28 00:08:23 +0000214}
215'''
José Fonsecae0e61402010-11-25 15:03:23 +0000216 api = glapi.glapi
217 retracer = GlRetracer()
218 retracer.retrace_api(glapi.glapi)
José Fonseca796a3042010-11-29 14:21:06 +0000219 print r'''
José Fonseca7e329022010-11-19 17:05:18 +0000220
José Fonseca3d245f42010-11-28 00:08:23 +0000221static Trace::Parser parser;
José Fonseca082051b2010-11-23 12:00:31 +0000222
José Fonsecadf66a902010-11-29 13:24:20 +0000223static void display_noop(void) {
224}
225
José Fonseca20f35e02010-12-04 12:21:12 +0000226#include "image.hpp"
José Fonseca796a3042010-11-29 14:21:06 +0000227
228static void frame_complete(void) {
229 ++__frame;
230
José Fonseca077142e2010-12-12 11:13:33 +0000231 if (!__reshape_window && (__mode == MODE_SCREENSHOT || __mode == MODE_COMPARE)) {
José Fonseca796a3042010-11-29 14:21:06 +0000232 char filename[PATH_MAX];
José Fonseca077142e2010-12-12 11:13:33 +0000233
José Fonseca0a91a3e2010-12-04 13:13:47 +0000234 snprintf(filename, sizeof filename, "screenshot_%04u.png", __frame);
José Fonseca077142e2010-12-12 11:13:33 +0000235
236 Image::Image *ref;
237 if (__mode == MODE_COMPARE) {
238 ref = Image::readPNG(filename);
239 if (!ref) {
240 return;
241 }
242 if (verbosity)
243 std::cout << "Read " << filename << "\n";
244 }
245
246 Image::Image src(__window_width, __window_height, true);
247 glReadPixels(0, 0, __window_width, __window_height, GL_RGBA, GL_UNSIGNED_BYTE, src.pixels);
248
249 if (__mode == MODE_SCREENSHOT) {
250 if (src.writePNG(filename) && verbosity) {
251 std::cout << "Wrote " << filename << "\n";
252 }
253 }
254
255 if (__mode == MODE_COMPARE) {
256 std::cout << "Frame " << __frame << " average precision of " << src.compare(*ref) << " bits\n";
257 delete ref;
258 }
José Fonseca796a3042010-11-29 14:21:06 +0000259 }
260
261}
262
José Fonseca6f51d3b2010-11-22 19:56:19 +0000263static void display(void) {
José Fonseca3d245f42010-11-28 00:08:23 +0000264 Trace::Call *call;
José Fonseca6f51d3b2010-11-22 19:56:19 +0000265
José Fonseca3d245f42010-11-28 00:08:23 +0000266 while ((call = parser.parse_call())) {
267 if (call->name() == "glFlush") {
José Fonsecafeb5d992010-11-25 17:14:18 +0000268 glFlush();
José Fonsecadf66a902010-11-29 13:24:20 +0000269 if (!double_buffer) {
José Fonseca796a3042010-11-29 14:21:06 +0000270 frame_complete();
José Fonsecadf66a902010-11-29 13:24:20 +0000271 }
José Fonseca3d245f42010-11-28 00:08:23 +0000272 }
273
274 if (!retrace_call(*call)) {
275 if (call->name() == "glXSwapBuffers" ||
276 call->name() == "wglSwapBuffers") {
277 if (double_buffer)
278 glutSwapBuffers();
279 else
280 glFlush();
José Fonseca796a3042010-11-29 14:21:06 +0000281 frame_complete();
José Fonseca3d245f42010-11-28 00:08:23 +0000282 return;
José Fonseca082051b2010-11-23 12:00:31 +0000283 }
José Fonseca3d245f42010-11-28 00:08:23 +0000284 }
285 }
José Fonseca6f51d3b2010-11-22 19:56:19 +0000286
José Fonsecadf66a902010-11-29 13:24:20 +0000287 // Reached the end of trace
José Fonseca3d245f42010-11-28 00:08:23 +0000288 glFlush();
José Fonsecadf66a902010-11-29 13:24:20 +0000289
290 long long endTime = OS::GetTime();
291 float timeInterval = (endTime - __startTime) * 1.0E-6;
292
293 std::cout <<
294 "Rendered " << __frame << " frames"
295 " in " << timeInterval << " secs,"
José Fonseca796a3042010-11-29 14:21:06 +0000296 " average of " << (__frame/timeInterval) << " fps\n";
José Fonsecadf66a902010-11-29 13:24:20 +0000297
José Fonseca077142e2010-12-12 11:13:33 +0000298 if (__mode == MODE_DISPLAY) {
299 glutDisplayFunc(&display_noop);
300 glutIdleFunc(NULL);
301 } else {
302 exit(0);
303 }
José Fonseca6f51d3b2010-11-22 19:56:19 +0000304}
305
306static void idle(void) {
José Fonsecacdb574a2010-11-29 12:23:35 +0000307 if (__reshape_window) {
308 // XXX: doesn't quite work
309 glutReshapeWindow(__window_width, __window_height);
310 __reshape_window = false;
311 }
José Fonseca3d245f42010-11-28 00:08:23 +0000312 glutPostRedisplay();
José Fonseca6f51d3b2010-11-22 19:56:19 +0000313}
José Fonseca7e329022010-11-19 17:05:18 +0000314
José Fonseca077142e2010-12-12 11:13:33 +0000315static void usage(void) {
316 std::cout <<
317 "Usage: glretrace [OPTION] TRACE\n"
318 "Replay TRACE.\n"
319 "\n"
320 " -c compare against screenshots\n"
321 " -db use a double buffer visual\n"
322 " -s take snapshots\n"
323 " -v verbose output\n";
324}
325
José Fonseca7e329022010-11-19 17:05:18 +0000326int main(int argc, char **argv)
327{
José Fonseca6f51d3b2010-11-22 19:56:19 +0000328
José Fonseca3d245f42010-11-28 00:08:23 +0000329 int i;
330 for (i = 1; i < argc; ++i) {
331 const char *arg = argv[i];
José Fonseca094cb2d2010-11-24 15:55:03 +0000332
José Fonseca3d245f42010-11-28 00:08:23 +0000333 if (arg[0] != '-') {
334 break;
335 }
José Fonseca094cb2d2010-11-24 15:55:03 +0000336
José Fonseca3d245f42010-11-28 00:08:23 +0000337 if (!strcmp(arg, "--")) {
338 break;
José Fonseca077142e2010-12-12 11:13:33 +0000339 } else if (!strcmp(arg, "-c")) {
340 __mode = MODE_COMPARE;
José Fonseca796a3042010-11-29 14:21:06 +0000341 } else if (!strcmp(arg, "-db")) {
José Fonseca3d245f42010-11-28 00:08:23 +0000342 double_buffer = true;
José Fonseca077142e2010-12-12 11:13:33 +0000343 } else if (!strcmp(arg, "--help")) {
344 usage();
345 return 0;
José Fonseca796a3042010-11-29 14:21:06 +0000346 } else if (!strcmp(arg, "-s")) {
José Fonseca077142e2010-12-12 11:13:33 +0000347 __mode = MODE_SCREENSHOT;
José Fonseca3d245f42010-11-28 00:08:23 +0000348 } else if (!strcmp(arg, "-v")) {
349 ++verbosity;
350 } else {
José Fonseca796a3042010-11-29 14:21:06 +0000351 std::cerr << "error: unknown option " << arg << "\n";
José Fonseca077142e2010-12-12 11:13:33 +0000352 usage();
José Fonseca3d245f42010-11-28 00:08:23 +0000353 return 1;
354 }
355 }
José Fonseca094cb2d2010-11-24 15:55:03 +0000356
José Fonseca3d245f42010-11-28 00:08:23 +0000357 glutInit(&argc, argv);
358 glutInitWindowPosition(0, 0);
José Fonsecacdb574a2010-11-29 12:23:35 +0000359 glutInitWindowSize(__window_width, __window_height);
José Fonseca3d245f42010-11-28 00:08:23 +0000360 glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | (double_buffer ? GLUT_DOUBLE : GLUT_SINGLE));
361 glutCreateWindow(argv[0]);
José Fonsecafeb5d992010-11-25 17:14:18 +0000362
José Fonseca3d245f42010-11-28 00:08:23 +0000363 glutDisplayFunc(&display);
364 glutIdleFunc(&idle);
José Fonsecafeb5d992010-11-25 17:14:18 +0000365
José Fonseca3d245f42010-11-28 00:08:23 +0000366 for (GLuint h = 0; h < 1024; ++h) {
367 __list_map[h] = h;
368 }
José Fonsecafeb5d992010-11-25 17:14:18 +0000369
José Fonseca3d245f42010-11-28 00:08:23 +0000370 for ( ; i < argc; ++i) {
371 if (parser.open(argv[i])) {
José Fonsecadf66a902010-11-29 13:24:20 +0000372 __startTime = OS::GetTime();
José Fonseca3d245f42010-11-28 00:08:23 +0000373 glutMainLoop();
374 parser.close();
375 }
376 }
José Fonseca6f51d3b2010-11-22 19:56:19 +0000377
José Fonseca3d245f42010-11-28 00:08:23 +0000378 return 0;
José Fonseca7e329022010-11-19 17:05:18 +0000379}
380
José Fonseca3d245f42010-11-28 00:08:23 +0000381'''