]> git.cworth.org Git - apitrace/blob - gltrace.py
Unify glenum.py and glstate.py parameter table into a single one.
[apitrace] / gltrace.py
1 ##########################################################################
2 #
3 # Copyright 2008-2010 VMware, Inc.
4 # All Rights Reserved.
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 # THE SOFTWARE.
23 #
24 ##########################################################################/
25
26
27 """GL tracing generator."""
28
29
30 import stdapi
31 import glapi
32 import glparams
33 from glxapi import glxapi
34 from trace import Tracer, dump_instance
35
36
37 class TypeGetter(stdapi.Visitor):
38     '''Determine which glGet*v function that matches the specified type.'''
39
40     def __init__(self, prefix = 'glGet', long_suffix = True):
41         self.prefix = prefix
42         self.long_suffix = long_suffix
43
44     def visit_const(self, const):
45         return self.visit(const.type)
46
47     def visit_alias(self, alias):
48         if alias.expr == 'GLboolean':
49             if self.long_suffix:
50                 return self.prefix + 'Booleanv', alias.expr
51             else:
52                 return self.prefix + 'iv', 'GLint'
53         elif alias.expr == 'GLdouble':
54             if self.long_suffix:
55                 return self.prefix + 'Doublev', alias.expr
56             else:
57                 return self.prefix + 'dv', alias.expr
58         elif alias.expr == 'GLfloat':
59             if self.long_suffix:
60                 return self.prefix + 'Floatv', alias.expr
61             else:
62                 return self.prefix + 'fv', alias.expr
63         elif alias.expr in ('GLint', 'GLuint', 'GLsizei'):
64             if self.long_suffix:
65                 return self.prefix + 'Integerv', 'GLint'
66             else:
67                 return self.prefix + 'iv', 'GLint'
68         else:
69             print alias.expr
70             assert False
71     
72     def visit_enum(self, enum):
73         return self.visit(glapi.GLint)
74
75     def visit_bitmask(self, bitmask):
76         return self.visit(glapi.GLint)
77
78     def visit_opaque(self, pointer):
79         return self.prefix + 'Pointerv', 'GLvoid *'
80
81
82 class GlTracer(Tracer):
83
84     arrays = [
85         ("Vertex", "VERTEX"),
86         ("Normal", "NORMAL"),
87         ("Color", "COLOR"),
88         ("Index", "INDEX"),
89         ("TexCoord", "TEXTURE_COORD"),
90         ("EdgeFlag", "EDGE_FLAG"),
91         ("FogCoord", "FOG_COORD"),
92         ("SecondaryColor", "SECONDARY_COLOR"),
93     ]
94     arrays.reverse()
95
96     def header(self, api):
97         Tracer.header(self, api)
98
99         print '// Whether user arrays were used'
100         print 'static bool __user_arrays = false;'
101         print
102         # Whether we need user arrays
103         print 'static inline bool __need_user_arrays(void)'
104         print '{'
105         print '    if (!__user_arrays) {'
106         print '        return false;'
107         print '    }'
108         print
109
110         for camelcase_name, uppercase_name in self.arrays:
111             function_name = 'gl%sPointer' % camelcase_name
112             enable_name = 'GL_%s_ARRAY' % uppercase_name
113             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
114             print '    // %s' % function_name
115             self.array_prolog(api, uppercase_name)
116             print '    if (__glIsEnabled(%s)) {' % enable_name
117             print '        GLint __binding = 0;'
118             print '        __glGetIntegerv(%s, &__binding);' % binding_name
119             print '        if (!__binding) {'
120             self.array_cleanup(api, uppercase_name)
121             print '            return true;'
122             print '        }'
123             print '    }'
124             self.array_epilog(api, uppercase_name)
125             print
126
127         print '    // glVertexAttribPointer'
128         print '    GLint __max_vertex_attribs = 0;'
129         print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
130         print '    for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
131         print '        GLint __enabled = 0;'
132         print '        __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
133         print '        if (__enabled) {'
134         print '            GLint __binding = 0;'
135         print '            __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
136         print '            if (!__binding) {'
137         print '                return true;'
138         print '            }'
139         print '        }'
140         print '    }'
141         print
142
143         print '    return false;'
144         print '}'
145         print
146
147         print 'static void __trace_user_arrays(GLuint maxindex);'
148         print
149
150         print 'struct buffer_mapping {'
151         print '    void *map;'
152         print '    GLint length;'
153         print '    bool write;'
154         print '};'
155         print
156         for target in self.buffer_targets:
157             print 'struct buffer_mapping __%s_mapping;' % target.lower();
158         print
159         print 'static inline struct buffer_mapping *'
160         print 'get_buffer_mapping(GLenum target) {'
161         print '    switch(target) {'
162         for target in self.buffer_targets:
163             print '    case GL_%s:' % target
164             print '        return & __%s_mapping;' % target.lower()
165         print '    default:'
166         print '        OS::DebugMessage("warning: unknown buffer target 0x%04X\\n", target);'
167         print '        return NULL;'
168         print '    }'
169         print '}'
170         print
171
172         # Generate memcpy's signature
173         self.trace_function_decl(glapi.memcpy)
174
175         # Generate a helper function to determine whether a parameter name
176         # refers to a symbolic value or not
177         print 'static bool'
178         print 'is_symbolic_pname(GLenum pname) {'
179         print '    switch(pname) {'
180         for function, type, count, name in glparams.parameters:
181             if type is glapi.GLenum:
182                 print '    case %s:' % name
183         print '        return true;'
184         print '    default:'
185         print '        return false;'
186         print '    }'
187         print '}'
188         print
189         
190         # Generate a helper function to determine whether a parameter value is
191         # potentially symbolic or not; i.e., if the value can be represented in
192         # an enum or not
193         print 'template<class T>'
194         print 'static inline bool'
195         print 'is_symbolic_param(T param) {'
196         print '    return static_cast<T>(static_cast<GLenum>(param)) == param;'
197         print '}'
198         print
199
200         # Generate a helper function to know how many elements a parameter has
201         print 'static size_t'
202         print 'pname_size(GLenum pname) {'
203         print '    switch(pname) {'
204         for function, type, count, name in glparams.parameters:
205             if type is not None:
206                 print '    case %s: return %u;' % (name, count)
207         print '    case GL_COMPRESSED_TEXTURE_FORMATS: {'
208         print '            GLint num_compressed_texture_formats = 0;'
209         print '            __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
210         print '            return num_compressed_texture_formats;'
211         print '        }'
212         print '    default:'
213         print r'        OS::DebugMessage("warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
214         print '        return 1;'
215         print '    }'
216         print '}'
217         print
218
219     
220     array_pointer_function_names = set((
221         "glVertexPointer",
222         "glNormalPointer",
223         "glColorPointer",
224         "glIndexPointer",
225         "glTexCoordPointer",
226         "glEdgeFlagPointer",
227         "glFogCoordPointer",
228         "glSecondaryColorPointer",
229         
230         "glVertexPointerEXT",
231         "glNormalPointerEXT",
232         "glColorPointerEXT",
233         "glIndexPointerEXT",
234         "glTexCoordPointerEXT",
235         "glEdgeFlagPointerEXT",
236         "glFogCoordPointerEXT",
237         "glSecondaryColorPointerEXT",
238
239         "glVertexAttribPointer",
240         "glVertexAttribPointerARB",
241         "glVertexAttribPointerNV",
242         "glVertexAttribLPointer",
243         "glVertexAttribLPointerEXT",
244         
245         #"glMatrixIndexPointerARB",
246     ))
247
248     draw_function_names = set((
249         'glDrawArrays',
250         'glDrawArraysEXT',
251         'glDrawElements',
252         'glDrawRangeElements',
253         'glDrawRangeElementsEXT',
254     ))
255
256     interleaved_formats = [
257          'GL_V2F',
258          'GL_V3F',
259          'GL_C4UB_V2F',
260          'GL_C4UB_V3F',
261          'GL_C3F_V3F',
262          'GL_N3F_V3F',
263          'GL_C4F_N3F_V3F',
264          'GL_T2F_V3F',
265          'GL_T4F_V4F',
266          'GL_T2F_C4UB_V3F',
267          'GL_T2F_C3F_V3F',
268          'GL_T2F_N3F_V3F',
269          'GL_T2F_C4F_N3F_V3F',
270          'GL_T4F_C4F_N3F_V4F',
271     ]
272
273     def trace_function_impl_body(self, function):
274         # Defer tracing of user array pointers...
275         if function.name in self.array_pointer_function_names:
276             print '    GLint __array_buffer = 0;'
277             print '    __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
278             print '    if (!__array_buffer) {'
279             print '        __user_arrays = true;'
280             self.dispatch_function(function)
281             print '        return;'
282             print '    }'
283
284         # ... to the draw calls
285         if function.name in self.draw_function_names:
286             print '    if (__need_user_arrays()) {'
287             arg_names = ', '.join([arg.name for arg in function.args[1:]])
288             print '        GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
289             print '        __trace_user_arrays(maxindex);'
290             print '    }'
291         
292         # And also break down glInterleavedArrays into the individual calls
293         if function.name == 'glInterleavedArrays':
294             print '    GLint __array_buffer = 0;'
295             print '    __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
296             print '    if (!__array_buffer) {'
297             print '        __user_arrays = true;'
298             self.dispatch_function(function)
299             print
300
301             # Initialize the enable flags
302             for camelcase_name, uppercase_name in self.arrays:
303                 flag_name = '__' + uppercase_name.lower()
304                 print '        GLboolean %s = GL_FALSE;' % flag_name
305             print
306
307             # Swicth for the interleaved formats
308             print '        switch (format) {'
309             for format in self.interleaved_formats:
310                 print '            case %s:' % format
311                 for camelcase_name, uppercase_name in self.arrays:
312                     flag_name = '__' + uppercase_name.lower()
313                     if format.find('_' + uppercase_name[0]) >= 0:
314                         print '                %s = GL_TRUE;' % flag_name
315                 print '                break;'
316             print '            default:'
317             print '               return;'
318             print '        }'
319             print
320
321             # Emit fake glEnableClientState/glDisableClientState flags
322             for camelcase_name, uppercase_name in self.arrays:
323                 flag_name = '__' + uppercase_name.lower()
324                 enable_name = 'GL_%s_ARRAY' % uppercase_name
325
326                 # Emit a fake function
327                 print '        {'
328                 print '            static const Trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
329                 print '            unsigned __call = Trace::BeginEnter(__sig);'
330                 print '            Trace::BeginArg(0);'
331                 dump_instance(glapi.GLenum, enable_name)
332                 print '            Trace::EndArg();'
333                 print '            Trace::EndEnter();'
334                 print '            Trace::BeginLeave(__call);'
335                 print '            Trace::EndLeave();'
336                 print '        }'
337
338             print '        return;'
339             print '    }'
340
341         # Emit a fake memcpy on
342         if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
343             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
344             print '    if (mapping && mapping->write) {'
345             print '        unsigned __call = Trace::BeginEnter(__memcpy_sig);'
346             print '        Trace::BeginArg(0);'
347             print '        Trace::LiteralOpaque(mapping->map);'
348             print '        Trace::EndArg();'
349             print '        Trace::BeginArg(1);'
350             print '        Trace::LiteralBlob(mapping->map, mapping->length);'
351             print '        Trace::EndArg();'
352             print '        Trace::BeginArg(2);'
353             print '        Trace::LiteralUInt(mapping->length);'
354             print '        Trace::EndArg();'
355             print '        Trace::EndEnter();'
356             print '        Trace::BeginLeave(__call);'
357             print '        Trace::EndLeave();'
358             print '    }'
359
360         Tracer.trace_function_impl_body(self, function)
361        
362     buffer_targets = [
363         'ARRAY_BUFFER',
364         'ELEMENT_ARRAY_BUFFER',
365         'PIXEL_PACK_BUFFER',
366         'PIXEL_UNPACK_BUFFER',
367     ]
368
369     def wrap_ret(self, function, instance):
370         Tracer.wrap_ret(self, function, instance)
371             
372         if function.name in ('glMapBuffer', 'glMapBufferARB'):
373             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
374             print '    if (mapping) {'
375             print '        mapping->map = %s;' % (instance)
376             print '        mapping->length = 0;'
377             print '        __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
378             print '        mapping->write = (access != GL_READ_ONLY);'
379             print '    }'
380
381         if function.name == 'glMapBufferRange':
382             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
383             print '    if (mapping) {'
384             print '        mapping->map = %s;' % (instance)
385             print '        mapping->length = length;'
386             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
387             print '    }'
388
389     boolean_names = [
390         'GL_FALSE',
391         'GL_TRUE',
392     ]
393
394     def gl_boolean(self, value):
395         return self.boolean_names[int(bool(value))]
396
397     def dump_arg_instance(self, function, arg):
398         if function.name in self.draw_function_names and arg.name == 'indices':
399             print '    GLint __element_array_buffer = 0;'
400             print '    __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
401             print '    if (!__element_array_buffer) {'
402             print '        Trace::LiteralBlob((const void *)%s, count*__gl_type_size(type));' % (arg.name)
403             print '    } else {'
404             print '        Trace::LiteralOpaque((const void *)%s);' % (arg.name)
405             print '    }'
406             return
407
408         # Several GL state functions take GLenum symbolic names as
409         # integer/floats; so dump the symbolic name whenever possible
410         if arg.type in (glapi.GLint, glapi.GLfloat) and arg.name == 'param':
411             assert arg.index > 0
412             assert function.args[arg.index - 1].name == 'pname'
413             assert function.args[arg.index - 1].type == glapi.GLenum
414             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
415             dump_instance(glapi.GLenum, arg.name)
416             print '    } else {'
417             Tracer.dump_arg_instance(self, function, arg)
418             print '    }'
419             return
420
421         Tracer.dump_arg_instance(self, function, arg)
422
423     def footer(self, api):
424         Tracer.footer(self, api)
425
426         # A simple state tracker to track the pointer values
427         # update the state
428         print 'static void __trace_user_arrays(GLuint maxindex)'
429         print '{'
430
431         for camelcase_name, uppercase_name in self.arrays:
432             function_name = 'gl%sPointer' % camelcase_name
433             enable_name = 'GL_%s_ARRAY' % uppercase_name
434             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
435             function = api.get_function_by_name(function_name)
436
437             print '    // %s' % function.name
438             self.array_trace_prolog(api, uppercase_name)
439             self.array_prolog(api, uppercase_name)
440             print '    if (__glIsEnabled(%s)) {' % enable_name
441             print '        GLint __binding = 0;'
442             print '        __glGetIntegerv(%s, &__binding);' % binding_name
443             print '        if (!__binding) {'
444
445             # Get the arguments via glGet*
446             for arg in function.args:
447                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
448                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
449                 print '            %s %s = 0;' % (arg_type, arg.name)
450                 print '            __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
451             
452             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
453             print '            size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
454
455             # Emit a fake function
456             self.array_trace_intermezzo(api, uppercase_name)
457             print '            unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name,)
458             for arg in function.args:
459                 assert not arg.output
460                 print '            Trace::BeginArg(%u);' % (arg.index,)
461                 if arg.name != 'pointer':
462                     dump_instance(arg.type, arg.name)
463                 else:
464                     print '            Trace::LiteralBlob((const void *)%s, __size);' % (arg.name)
465                 print '            Trace::EndArg();'
466             
467             print '            Trace::EndEnter();'
468             print '            Trace::BeginLeave(__call);'
469             print '            Trace::EndLeave();'
470             print '        }'
471             print '    }'
472             self.array_epilog(api, uppercase_name)
473             self.array_trace_epilog(api, uppercase_name)
474             print
475
476         # Samething, but for glVertexAttribPointer
477         print '    // glVertexAttribPointer'
478         print '    GLint __max_vertex_attribs = 0;'
479         print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
480         print '    for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
481         print '        GLint __enabled = 0;'
482         print '        __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
483         print '        if (__enabled) {'
484         print '            GLint __binding = 0;'
485         print '            __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
486         print '            if (!__binding) {'
487
488         function = api.get_function_by_name('glVertexAttribPointer')
489
490         # Get the arguments via glGet*
491         for arg in function.args[1:]:
492             arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s' % (arg.name.upper(),)
493             arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False).visit(arg.type)
494             print '                %s %s = 0;' % (arg_type, arg.name)
495             print '                __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
496         
497         arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
498         print '                size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
499
500         # Emit a fake function
501         print '                unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name,)
502         for arg in function.args:
503             assert not arg.output
504             print '                Trace::BeginArg(%u);' % (arg.index,)
505             if arg.name != 'pointer':
506                 dump_instance(arg.type, arg.name)
507             else:
508                 print '                Trace::LiteralBlob((const void *)%s, __size);' % (arg.name)
509             print '                Trace::EndArg();'
510         
511         print '                Trace::EndEnter();'
512         print '                Trace::BeginLeave(__call);'
513         print '                Trace::EndLeave();'
514         print '            }'
515         print '        }'
516         print '    }'
517         print
518
519         print '}'
520         print
521
522     #
523     # Hooks for glTexCoordPointer, which is identical to the other array
524     # pointers except the fact that it is indexed by glClientActiveTexture.
525     #
526
527     def array_prolog(self, api, uppercase_name):
528         if uppercase_name == 'TEXTURE_COORD':
529             print '    GLint client_active_texture = 0;'
530             print '    __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
531             print '    GLint max_texture_coords = 0;'
532             print '    __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
533             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
534             print '        GLenum texture = GL_TEXTURE0 + unit;'
535             print '        __glClientActiveTexture(texture);'
536
537     def array_trace_prolog(self, api, uppercase_name):
538         if uppercase_name == 'TEXTURE_COORD':
539             print '    bool client_active_texture_dirty = false;'
540
541     def array_epilog(self, api, uppercase_name):
542         if uppercase_name == 'TEXTURE_COORD':
543             print '    }'
544         self.array_cleanup(api, uppercase_name)
545
546     def array_cleanup(self, api, uppercase_name):
547         if uppercase_name == 'TEXTURE_COORD':
548             print '    __glClientActiveTexture(client_active_texture);'
549         
550     def array_trace_intermezzo(self, api, uppercase_name):
551         if uppercase_name == 'TEXTURE_COORD':
552             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
553             print '        client_active_texture_dirty = true;'
554             self.fake_glClientActiveTexture_call(api, "texture");
555             print '    }'
556
557     def array_trace_epilog(self, api, uppercase_name):
558         if uppercase_name == 'TEXTURE_COORD':
559             print '    if (client_active_texture_dirty) {'
560             self.fake_glClientActiveTexture_call(api, "client_active_texture");
561             print '    }'
562
563     def fake_glClientActiveTexture_call(self, api, texture):
564         function = api.get_function_by_name('glClientActiveTexture')
565         self.fake_call(function, [texture])
566
567     def fake_call(self, function, args):
568         print '            unsigned __fake_call = Trace::BeginEnter(__%s_sig);' % (function.name,)
569         for arg, instance in zip(function.args, args):
570             assert not arg.output
571             print '            Trace::BeginArg(%u);' % (arg.index,)
572             dump_instance(arg.type, instance)
573             print '            Trace::EndArg();'
574         print '            Trace::EndEnter();'
575         print '            Trace::BeginLeave(__fake_call);'
576         print '            Trace::EndLeave();'
577
578
579
580
581
582
583
584
585
586
587