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