blob: e047ed0c47e4c4222747ff7d598d80d000224865 [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é Fonsecadacd8dd2010-11-25 17:50:26 +0000134 self.extract_pointer(function, arg, arg_type, lvalue, rvalue)
135 else:
136 Retracer.extract_arg(self, function, arg, arg_type, lvalue, rvalue)
137
138 def extract_pointer(self, function, arg, arg_type, lvalue, rvalue):
139 print ' if (dynamic_cast<Trace::Null *>(&%s)) {' % rvalue
140 print ' %s = 0;' % (lvalue)
141 print ' } else {'
142 print ' %s = (%s)(uintptr_t)(%s);' % (lvalue, arg_type, rvalue)
143 print ' }'
José Fonsecae6a50bd2010-11-24 10:12:22 +0000144
145
José Fonseca7e329022010-11-19 17:05:18 +0000146if __name__ == '__main__':
José Fonseca796a3042010-11-29 14:21:06 +0000147 print r'''
José Fonsecadf66a902010-11-29 13:24:20 +0000148#include <string.h>
José Fonsecae0081492010-12-04 13:24:17 +0000149#include <stdio.h>
José Fonsecadf66a902010-11-29 13:24:20 +0000150#include <iostream>
151
152#include "glproc.hpp"
153#include <GL/glut.h>
154
155static bool double_buffer = false;
156static bool insideGlBeginEnd = false;
157
158static int __window_width = 256, __window_height = 256;
159bool __reshape_window = false;
160
161unsigned __frame = 0;
162long long __startTime = 0;
José Fonseca796a3042010-11-29 14:21:06 +0000163bool __screenshots = 0;
164
José Fonsecadf66a902010-11-29 13:24:20 +0000165
José Fonseca3d245f42010-11-28 00:08:23 +0000166static void
167checkGlError(void) {
168 if (insideGlBeginEnd) {
169 return;
170 }
171
172 GLenum error = glGetError();
173 if (error == GL_NO_ERROR) {
174 return;
175 }
176
177 std::cerr << "warning: glGetError() = ";
178 switch (error) {
179 case GL_INVALID_ENUM:
180 std::cerr << "GL_INVALID_ENUM";
181 break;
182 case GL_INVALID_VALUE:
183 std::cerr << "GL_INVALID_VALUE";
184 break;
185 case GL_INVALID_OPERATION:
186 std::cerr << "GL_INVALID_OPERATION";
187 break;
188 case GL_STACK_OVERFLOW:
189 std::cerr << "GL_STACK_OVERFLOW";
190 break;
191 case GL_STACK_UNDERFLOW:
192 std::cerr << "GL_STACK_UNDERFLOW";
193 break;
194 case GL_OUT_OF_MEMORY:
195 std::cerr << "GL_OUT_OF_MEMORY";
196 break;
197 case GL_INVALID_FRAMEBUFFER_OPERATION:
198 std::cerr << "GL_INVALID_FRAMEBUFFER_OPERATION";
199 break;
200 case GL_TABLE_TOO_LARGE:
201 std::cerr << "GL_TABLE_TOO_LARGE";
202 break;
203 default:
204 std::cerr << error;
205 break;
206 }
José Fonseca796a3042010-11-29 14:21:06 +0000207 std::cerr << "\n";
José Fonseca3d245f42010-11-28 00:08:23 +0000208}
209'''
José Fonsecae0e61402010-11-25 15:03:23 +0000210 api = glapi.glapi
211 retracer = GlRetracer()
212 retracer.retrace_api(glapi.glapi)
José Fonseca796a3042010-11-29 14:21:06 +0000213 print r'''
José Fonseca7e329022010-11-19 17:05:18 +0000214
José Fonseca3d245f42010-11-28 00:08:23 +0000215static Trace::Parser parser;
José Fonseca082051b2010-11-23 12:00:31 +0000216
José Fonsecadf66a902010-11-29 13:24:20 +0000217static void display_noop(void) {
218}
219
José Fonseca20f35e02010-12-04 12:21:12 +0000220#include "image.hpp"
José Fonseca796a3042010-11-29 14:21:06 +0000221
222static void frame_complete(void) {
223 ++__frame;
224
225 if (__screenshots && !__reshape_window) {
226 char filename[PATH_MAX];
José Fonseca0a91a3e2010-12-04 13:13:47 +0000227 snprintf(filename, sizeof filename, "screenshot_%04u.png", __frame);
José Fonseca20f35e02010-12-04 12:21:12 +0000228 Image::Image image(__window_width, __window_height, true);
229 glReadPixels(0, 0, __window_width, __window_height, GL_RGBA, GL_UNSIGNED_BYTE, image.pixels);
José Fonseca0a91a3e2010-12-04 13:13:47 +0000230 image.writePNG(filename);
José Fonseca796a3042010-11-29 14:21:06 +0000231 }
232
233}
234
José Fonseca6f51d3b2010-11-22 19:56:19 +0000235static void display(void) {
José Fonseca3d245f42010-11-28 00:08:23 +0000236 Trace::Call *call;
José Fonseca6f51d3b2010-11-22 19:56:19 +0000237
José Fonseca3d245f42010-11-28 00:08:23 +0000238 while ((call = parser.parse_call())) {
239 if (call->name() == "glFlush") {
José Fonsecafeb5d992010-11-25 17:14:18 +0000240 glFlush();
José Fonsecadf66a902010-11-29 13:24:20 +0000241 if (!double_buffer) {
José Fonseca796a3042010-11-29 14:21:06 +0000242 frame_complete();
José Fonsecadf66a902010-11-29 13:24:20 +0000243 }
José Fonseca3d245f42010-11-28 00:08:23 +0000244 }
245
246 if (!retrace_call(*call)) {
247 if (call->name() == "glXSwapBuffers" ||
248 call->name() == "wglSwapBuffers") {
249 if (double_buffer)
250 glutSwapBuffers();
251 else
252 glFlush();
José Fonseca796a3042010-11-29 14:21:06 +0000253 frame_complete();
José Fonseca3d245f42010-11-28 00:08:23 +0000254 return;
José Fonseca082051b2010-11-23 12:00:31 +0000255 }
José Fonseca3d245f42010-11-28 00:08:23 +0000256 }
257 }
José Fonseca6f51d3b2010-11-22 19:56:19 +0000258
José Fonsecadf66a902010-11-29 13:24:20 +0000259 // Reached the end of trace
José Fonseca3d245f42010-11-28 00:08:23 +0000260 glFlush();
José Fonsecadf66a902010-11-29 13:24:20 +0000261
262 long long endTime = OS::GetTime();
263 float timeInterval = (endTime - __startTime) * 1.0E-6;
264
265 std::cout <<
266 "Rendered " << __frame << " frames"
267 " in " << timeInterval << " secs,"
José Fonseca796a3042010-11-29 14:21:06 +0000268 " average of " << (__frame/timeInterval) << " fps\n";
José Fonsecadf66a902010-11-29 13:24:20 +0000269
270 glutDisplayFunc(&display_noop);
José Fonseca3d245f42010-11-28 00:08:23 +0000271 glutIdleFunc(NULL);
José Fonseca6f51d3b2010-11-22 19:56:19 +0000272}
273
274static void idle(void) {
José Fonsecacdb574a2010-11-29 12:23:35 +0000275 if (__reshape_window) {
276 // XXX: doesn't quite work
277 glutReshapeWindow(__window_width, __window_height);
278 __reshape_window = false;
279 }
José Fonseca3d245f42010-11-28 00:08:23 +0000280 glutPostRedisplay();
José Fonseca6f51d3b2010-11-22 19:56:19 +0000281}
José Fonseca7e329022010-11-19 17:05:18 +0000282
283int main(int argc, char **argv)
284{
José Fonseca6f51d3b2010-11-22 19:56:19 +0000285
José Fonseca3d245f42010-11-28 00:08:23 +0000286 int i;
287 for (i = 1; i < argc; ++i) {
288 const char *arg = argv[i];
José Fonseca094cb2d2010-11-24 15:55:03 +0000289
José Fonseca3d245f42010-11-28 00:08:23 +0000290 if (arg[0] != '-') {
291 break;
292 }
José Fonseca094cb2d2010-11-24 15:55:03 +0000293
José Fonseca3d245f42010-11-28 00:08:23 +0000294 if (!strcmp(arg, "--")) {
295 break;
José Fonseca796a3042010-11-29 14:21:06 +0000296 } else if (!strcmp(arg, "-db")) {
José Fonseca3d245f42010-11-28 00:08:23 +0000297 double_buffer = true;
José Fonseca796a3042010-11-29 14:21:06 +0000298 } else if (!strcmp(arg, "-s")) {
299 __screenshots = true;
José Fonseca3d245f42010-11-28 00:08:23 +0000300 } else if (!strcmp(arg, "-v")) {
301 ++verbosity;
302 } else {
José Fonseca796a3042010-11-29 14:21:06 +0000303 std::cerr << "error: unknown option " << arg << "\n";
José Fonseca3d245f42010-11-28 00:08:23 +0000304 return 1;
305 }
306 }
José Fonseca094cb2d2010-11-24 15:55:03 +0000307
José Fonseca3d245f42010-11-28 00:08:23 +0000308 glutInit(&argc, argv);
309 glutInitWindowPosition(0, 0);
José Fonsecacdb574a2010-11-29 12:23:35 +0000310 glutInitWindowSize(__window_width, __window_height);
José Fonseca3d245f42010-11-28 00:08:23 +0000311 glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | (double_buffer ? GLUT_DOUBLE : GLUT_SINGLE));
312 glutCreateWindow(argv[0]);
José Fonsecafeb5d992010-11-25 17:14:18 +0000313
José Fonseca3d245f42010-11-28 00:08:23 +0000314 glutDisplayFunc(&display);
315 glutIdleFunc(&idle);
José Fonsecafeb5d992010-11-25 17:14:18 +0000316
José Fonseca3d245f42010-11-28 00:08:23 +0000317 for (GLuint h = 0; h < 1024; ++h) {
318 __list_map[h] = h;
319 }
José Fonsecafeb5d992010-11-25 17:14:18 +0000320
José Fonseca3d245f42010-11-28 00:08:23 +0000321 for ( ; i < argc; ++i) {
322 if (parser.open(argv[i])) {
José Fonsecadf66a902010-11-29 13:24:20 +0000323 __startTime = OS::GetTime();
José Fonseca3d245f42010-11-28 00:08:23 +0000324 glutMainLoop();
325 parser.close();
326 }
327 }
José Fonseca6f51d3b2010-11-22 19:56:19 +0000328
José Fonseca3d245f42010-11-28 00:08:23 +0000329 return 0;
José Fonseca7e329022010-11-19 17:05:18 +0000330}
331
José Fonseca3d245f42010-11-28 00:08:23 +0000332'''