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