]> git.cworth.org Git - apitrace/blob - glretrace.py
f3ae91bda830965e951e6b20c00ab7ae534c6998
[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 retraceFunction(self, function):
41         Retracer.retraceFunction(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         "glBindFramebufferEXT",
124         "glBindFramebufferOES",
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         'glMapBufferOES',
158         'glMapBufferRange',
159         'glMapNamedBufferEXT',
160         'glMapNamedBufferRangeEXT'
161     ])
162
163     unmap_function_names = set([
164         'glUnmapBuffer',
165         'glUnmapBufferARB',
166         'glUnmapBufferOES',
167         'glUnmapNamedBufferEXT',
168     ])
169
170     def retraceFunctionBody(self, function):
171         is_array_pointer = function.name in self.array_pointer_function_names
172         is_draw_array = function.name in self.draw_array_function_names
173         is_draw_elements = function.name in self.draw_elements_function_names
174         is_misc_draw = function.name in self.misc_draw_function_names
175
176         if is_array_pointer or is_draw_array or is_draw_elements:
177             print '    if (glretrace::parser.version < 1) {'
178
179             if is_array_pointer or is_draw_array:
180                 print '        GLint __array_buffer = 0;'
181                 print '        glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
182                 print '        if (!__array_buffer) {'
183                 self.failFunction(function)
184                 print '        }'
185
186             if is_draw_elements:
187                 print '        GLint __element_array_buffer = 0;'
188                 print '        glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
189                 print '        if (!__element_array_buffer) {'
190                 self.failFunction(function)
191                 print '        }'
192             
193             print '    }'
194
195         # When no pack buffer object is bound, the pack functions are no-ops.
196         if function.name in self.pack_function_names:
197             print '    GLint __pack_buffer = 0;'
198             print '    glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &__pack_buffer);'
199             print '    if (!__pack_buffer) {'
200             if function.name == 'glReadPixels':
201                 print '    glFinish();'
202                 print '    if (glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAME ||'
203                 print '        glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAMEBUFFER) {'
204                 print '        glretrace::snapshot(call.no);'
205                 print '    }'
206             print '        return;'
207             print '    }'
208
209         # Pre-snapshots
210         if function.name in self.bind_framebuffer_function_names:
211             print '    assert(call.flags & trace::CALL_FLAG_SWAP_RENDERTARGET);'
212             print '    if (glretrace::snapshot_frequency == glretrace::FREQUENCY_FRAMEBUFFER) {'
213             print '        glretrace::snapshot(call.no - 1);'
214             print '    }'
215         if function.name == 'glFrameTerminatorGREMEDY':
216             print '    glretrace::frame_complete(call);'
217             return
218
219         Retracer.retraceFunctionBody(self, function)
220
221         # Post-snapshots
222         if function.name in ('glFlush', 'glFinish'):
223             print '    if (!glretrace::double_buffer) {'
224             print '        glretrace::frame_complete(call);'
225             print '    }'
226         if is_draw_array or is_draw_elements or is_misc_draw:
227             print '    assert(call.flags & trace::CALL_FLAG_RENDER);'
228             print '    if (glretrace::snapshot_frequency == glretrace::FREQUENCY_DRAW) {'
229             print '        glretrace::snapshot(call.no);'
230             print '    }'
231
232
233     def invokeFunction(self, function):
234         # Infer the drawable size from GL calls
235         if function.name == "glViewport":
236             print '    glretrace::updateDrawable(x + width, y + height);'
237         if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'):
238             # Some applications do all their rendering in a framebuffer, and
239             # then just blit to the drawable without ever calling glViewport.
240             print '    glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));'
241
242         if function.name == "glEnd":
243             print '    glretrace::insideGlBeginEnd = false;'
244
245         if function.name == 'memcpy':
246             print '    if (!dest || !src || !n) return;'
247         
248         Retracer.invokeFunction(self, function)
249
250         # Error checking
251         if function.name == "glBegin":
252             print '    glretrace::insideGlBeginEnd = true;'
253         elif function.name.startswith('gl'):
254             # glGetError is not allowed inside glBegin/glEnd
255             print '    if (!glretrace::benchmark && !glretrace::insideGlBeginEnd) {'
256             print '        glretrace::checkGlError(call);'
257             if function.name in ('glProgramStringARB', 'glProgramStringNV'):
258                 print r'        GLint error_position = -1;'
259                 print r'        glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_position);'
260                 print r'        if (error_position != -1) {'
261                 print r'            const char *error_string = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);'
262                 print r'            retrace::warning(call) << error_string << "\n";'
263                 print r'        }'
264             if function.name == 'glCompileShader':
265                 print r'        GLint compile_status = 0;'
266                 print r'        glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);'
267                 print r'        if (!compile_status) {'
268                 print r'             GLint info_log_length = 0;'
269                 print r'             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);'
270                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
271                 print r'             glGetShaderInfoLog(shader, info_log_length, NULL, infoLog);'
272                 print r'             retrace::warning(call) << infoLog << "\n";'
273                 print r'             delete [] infoLog;'
274                 print r'        }'
275             if function.name == 'glLinkProgram':
276                 print r'        GLint link_status = 0;'
277                 print r'        glGetProgramiv(program, GL_LINK_STATUS, &link_status);'
278                 print r'        if (!link_status) {'
279                 print r'             GLint info_log_length = 0;'
280                 print r'             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);'
281                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
282                 print r'             glGetProgramInfoLog(program, info_log_length, NULL, infoLog);'
283                 print r'             retrace::warning(call) << infoLog << "\n";'
284                 print r'             delete [] infoLog;'
285                 print r'        }'
286             if function.name == 'glCompileShaderARB':
287                 print r'        GLint compile_status = 0;'
288                 print r'        glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);'
289                 print r'        if (!compile_status) {'
290                 print r'             GLint info_log_length = 0;'
291                 print r'             glGetObjectParameterivARB(shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);'
292                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
293                 print r'             glGetInfoLogARB(shaderObj, info_log_length, NULL, infoLog);'
294                 print r'             retrace::warning(call) << infoLog << "\n";'
295                 print r'             delete [] infoLog;'
296                 print r'        }'
297             if function.name == 'glLinkProgramARB':
298                 print r'        GLint link_status = 0;'
299                 print r'        glGetObjectParameterivARB(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);'
300                 print r'        if (!link_status) {'
301                 print r'             GLint info_log_length = 0;'
302                 print r'             glGetObjectParameterivARB(programObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);'
303                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
304                 print r'             glGetInfoLogARB(programObj, info_log_length, NULL, infoLog);'
305                 print r'             retrace::warning(call) << infoLog << "\n";'
306                 print r'             delete [] infoLog;'
307                 print r'        }'
308             if function.name in self.map_function_names:
309                 print r'        if (!__result) {'
310                 print r'             retrace::warning(call) << "failed to map buffer\n";'
311                 print r'        }'
312             if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'):
313                 print r'    GLint __orig_result = call.ret->toSInt();'
314                 print r'    if (__result != __orig_result) {'
315                 print r'        retrace::warning(call) << "vertex attrib location mismatch " << __orig_result << " -> " << __result << "\n";'
316                 print r'    }'
317             if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatusEXT'):
318                 print r'    GLint __orig_result = call.ret->toSInt();'
319                 print r'    if (__orig_result == GL_FRAMEBUFFER_COMPLETE &&'
320                 print r'        __result != GL_FRAMEBUFFER_COMPLETE) {'
321                 print r'        retrace::warning(call) << "incomplete framebuffer (" << glstate::enumToString(__result) << ")\n";'
322                 print r'    }'
323             print '    }'
324
325             # Query the buffer length for whole buffer mappings
326             if function.name in self.map_function_names:
327                 if 'length' in function.argNames():
328                     assert 'BufferRange' in function.name
329                 else:
330                     assert 'BufferRange' not in function.name
331                     print r'    GLint length = 0;'
332                     if function.name in ('glMapBuffer', 'glMapBufferOES'):
333                         print r'    glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);'
334                     elif function.name == 'glMapBufferARB':
335                         print r'    glGetBufferParameterivARB(target, GL_BUFFER_SIZE_ARB, &length);'
336                     elif function.name == 'glMapNamedBufferEXT':
337                         print r'    glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_SIZE, &length);'
338                     else:
339                         assert False
340             # Destroy the buffer mapping
341             if function.name in self.unmap_function_names:
342                 print r'        GLvoid *ptr = NULL;'
343                 if function.name == 'glUnmapBuffer':
344                     print r'            glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &ptr);'
345                 elif function.name == 'glUnmapBufferARB':
346                     print r'            glGetBufferPointervARB(target, GL_BUFFER_MAP_POINTER_ARB, &ptr);'
347                 elif function.name == 'glUnmapBufferOES':
348                     print r'            glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &ptr);'
349                 elif function.name == 'glUnmapNamedBufferEXT':
350                     print r'            glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &ptr);'
351                 else:
352                     assert False
353                 print r'        if (ptr) {'
354                 print r'            retrace::delRegionByPointer(ptr);'
355                 print r'        }'
356
357     def extractArg(self, function, arg, arg_type, lvalue, rvalue):
358         if function.name in self.array_pointer_function_names and arg.name == 'pointer':
359             print '    %s = static_cast<%s>(retrace::toPointer(%s, true));' % (lvalue, arg_type, rvalue)
360             return
361
362         if function.name in self.draw_elements_function_names and arg.name == 'indices' or\
363            function.name in self.draw_indirect_function_names and arg.name == 'indirect':
364             self.extractOpaqueArg(function, arg, arg_type, lvalue, rvalue)
365             return
366
367         # Handle pointer with offsets into the current pack pixel buffer
368         # object.
369         if function.name in self.pack_function_names and arg.output:
370             self.extractOpaqueArg(function, arg, arg_type, lvalue, rvalue)
371             return
372
373         if arg.type is glapi.GLlocation \
374            and 'program' not in function.argNames():
375             print '    GLint program = -1;'
376             print '    glGetIntegerv(GL_CURRENT_PROGRAM, &program);'
377         
378         if arg.type is glapi.GLlocationARB \
379            and 'programObj' not in function.argNames():
380             print '    GLhandleARB programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);'
381
382         Retracer.extractArg(self, function, arg, arg_type, lvalue, rvalue)
383
384         # Don't try to use more samples than the implementation supports
385         if arg.name == 'samples':
386             assert arg.type is glapi.GLsizei
387             print '    GLint max_samples = 0;'
388             print '    glGetIntegerv(GL_MAX_SAMPLES, &max_samples);'
389             print '    if (samples > max_samples) {'
390             print '        samples = max_samples;'
391             print '    }'
392
393
394 if __name__ == '__main__':
395     print r'''
396 #include <string.h>
397
398 #include "glproc.hpp"
399 #include "glretrace.hpp"
400 #include "glstate.hpp"
401
402
403 '''
404     api = glapi.glapi
405     api.addApi(glesapi.glesapi)
406     retracer = GlRetracer()
407     retracer.retraceApi(api)