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