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