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