]> git.cworth.org Git - apitrace/blob - gltrace.py
Trace right number of parameters in GL_EXT_direct_state_access.
[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 '__gl_param_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     array_pointer_function_names = set((
220         "glVertexPointer",
221         "glNormalPointer",
222         "glColorPointer",
223         "glIndexPointer",
224         "glTexCoordPointer",
225         "glEdgeFlagPointer",
226         "glFogCoordPointer",
227         "glSecondaryColorPointer",
228         
229         "glInterleavedArrays",
230
231         "glVertexPointerEXT",
232         "glNormalPointerEXT",
233         "glColorPointerEXT",
234         "glIndexPointerEXT",
235         "glTexCoordPointerEXT",
236         "glEdgeFlagPointerEXT",
237         "glFogCoordPointerEXT",
238         "glSecondaryColorPointerEXT",
239
240         "glVertexAttribPointer",
241         "glVertexAttribPointerARB",
242         "glVertexAttribPointerNV",
243         "glVertexAttribIPointer",
244         "glVertexAttribIPointerEXT",
245         "glVertexAttribLPointer",
246         "glVertexAttribLPointerEXT",
247         
248         #"glMatrixIndexPointerARB",
249     ))
250
251     draw_function_names = set((
252         'glDrawArrays',
253         'glDrawArraysEXT',
254         'glDrawElements',
255         'glDrawRangeElements',
256         'glDrawRangeElementsEXT',
257     ))
258
259     interleaved_formats = [
260          'GL_V2F',
261          'GL_V3F',
262          'GL_C4UB_V2F',
263          'GL_C4UB_V3F',
264          'GL_C3F_V3F',
265          'GL_N3F_V3F',
266          'GL_C4F_N3F_V3F',
267          'GL_T2F_V3F',
268          'GL_T4F_V4F',
269          'GL_T2F_C4UB_V3F',
270          'GL_T2F_C3F_V3F',
271          'GL_T2F_N3F_V3F',
272          'GL_T2F_C4F_N3F_V3F',
273          'GL_T4F_C4F_N3F_V4F',
274     ]
275
276     def trace_function_impl_body(self, function):
277         # Defer tracing of user array pointers...
278         if function.name in self.array_pointer_function_names:
279             print '    GLint __array_buffer = 0;'
280             print '    __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
281             print '    if (!__array_buffer) {'
282             print '        __user_arrays = true;'
283             self.dispatch_function(function)
284
285             # And also break down glInterleavedArrays into the individual calls
286             if function.name == 'glInterleavedArrays':
287                 print
288
289                 # Initialize the enable flags
290                 for camelcase_name, uppercase_name in self.arrays:
291                     flag_name = '__' + uppercase_name.lower()
292                     print '        GLboolean %s = GL_FALSE;' % flag_name
293                 print
294
295                 # Switch for the interleaved formats
296                 print '        switch (format) {'
297                 for format in self.interleaved_formats:
298                     print '            case %s:' % format
299                     for camelcase_name, uppercase_name in self.arrays:
300                         flag_name = '__' + uppercase_name.lower()
301                         if format.find('_' + uppercase_name[0]) >= 0:
302                             print '                %s = GL_TRUE;' % flag_name
303                     print '                break;'
304                 print '            default:'
305                 print '               return;'
306                 print '        }'
307                 print
308
309                 # Emit fake glEnableClientState/glDisableClientState flags
310                 for camelcase_name, uppercase_name in self.arrays:
311                     flag_name = '__' + uppercase_name.lower()
312                     enable_name = 'GL_%s_ARRAY' % uppercase_name
313
314                     # Emit a fake function
315                     print '        {'
316                     print '            static const Trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
317                     print '            unsigned __call = Trace::BeginEnter(__sig);'
318                     print '            Trace::BeginArg(0);'
319                     dump_instance(glapi.GLenum, enable_name)
320                     print '            Trace::EndArg();'
321                     print '            Trace::EndEnter();'
322                     print '            Trace::BeginLeave(__call);'
323                     print '            Trace::EndLeave();'
324                     print '        }'
325
326             print '        return;'
327             print '    }'
328
329         # ... to the draw calls
330         if function.name in self.draw_function_names:
331             print '    if (__need_user_arrays()) {'
332             arg_names = ', '.join([arg.name for arg in function.args[1:]])
333             print '        GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
334             print '        __trace_user_arrays(maxindex);'
335             print '    }'
336         
337         # Emit a fake memcpy on
338         if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
339             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
340             print '    if (mapping && mapping->write) {'
341             print '        unsigned __call = Trace::BeginEnter(__memcpy_sig);'
342             print '        Trace::BeginArg(0);'
343             print '        Trace::LiteralOpaque(mapping->map);'
344             print '        Trace::EndArg();'
345             print '        Trace::BeginArg(1);'
346             print '        Trace::LiteralBlob(mapping->map, mapping->length);'
347             print '        Trace::EndArg();'
348             print '        Trace::BeginArg(2);'
349             print '        Trace::LiteralUInt(mapping->length);'
350             print '        Trace::EndArg();'
351             print '        Trace::EndEnter();'
352             print '        Trace::BeginLeave(__call);'
353             print '        Trace::EndLeave();'
354             print '    }'
355
356         Tracer.trace_function_impl_body(self, function)
357        
358     buffer_targets = [
359         'ARRAY_BUFFER',
360         'ELEMENT_ARRAY_BUFFER',
361         'PIXEL_PACK_BUFFER',
362         'PIXEL_UNPACK_BUFFER',
363     ]
364
365     def wrap_ret(self, function, instance):
366         Tracer.wrap_ret(self, function, instance)
367             
368         if function.name in ('glMapBuffer', 'glMapBufferARB'):
369             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
370             print '    if (mapping) {'
371             print '        mapping->map = %s;' % (instance)
372             print '        mapping->length = 0;'
373             print '        __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
374             print '        mapping->write = (access != GL_READ_ONLY);'
375             print '    }'
376
377         if function.name == 'glMapBufferRange':
378             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
379             print '    if (mapping) {'
380             print '        mapping->map = %s;' % (instance)
381             print '        mapping->length = length;'
382             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
383             print '    }'
384
385     boolean_names = [
386         'GL_FALSE',
387         'GL_TRUE',
388     ]
389
390     def gl_boolean(self, value):
391         return self.boolean_names[int(bool(value))]
392
393     def dump_arg_instance(self, function, arg):
394         if function.name in self.draw_function_names and arg.name == 'indices':
395             print '    GLint __element_array_buffer = 0;'
396             print '    __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
397             print '    if (!__element_array_buffer) {'
398             print '        Trace::LiteralBlob((const void *)%s, count*__gl_type_size(type));' % (arg.name)
399             print '    } else {'
400             print '        Trace::LiteralOpaque((const void *)%s);' % (arg.name)
401             print '    }'
402             return
403
404         # Several GL state functions take GLenum symbolic names as
405         # integer/floats; so dump the symbolic name whenever possible
406         if arg.type in (glapi.GLint, glapi.GLfloat) and arg.name == 'param':
407             assert arg.index > 0
408             assert function.args[arg.index - 1].name == 'pname'
409             assert function.args[arg.index - 1].type == glapi.GLenum
410             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
411             dump_instance(glapi.GLenum, arg.name)
412             print '    } else {'
413             Tracer.dump_arg_instance(self, function, arg)
414             print '    }'
415             return
416
417         Tracer.dump_arg_instance(self, function, arg)
418
419     def footer(self, api):
420         Tracer.footer(self, api)
421
422         # A simple state tracker to track the pointer values
423         # update the state
424         print 'static void __trace_user_arrays(GLuint maxindex)'
425         print '{'
426
427         for camelcase_name, uppercase_name in self.arrays:
428             function_name = 'gl%sPointer' % camelcase_name
429             enable_name = 'GL_%s_ARRAY' % uppercase_name
430             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
431             function = api.get_function_by_name(function_name)
432
433             print '    // %s' % function.name
434             self.array_trace_prolog(api, uppercase_name)
435             self.array_prolog(api, uppercase_name)
436             print '    if (__glIsEnabled(%s)) {' % enable_name
437             print '        GLint __binding = 0;'
438             print '        __glGetIntegerv(%s, &__binding);' % binding_name
439             print '        if (!__binding) {'
440
441             # Get the arguments via glGet*
442             for arg in function.args:
443                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
444                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
445                 print '            %s %s = 0;' % (arg_type, arg.name)
446                 print '            __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
447             
448             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
449             print '            size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
450
451             # Emit a fake function
452             self.array_trace_intermezzo(api, uppercase_name)
453             print '            unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name,)
454             for arg in function.args:
455                 assert not arg.output
456                 print '            Trace::BeginArg(%u);' % (arg.index,)
457                 if arg.name != 'pointer':
458                     dump_instance(arg.type, arg.name)
459                 else:
460                     print '            Trace::LiteralBlob((const void *)%s, __size);' % (arg.name)
461                 print '            Trace::EndArg();'
462             
463             print '            Trace::EndEnter();'
464             print '            Trace::BeginLeave(__call);'
465             print '            Trace::EndLeave();'
466             print '        }'
467             print '    }'
468             self.array_epilog(api, uppercase_name)
469             self.array_trace_epilog(api, uppercase_name)
470             print
471
472         # Samething, but for glVertexAttribPointer
473         print '    // glVertexAttribPointer'
474         print '    GLint __max_vertex_attribs = 0;'
475         print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
476         print '    for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
477         print '        GLint __enabled = 0;'
478         print '        __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
479         print '        if (__enabled) {'
480         print '            GLint __binding = 0;'
481         print '            __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
482         print '            if (!__binding) {'
483
484         function = api.get_function_by_name('glVertexAttribPointer')
485
486         # Get the arguments via glGet*
487         for arg in function.args[1:]:
488             arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s' % (arg.name.upper(),)
489             arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False).visit(arg.type)
490             print '                %s %s = 0;' % (arg_type, arg.name)
491             print '                __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
492         
493         arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
494         print '                size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
495
496         # Emit a fake function
497         print '                unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name,)
498         for arg in function.args:
499             assert not arg.output
500             print '                Trace::BeginArg(%u);' % (arg.index,)
501             if arg.name != 'pointer':
502                 dump_instance(arg.type, arg.name)
503             else:
504                 print '                Trace::LiteralBlob((const void *)%s, __size);' % (arg.name)
505             print '                Trace::EndArg();'
506         
507         print '                Trace::EndEnter();'
508         print '                Trace::BeginLeave(__call);'
509         print '                Trace::EndLeave();'
510         print '            }'
511         print '        }'
512         print '    }'
513         print
514
515         print '}'
516         print
517
518     #
519     # Hooks for glTexCoordPointer, which is identical to the other array
520     # pointers except the fact that it is indexed by glClientActiveTexture.
521     #
522
523     def array_prolog(self, api, uppercase_name):
524         if uppercase_name == 'TEXTURE_COORD':
525             print '    GLint client_active_texture = 0;'
526             print '    __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
527             print '    GLint max_texture_coords = 0;'
528             print '    __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
529             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
530             print '        GLenum texture = GL_TEXTURE0 + unit;'
531             print '        __glClientActiveTexture(texture);'
532
533     def array_trace_prolog(self, api, uppercase_name):
534         if uppercase_name == 'TEXTURE_COORD':
535             print '    bool client_active_texture_dirty = false;'
536
537     def array_epilog(self, api, uppercase_name):
538         if uppercase_name == 'TEXTURE_COORD':
539             print '    }'
540         self.array_cleanup(api, uppercase_name)
541
542     def array_cleanup(self, api, uppercase_name):
543         if uppercase_name == 'TEXTURE_COORD':
544             print '    __glClientActiveTexture(client_active_texture);'
545         
546     def array_trace_intermezzo(self, api, uppercase_name):
547         if uppercase_name == 'TEXTURE_COORD':
548             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
549             print '        client_active_texture_dirty = true;'
550             self.fake_glClientActiveTexture_call(api, "texture");
551             print '    }'
552
553     def array_trace_epilog(self, api, uppercase_name):
554         if uppercase_name == 'TEXTURE_COORD':
555             print '    if (client_active_texture_dirty) {'
556             self.fake_glClientActiveTexture_call(api, "client_active_texture");
557             print '    }'
558
559     def fake_glClientActiveTexture_call(self, api, texture):
560         function = api.get_function_by_name('glClientActiveTexture')
561         self.fake_call(function, [texture])
562
563     def fake_call(self, function, args):
564         print '            unsigned __fake_call = Trace::BeginEnter(__%s_sig);' % (function.name,)
565         for arg, instance in zip(function.args, args):
566             assert not arg.output
567             print '            Trace::BeginArg(%u);' % (arg.index,)
568             dump_instance(arg.type, instance)
569             print '            Trace::EndArg();'
570         print '            Trace::EndEnter();'
571         print '            Trace::BeginLeave(__fake_call);'
572         print '            Trace::EndLeave();'
573
574
575
576
577
578
579
580
581
582
583