]> git.cworth.org Git - apitrace/blob - retrace/glretrace.py
gltrace,glretrace: A few more tweaks to (no) side-effects flags.
[apitrace] / retrace / 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 from retrace import Retracer
31 import specs.stdapi as stdapi
32 import specs.glapi as glapi
33 import specs.glesapi as glesapi
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         'glGetCompressedTexImageARB',
134         'glGetCompressedTextureImageEXT',
135         'glGetCompressedMultiTexImageEXT',
136         'glGetConvolutionFilter',
137         'glGetHistogram',
138         'glGetMinmax',
139         'glGetPixelMapfv',
140         'glGetPixelMapuiv',
141         'glGetPixelMapusv',
142         'glGetPolygonStipple',
143         'glGetSeparableFilter',
144         'glGetTexImage',
145         'glGetTextureImageEXT',
146         'glGetMultiTexImageEXT',
147         'glReadPixels',
148         'glGetnCompressedTexImageARB',
149         'glGetnConvolutionFilterARB',
150         'glGetnHistogramARB',
151         'glGetnMinmaxARB',
152         'glGetnPixelMapfvARB',
153         'glGetnPixelMapuivARB',
154         'glGetnPixelMapusvARB',
155         'glGetnPolygonStippleARB',
156         'glGetnSeparableFilterARB',
157         'glGetnTexImageARB',
158         'glReadnPixelsARB',
159     ])
160
161     map_function_names = set([
162         'glMapBuffer',
163         'glMapBufferARB',
164         'glMapBufferOES',
165         'glMapBufferRange',
166         'glMapNamedBufferEXT',
167         'glMapNamedBufferRangeEXT',
168         'glMapObjectBufferATI',
169     ])
170
171     unmap_function_names = set([
172         'glUnmapBuffer',
173         'glUnmapBufferARB',
174         'glUnmapBufferOES',
175         'glUnmapNamedBufferEXT',
176         'glUnmapObjectBufferATI',
177     ])
178
179     def retraceFunctionBody(self, function):
180         is_array_pointer = function.name in self.array_pointer_function_names
181         is_draw_array = function.name in self.draw_array_function_names
182         is_draw_elements = function.name in self.draw_elements_function_names
183         is_misc_draw = function.name in self.misc_draw_function_names
184
185         if is_array_pointer or is_draw_array or is_draw_elements:
186             print '    if (retrace::parser.version < 1) {'
187
188             if is_array_pointer or is_draw_array:
189                 print '        GLint _array_buffer = 0;'
190                 print '        glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
191                 print '        if (!_array_buffer) {'
192                 self.failFunction(function)
193                 print '        }'
194
195             if is_draw_elements:
196                 print '        GLint _element_array_buffer = 0;'
197                 print '        glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &_element_array_buffer);'
198                 print '        if (!_element_array_buffer) {'
199                 self.failFunction(function)
200                 print '        }'
201             
202             print '    }'
203
204         # When no pack buffer object is bound, the pack functions are no-ops.
205         if function.name in self.pack_function_names:
206             print '    GLint _pack_buffer = 0;'
207             print '    glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &_pack_buffer);'
208             print '    if (!_pack_buffer) {'
209             print '        return;'
210             print '    }'
211
212         # Pre-snapshots
213         if function.name in self.bind_framebuffer_function_names:
214             print '    assert(call.flags & trace::CALL_FLAG_SWAP_RENDERTARGET);'
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 (!retrace::doubleBuffer) {'
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
229
230     def invokeFunction(self, function):
231         # Infer the drawable size from GL calls
232         if function.name == "glViewport":
233             print '    glretrace::updateDrawable(x + width, y + height);'
234         if function.name == "glViewportArray":
235             # We are concerned about drawables so only care for the first viewport
236             print '    if (first == 0 && count > 0) {'
237             print '        GLfloat x = v[0], y = v[1], w = v[2], h = v[3];'
238             print '        glretrace::updateDrawable(x + w, y + h);'
239             print '    }'
240         if function.name == "glViewportIndexedf":
241             print '    if (index == 0) {'
242             print '        glretrace::updateDrawable(x + w, y + h);'
243             print '    }'
244         if function.name == "glViewportIndexedfv":
245             print '    if (index == 0) {'
246             print '        GLfloat x = v[0], y = v[1], w = v[2], h = v[3];'
247             print '        glretrace::updateDrawable(x + w, y + h);'
248             print '    }'
249         if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'):
250             # Some applications do all their rendering in a framebuffer, and
251             # then just blit to the drawable without ever calling glViewport.
252             print '    glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));'
253
254         if function.name == "glEnd":
255             print '    glretrace::insideGlBeginEnd = false;'
256
257         if function.name.startswith('gl') and not function.name.startswith('glX'):
258             print r'    if (retrace::debug && !glretrace::getCurrentContext()) {'
259             print r'        retrace::warning(call) << "no current context\n";'
260             print r'    }'
261
262         if function.name == 'memcpy':
263             print '    if (!dest || !src || !n) return;'
264
265         # Skip glEnable/Disable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) as we don't
266         # faithfully set the CONTEXT_DEBUG_BIT_ARB flags on context creation.
267         if function.name in ('glEnable', 'glDisable'):
268             print '    if (cap == GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) return;'
269
270         # Destroy the buffer mapping
271         if function.name in self.unmap_function_names:
272             print r'        GLvoid *ptr = NULL;'
273             if function.name == 'glUnmapBuffer':
274                 print r'            glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &ptr);'
275             elif function.name == 'glUnmapBufferARB':
276                 print r'            glGetBufferPointervARB(target, GL_BUFFER_MAP_POINTER_ARB, &ptr);'
277             elif function.name == 'glUnmapBufferOES':
278                 print r'            glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &ptr);'
279             elif function.name == 'glUnmapNamedBufferEXT':
280                 print r'            glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &ptr);'
281             elif function.name == 'glUnmapObjectBufferATI':
282                 # TODO
283                 pass
284             else:
285                 assert False
286             print r'        if (ptr) {'
287             print r'            retrace::delRegionByPointer(ptr);'
288             print r'        } else {'
289             print r'            retrace::warning(call) << "no current context\n";'
290             print r'        }'
291
292         if function.name in ('glBindProgramPipeline', 'glBindProgramPipelineEXT'):
293             # Note if glBindProgramPipeline has ever been called
294             print r'    if (pipeline) {'
295             print r'        _pipelineHasBeenBound = true;'
296             print r'    }'
297
298         profileDraw = (
299             function.name in self.draw_array_function_names or
300             function.name in self.draw_elements_function_names or
301             function.name in self.draw_indirect_function_names or
302             function.name in self.misc_draw_function_names or
303             function.name == 'glBegin'
304         )
305
306         if function.name in ('glUseProgram', 'glUseProgramObjectARB'):
307             print r'    glretrace::Context *currentContext = glretrace::getCurrentContext();'
308             print r'    if (currentContext) {'
309             print r'        currentContext->activeProgram = call.arg(0).toUInt();'
310             print r'    }'
311
312         # Only profile if not inside a list as the queries get inserted into list
313         if function.name == 'glNewList':
314             print r'    glretrace::insideList = true;'
315
316         if function.name == 'glEndList':
317             print r'    glretrace::insideList = false;'
318
319         if function.name != 'glEnd':
320             print r'    if (!glretrace::insideList && !glretrace::insideGlBeginEnd && retrace::profiling) {'
321             if profileDraw:
322                 print r'        glretrace::beginProfile(call, true);'
323             else:
324                 print r'        glretrace::beginProfile(call, false);'
325             print r'    }'
326
327         if function.name == 'glCreateShaderProgramv':
328             # When dumping state, break down glCreateShaderProgramv so that the
329             # shader source can be recovered.
330             print r'    if (retrace::dumpingState) {'
331             print r'        GLuint _shader = glCreateShader(type);'
332             print r'        if (_shader) {'
333             print r'            glShaderSource(_shader, count, strings, NULL);'
334             print r'            glCompileShader(_shader);'
335             print r'            const GLuint _program = glCreateProgram();'
336             print r'            if (_program) {'
337             print r'                GLint compiled = GL_FALSE;'
338             print r'                glGetShaderiv(_shader, GL_COMPILE_STATUS, &compiled);'
339             print r'                glProgramParameteri(_program, GL_PROGRAM_SEPARABLE, GL_TRUE);'
340             print r'                if (compiled) {'
341             print r'                    glAttachShader(_program, _shader);'
342             print r'                    glLinkProgram(_program);'
343             print r'                    //glDetachShader(_program, _shader);'
344             print r'                }'
345             print r'                //append-shader-info-log-to-program-info-log'
346             print r'            }'
347             print r'            //glDeleteShader(_shader);'
348             print r'            _result = _program;'
349             print r'        } else {'
350             print r'            _result = 0;'
351             print r'        }'
352             print r'    } else {'
353             Retracer.invokeFunction(self, function)
354             print r'    }'
355         else:
356             Retracer.invokeFunction(self, function)
357
358         if function.name == "glBegin":
359             print '    glretrace::insideGlBeginEnd = true;'
360
361         print r'    if (!glretrace::insideList && !glretrace::insideGlBeginEnd && retrace::profiling) {'
362         if profileDraw:
363             print r'        glretrace::endProfile(call, true);'
364         else:
365             print r'        glretrace::endProfile(call, false);'
366         print r'    }'
367
368         # Error checking
369         if function.name.startswith('gl'):
370             # glGetError is not allowed inside glBegin/glEnd
371             print '    if (retrace::debug && !glretrace::insideGlBeginEnd && glretrace::getCurrentContext()) {'
372             print '        glretrace::checkGlError(call);'
373             if function.name in ('glProgramStringARB', 'glProgramStringNV'):
374                 print r'        GLint error_position = -1;'
375                 print r'        glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_position);'
376                 print r'        if (error_position != -1) {'
377                 print r'            const char *error_string = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);'
378                 print r'            retrace::warning(call) << error_string << "\n";'
379                 print r'        }'
380             if function.name == 'glCompileShader':
381                 print r'        GLint compile_status = 0;'
382                 print r'        glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);'
383                 print r'        if (!compile_status) {'
384                 print r'             GLint info_log_length = 0;'
385                 print r'             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);'
386                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
387                 print r'             glGetShaderInfoLog(shader, info_log_length, NULL, infoLog);'
388                 print r'             retrace::warning(call) << infoLog << "\n";'
389                 print r'             delete [] infoLog;'
390                 print r'        }'
391             if function.name in ('glLinkProgram', 'glCreateShaderProgramv', 'glCreateShaderProgramEXT'):
392                 if function.name != 'glLinkProgram':
393                     print r'        GLuint program = _result;'
394                 print r'        GLint link_status = 0;'
395                 print r'        glGetProgramiv(program, GL_LINK_STATUS, &link_status);'
396                 print r'        if (!link_status) {'
397                 print r'             GLint info_log_length = 0;'
398                 print r'             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);'
399                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
400                 print r'             glGetProgramInfoLog(program, info_log_length, NULL, infoLog);'
401                 print r'             retrace::warning(call) << infoLog << "\n";'
402                 print r'             delete [] infoLog;'
403                 print r'        }'
404             if function.name == 'glCompileShaderARB':
405                 print r'        GLint compile_status = 0;'
406                 print r'        glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);'
407                 print r'        if (!compile_status) {'
408                 print r'             GLint info_log_length = 0;'
409                 print r'             glGetObjectParameterivARB(shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);'
410                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
411                 print r'             glGetInfoLogARB(shaderObj, info_log_length, NULL, infoLog);'
412                 print r'             retrace::warning(call) << infoLog << "\n";'
413                 print r'             delete [] infoLog;'
414                 print r'        }'
415             if function.name == 'glLinkProgramARB':
416                 print r'        GLint link_status = 0;'
417                 print r'        glGetObjectParameterivARB(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);'
418                 print r'        if (!link_status) {'
419                 print r'             GLint info_log_length = 0;'
420                 print r'             glGetObjectParameterivARB(programObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);'
421                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
422                 print r'             glGetInfoLogARB(programObj, info_log_length, NULL, infoLog);'
423                 print r'             retrace::warning(call) << infoLog << "\n";'
424                 print r'             delete [] infoLog;'
425                 print r'        }'
426             if function.name in self.map_function_names:
427                 print r'        if (!_result) {'
428                 print r'             retrace::warning(call) << "failed to map buffer\n";'
429                 print r'        }'
430             if function.name in self.unmap_function_names and function.type is not stdapi.Void:
431                 print r'        if (!_result) {'
432                 print r'             retrace::warning(call) << "failed to unmap buffer\n";'
433                 print r'        }'
434             if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'):
435                 print r'    GLint _origResult = call.ret->toSInt();'
436                 print r'    if (_result != _origResult) {'
437                 print r'        retrace::warning(call) << "vertex attrib location mismatch " << _origResult << " -> " << _result << "\n";'
438                 print r'    }'
439             if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatusEXT'):
440                 print r'    GLint _origResult = call.ret->toSInt();'
441                 print r'    if (_origResult == GL_FRAMEBUFFER_COMPLETE &&'
442                 print r'        _result != GL_FRAMEBUFFER_COMPLETE) {'
443                 print r'        retrace::warning(call) << "incomplete framebuffer (" << glstate::enumToString(_result) << ")\n";'
444                 print r'    }'
445             print '    }'
446
447         # Query the buffer length for whole buffer mappings
448         if function.name in self.map_function_names:
449             if 'length' in function.argNames():
450                 assert 'BufferRange' in function.name
451             else:
452                 assert 'BufferRange' not in function.name
453                 print r'    GLint length = 0;'
454                 if function.name in ('glMapBuffer', 'glMapBufferOES'):
455                     print r'    glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);'
456                 elif function.name == 'glMapBufferARB':
457                     print r'    glGetBufferParameterivARB(target, GL_BUFFER_SIZE_ARB, &length);'
458                 elif function.name == 'glMapNamedBufferEXT':
459                     print r'    glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_SIZE, &length);'
460                 elif function.name == 'glMapObjectBufferATI':
461                     print r'    glGetObjectBufferivATI(buffer, GL_OBJECT_BUFFER_SIZE_ATI, &length);'
462                 else:
463                     assert False
464
465     def extractArg(self, function, arg, arg_type, lvalue, rvalue):
466         if function.name in self.array_pointer_function_names and arg.name == 'pointer':
467             print '    %s = static_cast<%s>(retrace::toPointer(%s, true));' % (lvalue, arg_type, rvalue)
468             return
469
470         if function.name in self.draw_elements_function_names and arg.name == 'indices' or\
471            function.name in self.draw_indirect_function_names and arg.name == 'indirect':
472             self.extractOpaqueArg(function, arg, arg_type, lvalue, rvalue)
473             return
474
475         # Handle pointer with offsets into the current pack pixel buffer
476         # object.
477         if function.name in self.pack_function_names and arg.output:
478             assert isinstance(arg_type, (stdapi.Pointer, stdapi.Array, stdapi.Blob, stdapi.Opaque))
479             print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, arg_type, rvalue)
480             return
481
482         if arg.type is glapi.GLlocation \
483            and 'program' not in function.argNames():
484             # Determine the active program for uniforms swizzling
485             print '    GLint program = -1;'
486             print '    if (glretrace::insideList) {'
487             print '        // glUseProgram & glUseProgramObjectARB are display-list-able'
488             print r'    glretrace::Context *currentContext = glretrace::getCurrentContext();'
489             print '        program = _program_map[currentContext->activeProgram];'
490             print '    } else {'
491             print '        GLint pipeline = 0;'
492             print '        if (_pipelineHasBeenBound) {'
493             print '            glGetIntegerv(GL_PROGRAM_PIPELINE_BINDING, &pipeline);'
494             print '        }'
495             print '        if (pipeline) {'
496             print '            glGetProgramPipelineiv(pipeline, GL_ACTIVE_PROGRAM, &program);'
497             print '        } else {'
498             print '            glGetIntegerv(GL_CURRENT_PROGRAM, &program);'
499             print '        }'
500             print '    }'
501             print
502
503         if arg.type is glapi.GLlocationARB \
504            and 'programObj' not in function.argNames():
505             print '    GLhandleARB programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);'
506
507         Retracer.extractArg(self, function, arg, arg_type, lvalue, rvalue)
508
509         # Don't try to use more samples than the implementation supports
510         if arg.name == 'samples':
511             assert arg.type is glapi.GLsizei
512             print '    GLint max_samples = 0;'
513             print '    glGetIntegerv(GL_MAX_SAMPLES, &max_samples);'
514             print '    if (samples > max_samples) {'
515             print '        samples = max_samples;'
516             print '    }'
517
518         # These parameters are referred beyond the call life-time
519         # TODO: Replace ad-hoc solution for bindable parameters with general one
520         if function.name in ('glFeedbackBuffer', 'glSelectBuffer') and arg.output:
521             print '    _allocator.bind(%s);' % arg.name
522
523
524
525 if __name__ == '__main__':
526     print r'''
527 #include <string.h>
528
529 #include "glproc.hpp"
530 #include "glretrace.hpp"
531 #include "glstate.hpp"
532
533
534 static bool _pipelineHasBeenBound = false;
535 '''
536     api = stdapi.API()
537     api.addModule(glapi.glapi)
538     api.addModule(glesapi.glesapi)
539     retracer = GlRetracer()
540     retracer.retraceApi(api)