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