]> git.cworth.org Git - apitrace/blob - gltrace.py
TODO: Add some notes on additions we want to the command-line interface
[apitrace] / gltrace.py
1 ##########################################################################
2 #
3 # Copyright 2008-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 tracing generator."""
28
29
30 import specs.stdapi as stdapi
31 import specs.glapi as glapi
32 import specs.glparams as glparams
33 from specs.glxapi import glxapi
34 from trace import Tracer, dump_instance
35
36
37 class TypeGetter(stdapi.Visitor):
38     '''Determine which glGet*v function that matches the specified type.'''
39
40     def __init__(self, prefix = 'glGet', long_suffix = True, ext_suffix = ''):
41         self.prefix = prefix
42         self.long_suffix = long_suffix
43         self.ext_suffix = ext_suffix
44
45     def visit_const(self, const):
46         return self.visit(const.type)
47
48     def visit_alias(self, alias):
49         if alias.expr == 'GLboolean':
50             if self.long_suffix:
51                 suffix = 'Booleanv'
52                 arg_type = alias.expr
53             else:
54                 suffix = 'iv'
55                 arg_type = 'GLint'
56         elif alias.expr == 'GLdouble':
57             if self.long_suffix:
58                 suffix = 'Doublev'
59                 arg_type = alias.expr
60             else:
61                 suffix = 'dv'
62                 arg_type = alias.expr
63         elif alias.expr == 'GLfloat':
64             if self.long_suffix:
65                 suffix = 'Floatv'
66                 arg_type = alias.expr
67             else:
68                 suffix = 'fv'
69                 arg_type = alias.expr
70         elif alias.expr in ('GLint', 'GLuint', 'GLsizei'):
71             if self.long_suffix:
72                 suffix = 'Integerv'
73                 arg_type = 'GLint'
74             else:
75                 suffix = 'iv'
76                 arg_type = 'GLint'
77         else:
78             print alias.expr
79             assert False
80         function_name = self.prefix + suffix + self.ext_suffix
81         return function_name, arg_type
82     
83     def visit_enum(self, enum):
84         return self.visit(glapi.GLint)
85
86     def visit_bitmask(self, bitmask):
87         return self.visit(glapi.GLint)
88
89     def visit_opaque(self, pointer):
90         return self.prefix + 'Pointerv' + self.ext_suffix, 'GLvoid *'
91
92
93 class GlTracer(Tracer):
94
95     arrays = [
96         ("Vertex", "VERTEX"),
97         ("Normal", "NORMAL"),
98         ("Color", "COLOR"),
99         ("Index", "INDEX"),
100         ("TexCoord", "TEXTURE_COORD"),
101         ("EdgeFlag", "EDGE_FLAG"),
102         ("FogCoord", "FOG_COORD"),
103         ("SecondaryColor", "SECONDARY_COLOR"),
104     ]
105     arrays.reverse()
106
107     def header(self, api):
108         Tracer.header(self, api)
109
110         print '#include "gltrace.hpp"'
111         print
112         print '// Whether user arrays were used'
113         print 'static bool __user_arrays = false;'
114         print 'static bool __user_arrays_arb = false;'
115         print 'static bool __user_arrays_nv = false;'
116         print
117         
118         # Which glVertexAttrib* variant to use
119         print 'enum vertex_attrib {'
120         print '    VERTEX_ATTRIB,'
121         print '    VERTEX_ATTRIB_ARB,'
122         print '    VERTEX_ATTRIB_NV,'
123         print '};'
124         print
125         print 'static vertex_attrib __get_vertex_attrib(void) {'
126         print '    if (__user_arrays_arb || __user_arrays_nv) {'
127         print '        GLboolean __vertex_program = GL_FALSE;'
128         print '        __glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &__vertex_program);'
129         print '        if (__vertex_program) {'
130         print '            if (__user_arrays_nv) {'
131         print '                GLint __vertex_program_binding_nv = 0;'
132         print '                __glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &__vertex_program_binding_nv);'
133         print '                if (__vertex_program_binding_nv) {'
134         print '                    return VERTEX_ATTRIB_NV;'
135         print '                }'
136         print '            }'
137         print '            return VERTEX_ATTRIB_ARB;'
138         print '        }'
139         print '    }'
140         print '    return VERTEX_ATTRIB;'
141         print '}'
142         print
143
144         # Whether we need user arrays
145         print 'static inline bool __need_user_arrays(void)'
146         print '{'
147         print '    if (!__user_arrays) {'
148         print '        return false;'
149         print '    }'
150         print
151
152         for camelcase_name, uppercase_name in self.arrays:
153             function_name = 'gl%sPointer' % camelcase_name
154             enable_name = 'GL_%s_ARRAY' % uppercase_name
155             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
156             print '    // %s' % function_name
157             self.array_prolog(api, uppercase_name)
158             print '    if (__glIsEnabled(%s)) {' % enable_name
159             print '        GLint __binding = 0;'
160             print '        __glGetIntegerv(%s, &__binding);' % binding_name
161             print '        if (!__binding) {'
162             self.array_cleanup(api, uppercase_name)
163             print '            return true;'
164             print '        }'
165             print '    }'
166             self.array_epilog(api, uppercase_name)
167             print
168
169         print '    vertex_attrib __vertex_attrib = __get_vertex_attrib();'
170         print
171         print '    // glVertexAttribPointer'
172         print '    if (__vertex_attrib == VERTEX_ATTRIB) {'
173         print '        GLint __max_vertex_attribs = 0;'
174         print '        __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
175         print '        for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
176         print '            GLint __enabled = 0;'
177         print '            __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
178         print '            if (__enabled) {'
179         print '                GLint __binding = 0;'
180         print '                __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
181         print '                if (!__binding) {'
182         print '                    return true;'
183         print '                }'
184         print '            }'
185         print '        }'
186         print '    }'
187         print
188         print '    // glVertexAttribPointerARB'
189         print '    if (__vertex_attrib == VERTEX_ATTRIB_ARB) {'
190         print '        GLint __max_vertex_attribs = 0;'
191         print '        __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &__max_vertex_attribs);'
192         print '        for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
193         print '            GLint __enabled = 0;'
194         print '            __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &__enabled);'
195         print '            if (__enabled) {'
196         print '                GLint __binding = 0;'
197         print '                __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &__binding);'
198         print '                if (!__binding) {'
199         print '                    return true;'
200         print '                }'
201         print '            }'
202         print '        }'
203         print '    }'
204         print
205         print '    // glVertexAttribPointerNV'
206         print '    if (__vertex_attrib == VERTEX_ATTRIB_NV) {'
207         print '        for (GLint index = 0; index < 16; ++index) {'
208         print '            GLint __enabled = 0;'
209         print '            __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
210         print '            if (__enabled) {'
211         print '                return true;'
212         print '            }'
213         print '        }'
214         print '    }'
215         print
216
217         print '    return false;'
218         print '}'
219         print
220
221         print 'static void __trace_user_arrays(GLuint maxindex);'
222         print
223
224         print 'struct buffer_mapping {'
225         print '    void *map;'
226         print '    GLint length;'
227         print '    bool write;'
228         print '    bool explicit_flush;'
229         print '};'
230         print
231         for target in self.buffer_targets:
232             print 'struct buffer_mapping __%s_mapping;' % target.lower();
233         print
234         print 'static inline struct buffer_mapping *'
235         print 'get_buffer_mapping(GLenum target) {'
236         print '    switch (target) {'
237         for target in self.buffer_targets:
238             print '    case GL_%s:' % target
239             print '        return & __%s_mapping;' % target.lower()
240         print '    default:'
241         print '        os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
242         print '        return NULL;'
243         print '    }'
244         print '}'
245         print
246
247         # Generate a helper function to determine whether a parameter name
248         # refers to a symbolic value or not
249         print 'static bool'
250         print 'is_symbolic_pname(GLenum pname) {'
251         print '    switch (pname) {'
252         for function, type, count, name in glparams.parameters:
253             if type is glapi.GLenum:
254                 print '    case %s:' % name
255         print '        return true;'
256         print '    default:'
257         print '        return false;'
258         print '    }'
259         print '}'
260         print
261         
262         # Generate a helper function to determine whether a parameter value is
263         # potentially symbolic or not; i.e., if the value can be represented in
264         # an enum or not
265         print 'template<class T>'
266         print 'static inline bool'
267         print 'is_symbolic_param(T param) {'
268         print '    return static_cast<T>(static_cast<GLenum>(param)) == param;'
269         print '}'
270         print
271
272         # Generate a helper function to know how many elements a parameter has
273         print 'static size_t'
274         print '__gl_param_size(GLenum pname) {'
275         print '    switch (pname) {'
276         for function, type, count, name in glparams.parameters:
277             if type is not None:
278                 print '    case %s: return %u;' % (name, count)
279         print '    case GL_COMPRESSED_TEXTURE_FORMATS: {'
280         print '            GLint num_compressed_texture_formats = 0;'
281         print '            __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
282         print '            return num_compressed_texture_formats;'
283         print '        }'
284         print '    default:'
285         print r'        os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
286         print '        return 1;'
287         print '    }'
288         print '}'
289         print
290
291     array_pointer_function_names = set((
292         "glVertexPointer",
293         "glNormalPointer",
294         "glColorPointer",
295         "glIndexPointer",
296         "glTexCoordPointer",
297         "glEdgeFlagPointer",
298         "glFogCoordPointer",
299         "glSecondaryColorPointer",
300         
301         "glInterleavedArrays",
302
303         "glVertexPointerEXT",
304         "glNormalPointerEXT",
305         "glColorPointerEXT",
306         "glIndexPointerEXT",
307         "glTexCoordPointerEXT",
308         "glEdgeFlagPointerEXT",
309         "glFogCoordPointerEXT",
310         "glSecondaryColorPointerEXT",
311
312         "glVertexAttribPointer",
313         "glVertexAttribPointerARB",
314         "glVertexAttribPointerNV",
315         "glVertexAttribIPointer",
316         "glVertexAttribIPointerEXT",
317         "glVertexAttribLPointer",
318         "glVertexAttribLPointerEXT",
319         
320         #"glMatrixIndexPointerARB",
321     ))
322
323     draw_function_names = set((
324         'glDrawArrays',
325         'glDrawElements',
326         'glDrawRangeElements',
327         'glMultiDrawArrays',
328         'glMultiDrawElements',
329         'glDrawArraysInstanced',
330         "glDrawArraysInstancedBaseInstance",
331         'glDrawElementsInstanced',
332         'glDrawArraysInstancedARB',
333         'glDrawElementsInstancedARB',
334         'glDrawElementsBaseVertex',
335         'glDrawRangeElementsBaseVertex',
336         'glDrawElementsInstancedBaseVertex',
337         "glDrawElementsInstancedBaseInstance",
338         "glDrawElementsInstancedBaseVertexBaseInstance",
339         'glMultiDrawElementsBaseVertex',
340         'glDrawArraysIndirect',
341         'glDrawElementsIndirect',
342         'glDrawArraysEXT',
343         'glDrawRangeElementsEXT',
344         'glDrawRangeElementsEXT_size',
345         'glMultiDrawArraysEXT',
346         'glMultiDrawElementsEXT',
347         'glMultiModeDrawArraysIBM',
348         'glMultiModeDrawElementsIBM',
349         'glDrawArraysInstancedEXT',
350         'glDrawElementsInstancedEXT',
351     ))
352
353     interleaved_formats = [
354          'GL_V2F',
355          'GL_V3F',
356          'GL_C4UB_V2F',
357          'GL_C4UB_V3F',
358          'GL_C3F_V3F',
359          'GL_N3F_V3F',
360          'GL_C4F_N3F_V3F',
361          'GL_T2F_V3F',
362          'GL_T4F_V4F',
363          'GL_T2F_C4UB_V3F',
364          'GL_T2F_C3F_V3F',
365          'GL_T2F_N3F_V3F',
366          'GL_T2F_C4F_N3F_V3F',
367          'GL_T4F_C4F_N3F_V4F',
368     ]
369
370     def trace_function_impl_body(self, function):
371         # Defer tracing of user array pointers...
372         if function.name in self.array_pointer_function_names:
373             print '    GLint __array_buffer = 0;'
374             print '    __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
375             print '    if (!__array_buffer) {'
376             print '        __user_arrays = true;'
377             if function.name == "glVertexAttribPointerARB":
378                 print '        __user_arrays_arb = true;'
379             if function.name == "glVertexAttribPointerNV":
380                 print '        __user_arrays_nv = true;'
381             self.dispatch_function(function)
382
383             # And also break down glInterleavedArrays into the individual calls
384             if function.name == 'glInterleavedArrays':
385                 print
386
387                 # Initialize the enable flags
388                 for camelcase_name, uppercase_name in self.arrays:
389                     flag_name = '__' + uppercase_name.lower()
390                     print '        GLboolean %s = GL_FALSE;' % flag_name
391                 print
392
393                 # Switch for the interleaved formats
394                 print '        switch (format) {'
395                 for format in self.interleaved_formats:
396                     print '            case %s:' % format
397                     for camelcase_name, uppercase_name in self.arrays:
398                         flag_name = '__' + uppercase_name.lower()
399                         if format.find('_' + uppercase_name[0]) >= 0:
400                             print '                %s = GL_TRUE;' % flag_name
401                     print '                break;'
402                 print '            default:'
403                 print '               return;'
404                 print '        }'
405                 print
406
407                 # Emit fake glEnableClientState/glDisableClientState flags
408                 for camelcase_name, uppercase_name in self.arrays:
409                     flag_name = '__' + uppercase_name.lower()
410                     enable_name = 'GL_%s_ARRAY' % uppercase_name
411
412                     # Emit a fake function
413                     print '        {'
414                     print '            static const trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
415                     print '            unsigned __call = trace::localWriter.beginEnter(&__sig);'
416                     print '            trace::localWriter.beginArg(0);'
417                     dump_instance(glapi.GLenum, enable_name)
418                     print '            trace::localWriter.endArg();'
419                     print '            trace::localWriter.endEnter();'
420                     print '            trace::localWriter.beginLeave(__call);'
421                     print '            trace::localWriter.endLeave();'
422                     print '        }'
423
424             print '        return;'
425             print '    }'
426
427         # ... to the draw calls
428         if function.name in self.draw_function_names:
429             print '    if (__need_user_arrays()) {'
430             arg_names = ', '.join([arg.name for arg in function.args[1:]])
431             print '        GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
432             print '        __trace_user_arrays(maxindex);'
433             print '    }'
434         
435         # Emit a fake memcpy on buffer uploads
436         if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', ):
437             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
438             print '    if (mapping && mapping->write && !mapping->explicit_flush) {'
439             self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
440             print '    }'
441         if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
442             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
443             print '    if (mapping) {'
444             if function.name.endswith('APPLE'):
445                  print '        GLsizeiptr length = size;'
446                  print '        mapping->explicit_flush = true;'
447             print '        //assert(offset + length <= mapping->length);'
448             self.emit_memcpy('(char *)mapping->map + offset', '(const char *)mapping->map + offset', 'length')
449             print '    }'
450         # FIXME: glFlushMappedNamedBufferRangeEXT
451
452         # Don't leave vertex attrib locations to chance.  Instead emit fake
453         # glBindAttribLocation calls to ensure that the same locations will be
454         # used when retracing.  Trying to remap locations after the fact would
455         # be an herculian task given that vertex attrib locations appear in
456         # many entry-points, including non-shader related ones.
457         if function.name == 'glLinkProgram':
458             Tracer.dispatch_function(self, function)
459             print '    GLint active_attributes = 0;'
460             print '    __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
461             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
462             print '        GLint size = 0;'
463             print '        GLenum type = 0;'
464             print '        GLchar name[256];'
465             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
466             print '        __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
467             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
468             print '            GLint location = __glGetAttribLocation(program, name);'
469             print '            if (location >= 0) {'
470             bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
471             self.fake_call(bind_function, ['program', 'location', 'name'])
472             print '            }'
473             print '        }'
474             print '    }'
475         if function.name == 'glLinkProgramARB':
476             Tracer.dispatch_function(self, function)
477             print '    GLint active_attributes = 0;'
478             print '    __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
479             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
480             print '        GLint size = 0;'
481             print '        GLenum type = 0;'
482             print '        GLcharARB name[256];'
483             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
484             print '        __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
485             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
486             print '            GLint location = __glGetAttribLocationARB(programObj, name);'
487             print '            if (location >= 0) {'
488             bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
489             self.fake_call(bind_function, ['programObj', 'location', 'name'])
490             print '            }'
491             print '        }'
492             print '    }'
493
494         Tracer.trace_function_impl_body(self, function)
495
496     gremedy_functions = [
497         'glStringMarkerGREMEDY',
498         'glFrameTerminatorGREMEDY',
499     ]
500
501     def dispatch_function(self, function):
502         if function.name in ('glLinkProgram', 'glLinkProgramARB'):
503             # These functions have been dispatched already
504             return
505
506         # We implement the GREMEDY extensions, not the driver
507         if function.name in self.gremedy_functions:
508             return
509
510         if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
511             if_ = 'if'
512             for gremedy_function in self.gremedy_functions:
513                 print '    %s (strcmp("%s", (const char *)%s) == 0) {' % (if_, gremedy_function, function.args[0].name)
514                 print '        __result = (%s)&%s;' % (function.type, gremedy_function)
515                 print '    }'
516                 if_ = 'else if'
517             print '    else {'
518             Tracer.dispatch_function(self, function)
519             print '    }'
520             return
521
522         # Override GL extensions
523         if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
524             Tracer.dispatch_function(self, function, prefix = 'gltrace::__', suffix = '_override')
525             return
526
527         Tracer.dispatch_function(self, function)
528
529     def emit_memcpy(self, dest, src, length):
530         print '        unsigned __call = trace::localWriter.beginEnter(&trace::memcpy_sig);'
531         print '        trace::localWriter.beginArg(0);'
532         print '        trace::localWriter.writeOpaque(%s);' % dest
533         print '        trace::localWriter.endArg();'
534         print '        trace::localWriter.beginArg(1);'
535         print '        trace::localWriter.writeBlob(%s, %s);' % (src, length)
536         print '        trace::localWriter.endArg();'
537         print '        trace::localWriter.beginArg(2);'
538         print '        trace::localWriter.writeUInt(%s);' % length
539         print '        trace::localWriter.endArg();'
540         print '        trace::localWriter.endEnter();'
541         print '        trace::localWriter.beginLeave(__call);'
542         print '        trace::localWriter.endLeave();'
543        
544     buffer_targets = [
545         'ARRAY_BUFFER',
546         'ELEMENT_ARRAY_BUFFER',
547         'PIXEL_PACK_BUFFER',
548         'PIXEL_UNPACK_BUFFER',
549     ]
550
551     def wrap_ret(self, function, instance):
552         Tracer.wrap_ret(self, function, instance)
553
554             
555         if function.name in ('glMapBuffer', 'glMapBufferARB'):
556             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
557             print '    if (mapping) {'
558             print '        mapping->map = %s;' % (instance)
559             print '        mapping->length = 0;'
560             print '        __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
561             print '        mapping->write = (access != GL_READ_ONLY);'
562             print '        mapping->explicit_flush = false;'
563             print '    }'
564
565         if function.name == 'glMapBufferRange':
566             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
567             print '    if (mapping) {'
568             print '        mapping->map = %s;' % (instance)
569             print '        mapping->length = length;'
570             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
571             print '        mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
572             print '    }'
573
574     boolean_names = [
575         'GL_FALSE',
576         'GL_TRUE',
577     ]
578
579     def gl_boolean(self, value):
580         return self.boolean_names[int(bool(value))]
581
582     # Names of the functions that unpack from a pixel buffer object.  See the
583     # ARB_pixel_buffer_object specification.
584     unpack_function_names = set([
585         'glBitmap',
586         'glColorSubTable',
587         'glColorTable',
588         'glCompressedTexImage1D',
589         'glCompressedTexImage2D',
590         'glCompressedTexImage3D',
591         'glCompressedTexSubImage1D',
592         'glCompressedTexSubImage2D',
593         'glCompressedTexSubImage3D',
594         'glConvolutionFilter1D',
595         'glConvolutionFilter2D',
596         'glDrawPixels',
597         'glMultiTexImage1DEXT',
598         'glMultiTexImage2DEXT',
599         'glMultiTexImage3DEXT',
600         'glMultiTexSubImage1DEXT',
601         'glMultiTexSubImage2DEXT',
602         'glMultiTexSubImage3DEXT',
603         'glPixelMapfv',
604         'glPixelMapuiv',
605         'glPixelMapusv',
606         'glPolygonStipple',
607         'glSeparableFilter2D',
608         'glTexImage1D',
609         'glTexImage1DEXT',
610         'glTexImage2D',
611         'glTexImage2DEXT',
612         'glTexImage3D',
613         'glTexImage3DEXT',
614         'glTexSubImage1D',
615         'glTexSubImage1DEXT',
616         'glTexSubImage2D',
617         'glTexSubImage2DEXT',
618         'glTexSubImage3D',
619         'glTexSubImage3DEXT',
620         'glTextureImage1DEXT',
621         'glTextureImage2DEXT',
622         'glTextureImage3DEXT',
623         'glTextureSubImage1DEXT',
624         'glTextureSubImage2DEXT',
625         'glTextureSubImage3DEXT',
626     ])
627
628     def dump_arg_instance(self, function, arg):
629         if function.name in self.draw_function_names and arg.name == 'indices':
630             print '    GLint __element_array_buffer = 0;'
631             print '    __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
632             print '    if (!__element_array_buffer) {'
633             if isinstance(arg.type, stdapi.Array):
634                 print '        trace::localWriter.beginArray(%s);' % arg.type.length
635                 print '        for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
636                 print '            trace::localWriter.beginElement();'
637                 print '            trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
638                 print '            trace::localWriter.endElement();'
639                 print '        }'
640                 print '        trace::localWriter.endArray();'
641             else:
642                 print '        trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
643             print '    } else {'
644             Tracer.dump_arg_instance(self, function, arg)
645             print '    }'
646             return
647
648         # Recognize offsets instead of blobs when a PBO is bound
649         if function.name in self.unpack_function_names \
650            and (isinstance(arg.type, stdapi.Blob) \
651                 or (isinstance(arg.type, stdapi.Const) \
652                     and isinstance(arg.type.type, stdapi.Blob))):
653             print '    {'
654             print '        GLint __unpack_buffer = 0;'
655             print '        __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
656             print '        if (__unpack_buffer) {'
657             print '            trace::localWriter.writeOpaque(%s);' % arg.name
658             print '        } else {'
659             Tracer.dump_arg_instance(self, function, arg)
660             print '        }'
661             print '    }'
662             return
663
664         # Several GL state functions take GLenum symbolic names as
665         # integer/floats; so dump the symbolic name whenever possible
666         if function.name.startswith('gl') \
667            and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
668            and arg.name == 'param':
669             assert arg.index > 0
670             assert function.args[arg.index - 1].name == 'pname'
671             assert function.args[arg.index - 1].type == glapi.GLenum
672             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
673             dump_instance(glapi.GLenum, arg.name)
674             print '    } else {'
675             Tracer.dump_arg_instance(self, function, arg)
676             print '    }'
677             return
678
679         Tracer.dump_arg_instance(self, function, arg)
680
681     def footer(self, api):
682         Tracer.footer(self, api)
683
684         # A simple state tracker to track the pointer values
685         # update the state
686         print 'static void __trace_user_arrays(GLuint maxindex)'
687         print '{'
688
689         for camelcase_name, uppercase_name in self.arrays:
690             function_name = 'gl%sPointer' % camelcase_name
691             enable_name = 'GL_%s_ARRAY' % uppercase_name
692             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
693             function = api.get_function_by_name(function_name)
694
695             print '    // %s' % function.prototype()
696             self.array_trace_prolog(api, uppercase_name)
697             self.array_prolog(api, uppercase_name)
698             print '    if (__glIsEnabled(%s)) {' % enable_name
699             print '        GLint __binding = 0;'
700             print '        __glGetIntegerv(%s, &__binding);' % binding_name
701             print '        if (!__binding) {'
702
703             # Get the arguments via glGet*
704             for arg in function.args:
705                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
706                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
707                 print '            %s %s = 0;' % (arg_type, arg.name)
708                 print '            __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
709             
710             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
711             print '            size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
712
713             # Emit a fake function
714             self.array_trace_intermezzo(api, uppercase_name)
715             print '            unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
716             for arg in function.args:
717                 assert not arg.output
718                 print '            trace::localWriter.beginArg(%u);' % (arg.index,)
719                 if arg.name != 'pointer':
720                     dump_instance(arg.type, arg.name)
721                 else:
722                     print '            trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
723                 print '            trace::localWriter.endArg();'
724             
725             print '            trace::localWriter.endEnter();'
726             print '            trace::localWriter.beginLeave(__call);'
727             print '            trace::localWriter.endLeave();'
728             print '        }'
729             print '    }'
730             self.array_epilog(api, uppercase_name)
731             self.array_trace_epilog(api, uppercase_name)
732             print
733
734         # Samething, but for glVertexAttribPointer*
735         #
736         # Some variants of glVertexAttribPointer alias conventional and generic attributes:
737         # - glVertexAttribPointer: no
738         # - glVertexAttribPointerARB: implementation dependent
739         # - glVertexAttribPointerNV: yes
740         #
741         # This means that the implementations of these functions do not always
742         # alias, and they need to be considered independently.
743         #
744         print '    vertex_attrib __vertex_attrib = __get_vertex_attrib();'
745         print
746         for suffix in ['', 'ARB', 'NV']:
747             if suffix:
748                 SUFFIX = '_' + suffix
749             else:
750                 SUFFIX = suffix
751             function_name = 'glVertexAttribPointer' + suffix
752             function = api.get_function_by_name(function_name)
753
754             print '    // %s' % function.prototype()
755             print '    if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
756             if suffix == 'NV':
757                 print '        GLint __max_vertex_attribs = 16;'
758             else:
759                 print '        GLint __max_vertex_attribs = 0;'
760                 print '        __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
761             print '        for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
762             print '            GLint __enabled = 0;'
763             if suffix == 'NV':
764                 print '            __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
765             else:
766                 print '            __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
767             print '            if (__enabled) {'
768             print '                GLint __binding = 0;'
769             if suffix != 'NV':
770                 # It doesn't seem possible to use VBOs with NV_vertex_program.
771                 print '                __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
772             print '                if (!__binding) {'
773
774             # Get the arguments via glGet*
775             for arg in function.args[1:]:
776                 if suffix == 'NV':
777                     arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
778                 else:
779                     arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
780                 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
781                 print '                    %s %s = 0;' % (arg_type, arg.name)
782                 print '                    __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
783             
784             arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
785             print '                    size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
786
787             # Emit a fake function
788             print '                    unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
789             for arg in function.args:
790                 assert not arg.output
791                 print '                    trace::localWriter.beginArg(%u);' % (arg.index,)
792                 if arg.name != 'pointer':
793                     dump_instance(arg.type, arg.name)
794                 else:
795                     print '                    trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
796                 print '                    trace::localWriter.endArg();'
797             
798             print '                    trace::localWriter.endEnter();'
799             print '                    trace::localWriter.beginLeave(__call);'
800             print '                    trace::localWriter.endLeave();'
801             print '                }'
802             print '            }'
803             print '        }'
804             print '    }'
805             print
806
807         print '}'
808         print
809
810     #
811     # Hooks for glTexCoordPointer, which is identical to the other array
812     # pointers except the fact that it is indexed by glClientActiveTexture.
813     #
814
815     def array_prolog(self, api, uppercase_name):
816         if uppercase_name == 'TEXTURE_COORD':
817             print '    GLint client_active_texture = 0;'
818             print '    __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
819             print '    GLint max_texture_coords = 0;'
820             print '    __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
821             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
822             print '        GLint texture = GL_TEXTURE0 + unit;'
823             print '        __glClientActiveTexture(texture);'
824
825     def array_trace_prolog(self, api, uppercase_name):
826         if uppercase_name == 'TEXTURE_COORD':
827             print '    bool client_active_texture_dirty = false;'
828
829     def array_epilog(self, api, uppercase_name):
830         if uppercase_name == 'TEXTURE_COORD':
831             print '    }'
832         self.array_cleanup(api, uppercase_name)
833
834     def array_cleanup(self, api, uppercase_name):
835         if uppercase_name == 'TEXTURE_COORD':
836             print '    __glClientActiveTexture(client_active_texture);'
837         
838     def array_trace_intermezzo(self, api, uppercase_name):
839         if uppercase_name == 'TEXTURE_COORD':
840             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
841             print '        client_active_texture_dirty = true;'
842             self.fake_glClientActiveTexture_call(api, "texture");
843             print '    }'
844
845     def array_trace_epilog(self, api, uppercase_name):
846         if uppercase_name == 'TEXTURE_COORD':
847             print '    if (client_active_texture_dirty) {'
848             self.fake_glClientActiveTexture_call(api, "client_active_texture");
849             print '    }'
850
851     def fake_glClientActiveTexture_call(self, api, texture):
852         function = api.get_function_by_name('glClientActiveTexture')
853         self.fake_call(function, [texture])
854
855     def fake_call(self, function, args):
856         print '            unsigned __fake_call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
857         for arg, instance in zip(function.args, args):
858             assert not arg.output
859             print '            trace::localWriter.beginArg(%u);' % (arg.index,)
860             dump_instance(arg.type, instance)
861             print '            trace::localWriter.endArg();'
862         print '            trace::localWriter.endEnter();'
863         print '            trace::localWriter.beginLeave(__fake_call);'
864         print '            trace::localWriter.endLeave();'
865
866
867
868
869
870
871
872
873
874
875