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