]> git.cworth.org Git - apitrace/blob - gltrace.py
Uniformize the debug messages.
[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("apitrace: 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("apitrace: 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     unpack_function_names = set([
479         'glBitmap',
480         'glDrawPixels',
481         'glMultiTexImage1DEXT',
482         'glMultiTexImage2DEXT',
483         'glMultiTexImage3DEXT',
484         'glMultiTexSubImage1DEXT',
485         'glMultiTexSubImage2DEXT',
486         'glMultiTexSubImage3DEXT',
487         'glPolygonStipple',
488         'glTexImage1D',
489         'glTexImage1DEXT',
490         'glTexImage2D',
491         'glTexImage2DEXT',
492         'glTexImage3D',
493         'glTexImage3DEXT',
494         'glTexSubImage1D',
495         'glTexSubImage1DEXT',
496         'glTexSubImage2D',
497         'glTexSubImage2DEXT',
498         'glTexSubImage3D',
499         'glTexSubImage3DEXT',
500         'glTextureImage1DEXT',
501         'glTextureImage2DEXT',
502         'glTextureImage3DEXT',
503         'glTextureSubImage1DEXT',
504         'glTextureSubImage2DEXT',
505         'glTextureSubImage3DEXT',
506     ])
507
508     def dump_arg_instance(self, function, arg):
509         if function.name in self.draw_function_names and arg.name == 'indices':
510             print '    GLint __element_array_buffer = 0;'
511             print '    __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
512             print '    if (!__element_array_buffer) {'
513             if isinstance(arg.type, stdapi.Array):
514                 print '        __writer.beginArray(%s);' % arg.type.length
515                 print '        for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
516                 print '            __writer.beginElement();'
517                 print '            __writer.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
518                 print '            __writer.endElement();'
519                 print '        }'
520                 print '        __writer.endArray();'
521             else:
522                 print '        __writer.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
523             print '    } else {'
524             Tracer.dump_arg_instance(self, function, arg)
525             print '    }'
526             return
527
528         # Recognize offsets instead of blobs when a PBO is bound
529         if function.name in self.unpack_function_names \
530            and (isinstance(arg.type, stdapi.Blob) \
531                 or (isinstance(arg.type, stdapi.Const) \
532                     and isinstance(arg.type.type, stdapi.Blob))):
533             print '    GLint __unpack_buffer = 0;'
534             print '    __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
535             print '    if (__unpack_buffer) {'
536             print '        __writer.writeOpaque(%s);' % arg.name
537             print '    } else {'
538             Tracer.dump_arg_instance(self, function, arg)
539             print '    }'
540             return
541
542         # Several GL state functions take GLenum symbolic names as
543         # integer/floats; so dump the symbolic name whenever possible
544         if function.name.startswith('gl') \
545            and arg.type in (glapi.GLint, glapi.GLfloat) \
546            and arg.name == 'param':
547             assert arg.index > 0
548             assert function.args[arg.index - 1].name == 'pname'
549             assert function.args[arg.index - 1].type == glapi.GLenum
550             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
551             dump_instance(glapi.GLenum, arg.name)
552             print '    } else {'
553             Tracer.dump_arg_instance(self, function, arg)
554             print '    }'
555             return
556
557         Tracer.dump_arg_instance(self, function, arg)
558
559     def footer(self, api):
560         Tracer.footer(self, api)
561
562         # A simple state tracker to track the pointer values
563         # update the state
564         print 'static void __trace_user_arrays(GLuint maxindex)'
565         print '{'
566
567         for camelcase_name, uppercase_name in self.arrays:
568             function_name = 'gl%sPointer' % camelcase_name
569             enable_name = 'GL_%s_ARRAY' % uppercase_name
570             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
571             function = api.get_function_by_name(function_name)
572
573             print '    // %s' % function.name
574             self.array_trace_prolog(api, uppercase_name)
575             self.array_prolog(api, uppercase_name)
576             print '    if (__glIsEnabled(%s)) {' % enable_name
577             print '        GLint __binding = 0;'
578             print '        __glGetIntegerv(%s, &__binding);' % binding_name
579             print '        if (!__binding) {'
580
581             # Get the arguments via glGet*
582             for arg in function.args:
583                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
584                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
585                 print '            %s %s = 0;' % (arg_type, arg.name)
586                 print '            __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
587             
588             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
589             print '            size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
590
591             # Emit a fake function
592             self.array_trace_intermezzo(api, uppercase_name)
593             print '            unsigned __call = __writer.beginEnter(&__%s_sig);' % (function.name,)
594             for arg in function.args:
595                 assert not arg.output
596                 print '            __writer.beginArg(%u);' % (arg.index,)
597                 if arg.name != 'pointer':
598                     dump_instance(arg.type, arg.name)
599                 else:
600                     print '            __writer.writeBlob((const void *)%s, __size);' % (arg.name)
601                 print '            __writer.endArg();'
602             
603             print '            __writer.endEnter();'
604             print '            __writer.beginLeave(__call);'
605             print '            __writer.endLeave();'
606             print '        }'
607             print '    }'
608             self.array_epilog(api, uppercase_name)
609             self.array_trace_epilog(api, uppercase_name)
610             print
611
612         # Samething, but for glVertexAttribPointer
613         print '    // glVertexAttribPointer'
614         print '    GLint __max_vertex_attribs = 0;'
615         print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
616         print '    for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
617         print '        GLint __enabled = 0;'
618         print '        __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
619         print '        if (__enabled) {'
620         print '            GLint __binding = 0;'
621         print '            __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
622         print '            if (!__binding) {'
623
624         function = api.get_function_by_name('glVertexAttribPointer')
625
626         # Get the arguments via glGet*
627         for arg in function.args[1:]:
628             arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s' % (arg.name.upper(),)
629             arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False).visit(arg.type)
630             print '                %s %s = 0;' % (arg_type, arg.name)
631             print '                __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
632         
633         arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
634         print '                size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
635
636         # Emit a fake function
637         print '                unsigned __call = __writer.beginEnter(&__%s_sig);' % (function.name,)
638         for arg in function.args:
639             assert not arg.output
640             print '                __writer.beginArg(%u);' % (arg.index,)
641             if arg.name != 'pointer':
642                 dump_instance(arg.type, arg.name)
643             else:
644                 print '                __writer.writeBlob((const void *)%s, __size);' % (arg.name)
645             print '                __writer.endArg();'
646         
647         print '                __writer.endEnter();'
648         print '                __writer.beginLeave(__call);'
649         print '                __writer.endLeave();'
650         print '            }'
651         print '        }'
652         print '    }'
653         print
654
655         print '}'
656         print
657
658     #
659     # Hooks for glTexCoordPointer, which is identical to the other array
660     # pointers except the fact that it is indexed by glClientActiveTexture.
661     #
662
663     def array_prolog(self, api, uppercase_name):
664         if uppercase_name == 'TEXTURE_COORD':
665             print '    GLint client_active_texture = 0;'
666             print '    __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
667             print '    GLint max_texture_coords = 0;'
668             print '    __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
669             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
670             print '        GLenum texture = GL_TEXTURE0 + unit;'
671             print '        __glClientActiveTexture(texture);'
672
673     def array_trace_prolog(self, api, uppercase_name):
674         if uppercase_name == 'TEXTURE_COORD':
675             print '    bool client_active_texture_dirty = false;'
676
677     def array_epilog(self, api, uppercase_name):
678         if uppercase_name == 'TEXTURE_COORD':
679             print '    }'
680         self.array_cleanup(api, uppercase_name)
681
682     def array_cleanup(self, api, uppercase_name):
683         if uppercase_name == 'TEXTURE_COORD':
684             print '    __glClientActiveTexture(client_active_texture);'
685         
686     def array_trace_intermezzo(self, api, uppercase_name):
687         if uppercase_name == 'TEXTURE_COORD':
688             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
689             print '        client_active_texture_dirty = true;'
690             self.fake_glClientActiveTexture_call(api, "texture");
691             print '    }'
692
693     def array_trace_epilog(self, api, uppercase_name):
694         if uppercase_name == 'TEXTURE_COORD':
695             print '    if (client_active_texture_dirty) {'
696             self.fake_glClientActiveTexture_call(api, "client_active_texture");
697             print '    }'
698
699     def fake_glClientActiveTexture_call(self, api, texture):
700         function = api.get_function_by_name('glClientActiveTexture')
701         self.fake_call(function, [texture])
702
703     def fake_call(self, function, args):
704         print '            unsigned __fake_call = __writer.beginEnter(&__%s_sig);' % (function.name,)
705         for arg, instance in zip(function.args, args):
706             assert not arg.output
707             print '            __writer.beginArg(%u);' % (arg.index,)
708             dump_instance(arg.type, instance)
709             print '            __writer.endArg();'
710         print '            __writer.endEnter();'
711         print '            __writer.beginLeave(__fake_call);'
712         print '            __writer.endLeave();'
713
714
715
716
717
718
719
720
721
722
723