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