]> git.cworth.org Git - apitrace/blob - gltrace.py
Basic glVertexAttribPointer support.
[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 from glxapi import glxapi
33 from trace import Tracer, dump_instance
34
35
36 class TypeGetter(stdapi.Visitor):
37     '''Determine which glGet*v function that matches the specified type.'''
38
39     def __init__(self, prefix = 'glGet', long_suffix = True):
40         self.prefix = prefix
41         self.long_suffix = long_suffix
42
43     def visit_const(self, const):
44         return self.visit(const.type)
45
46     def visit_alias(self, alias):
47         if alias.expr == 'GLboolean':
48             if self.long_suffix:
49                 return self.prefix + 'Booleanv', alias.expr
50             else:
51                 return self.prefix + 'iv', 'GLint'
52         elif alias.expr == 'GLdouble':
53             if self.long_suffix:
54                 return self.prefix + 'Doublev', alias.expr
55             else:
56                 return self.prefix + 'dv', alias.expr
57         elif alias.expr == 'GLfloat':
58             if self.long_suffix:
59                 return self.prefix + 'Floatv', alias.expr
60             else:
61                 return self.prefix + 'fv', alias.expr
62         elif alias.expr in ('GLint', 'GLuint', 'GLsizei'):
63             if self.long_suffix:
64                 return self.prefix + 'Integerv', 'GLint'
65             else:
66                 return self.prefix + 'iv', 'GLint'
67         else:
68             print alias.expr
69             assert False
70     
71     def visit_enum(self, enum):
72         return self.visit(glapi.GLint)
73
74     def visit_bitmask(self, bitmask):
75         return self.visit(glapi.GLint)
76
77     def visit_opaque(self, pointer):
78         return self.prefix + 'Pointerv', 'GLvoid *'
79
80
81 class GlTracer(Tracer):
82
83     def header(self, api):
84         Tracer.header(self, api)
85         self.state_tracker_decl(api)
86
87     def footer(self, api):
88         Tracer.footer(self, api)
89         self.state_tracker_impl(api)
90
91     arrays = [
92         ("Vertex", "VERTEX"),
93         ("Normal", "NORMAL"),
94         ("Color", "COLOR"),
95         ("Index", "INDEX"),
96         ("TexCoord", "TEXTURE_COORD"),
97         ("EdgeFlag", "EDGE_FLAG"),
98         ("FogCoord", "FOG_COORD"),
99         ("SecondaryColor", "SECONDARY_COLOR"),
100     ]
101     arrays.reverse()
102
103     def state_tracker_decl(self, api):
104         # Whether we need user arrays
105         print 'static inline bool __need_user_arrays(void)'
106         print '{'
107
108         for camelcase_name, uppercase_name in self.arrays:
109             function_name = 'gl%sPointer' % camelcase_name
110             enable_name = 'GL_%s_ARRAY' % uppercase_name
111             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
112             print '    // %s' % function_name
113             print '    if (__glIsEnabled(%s)) {' % enable_name
114             print '        GLint __binding = 0;'
115             print '        __glGetIntegerv(%s, &__binding);' % binding_name
116             print '        if (!__binding) {'
117             print '            return true;'
118             print '        }'
119             print '    }'
120             print
121
122         print '    // glVertexAttribPointer'
123         print '    GLint __max_vertex_attribs;'
124         print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
125         print '    for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
126         print '        GLint __enabled = 0;'
127         print '        __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
128         print '        if (__enabled) {'
129         print '            GLint __binding = 0;'
130         print '            __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
131         print '            if (!__binding) {'
132         print '                return true;'
133         print '            }'
134         print '        }'
135         print '    }'
136         print
137
138         print '    return false;'
139         print '}'
140         print
141
142         print 'static void __trace_user_arrays(GLuint maxindex);'
143         print
144     
145     array_pointer_function_names = set((
146         "glVertexPointer",
147         "glNormalPointer",
148         "glColorPointer",
149         "glIndexPointer",
150         "glTexCoordPointer",
151         "glEdgeFlagPointer",
152         "glFogCoordPointer",
153         "glSecondaryColorPointer",
154         
155         "glVertexPointerEXT",
156         "glNormalPointerEXT",
157         "glColorPointerEXT",
158         "glIndexPointerEXT",
159         "glTexCoordPointerEXT",
160         "glEdgeFlagPointerEXT",
161         "glFogCoordPointerEXT",
162         "glSecondaryColorPointerEXT",
163
164         "glVertexAttribPointer",
165         "glVertexAttribPointerARB",
166         "glVertexAttribPointerNV",
167         "glVertexAttribLPointer",
168         "glVertexAttribLPointerEXT",
169         
170         #"glMatrixIndexPointerARB",
171     ))
172
173     draw_function_names = set((
174         'glDrawArrays',
175         'glDrawElements',
176         'glDrawRangeElements',
177     ))
178
179     interleaved_formats = [
180          'GL_V2F',
181          'GL_V3F',
182          'GL_C4UB_V2F',
183          'GL_C4UB_V3F',
184          'GL_C3F_V3F',
185          'GL_N3F_V3F',
186          'GL_C4F_N3F_V3F',
187          'GL_T2F_V3F',
188          'GL_T4F_V4F',
189          'GL_T2F_C4UB_V3F',
190          'GL_T2F_C3F_V3F',
191          'GL_T2F_N3F_V3F',
192          'GL_T2F_C4F_N3F_V3F',
193          'GL_T4F_C4F_N3F_V4F',
194     ]
195
196     def trace_function_impl_body(self, function):
197         # Defer tracing of user array pointers...
198         if function.name in self.array_pointer_function_names:
199             print '    GLint __array_buffer = 0;'
200             print '    __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
201             print '    if (!__array_buffer) {'
202             self.dispatch_function(function)
203             print '        return;'
204             print '    }'
205
206         # ... to the draw calls
207         if function.name in self.draw_function_names:
208             print '    if (__need_user_arrays()) {'
209             arg_names = ', '.join([arg.name for arg in function.args[1:]])
210             print '        GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
211             print '        __trace_user_arrays(maxindex);'
212             print '    }'
213         
214         # And also break down glInterleavedArrays into the individual calls
215         if function.name == 'glInterleavedArrays':
216             print '    GLint __array_buffer = 0;'
217             print '    __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
218             print '    if (!__array_buffer) {'
219             self.dispatch_function(function)
220             print
221
222             # Initialize the enable flags
223             for camelcase_name, uppercase_name in self.arrays:
224                 flag_name = '__' + uppercase_name.lower()
225                 print '        GLboolean %s = GL_FALSE;' % flag_name
226             print
227
228             # Swicth for the interleaved formats
229             print '        switch (format) {'
230             for format in self.interleaved_formats:
231                 print '            case %s:' % format
232                 for camelcase_name, uppercase_name in self.arrays:
233                     flag_name = '__' + uppercase_name.lower()
234                     if format.find('_' + uppercase_name[0]) >= 0:
235                         print '                %s = GL_TRUE;' % flag_name
236                 print '                break;'
237             print '            default:'
238             print '               return;'
239             print '        }'
240             print
241
242             # Emit fake glEnableClientState/glDisableClientState flags
243             for camelcase_name, uppercase_name in self.arrays:
244                 flag_name = '__' + uppercase_name.lower()
245                 enable_name = 'GL_%s_ARRAY' % uppercase_name
246
247                 # Emit a fake function
248                 print '        {'
249                 print '            static const Trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
250                 print '            unsigned __call = Trace::BeginEnter(__sig);'
251                 print '            Trace::BeginArg(0);'
252                 dump_instance(glapi.GLenum, enable_name)
253                 print '            Trace::EndArg();'
254                 print '            Trace::EndEnter();'
255                 print '            Trace::BeginLeave(__call);'
256                 print '            Trace::EndLeave();'
257                 print '        }'
258
259             print '        return;'
260             print '    }'
261
262         Tracer.trace_function_impl_body(self, function)
263
264     boolean_names = [
265         'GL_FALSE',
266         'GL_TRUE',
267     ]
268
269     def gl_boolean(self, value):
270         return self.boolean_names[int(bool(value))]
271
272     def dump_arg_instance(self, function, arg):
273         if function.name in self.draw_function_names and arg.name == 'indices':
274             print '    GLint __element_array_buffer = 0;'
275             print '    __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
276             print '    if (!__element_array_buffer) {'
277             print '        Trace::LiteralBlob((const void *)%s, count*__gl_type_size(type));' % (arg.name)
278             print '    } else {'
279             print '        Trace::LiteralOpaque((const void *)%s);' % (arg.name)
280             print '    }'
281             return
282
283         Tracer.dump_arg_instance(self, function, arg)
284
285     def state_tracker_impl(self, api):
286         # A simple state tracker to track the pointer values
287
288         # update the state
289         print 'static void __trace_user_arrays(GLuint maxindex)'
290         print '{'
291
292         for camelcase_name, uppercase_name in self.arrays:
293             function_name = 'gl%sPointer' % camelcase_name
294             enable_name = 'GL_%s_ARRAY' % uppercase_name
295             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
296             function = api.get_function_by_name(function_name)
297
298             print '    // %s' % function.name
299             print '    if (__glIsEnabled(%s)) {;' % enable_name
300             print '        GLint __binding = 0;'
301             print '        __glGetIntegerv(%s, &__binding);' % binding_name
302             print '        if (!__binding) {'
303
304             # Get the arguments via glGet*
305             for arg in function.args:
306                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
307                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
308                 print '            %s %s = 0;' % (arg_type, arg.name)
309                 print '            __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
310             
311             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
312             print '            size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
313
314             # Emit a fake function
315             print '            unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name,)
316             for arg in function.args:
317                 assert not arg.output
318                 print '            Trace::BeginArg(%u);' % (arg.index,)
319                 if arg.name != 'pointer':
320                     dump_instance(arg.type, arg.name)
321                 else:
322                     print '            Trace::LiteralBlob((const void *)%s, __size);' % (arg.name)
323                 print '            Trace::EndArg();'
324             
325             print '            Trace::EndEnter();'
326             print '            Trace::BeginLeave(__call);'
327             print '            Trace::EndLeave();'
328             print '        }'
329             print '    }'
330             print
331
332         # Samething, but for glVertexAttribPointer
333         print '    // glVertexAttribPointer'
334         print '    GLint __max_vertex_attribs;'
335         print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
336         print '    for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
337         print '        GLint __enabled = 0;'
338         print '        __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
339         print '        if (__enabled) {'
340         print '            GLint __binding = 0;'
341         print '            __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
342         print '            if (!__binding) {'
343
344         function = api.get_function_by_name('glVertexAttribPointer')
345
346         # Get the arguments via glGet*
347         for arg in function.args[1:]:
348             arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s' % (arg.name.upper(),)
349             arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False).visit(arg.type)
350             print '                %s %s = 0;' % (arg_type, arg.name)
351             print '                __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
352         
353         arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
354         print '                size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
355
356         # Emit a fake function
357         print '                unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name,)
358         for arg in function.args:
359             assert not arg.output
360             print '                Trace::BeginArg(%u);' % (arg.index,)
361             if arg.name != 'pointer':
362                 dump_instance(arg.type, arg.name)
363             else:
364                 print '                Trace::LiteralBlob((const void *)%s, __size);' % (arg.name)
365             print '                Trace::EndArg();'
366         
367         print '                Trace::EndEnter();'
368         print '                Trace::BeginLeave(__call);'
369         print '                Trace::EndLeave();'
370         print '            }'
371         print '        }'
372         print '    }'
373         print
374
375         print '}'
376         print
377
378
379
380
381
382
383