]> git.cworth.org Git - apitrace/blob - gltrace.py
Move all API specs to a separate dir.
[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 specs.stdapi as stdapi
31 import specs.glapi as glapi
32 import specs.glparams as glparams
33 from specs.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         # Override GL extensions
524         if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
525             Tracer.dispatch_function(self, function, prefix = 'gltrace::__', suffix = '_override')
526             return
527
528         Tracer.dispatch_function(self, function)
529
530     def emit_memcpy(self, dest, src, length):
531         print '        unsigned __call = Trace::localWriter.beginEnter(&__memcpy_sig);'
532         print '        Trace::localWriter.beginArg(0);'
533         print '        Trace::localWriter.writeOpaque(%s);' % dest
534         print '        Trace::localWriter.endArg();'
535         print '        Trace::localWriter.beginArg(1);'
536         print '        Trace::localWriter.writeBlob(%s, %s);' % (src, length)
537         print '        Trace::localWriter.endArg();'
538         print '        Trace::localWriter.beginArg(2);'
539         print '        Trace::localWriter.writeUInt(%s);' % length
540         print '        Trace::localWriter.endArg();'
541         print '        Trace::localWriter.endEnter();'
542         print '        Trace::localWriter.beginLeave(__call);'
543         print '        Trace::localWriter.endLeave();'
544        
545     buffer_targets = [
546         'ARRAY_BUFFER',
547         'ELEMENT_ARRAY_BUFFER',
548         'PIXEL_PACK_BUFFER',
549         'PIXEL_UNPACK_BUFFER',
550     ]
551
552     def wrap_ret(self, function, instance):
553         Tracer.wrap_ret(self, function, instance)
554
555             
556         if function.name in ('glMapBuffer', 'glMapBufferARB'):
557             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
558             print '    if (mapping) {'
559             print '        mapping->map = %s;' % (instance)
560             print '        mapping->length = 0;'
561             print '        __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
562             print '        mapping->write = (access != GL_READ_ONLY);'
563             print '        mapping->explicit_flush = false;'
564             print '    }'
565
566         if function.name == 'glMapBufferRange':
567             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
568             print '    if (mapping) {'
569             print '        mapping->map = %s;' % (instance)
570             print '        mapping->length = length;'
571             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
572             print '        mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
573             print '    }'
574
575     boolean_names = [
576         'GL_FALSE',
577         'GL_TRUE',
578     ]
579
580     def gl_boolean(self, value):
581         return self.boolean_names[int(bool(value))]
582
583     # Names of the functions that unpack from a pixel buffer object.  See the
584     # ARB_pixel_buffer_object specification.
585     unpack_function_names = set([
586         'glBitmap',
587         'glColorSubTable',
588         'glColorTable',
589         'glCompressedTexImage1D',
590         'glCompressedTexImage2D',
591         'glCompressedTexImage3D',
592         'glCompressedTexSubImage1D',
593         'glCompressedTexSubImage2D',
594         'glCompressedTexSubImage3D',
595         'glConvolutionFilter1D',
596         'glConvolutionFilter2D',
597         'glDrawPixels',
598         'glMultiTexImage1DEXT',
599         'glMultiTexImage2DEXT',
600         'glMultiTexImage3DEXT',
601         'glMultiTexSubImage1DEXT',
602         'glMultiTexSubImage2DEXT',
603         'glMultiTexSubImage3DEXT',
604         'glPixelMapfv',
605         'glPixelMapuiv',
606         'glPixelMapusv',
607         'glPolygonStipple',
608         'glSeparableFilter2D',
609         'glTexImage1D',
610         'glTexImage1DEXT',
611         'glTexImage2D',
612         'glTexImage2DEXT',
613         'glTexImage3D',
614         'glTexImage3DEXT',
615         'glTexSubImage1D',
616         'glTexSubImage1DEXT',
617         'glTexSubImage2D',
618         'glTexSubImage2DEXT',
619         'glTexSubImage3D',
620         'glTexSubImage3DEXT',
621         'glTextureImage1DEXT',
622         'glTextureImage2DEXT',
623         'glTextureImage3DEXT',
624         'glTextureSubImage1DEXT',
625         'glTextureSubImage2DEXT',
626         'glTextureSubImage3DEXT',
627     ])
628
629     def dump_arg_instance(self, function, arg):
630         if function.name in self.draw_function_names and arg.name == 'indices':
631             print '    GLint __element_array_buffer = 0;'
632             print '    __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
633             print '    if (!__element_array_buffer) {'
634             if isinstance(arg.type, stdapi.Array):
635                 print '        Trace::localWriter.beginArray(%s);' % arg.type.length
636                 print '        for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
637                 print '            Trace::localWriter.beginElement();'
638                 print '            Trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
639                 print '            Trace::localWriter.endElement();'
640                 print '        }'
641                 print '        Trace::localWriter.endArray();'
642             else:
643                 print '        Trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
644             print '    } else {'
645             Tracer.dump_arg_instance(self, function, arg)
646             print '    }'
647             return
648
649         # Recognize offsets instead of blobs when a PBO is bound
650         if function.name in self.unpack_function_names \
651            and (isinstance(arg.type, stdapi.Blob) \
652                 or (isinstance(arg.type, stdapi.Const) \
653                     and isinstance(arg.type.type, stdapi.Blob))):
654             print '    {'
655             print '        GLint __unpack_buffer = 0;'
656             print '        __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
657             print '        if (__unpack_buffer) {'
658             print '            Trace::localWriter.writeOpaque(%s);' % arg.name
659             print '        } else {'
660             Tracer.dump_arg_instance(self, function, arg)
661             print '        }'
662             print '    }'
663             return
664
665         # Several GL state functions take GLenum symbolic names as
666         # integer/floats; so dump the symbolic name whenever possible
667         if function.name.startswith('gl') \
668            and arg.type in (glapi.GLint, glapi.GLfloat) \
669            and arg.name == 'param':
670             assert arg.index > 0
671             assert function.args[arg.index - 1].name == 'pname'
672             assert function.args[arg.index - 1].type == glapi.GLenum
673             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
674             dump_instance(glapi.GLenum, arg.name)
675             print '    } else {'
676             Tracer.dump_arg_instance(self, function, arg)
677             print '    }'
678             return
679
680         Tracer.dump_arg_instance(self, function, arg)
681
682     def footer(self, api):
683         Tracer.footer(self, api)
684
685         # A simple state tracker to track the pointer values
686         # update the state
687         print 'static void __trace_user_arrays(GLuint maxindex)'
688         print '{'
689
690         for camelcase_name, uppercase_name in self.arrays:
691             function_name = 'gl%sPointer' % camelcase_name
692             enable_name = 'GL_%s_ARRAY' % uppercase_name
693             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
694             function = api.get_function_by_name(function_name)
695
696             print '    // %s' % function.name
697             self.array_trace_prolog(api, uppercase_name)
698             self.array_prolog(api, uppercase_name)
699             print '    if (__glIsEnabled(%s)) {' % enable_name
700             print '        GLint __binding = 0;'
701             print '        __glGetIntegerv(%s, &__binding);' % binding_name
702             print '        if (!__binding) {'
703
704             # Get the arguments via glGet*
705             for arg in function.args:
706                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
707                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
708                 print '            %s %s = 0;' % (arg_type, arg.name)
709                 print '            __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
710             
711             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
712             print '            size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
713
714             # Emit a fake function
715             self.array_trace_intermezzo(api, uppercase_name)
716             print '            unsigned __call = Trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
717             for arg in function.args:
718                 assert not arg.output
719                 print '            Trace::localWriter.beginArg(%u);' % (arg.index,)
720                 if arg.name != 'pointer':
721                     dump_instance(arg.type, arg.name)
722                 else:
723                     print '            Trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
724                 print '            Trace::localWriter.endArg();'
725             
726             print '            Trace::localWriter.endEnter();'
727             print '            Trace::localWriter.beginLeave(__call);'
728             print '            Trace::localWriter.endLeave();'
729             print '        }'
730             print '    }'
731             self.array_epilog(api, uppercase_name)
732             self.array_trace_epilog(api, uppercase_name)
733             print
734
735         # Samething, but for glVertexAttribPointer*
736         #
737         # Some variants of glVertexAttribPointer alias conventional and generic attributes:
738         # - glVertexAttribPointer: no
739         # - glVertexAttribPointerARB: implementation dependent
740         # - glVertexAttribPointerNV: yes
741         #
742         # This means that the implementations of these functions do not always
743         # alias, and they need to be considered independently.
744         #
745         print '    vertex_attrib __vertex_attrib = __get_vertex_attrib();'
746         print
747         for suffix in ['', 'ARB', 'NV']:
748             if suffix:
749                 SUFFIX = '_' + suffix
750             else:
751                 SUFFIX = suffix
752             function_name = 'glVertexAttribPointer' + suffix
753             print '    // %s' % function_name
754             print '    if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
755             if suffix == 'NV':
756                 print '        GLint __max_vertex_attribs = 16;'
757             else:
758                 print '        GLint __max_vertex_attribs = 0;'
759                 print '        __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
760             print '        for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
761             print '            GLint __enabled = 0;'
762             if suffix == 'NV':
763                 print '            __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
764             else:
765                 print '            __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
766             print '            if (__enabled) {'
767             print '                GLint __binding = 0;'
768             if suffix != 'NV':
769                 # It doesn't seem possible to use VBOs with NV_vertex_program.
770                 print '                __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
771             print '                if (!__binding) {'
772
773             function = api.get_function_by_name(function_name)
774
775             # Get the arguments via glGet*
776             for arg in function.args[1:]:
777                 if suffix == 'NV':
778                     arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
779                 else:
780                     arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
781                 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
782                 print '                    %s %s = 0;' % (arg_type, arg.name)
783                 print '                    __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
784             
785             arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
786             print '                    size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
787
788             # Emit a fake function
789             print '                    unsigned __call = Trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
790             for arg in function.args:
791                 assert not arg.output
792                 print '                    Trace::localWriter.beginArg(%u);' % (arg.index,)
793                 if arg.name != 'pointer':
794                     dump_instance(arg.type, arg.name)
795                 else:
796                     print '                    Trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
797                 print '                    Trace::localWriter.endArg();'
798             
799             print '                    Trace::localWriter.endEnter();'
800             print '                    Trace::localWriter.beginLeave(__call);'
801             print '                    Trace::localWriter.endLeave();'
802             print '                }'
803             print '            }'
804             print '        }'
805             print '    }'
806             print
807
808         print '}'
809         print
810
811     #
812     # Hooks for glTexCoordPointer, which is identical to the other array
813     # pointers except the fact that it is indexed by glClientActiveTexture.
814     #
815
816     def array_prolog(self, api, uppercase_name):
817         if uppercase_name == 'TEXTURE_COORD':
818             print '    GLint client_active_texture = 0;'
819             print '    __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
820             print '    GLint max_texture_coords = 0;'
821             print '    __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
822             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
823             print '        GLenum texture = GL_TEXTURE0 + unit;'
824             print '        __glClientActiveTexture(texture);'
825
826     def array_trace_prolog(self, api, uppercase_name):
827         if uppercase_name == 'TEXTURE_COORD':
828             print '    bool client_active_texture_dirty = false;'
829
830     def array_epilog(self, api, uppercase_name):
831         if uppercase_name == 'TEXTURE_COORD':
832             print '    }'
833         self.array_cleanup(api, uppercase_name)
834
835     def array_cleanup(self, api, uppercase_name):
836         if uppercase_name == 'TEXTURE_COORD':
837             print '    __glClientActiveTexture(client_active_texture);'
838         
839     def array_trace_intermezzo(self, api, uppercase_name):
840         if uppercase_name == 'TEXTURE_COORD':
841             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
842             print '        client_active_texture_dirty = true;'
843             self.fake_glClientActiveTexture_call(api, "texture");
844             print '    }'
845
846     def array_trace_epilog(self, api, uppercase_name):
847         if uppercase_name == 'TEXTURE_COORD':
848             print '    if (client_active_texture_dirty) {'
849             self.fake_glClientActiveTexture_call(api, "client_active_texture");
850             print '    }'
851
852     def fake_glClientActiveTexture_call(self, api, texture):
853         function = api.get_function_by_name('glClientActiveTexture')
854         self.fake_call(function, [texture])
855
856     def fake_call(self, function, args):
857         print '            unsigned __fake_call = Trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
858         for arg, instance in zip(function.args, args):
859             assert not arg.output
860             print '            Trace::localWriter.beginArg(%u);' % (arg.index,)
861             dump_instance(arg.type, instance)
862             print '            Trace::localWriter.endArg();'
863         print '            Trace::localWriter.endEnter();'
864         print '            Trace::localWriter.beginLeave(__fake_call);'
865         print '            Trace::localWriter.endLeave();'
866
867
868
869
870
871
872
873
874
875
876