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