blob: 451c938033e9fa9413442f0c58c9e26bb884ca9b [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
José Fonseca68ec4122011-02-20 11:25:25 +0000154#define RETRACE
155
José Fonsecadf66a902010-11-29 13:24:20 +0000156#include "glproc.hpp"
157#include <GL/glut.h>
158
159static bool double_buffer = false;
160static bool insideGlBeginEnd = false;
161
162static int __window_width = 256, __window_height = 256;
163bool __reshape_window = false;
164
165unsigned __frame = 0;
166long long __startTime = 0;
José Fonseca4c04b642011-02-01 19:35:41 +0000167bool __wait = false;
José Fonseca796a3042010-11-29 14:21:06 +0000168
José Fonsecaecf2f742011-02-09 14:51:07 +0000169bool __benchmark = false;
José Fonseca87f19712011-02-09 14:49:50 +0000170const char *__compare_prefix = NULL;
171const char *__snapshot_prefix = NULL;
José Fonseca7fe1dc52010-12-13 20:18:39 +0000172
José Fonsecadf66a902010-11-29 13:24:20 +0000173
José Fonseca3d245f42010-11-28 00:08:23 +0000174static void
175checkGlError(void) {
José Fonsecaecf2f742011-02-09 14:51:07 +0000176 if (__benchmark || insideGlBeginEnd) {
José Fonseca3d245f42010-11-28 00:08:23 +0000177 return;
178 }
179
180 GLenum error = glGetError();
181 if (error == GL_NO_ERROR) {
182 return;
183 }
184
185 std::cerr << "warning: glGetError() = ";
186 switch (error) {
187 case GL_INVALID_ENUM:
188 std::cerr << "GL_INVALID_ENUM";
189 break;
190 case GL_INVALID_VALUE:
191 std::cerr << "GL_INVALID_VALUE";
192 break;
193 case GL_INVALID_OPERATION:
194 std::cerr << "GL_INVALID_OPERATION";
195 break;
196 case GL_STACK_OVERFLOW:
197 std::cerr << "GL_STACK_OVERFLOW";
198 break;
199 case GL_STACK_UNDERFLOW:
200 std::cerr << "GL_STACK_UNDERFLOW";
201 break;
202 case GL_OUT_OF_MEMORY:
203 std::cerr << "GL_OUT_OF_MEMORY";
204 break;
205 case GL_INVALID_FRAMEBUFFER_OPERATION:
206 std::cerr << "GL_INVALID_FRAMEBUFFER_OPERATION";
207 break;
208 case GL_TABLE_TOO_LARGE:
209 std::cerr << "GL_TABLE_TOO_LARGE";
210 break;
211 default:
212 std::cerr << error;
213 break;
214 }
José Fonseca796a3042010-11-29 14:21:06 +0000215 std::cerr << "\n";
José Fonseca3d245f42010-11-28 00:08:23 +0000216}
217'''
José Fonsecae0e61402010-11-25 15:03:23 +0000218 api = glapi.glapi
219 retracer = GlRetracer()
220 retracer.retrace_api(glapi.glapi)
José Fonseca796a3042010-11-29 14:21:06 +0000221 print r'''
José Fonseca7e329022010-11-19 17:05:18 +0000222
José Fonseca3d245f42010-11-28 00:08:23 +0000223static Trace::Parser parser;
José Fonseca082051b2010-11-23 12:00:31 +0000224
José Fonsecadf66a902010-11-29 13:24:20 +0000225static void display_noop(void) {
226}
227
José Fonseca20f35e02010-12-04 12:21:12 +0000228#include "image.hpp"
José Fonseca796a3042010-11-29 14:21:06 +0000229
José Fonseca1ff16732011-02-09 15:58:51 +0000230static void snapshot(Image::Image &image) {
231 GLint drawbuffer = double_buffer ? GL_BACK : GL_FRONT;
232 GLint readbuffer = double_buffer ? GL_BACK : GL_FRONT;
233 glGetIntegerv(GL_READ_BUFFER, &drawbuffer);
234 glGetIntegerv(GL_READ_BUFFER, &readbuffer);
235 glReadBuffer(drawbuffer);
236 glReadPixels(0, 0, image.width, image.height, GL_RGBA, GL_UNSIGNED_BYTE, image.pixels);
237 checkGlError();
238 glReadBuffer(readbuffer);
239}
240
José Fonseca796a3042010-11-29 14:21:06 +0000241static void frame_complete(void) {
242 ++__frame;
243
José Fonseca4fe63f72011-02-08 16:01:10 +0000244 if (!__reshape_window && (__snapshot_prefix || __compare_prefix)) {
José Fonseca5780c442010-12-14 14:13:53 +0000245 Image::Image *ref = NULL;
José Fonseca4fe63f72011-02-08 16:01:10 +0000246 if (__compare_prefix) {
247 char filename[PATH_MAX];
248 snprintf(filename, sizeof filename, "%s%04u.png", __compare_prefix, __frame);
José Fonseca077142e2010-12-12 11:13:33 +0000249 ref = Image::readPNG(filename);
250 if (!ref) {
251 return;
252 }
José Fonsecaecf2f742011-02-09 14:51:07 +0000253 if (verbosity >= 0)
José Fonseca077142e2010-12-12 11:13:33 +0000254 std::cout << "Read " << filename << "\n";
255 }
256
257 Image::Image src(__window_width, __window_height, true);
José Fonseca1ff16732011-02-09 15:58:51 +0000258 snapshot(src);
José Fonseca077142e2010-12-12 11:13:33 +0000259
José Fonseca4fe63f72011-02-08 16:01:10 +0000260 if (__snapshot_prefix) {
261 char filename[PATH_MAX];
262 snprintf(filename, sizeof filename, "%s%04u.png", __snapshot_prefix, __frame);
José Fonsecaecf2f742011-02-09 14:51:07 +0000263 if (src.writePNG(filename) && verbosity >= 0) {
José Fonseca077142e2010-12-12 11:13:33 +0000264 std::cout << "Wrote " << filename << "\n";
265 }
266 }
267
José Fonseca4fe63f72011-02-08 16:01:10 +0000268 if (ref) {
José Fonseca077142e2010-12-12 11:13:33 +0000269 std::cout << "Frame " << __frame << " average precision of " << src.compare(*ref) << " bits\n";
270 delete ref;
271 }
José Fonseca796a3042010-11-29 14:21:06 +0000272 }
273
274}
275
José Fonseca6f51d3b2010-11-22 19:56:19 +0000276static void display(void) {
José Fonseca3d245f42010-11-28 00:08:23 +0000277 Trace::Call *call;
José Fonseca6f51d3b2010-11-22 19:56:19 +0000278
José Fonseca3d245f42010-11-28 00:08:23 +0000279 while ((call = parser.parse_call())) {
José Fonseca83a1e152010-12-13 20:26:51 +0000280 const std::string &name = call->name();
281
282 if ((name[0] == 'w' && name[1] == 'g' && name[2] == 'l') ||
283 (name[0] == 'g' && name[1] == 'l' && name[2] == 'X')) {
284 // XXX: We ignore the majority of the OS-specific calls for now
285 if (name == "glXSwapBuffers" ||
286 name == "wglSwapBuffers") {
José Fonseca1ff16732011-02-09 15:58:51 +0000287 frame_complete();
José Fonseca3d245f42010-11-28 00:08:23 +0000288 if (double_buffer)
289 glutSwapBuffers();
290 else
291 glFlush();
292 return;
José Fonseca83a1e152010-12-13 20:26:51 +0000293 } else {
294 continue;
José Fonseca082051b2010-11-23 12:00:31 +0000295 }
José Fonseca3d245f42010-11-28 00:08:23 +0000296 }
José Fonseca83a1e152010-12-13 20:26:51 +0000297
298 if (name == "glFlush") {
José Fonseca83a1e152010-12-13 20:26:51 +0000299 if (!double_buffer) {
300 frame_complete();
301 }
José Fonseca1ff16732011-02-09 15:58:51 +0000302 glFlush();
José Fonseca83a1e152010-12-13 20:26:51 +0000303 }
304
305 retrace_call(*call);
José Fonsecaae9668b2011-02-09 15:15:08 +0000306
307 delete call;
José Fonseca3d245f42010-11-28 00:08:23 +0000308 }
José Fonseca6f51d3b2010-11-22 19:56:19 +0000309
José Fonsecadf66a902010-11-29 13:24:20 +0000310 // Reached the end of trace
José Fonseca3d245f42010-11-28 00:08:23 +0000311 glFlush();
José Fonsecadf66a902010-11-29 13:24:20 +0000312
313 long long endTime = OS::GetTime();
314 float timeInterval = (endTime - __startTime) * 1.0E-6;
315
316 std::cout <<
317 "Rendered " << __frame << " frames"
318 " in " << timeInterval << " secs,"
José Fonseca796a3042010-11-29 14:21:06 +0000319 " average of " << (__frame/timeInterval) << " fps\n";
José Fonsecadf66a902010-11-29 13:24:20 +0000320
José Fonseca4c04b642011-02-01 19:35:41 +0000321 if (__wait) {
José Fonseca077142e2010-12-12 11:13:33 +0000322 glutDisplayFunc(&display_noop);
323 glutIdleFunc(NULL);
324 } else {
325 exit(0);
326 }
José Fonseca6f51d3b2010-11-22 19:56:19 +0000327}
328
329static void idle(void) {
José Fonsecacdb574a2010-11-29 12:23:35 +0000330 if (__reshape_window) {
331 // XXX: doesn't quite work
332 glutReshapeWindow(__window_width, __window_height);
333 __reshape_window = false;
334 }
José Fonseca3d245f42010-11-28 00:08:23 +0000335 glutPostRedisplay();
José Fonseca6f51d3b2010-11-22 19:56:19 +0000336}
José Fonseca7e329022010-11-19 17:05:18 +0000337
José Fonseca077142e2010-12-12 11:13:33 +0000338static void usage(void) {
339 std::cout <<
340 "Usage: glretrace [OPTION] TRACE\n"
341 "Replay TRACE.\n"
342 "\n"
José Fonsecaecf2f742011-02-09 14:51:07 +0000343 " -b benchmark (no glgeterror; no messages)\n"
José Fonseca4fe63f72011-02-08 16:01:10 +0000344 " -c PREFIX compare against snapshots\n"
José Fonseca077142e2010-12-12 11:13:33 +0000345 " -db use a double buffer visual\n"
José Fonseca4fe63f72011-02-08 16:01:10 +0000346 " -s PREFIX take snapshots\n"
José Fonseca077142e2010-12-12 11:13:33 +0000347 " -v verbose output\n";
348}
349
José Fonseca7e329022010-11-19 17:05:18 +0000350int main(int argc, char **argv)
351{
José Fonseca6f51d3b2010-11-22 19:56:19 +0000352
José Fonseca3d245f42010-11-28 00:08:23 +0000353 int i;
354 for (i = 1; i < argc; ++i) {
355 const char *arg = argv[i];
José Fonseca094cb2d2010-11-24 15:55:03 +0000356
José Fonseca3d245f42010-11-28 00:08:23 +0000357 if (arg[0] != '-') {
358 break;
359 }
José Fonseca094cb2d2010-11-24 15:55:03 +0000360
José Fonseca3d245f42010-11-28 00:08:23 +0000361 if (!strcmp(arg, "--")) {
362 break;
José Fonsecaecf2f742011-02-09 14:51:07 +0000363 } else if (!strcmp(arg, "-b")) {
364 __benchmark = true;
365 --verbosity;
José Fonseca077142e2010-12-12 11:13:33 +0000366 } else if (!strcmp(arg, "-c")) {
José Fonseca4fe63f72011-02-08 16:01:10 +0000367 __compare_prefix = argv[++i];
José Fonseca796a3042010-11-29 14:21:06 +0000368 } else if (!strcmp(arg, "-db")) {
José Fonseca3d245f42010-11-28 00:08:23 +0000369 double_buffer = true;
José Fonseca077142e2010-12-12 11:13:33 +0000370 } else if (!strcmp(arg, "--help")) {
371 usage();
372 return 0;
José Fonseca796a3042010-11-29 14:21:06 +0000373 } else if (!strcmp(arg, "-s")) {
José Fonseca4fe63f72011-02-08 16:01:10 +0000374 __snapshot_prefix = argv[++i];
José Fonseca3d245f42010-11-28 00:08:23 +0000375 } else if (!strcmp(arg, "-v")) {
376 ++verbosity;
José Fonseca4c04b642011-02-01 19:35:41 +0000377 } else if (!strcmp(arg, "-w")) {
378 __wait = true;
José Fonseca3d245f42010-11-28 00:08:23 +0000379 } else {
José Fonseca796a3042010-11-29 14:21:06 +0000380 std::cerr << "error: unknown option " << arg << "\n";
José Fonseca077142e2010-12-12 11:13:33 +0000381 usage();
José Fonseca3d245f42010-11-28 00:08:23 +0000382 return 1;
383 }
384 }
José Fonseca094cb2d2010-11-24 15:55:03 +0000385
José Fonseca3d245f42010-11-28 00:08:23 +0000386 glutInit(&argc, argv);
387 glutInitWindowPosition(0, 0);
José Fonsecacdb574a2010-11-29 12:23:35 +0000388 glutInitWindowSize(__window_width, __window_height);
José Fonseca3d245f42010-11-28 00:08:23 +0000389 glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | (double_buffer ? GLUT_DOUBLE : GLUT_SINGLE));
390 glutCreateWindow(argv[0]);
José Fonsecafeb5d992010-11-25 17:14:18 +0000391
José Fonseca3d245f42010-11-28 00:08:23 +0000392 glutDisplayFunc(&display);
393 glutIdleFunc(&idle);
José Fonsecafeb5d992010-11-25 17:14:18 +0000394
José Fonseca3d245f42010-11-28 00:08:23 +0000395 for (GLuint h = 0; h < 1024; ++h) {
396 __list_map[h] = h;
397 }
José Fonsecafeb5d992010-11-25 17:14:18 +0000398
José Fonseca3d245f42010-11-28 00:08:23 +0000399 for ( ; i < argc; ++i) {
400 if (parser.open(argv[i])) {
José Fonsecadf66a902010-11-29 13:24:20 +0000401 __startTime = OS::GetTime();
José Fonseca3d245f42010-11-28 00:08:23 +0000402 glutMainLoop();
403 parser.close();
404 }
405 }
José Fonseca6f51d3b2010-11-22 19:56:19 +0000406
José Fonseca3d245f42010-11-28 00:08:23 +0000407 return 0;
José Fonseca7e329022010-11-19 17:05:18 +0000408}
409
José Fonseca3d245f42010-11-28 00:08:23 +0000410'''