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