blob: c74d88a936fd1825e5c7df7b8cc38834108d6886 [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é Fonseca796a3042010-11-29 14:21:06 +0000165bool __screenshots = 0;
166
José Fonsecadf66a902010-11-29 13:24:20 +0000167
José Fonseca3d245f42010-11-28 00:08:23 +0000168static void
169checkGlError(void) {
170 if (insideGlBeginEnd) {
171 return;
172 }
173
174 GLenum error = glGetError();
175 if (error == GL_NO_ERROR) {
176 return;
177 }
178
179 std::cerr << "warning: glGetError() = ";
180 switch (error) {
181 case GL_INVALID_ENUM:
182 std::cerr << "GL_INVALID_ENUM";
183 break;
184 case GL_INVALID_VALUE:
185 std::cerr << "GL_INVALID_VALUE";
186 break;
187 case GL_INVALID_OPERATION:
188 std::cerr << "GL_INVALID_OPERATION";
189 break;
190 case GL_STACK_OVERFLOW:
191 std::cerr << "GL_STACK_OVERFLOW";
192 break;
193 case GL_STACK_UNDERFLOW:
194 std::cerr << "GL_STACK_UNDERFLOW";
195 break;
196 case GL_OUT_OF_MEMORY:
197 std::cerr << "GL_OUT_OF_MEMORY";
198 break;
199 case GL_INVALID_FRAMEBUFFER_OPERATION:
200 std::cerr << "GL_INVALID_FRAMEBUFFER_OPERATION";
201 break;
202 case GL_TABLE_TOO_LARGE:
203 std::cerr << "GL_TABLE_TOO_LARGE";
204 break;
205 default:
206 std::cerr << error;
207 break;
208 }
José Fonseca796a3042010-11-29 14:21:06 +0000209 std::cerr << "\n";
José Fonseca3d245f42010-11-28 00:08:23 +0000210}
211'''
José Fonsecae0e61402010-11-25 15:03:23 +0000212 api = glapi.glapi
213 retracer = GlRetracer()
214 retracer.retrace_api(glapi.glapi)
José Fonseca796a3042010-11-29 14:21:06 +0000215 print r'''
José Fonseca7e329022010-11-19 17:05:18 +0000216
José Fonseca3d245f42010-11-28 00:08:23 +0000217static Trace::Parser parser;
José Fonseca082051b2010-11-23 12:00:31 +0000218
José Fonsecadf66a902010-11-29 13:24:20 +0000219static void display_noop(void) {
220}
221
José Fonseca20f35e02010-12-04 12:21:12 +0000222#include "image.hpp"
José Fonseca796a3042010-11-29 14:21:06 +0000223
224static void frame_complete(void) {
225 ++__frame;
226
227 if (__screenshots && !__reshape_window) {
228 char filename[PATH_MAX];
José Fonseca0a91a3e2010-12-04 13:13:47 +0000229 snprintf(filename, sizeof filename, "screenshot_%04u.png", __frame);
José Fonseca20f35e02010-12-04 12:21:12 +0000230 Image::Image image(__window_width, __window_height, true);
231 glReadPixels(0, 0, __window_width, __window_height, GL_RGBA, GL_UNSIGNED_BYTE, image.pixels);
José Fonseca0a91a3e2010-12-04 13:13:47 +0000232 image.writePNG(filename);
José Fonseca796a3042010-11-29 14:21:06 +0000233 }
234
235}
236
José Fonseca6f51d3b2010-11-22 19:56:19 +0000237static void display(void) {
José Fonseca3d245f42010-11-28 00:08:23 +0000238 Trace::Call *call;
José Fonseca6f51d3b2010-11-22 19:56:19 +0000239
José Fonseca3d245f42010-11-28 00:08:23 +0000240 while ((call = parser.parse_call())) {
241 if (call->name() == "glFlush") {
José Fonsecafeb5d992010-11-25 17:14:18 +0000242 glFlush();
José Fonsecadf66a902010-11-29 13:24:20 +0000243 if (!double_buffer) {
José Fonseca796a3042010-11-29 14:21:06 +0000244 frame_complete();
José Fonsecadf66a902010-11-29 13:24:20 +0000245 }
José Fonseca3d245f42010-11-28 00:08:23 +0000246 }
247
248 if (!retrace_call(*call)) {
249 if (call->name() == "glXSwapBuffers" ||
250 call->name() == "wglSwapBuffers") {
251 if (double_buffer)
252 glutSwapBuffers();
253 else
254 glFlush();
José Fonseca796a3042010-11-29 14:21:06 +0000255 frame_complete();
José Fonseca3d245f42010-11-28 00:08:23 +0000256 return;
José Fonseca082051b2010-11-23 12:00:31 +0000257 }
José Fonseca3d245f42010-11-28 00:08:23 +0000258 }
259 }
José Fonseca6f51d3b2010-11-22 19:56:19 +0000260
José Fonsecadf66a902010-11-29 13:24:20 +0000261 // Reached the end of trace
José Fonseca3d245f42010-11-28 00:08:23 +0000262 glFlush();
José Fonsecadf66a902010-11-29 13:24:20 +0000263
264 long long endTime = OS::GetTime();
265 float timeInterval = (endTime - __startTime) * 1.0E-6;
266
267 std::cout <<
268 "Rendered " << __frame << " frames"
269 " in " << timeInterval << " secs,"
José Fonseca796a3042010-11-29 14:21:06 +0000270 " average of " << (__frame/timeInterval) << " fps\n";
José Fonsecadf66a902010-11-29 13:24:20 +0000271
272 glutDisplayFunc(&display_noop);
José Fonseca3d245f42010-11-28 00:08:23 +0000273 glutIdleFunc(NULL);
José Fonseca6f51d3b2010-11-22 19:56:19 +0000274}
275
276static void idle(void) {
José Fonsecacdb574a2010-11-29 12:23:35 +0000277 if (__reshape_window) {
278 // XXX: doesn't quite work
279 glutReshapeWindow(__window_width, __window_height);
280 __reshape_window = false;
281 }
José Fonseca3d245f42010-11-28 00:08:23 +0000282 glutPostRedisplay();
José Fonseca6f51d3b2010-11-22 19:56:19 +0000283}
José Fonseca7e329022010-11-19 17:05:18 +0000284
285int main(int argc, char **argv)
286{
José Fonseca6f51d3b2010-11-22 19:56:19 +0000287
José Fonseca3d245f42010-11-28 00:08:23 +0000288 int i;
289 for (i = 1; i < argc; ++i) {
290 const char *arg = argv[i];
José Fonseca094cb2d2010-11-24 15:55:03 +0000291
José Fonseca3d245f42010-11-28 00:08:23 +0000292 if (arg[0] != '-') {
293 break;
294 }
José Fonseca094cb2d2010-11-24 15:55:03 +0000295
José Fonseca3d245f42010-11-28 00:08:23 +0000296 if (!strcmp(arg, "--")) {
297 break;
José Fonseca796a3042010-11-29 14:21:06 +0000298 } else if (!strcmp(arg, "-db")) {
José Fonseca3d245f42010-11-28 00:08:23 +0000299 double_buffer = true;
José Fonseca796a3042010-11-29 14:21:06 +0000300 } else if (!strcmp(arg, "-s")) {
301 __screenshots = true;
José Fonseca3d245f42010-11-28 00:08:23 +0000302 } else if (!strcmp(arg, "-v")) {
303 ++verbosity;
304 } else {
José Fonseca796a3042010-11-29 14:21:06 +0000305 std::cerr << "error: unknown option " << arg << "\n";
José Fonseca3d245f42010-11-28 00:08:23 +0000306 return 1;
307 }
308 }
José Fonseca094cb2d2010-11-24 15:55:03 +0000309
José Fonseca3d245f42010-11-28 00:08:23 +0000310 glutInit(&argc, argv);
311 glutInitWindowPosition(0, 0);
José Fonsecacdb574a2010-11-29 12:23:35 +0000312 glutInitWindowSize(__window_width, __window_height);
José Fonseca3d245f42010-11-28 00:08:23 +0000313 glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | (double_buffer ? GLUT_DOUBLE : GLUT_SINGLE));
314 glutCreateWindow(argv[0]);
José Fonsecafeb5d992010-11-25 17:14:18 +0000315
José Fonseca3d245f42010-11-28 00:08:23 +0000316 glutDisplayFunc(&display);
317 glutIdleFunc(&idle);
José Fonsecafeb5d992010-11-25 17:14:18 +0000318
José Fonseca3d245f42010-11-28 00:08:23 +0000319 for (GLuint h = 0; h < 1024; ++h) {
320 __list_map[h] = h;
321 }
José Fonsecafeb5d992010-11-25 17:14:18 +0000322
José Fonseca3d245f42010-11-28 00:08:23 +0000323 for ( ; i < argc; ++i) {
324 if (parser.open(argv[i])) {
José Fonsecadf66a902010-11-29 13:24:20 +0000325 __startTime = OS::GetTime();
José Fonseca3d245f42010-11-28 00:08:23 +0000326 glutMainLoop();
327 parser.close();
328 }
329 }
José Fonseca6f51d3b2010-11-22 19:56:19 +0000330
José Fonseca3d245f42010-11-28 00:08:23 +0000331 return 0;
José Fonseca7e329022010-11-19 17:05:18 +0000332}
333
José Fonseca3d245f42010-11-28 00:08:23 +0000334'''