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