]> git.cworth.org Git - apitrace/blob - glretrace.py
cli: Add a new "apitrace diff" command.
[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 specs.stdapi as stdapi
31 import specs.glapi as glapi
32 from retrace import Retracer
33
34
35 class GlRetracer(Retracer):
36
37     table_name = 'glretrace::gl_callbacks'
38
39     def retrace_function(self, function):
40         Retracer.retrace_function(self, function)
41
42     array_pointer_function_names = set((
43         "glVertexPointer",
44         "glNormalPointer",
45         "glColorPointer",
46         "glIndexPointer",
47         "glTexCoordPointer",
48         "glEdgeFlagPointer",
49         "glFogCoordPointer",
50         "glSecondaryColorPointer",
51
52         "glInterleavedArrays",
53
54         "glVertexPointerEXT",
55         "glNormalPointerEXT",
56         "glColorPointerEXT",
57         "glIndexPointerEXT",
58         "glTexCoordPointerEXT",
59         "glEdgeFlagPointerEXT",
60         "glFogCoordPointerEXT",
61         "glSecondaryColorPointerEXT",
62
63         "glVertexAttribPointer",
64         "glVertexAttribPointerARB",
65         "glVertexAttribPointerNV",
66         "glVertexAttribIPointer",
67         "glVertexAttribIPointerEXT",
68         "glVertexAttribLPointer",
69         "glVertexAttribLPointerEXT",
70         
71         #"glMatrixIndexPointerARB",
72     ))
73
74     draw_array_function_names = set([
75         "glDrawArrays",
76         "glDrawArraysEXT",
77         "glDrawArraysIndirect",
78         "glDrawArraysInstanced",
79         "glDrawArraysInstancedARB",
80         "glDrawArraysInstancedEXT",
81         "glDrawArraysInstancedBaseInstance",
82         "glDrawMeshArraysSUN",
83         "glMultiDrawArrays",
84         "glMultiDrawArraysEXT",
85         "glMultiModeDrawArraysIBM",
86     ])
87
88     draw_elements_function_names = set([
89         "glDrawElements",
90         "glDrawElementsBaseVertex",
91         "glDrawElementsIndirect",
92         "glDrawElementsInstanced",
93         "glDrawElementsInstancedARB",
94         "glDrawElementsInstancedEXT",
95         "glDrawElementsInstancedBaseVertex",
96         "glDrawElementsInstancedBaseInstance",
97         "glDrawElementsInstancedBaseVertexBaseInstance",
98         "glDrawRangeElements",
99         "glDrawRangeElementsEXT",
100         "glDrawRangeElementsBaseVertex",
101         "glMultiDrawElements",
102         "glMultiDrawElementsBaseVertex",
103         "glMultiDrawElementsEXT",
104         "glMultiModeDrawElementsIBM",
105     ])
106
107     draw_indirect_function_names = set([
108         "glDrawArraysIndirect",
109         "glDrawElementsIndirect",
110     ])
111
112     misc_draw_function_names = set([
113         "glClear",
114         "glEnd",
115         "glDrawPixels",
116         "glBlitFramebuffer",
117         "glBlitFramebufferEXT",
118     ])
119
120     bind_framebuffer_function_names = set([
121         "glBindFramebuffer",
122         "glBindFramebufferARB",
123         "glBindFramebufferEXT",
124     ])
125
126     # Names of the functions that can pack into the current pixel buffer
127     # object.  See also the ARB_pixel_buffer_object specification.
128     pack_function_names = set([
129         'glGetCompressedTexImage',
130         'glGetConvolutionFilter',
131         'glGetHistogram',
132         'glGetMinmax',
133         'glGetPixelMapfv',
134         'glGetPixelMapuiv',
135         'glGetPixelMapusv',
136         'glGetPolygonStipple',
137         'glGetSeparableFilter',
138         'glGetTexImage',
139         'glReadPixels',
140         'glGetnCompressedTexImageARB',
141         'glGetnConvolutionFilterARB',
142         'glGetnHistogramARB',
143         'glGetnMinmaxARB',
144         'glGetnPixelMapfvARB',
145         'glGetnPixelMapuivARB',
146         'glGetnPixelMapusvARB',
147         'glGetnPolygonStippleARB',
148         'glGetnSeparableFilterARB',
149         'glGetnTexImageARB',
150         'glReadnPixelsARB',
151     ])
152
153     map_function_names = set([
154         'glMapBuffer',
155         'glMapBufferARB',
156         'glMapBufferRange',
157         'glMapNamedBufferEXT',
158         'glMapNamedBufferRangeEXT'
159     ])
160
161     unmap_function_names = set([
162         'glUnmapBuffer',
163         'glUnmapBufferARB',
164         'glUnmapNamedBufferEXT',
165     ])
166
167     def retrace_function_body(self, function):
168         is_array_pointer = function.name in self.array_pointer_function_names
169         is_draw_array = function.name in self.draw_array_function_names
170         is_draw_elements = function.name in self.draw_elements_function_names
171         is_misc_draw = function.name in self.misc_draw_function_names
172
173         if is_array_pointer or is_draw_array or is_draw_elements:
174             print '    if (glretrace::parser.version < 1) {'
175
176             if is_array_pointer or is_draw_array:
177                 print '        GLint __array_buffer = 0;'
178                 print '        glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
179                 print '        if (!__array_buffer) {'
180                 self.fail_function(function)
181                 print '        }'
182
183             if is_draw_elements:
184                 print '        GLint __element_array_buffer = 0;'
185                 print '        glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
186                 print '        if (!__element_array_buffer) {'
187                 self.fail_function(function)
188                 print '        }'
189             
190             print '    }'
191
192         # When no pack buffer object is bound, the pack functions are no-ops.
193         if function.name in self.pack_function_names:
194             print '    GLint __pack_buffer = 0;'
195             print '    glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &__pack_buffer);'
196             print '    if (!__pack_buffer) {'
197             if function.name == 'glReadPixels':
198                 print '    glFinish();'
199                 print '    if (glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAME ||'
200                 print '        glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAMEBUFFER) {'
201                 print '        glretrace::snapshot(call.no);'
202                 print '    }'
203             print '        return;'
204             print '    }'
205
206         # Pre-snapshots
207         if function.name in self.bind_framebuffer_function_names:
208             print '    if (glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAMEBUFFER) {'
209             print '        glretrace::snapshot(call.no - 1);'
210             print '    }'
211         if function.name == 'glFrameTerminatorGREMEDY':
212             print '    glretrace::frame_complete(call);'
213             return
214
215         Retracer.retrace_function_body(self, function)
216
217         # Post-snapshots
218         if function.name in ('glFlush', 'glFinish'):
219             print '    if (!glretrace::double_buffer) {'
220             print '        glretrace::frame_complete(call);'
221             print '    }'
222         if is_draw_array or is_draw_elements or is_misc_draw:
223             print '    if (glretrace::snapshot_frequency == glretrace::FREQUENCY_DRAW) {'
224             print '        glretrace::snapshot(call.no);'
225             print '    }'
226
227
228     def call_function(self, function):
229         # Infer the drawable size from GL calls
230         if function.name == "glViewport":
231             print '    glretrace::updateDrawable(x + width, y + height);'
232         if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'):
233             # Some applications do all their rendering in a framebuffer, and
234             # then just blit to the drawable without ever calling glViewport.
235             print '    glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));'
236
237         if function.name == "glEnd":
238             print '    glretrace::insideGlBeginEnd = false;'
239
240         if function.name == 'memcpy':
241             print '    if (!dest || !src || !n) return;'
242         
243         Retracer.call_function(self, function)
244
245         # Error checking
246         if function.name == "glBegin":
247             print '    glretrace::insideGlBeginEnd = true;'
248         elif function.name.startswith('gl'):
249             # glGetError is not allowed inside glBegin/glEnd
250             print '    if (!glretrace::benchmark && !glretrace::insideGlBeginEnd) {'
251             print '        glretrace::checkGlError(call);'
252             if function.name in ('glProgramStringARB', 'glProgramStringNV'):
253                 print r'        GLint error_position = -1;'
254                 print r'        glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_position);'
255                 print r'        if (error_position != -1) {'
256                 print r'            const char *error_string = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);'
257                 print r'            retrace::warning(call) << error_string << "\n";'
258                 print r'        }'
259             if function.name == 'glCompileShader':
260                 print r'        GLint compile_status = 0;'
261                 print r'        glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);'
262                 print r'        if (!compile_status) {'
263                 print r'             GLint info_log_length = 0;'
264                 print r'             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);'
265                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
266                 print r'             glGetShaderInfoLog(shader, info_log_length, NULL, infoLog);'
267                 print r'             retrace::warning(call) << infoLog << "\n";'
268                 print r'             delete [] infoLog;'
269                 print r'        }'
270             if function.name == 'glLinkProgram':
271                 print r'        GLint link_status = 0;'
272                 print r'        glGetProgramiv(program, GL_LINK_STATUS, &link_status);'
273                 print r'        if (!link_status) {'
274                 print r'             GLint info_log_length = 0;'
275                 print r'             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);'
276                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
277                 print r'             glGetProgramInfoLog(program, info_log_length, NULL, infoLog);'
278                 print r'             retrace::warning(call) << infoLog << "\n";'
279                 print r'             delete [] infoLog;'
280                 print r'        }'
281             if function.name == 'glCompileShaderARB':
282                 print r'        GLint compile_status = 0;'
283                 print r'        glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);'
284                 print r'        if (!compile_status) {'
285                 print r'             GLint info_log_length = 0;'
286                 print r'             glGetObjectParameterivARB(shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);'
287                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
288                 print r'             glGetInfoLogARB(shaderObj, info_log_length, NULL, infoLog);'
289                 print r'             retrace::warning(call) << infoLog << "\n";'
290                 print r'             delete [] infoLog;'
291                 print r'        }'
292             if function.name == 'glLinkProgramARB':
293                 print r'        GLint link_status = 0;'
294                 print r'        glGetObjectParameterivARB(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);'
295                 print r'        if (!link_status) {'
296                 print r'             GLint info_log_length = 0;'
297                 print r'             glGetObjectParameterivARB(programObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);'
298                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
299                 print r'             glGetInfoLogARB(programObj, info_log_length, NULL, infoLog);'
300                 print r'             retrace::warning(call) << infoLog << "\n";'
301                 print r'             delete [] infoLog;'
302                 print r'        }'
303             if function.name in self.map_function_names:
304                 print r'        if (!__result) {'
305                 print r'             retrace::warning(call) << "failed to map buffer\n";'
306                 print r'        }'
307             if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'):
308                 print r'    GLint __orig_result = call.ret->toSInt();'
309                 print r'    if (__result != __orig_result) {'
310                 print r'        retrace::warning(call) << "vertex attrib location mismatch " << __orig_result << " -> " << __result << "\n";'
311                 print r'    }'
312             if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatusEXT'):
313                 print r'    GLint __orig_result = call.ret->toSInt();'
314                 print r'    if (__orig_result == GL_FRAMEBUFFER_COMPLETE &&'
315                 print r'        __result != GL_FRAMEBUFFER_COMPLETE) {'
316                 print r'        retrace::warning(call) << "incomplete framebuffer (" << glstate::enumToString(__result) << ")\n";'
317                 print r'    }'
318             print '    }'
319
320             # Update buffer mappings
321             if function.name in self.map_function_names:
322                 print r'        if (__result) {'
323                 print r'            unsigned long long __address = call.ret->toUIntPtr();'
324                 if 'BufferRange' not in function.name:
325                     print r'            GLint length = 0;'
326                     if function.name == 'glMapBuffer':
327                         print r'            glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);'
328                     elif function.name == 'glMapBufferARB':
329                         print r'            glGetBufferParameterivARB(target, GL_BUFFER_SIZE_ARB, &length);'
330                     elif function.name == 'glMapNamedBufferEXT':
331                         print r'            glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_SIZE, &length);'
332                     else:
333                         assert False
334                 print r'             retrace::addRegion(__address, __result, length);'
335                 print r'        }'
336             if function.name in self.unmap_function_names:
337                 print r'        GLvoid *ptr = NULL;'
338                 if function.name == 'glUnmapBuffer':
339                     print r'            glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &ptr);'
340                 elif function.name == 'glUnmapBufferARB':
341                     print r'            glGetBufferPointervARB(target, GL_BUFFER_MAP_POINTER_ARB, &ptr);'
342                 elif function.name == 'glUnmapNamedBufferEXT':
343                     print r'            glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &ptr);'
344                 else:
345                     assert False
346                 print r'        if (ptr) {'
347                 print r'            retrace::delRegionByPointer(ptr);'
348                 print r'        }'
349
350     def extract_arg(self, function, arg, arg_type, lvalue, rvalue):
351         if function.name in self.array_pointer_function_names and arg.name == 'pointer':
352             print '    %s = static_cast<%s>(retrace::toPointer(%s, true));' % (lvalue, arg_type, rvalue)
353             return
354
355         if function.name in self.draw_elements_function_names and arg.name == 'indices' or\
356            function.name in self.draw_indirect_function_names and arg.name == 'indirect':
357             self.extract_opaque_arg(function, arg, arg_type, lvalue, rvalue)
358             return
359
360         # Handle pointer with offsets into the current pack pixel buffer
361         # object.
362         if function.name in self.pack_function_names and arg.output:
363             self.extract_opaque_arg(function, arg, arg_type, lvalue, rvalue)
364             return
365
366         if arg.type is glapi.GLlocation \
367            and 'program' not in [arg.name for arg in function.args]:
368             print '    GLint program = -1;'
369             print '    glGetIntegerv(GL_CURRENT_PROGRAM, &program);'
370         
371         if arg.type is glapi.GLlocationARB \
372            and 'programObj' not in [arg.name for arg in function.args]:
373             print '    GLhandleARB programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);'
374
375         Retracer.extract_arg(self, function, arg, arg_type, lvalue, rvalue)
376
377         # Don't try to use more samples than the implementation supports
378         if arg.name == 'samples':
379             assert arg.type is glapi.GLsizei
380             print '    GLint max_samples = 0;'
381             print '    glGetIntegerv(GL_MAX_SAMPLES, &max_samples);'
382             print '    if (samples > max_samples) {'
383             print '        samples = max_samples;'
384             print '    }'
385
386
387 if __name__ == '__main__':
388     print r'''
389 #include <string.h>
390
391 #include "glproc.hpp"
392 #include "glretrace.hpp"
393 #include "glstate.hpp"
394
395
396 '''
397     api = glapi.glapi
398     retracer = GlRetracer()
399     retracer.retrace_api(api)