]> git.cworth.org Git - apitrace/blob - gltrace.py
More D2D spec tweaks.
[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         "glDrawArraysInstancedBaseInstance",
334         'glDrawElementsInstanced',
335         'glDrawArraysInstancedARB',
336         'glDrawElementsInstancedARB',
337         'glDrawElementsBaseVertex',
338         'glDrawRangeElementsBaseVertex',
339         'glDrawElementsInstancedBaseVertex',
340         "glDrawElementsInstancedBaseInstance",
341         "glDrawElementsInstancedBaseVertexBaseInstance",
342         'glMultiDrawElementsBaseVertex',
343         'glDrawArraysIndirect',
344         'glDrawElementsIndirect',
345         'glDrawArraysEXT',
346         'glDrawRangeElementsEXT',
347         'glDrawRangeElementsEXT_size',
348         'glMultiDrawArraysEXT',
349         'glMultiDrawElementsEXT',
350         'glMultiModeDrawArraysIBM',
351         'glMultiModeDrawElementsIBM',
352         'glDrawArraysInstancedEXT',
353         'glDrawElementsInstancedEXT',
354     ))
355
356     interleaved_formats = [
357          'GL_V2F',
358          'GL_V3F',
359          'GL_C4UB_V2F',
360          'GL_C4UB_V3F',
361          'GL_C3F_V3F',
362          'GL_N3F_V3F',
363          'GL_C4F_N3F_V3F',
364          'GL_T2F_V3F',
365          'GL_T4F_V4F',
366          'GL_T2F_C4UB_V3F',
367          'GL_T2F_C3F_V3F',
368          'GL_T2F_N3F_V3F',
369          'GL_T2F_C4F_N3F_V3F',
370          'GL_T4F_C4F_N3F_V4F',
371     ]
372
373     def trace_function_impl_body(self, function):
374         # Defer tracing of user array pointers...
375         if function.name in self.array_pointer_function_names:
376             print '    GLint __array_buffer = 0;'
377             print '    __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
378             print '    if (!__array_buffer) {'
379             print '        __user_arrays = true;'
380             if function.name == "glVertexAttribPointerARB":
381                 print '        __user_arrays_arb = true;'
382             if function.name == "glVertexAttribPointerNV":
383                 print '        __user_arrays_nv = true;'
384             self.dispatch_function(function)
385
386             # And also break down glInterleavedArrays into the individual calls
387             if function.name == 'glInterleavedArrays':
388                 print
389
390                 # Initialize the enable flags
391                 for camelcase_name, uppercase_name in self.arrays:
392                     flag_name = '__' + uppercase_name.lower()
393                     print '        GLboolean %s = GL_FALSE;' % flag_name
394                 print
395
396                 # Switch for the interleaved formats
397                 print '        switch (format) {'
398                 for format in self.interleaved_formats:
399                     print '            case %s:' % format
400                     for camelcase_name, uppercase_name in self.arrays:
401                         flag_name = '__' + uppercase_name.lower()
402                         if format.find('_' + uppercase_name[0]) >= 0:
403                             print '                %s = GL_TRUE;' % flag_name
404                     print '                break;'
405                 print '            default:'
406                 print '               return;'
407                 print '        }'
408                 print
409
410                 # Emit fake glEnableClientState/glDisableClientState flags
411                 for camelcase_name, uppercase_name in self.arrays:
412                     flag_name = '__' + uppercase_name.lower()
413                     enable_name = 'GL_%s_ARRAY' % uppercase_name
414
415                     # Emit a fake function
416                     print '        {'
417                     print '            static const Trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
418                     print '            unsigned __call = Trace::localWriter.beginEnter(&__sig);'
419                     print '            Trace::localWriter.beginArg(0);'
420                     dump_instance(glapi.GLenum, enable_name)
421                     print '            Trace::localWriter.endArg();'
422                     print '            Trace::localWriter.endEnter();'
423                     print '            Trace::localWriter.beginLeave(__call);'
424                     print '            Trace::localWriter.endLeave();'
425                     print '        }'
426
427             print '        return;'
428             print '    }'
429
430         # ... to the draw calls
431         if function.name in self.draw_function_names:
432             print '    if (__need_user_arrays()) {'
433             arg_names = ', '.join([arg.name for arg in function.args[1:]])
434             print '        GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
435             print '        __trace_user_arrays(maxindex);'
436             print '    }'
437         
438         # Emit a fake memcpy on buffer uploads
439         if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', ):
440             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
441             print '    if (mapping && mapping->write && !mapping->explicit_flush) {'
442             self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
443             print '    }'
444         if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
445             # TODO: avoid copying [0, offset] bytes
446             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
447             print '    if (mapping) {'
448             if function.name.endswith('APPLE'):
449                  print '        GLsizeiptr length = size;'
450                  print '        mapping->explicit_flush = true;'
451             print '        //assert(offset + length <= mapping->length);'
452             self.emit_memcpy('mapping->map', 'mapping->map', 'offset + length')
453             print '    }'
454         # FIXME: glFlushMappedNamedBufferRangeEXT
455
456         # Don't leave vertex attrib locations to chance.  Instead emit fake
457         # glBindAttribLocation calls to ensure that the same locations will be
458         # used when retracing.  Trying to remap locations after the fact would
459         # be an herculian task given that vertex attrib locations appear in
460         # many entry-points, including non-shader related ones.
461         if function.name == 'glLinkProgram':
462             Tracer.dispatch_function(self, function)
463             print '    GLint active_attributes = 0;'
464             print '    __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
465             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
466             print '        GLint size = 0;'
467             print '        GLenum type = 0;'
468             print '        GLchar name[256];'
469             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
470             print '        __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
471             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
472             print '            GLint location = __glGetAttribLocation(program, name);'
473             print '            if (location >= 0) {'
474             bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
475             self.fake_call(bind_function, ['program', 'location', 'name'])
476             print '            }'
477             print '        }'
478             print '    }'
479         if function.name == 'glLinkProgramARB':
480             Tracer.dispatch_function(self, function)
481             print '    GLint active_attributes = 0;'
482             print '    __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
483             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
484             print '        GLint size = 0;'
485             print '        GLenum type = 0;'
486             print '        GLcharARB name[256];'
487             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
488             print '        __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
489             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
490             print '            GLint location = __glGetAttribLocationARB(programObj, name);'
491             print '            if (location >= 0) {'
492             bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
493             self.fake_call(bind_function, ['programObj', 'location', 'name'])
494             print '            }'
495             print '        }'
496             print '    }'
497
498         Tracer.trace_function_impl_body(self, function)
499
500     gremedy_functions = [
501         'glStringMarkerGREMEDY',
502         'glFrameTerminatorGREMEDY',
503     ]
504
505     def dispatch_function(self, function):
506         if function.name in ('glLinkProgram', 'glLinkProgramARB'):
507             # These functions have been dispatched already
508             return
509
510         # We implement the GREMEDY extensions, not the driver
511         if function.name in self.gremedy_functions:
512             return
513
514         if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
515             if_ = 'if'
516             for gremedy_function in self.gremedy_functions:
517                 print '    %s (strcmp("%s", (const char *)%s) == 0) {' % (if_, gremedy_function, function.args[0].name)
518                 print '        __result = (%s)&%s;' % (function.type, gremedy_function)
519                 print '    }'
520                 if_ = 'else if'
521             print '    else {'
522             Tracer.dispatch_function(self, function)
523             print '    }'
524             return
525
526         # Override GL extensions
527         if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
528             Tracer.dispatch_function(self, function, prefix = 'gltrace::__', suffix = '_override')
529             return
530
531         Tracer.dispatch_function(self, function)
532
533     def emit_memcpy(self, dest, src, length):
534         print '        unsigned __call = Trace::localWriter.beginEnter(&__memcpy_sig);'
535         print '        Trace::localWriter.beginArg(0);'
536         print '        Trace::localWriter.writeOpaque(%s);' % dest
537         print '        Trace::localWriter.endArg();'
538         print '        Trace::localWriter.beginArg(1);'
539         print '        Trace::localWriter.writeBlob(%s, %s);' % (src, length)
540         print '        Trace::localWriter.endArg();'
541         print '        Trace::localWriter.beginArg(2);'
542         print '        Trace::localWriter.writeUInt(%s);' % length
543         print '        Trace::localWriter.endArg();'
544         print '        Trace::localWriter.endEnter();'
545         print '        Trace::localWriter.beginLeave(__call);'
546         print '        Trace::localWriter.endLeave();'
547        
548     buffer_targets = [
549         'ARRAY_BUFFER',
550         'ELEMENT_ARRAY_BUFFER',
551         'PIXEL_PACK_BUFFER',
552         'PIXEL_UNPACK_BUFFER',
553     ]
554
555     def wrap_ret(self, function, instance):
556         Tracer.wrap_ret(self, function, instance)
557
558             
559         if function.name in ('glMapBuffer', 'glMapBufferARB'):
560             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
561             print '    if (mapping) {'
562             print '        mapping->map = %s;' % (instance)
563             print '        mapping->length = 0;'
564             print '        __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
565             print '        mapping->write = (access != GL_READ_ONLY);'
566             print '        mapping->explicit_flush = false;'
567             print '    }'
568
569         if function.name == 'glMapBufferRange':
570             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
571             print '    if (mapping) {'
572             print '        mapping->map = %s;' % (instance)
573             print '        mapping->length = length;'
574             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
575             print '        mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
576             print '    }'
577
578     boolean_names = [
579         'GL_FALSE',
580         'GL_TRUE',
581     ]
582
583     def gl_boolean(self, value):
584         return self.boolean_names[int(bool(value))]
585
586     # Names of the functions that unpack from a pixel buffer object.  See the
587     # ARB_pixel_buffer_object specification.
588     unpack_function_names = set([
589         'glBitmap',
590         'glColorSubTable',
591         'glColorTable',
592         'glCompressedTexImage1D',
593         'glCompressedTexImage2D',
594         'glCompressedTexImage3D',
595         'glCompressedTexSubImage1D',
596         'glCompressedTexSubImage2D',
597         'glCompressedTexSubImage3D',
598         'glConvolutionFilter1D',
599         'glConvolutionFilter2D',
600         'glDrawPixels',
601         'glMultiTexImage1DEXT',
602         'glMultiTexImage2DEXT',
603         'glMultiTexImage3DEXT',
604         'glMultiTexSubImage1DEXT',
605         'glMultiTexSubImage2DEXT',
606         'glMultiTexSubImage3DEXT',
607         'glPixelMapfv',
608         'glPixelMapuiv',
609         'glPixelMapusv',
610         'glPolygonStipple',
611         'glSeparableFilter2D',
612         'glTexImage1D',
613         'glTexImage1DEXT',
614         'glTexImage2D',
615         'glTexImage2DEXT',
616         'glTexImage3D',
617         'glTexImage3DEXT',
618         'glTexSubImage1D',
619         'glTexSubImage1DEXT',
620         'glTexSubImage2D',
621         'glTexSubImage2DEXT',
622         'glTexSubImage3D',
623         'glTexSubImage3DEXT',
624         'glTextureImage1DEXT',
625         'glTextureImage2DEXT',
626         'glTextureImage3DEXT',
627         'glTextureSubImage1DEXT',
628         'glTextureSubImage2DEXT',
629         'glTextureSubImage3DEXT',
630     ])
631
632     def dump_arg_instance(self, function, arg):
633         if function.name in self.draw_function_names and arg.name == 'indices':
634             print '    GLint __element_array_buffer = 0;'
635             print '    __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
636             print '    if (!__element_array_buffer) {'
637             if isinstance(arg.type, stdapi.Array):
638                 print '        Trace::localWriter.beginArray(%s);' % arg.type.length
639                 print '        for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
640                 print '            Trace::localWriter.beginElement();'
641                 print '            Trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
642                 print '            Trace::localWriter.endElement();'
643                 print '        }'
644                 print '        Trace::localWriter.endArray();'
645             else:
646                 print '        Trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
647             print '    } else {'
648             Tracer.dump_arg_instance(self, function, arg)
649             print '    }'
650             return
651
652         # Recognize offsets instead of blobs when a PBO is bound
653         if function.name in self.unpack_function_names \
654            and (isinstance(arg.type, stdapi.Blob) \
655                 or (isinstance(arg.type, stdapi.Const) \
656                     and isinstance(arg.type.type, stdapi.Blob))):
657             print '    {'
658             print '        GLint __unpack_buffer = 0;'
659             print '        __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
660             print '        if (__unpack_buffer) {'
661             print '            Trace::localWriter.writeOpaque(%s);' % arg.name
662             print '        } else {'
663             Tracer.dump_arg_instance(self, function, arg)
664             print '        }'
665             print '    }'
666             return
667
668         # Several GL state functions take GLenum symbolic names as
669         # integer/floats; so dump the symbolic name whenever possible
670         if function.name.startswith('gl') \
671            and arg.type in (glapi.GLint, glapi.GLfloat) \
672            and arg.name == 'param':
673             assert arg.index > 0
674             assert function.args[arg.index - 1].name == 'pname'
675             assert function.args[arg.index - 1].type == glapi.GLenum
676             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
677             dump_instance(glapi.GLenum, arg.name)
678             print '    } else {'
679             Tracer.dump_arg_instance(self, function, arg)
680             print '    }'
681             return
682
683         Tracer.dump_arg_instance(self, function, arg)
684
685     def footer(self, api):
686         Tracer.footer(self, api)
687
688         # A simple state tracker to track the pointer values
689         # update the state
690         print 'static void __trace_user_arrays(GLuint maxindex)'
691         print '{'
692
693         for camelcase_name, uppercase_name in self.arrays:
694             function_name = 'gl%sPointer' % camelcase_name
695             enable_name = 'GL_%s_ARRAY' % uppercase_name
696             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
697             function = api.get_function_by_name(function_name)
698
699             print '    // %s' % function.name
700             self.array_trace_prolog(api, uppercase_name)
701             self.array_prolog(api, uppercase_name)
702             print '    if (__glIsEnabled(%s)) {' % enable_name
703             print '        GLint __binding = 0;'
704             print '        __glGetIntegerv(%s, &__binding);' % binding_name
705             print '        if (!__binding) {'
706
707             # Get the arguments via glGet*
708             for arg in function.args:
709                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
710                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
711                 print '            %s %s = 0;' % (arg_type, arg.name)
712                 print '            __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
713             
714             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
715             print '            size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
716
717             # Emit a fake function
718             self.array_trace_intermezzo(api, uppercase_name)
719             print '            unsigned __call = Trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
720             for arg in function.args:
721                 assert not arg.output
722                 print '            Trace::localWriter.beginArg(%u);' % (arg.index,)
723                 if arg.name != 'pointer':
724                     dump_instance(arg.type, arg.name)
725                 else:
726                     print '            Trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
727                 print '            Trace::localWriter.endArg();'
728             
729             print '            Trace::localWriter.endEnter();'
730             print '            Trace::localWriter.beginLeave(__call);'
731             print '            Trace::localWriter.endLeave();'
732             print '        }'
733             print '    }'
734             self.array_epilog(api, uppercase_name)
735             self.array_trace_epilog(api, uppercase_name)
736             print
737
738         # Samething, but for glVertexAttribPointer*
739         #
740         # Some variants of glVertexAttribPointer alias conventional and generic attributes:
741         # - glVertexAttribPointer: no
742         # - glVertexAttribPointerARB: implementation dependent
743         # - glVertexAttribPointerNV: yes
744         #
745         # This means that the implementations of these functions do not always
746         # alias, and they need to be considered independently.
747         #
748         print '    vertex_attrib __vertex_attrib = __get_vertex_attrib();'
749         print
750         for suffix in ['', 'ARB', 'NV']:
751             if suffix:
752                 SUFFIX = '_' + suffix
753             else:
754                 SUFFIX = suffix
755             function_name = 'glVertexAttribPointer' + suffix
756             print '    // %s' % function_name
757             print '    if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
758             if suffix == 'NV':
759                 print '        GLint __max_vertex_attribs = 16;'
760             else:
761                 print '        GLint __max_vertex_attribs = 0;'
762                 print '        __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
763             print '        for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
764             print '            GLint __enabled = 0;'
765             if suffix == 'NV':
766                 print '            __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
767             else:
768                 print '            __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
769             print '            if (__enabled) {'
770             print '                GLint __binding = 0;'
771             if suffix != 'NV':
772                 # It doesn't seem possible to use VBOs with NV_vertex_program.
773                 print '                __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
774             print '                if (!__binding) {'
775
776             function = api.get_function_by_name(function_name)
777
778             # Get the arguments via glGet*
779             for arg in function.args[1:]:
780                 if suffix == 'NV':
781                     arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
782                 else:
783                     arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
784                 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
785                 print '                    %s %s = 0;' % (arg_type, arg.name)
786                 print '                    __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
787             
788             arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
789             print '                    size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
790
791             # Emit a fake function
792             print '                    unsigned __call = Trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
793             for arg in function.args:
794                 assert not arg.output
795                 print '                    Trace::localWriter.beginArg(%u);' % (arg.index,)
796                 if arg.name != 'pointer':
797                     dump_instance(arg.type, arg.name)
798                 else:
799                     print '                    Trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
800                 print '                    Trace::localWriter.endArg();'
801             
802             print '                    Trace::localWriter.endEnter();'
803             print '                    Trace::localWriter.beginLeave(__call);'
804             print '                    Trace::localWriter.endLeave();'
805             print '                }'
806             print '            }'
807             print '        }'
808             print '    }'
809             print
810
811         print '}'
812         print
813
814     #
815     # Hooks for glTexCoordPointer, which is identical to the other array
816     # pointers except the fact that it is indexed by glClientActiveTexture.
817     #
818
819     def array_prolog(self, api, uppercase_name):
820         if uppercase_name == 'TEXTURE_COORD':
821             print '    GLint client_active_texture = 0;'
822             print '    __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
823             print '    GLint max_texture_coords = 0;'
824             print '    __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
825             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
826             print '        GLint texture = GL_TEXTURE0 + unit;'
827             print '        __glClientActiveTexture(texture);'
828
829     def array_trace_prolog(self, api, uppercase_name):
830         if uppercase_name == 'TEXTURE_COORD':
831             print '    bool client_active_texture_dirty = false;'
832
833     def array_epilog(self, api, uppercase_name):
834         if uppercase_name == 'TEXTURE_COORD':
835             print '    }'
836         self.array_cleanup(api, uppercase_name)
837
838     def array_cleanup(self, api, uppercase_name):
839         if uppercase_name == 'TEXTURE_COORD':
840             print '    __glClientActiveTexture(client_active_texture);'
841         
842     def array_trace_intermezzo(self, api, uppercase_name):
843         if uppercase_name == 'TEXTURE_COORD':
844             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
845             print '        client_active_texture_dirty = true;'
846             self.fake_glClientActiveTexture_call(api, "texture");
847             print '    }'
848
849     def array_trace_epilog(self, api, uppercase_name):
850         if uppercase_name == 'TEXTURE_COORD':
851             print '    if (client_active_texture_dirty) {'
852             self.fake_glClientActiveTexture_call(api, "client_active_texture");
853             print '    }'
854
855     def fake_glClientActiveTexture_call(self, api, texture):
856         function = api.get_function_by_name('glClientActiveTexture')
857         self.fake_call(function, [texture])
858
859     def fake_call(self, function, args):
860         print '            unsigned __fake_call = Trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
861         for arg, instance in zip(function.args, args):
862             assert not arg.output
863             print '            Trace::localWriter.beginArg(%u);' % (arg.index,)
864             dump_instance(arg.type, instance)
865             print '            Trace::localWriter.endArg();'
866         print '            Trace::localWriter.endEnter();'
867         print '            Trace::localWriter.beginLeave(__fake_call);'
868         print '            Trace::localWriter.endLeave();'
869
870
871
872
873
874
875
876
877
878
879