]> git.cworth.org Git - apitrace/blob - gltrace.py
Cleanup glFlushMappedBufferRange/glFlushMappedBufferRangeAPPLE
[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 specs.stdapi as stdapi
31 import specs.glapi as glapi
32 import specs.glparams as glparams
33 from specs.glxapi import glxapi
34 from trace import Tracer
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 visitConst(self, const):
46         return self.visit(const.type)
47
48     def visitAlias(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 visitEnum(self, enum):
84         return self.visit(glapi.GLint)
85
86     def visitBitmask(self, bitmask):
87         return self.visit(glapi.GLint)
88
89     def visitOpaque(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     # arrays available in PROFILE_ES1
108     arrays_es1 = ("Vertex", "Normal", "Color", "TexCoord")
109
110     def header(self, api):
111         Tracer.header(self, api)
112
113         print '#include "gltrace.hpp"'
114         print
115         
116         # Which glVertexAttrib* variant to use
117         print 'enum vertex_attrib {'
118         print '    VERTEX_ATTRIB,'
119         print '    VERTEX_ATTRIB_ARB,'
120         print '    VERTEX_ATTRIB_NV,'
121         print '};'
122         print
123         print 'gltrace::Context *'
124         print 'gltrace::getContext(void)'
125         print '{'
126         print '    // TODO return the context set by other APIs (GLX, EGL, and etc.)'
127         print '    static gltrace::Context __ctx = { gltrace::PROFILE_COMPAT, false, false, false };'
128         print '    return &__ctx;'
129         print '}'
130         print
131         print 'static vertex_attrib __get_vertex_attrib(void) {'
132         print '    gltrace::Context *ctx = gltrace::getContext();'
133         print '    if (ctx->user_arrays_arb || ctx->user_arrays_nv) {'
134         print '        GLboolean __vertex_program = GL_FALSE;'
135         print '        __glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &__vertex_program);'
136         print '        if (__vertex_program) {'
137         print '            if (ctx->user_arrays_nv) {'
138         print '                GLint __vertex_program_binding_nv = 0;'
139         print '                __glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &__vertex_program_binding_nv);'
140         print '                if (__vertex_program_binding_nv) {'
141         print '                    return VERTEX_ATTRIB_NV;'
142         print '                }'
143         print '            }'
144         print '            return VERTEX_ATTRIB_ARB;'
145         print '        }'
146         print '    }'
147         print '    return VERTEX_ATTRIB;'
148         print '}'
149         print
150
151         # Whether we need user arrays
152         print 'static inline bool __need_user_arrays(void)'
153         print '{'
154         print '    gltrace::Context *ctx = gltrace::getContext();'
155         print '    if (!ctx->user_arrays) {'
156         print '        return false;'
157         print '    }'
158         print
159
160         for camelcase_name, uppercase_name in self.arrays:
161             # in which profile is the array available?
162             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
163             if camelcase_name in self.arrays_es1:
164                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
165
166             function_name = 'gl%sPointer' % camelcase_name
167             enable_name = 'GL_%s_ARRAY' % uppercase_name
168             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
169             print '    // %s' % function_name
170             print '  if (%s) {' % profile_check
171             self.array_prolog(api, uppercase_name)
172             print '    if (__glIsEnabled(%s)) {' % enable_name
173             print '        GLint __binding = 0;'
174             print '        __glGetIntegerv(%s, &__binding);' % binding_name
175             print '        if (!__binding) {'
176             self.array_cleanup(api, uppercase_name)
177             print '            return true;'
178             print '        }'
179             print '    }'
180             self.array_epilog(api, uppercase_name)
181             print '  }'
182             print
183
184         print '    // ES1 does not support generic vertex attributes'
185         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
186         print '        return false;'
187         print
188         print '    vertex_attrib __vertex_attrib = __get_vertex_attrib();'
189         print
190         print '    // glVertexAttribPointer'
191         print '    if (__vertex_attrib == VERTEX_ATTRIB) {'
192         print '        GLint __max_vertex_attribs = 0;'
193         print '        __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
194         print '        for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
195         print '            GLint __enabled = 0;'
196         print '            __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
197         print '            if (__enabled) {'
198         print '                GLint __binding = 0;'
199         print '                __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
200         print '                if (!__binding) {'
201         print '                    return true;'
202         print '                }'
203         print '            }'
204         print '        }'
205         print '    }'
206         print
207         print '    // glVertexAttribPointerARB'
208         print '    if (__vertex_attrib == VERTEX_ATTRIB_ARB) {'
209         print '        GLint __max_vertex_attribs = 0;'
210         print '        __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &__max_vertex_attribs);'
211         print '        for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
212         print '            GLint __enabled = 0;'
213         print '            __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &__enabled);'
214         print '            if (__enabled) {'
215         print '                GLint __binding = 0;'
216         print '                __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &__binding);'
217         print '                if (!__binding) {'
218         print '                    return true;'
219         print '                }'
220         print '            }'
221         print '        }'
222         print '    }'
223         print
224         print '    // glVertexAttribPointerNV'
225         print '    if (__vertex_attrib == VERTEX_ATTRIB_NV) {'
226         print '        for (GLint index = 0; index < 16; ++index) {'
227         print '            GLint __enabled = 0;'
228         print '            __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
229         print '            if (__enabled) {'
230         print '                return true;'
231         print '            }'
232         print '        }'
233         print '    }'
234         print
235
236         print '    return false;'
237         print '}'
238         print
239
240         print 'static void __trace_user_arrays(GLuint maxindex);'
241         print
242
243         print 'struct buffer_mapping {'
244         print '    void *map;'
245         print '    GLint length;'
246         print '    bool write;'
247         print '    bool explicit_flush;'
248         print '};'
249         print
250         for target in self.buffer_targets:
251             print 'struct buffer_mapping __%s_mapping;' % target.lower();
252         print
253         print 'static inline struct buffer_mapping *'
254         print 'get_buffer_mapping(GLenum target) {'
255         print '    switch (target) {'
256         for target in self.buffer_targets:
257             print '    case GL_%s:' % target
258             print '        return & __%s_mapping;' % target.lower()
259         print '    default:'
260         print '        os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
261         print '        return NULL;'
262         print '    }'
263         print '}'
264         print
265
266         # Generate a helper function to determine whether a parameter name
267         # refers to a symbolic value or not
268         print 'static bool'
269         print 'is_symbolic_pname(GLenum pname) {'
270         print '    switch (pname) {'
271         for function, type, count, name in glparams.parameters:
272             if type is glapi.GLenum:
273                 print '    case %s:' % name
274         print '        return true;'
275         print '    default:'
276         print '        return false;'
277         print '    }'
278         print '}'
279         print
280         
281         # Generate a helper function to determine whether a parameter value is
282         # potentially symbolic or not; i.e., if the value can be represented in
283         # an enum or not
284         print 'template<class T>'
285         print 'static inline bool'
286         print 'is_symbolic_param(T param) {'
287         print '    return static_cast<T>(static_cast<GLenum>(param)) == param;'
288         print '}'
289         print
290
291         # Generate a helper function to know how many elements a parameter has
292         print 'static size_t'
293         print '__gl_param_size(GLenum pname) {'
294         print '    switch (pname) {'
295         for function, type, count, name in glparams.parameters:
296             if type is not None:
297                 print '    case %s: return %u;' % (name, count)
298         print '    case GL_COMPRESSED_TEXTURE_FORMATS: {'
299         print '            GLint num_compressed_texture_formats = 0;'
300         print '            __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
301         print '            return num_compressed_texture_formats;'
302         print '        }'
303         print '    default:'
304         print r'        os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
305         print '        return 1;'
306         print '    }'
307         print '}'
308         print
309
310         # states such as GL_UNPACK_ROW_LENGTH are not available in GLES
311         print 'static inline bool'
312         print 'can_unpack_subimage(void) {'
313         print '    gltrace::Context *ctx = gltrace::getContext();'
314         print '    return (ctx->profile == gltrace::PROFILE_COMPAT);'
315         print '}'
316         print
317
318     array_pointer_function_names = set((
319         "glVertexPointer",
320         "glNormalPointer",
321         "glColorPointer",
322         "glIndexPointer",
323         "glTexCoordPointer",
324         "glEdgeFlagPointer",
325         "glFogCoordPointer",
326         "glSecondaryColorPointer",
327         
328         "glInterleavedArrays",
329
330         "glVertexPointerEXT",
331         "glNormalPointerEXT",
332         "glColorPointerEXT",
333         "glIndexPointerEXT",
334         "glTexCoordPointerEXT",
335         "glEdgeFlagPointerEXT",
336         "glFogCoordPointerEXT",
337         "glSecondaryColorPointerEXT",
338
339         "glVertexAttribPointer",
340         "glVertexAttribPointerARB",
341         "glVertexAttribPointerNV",
342         "glVertexAttribIPointer",
343         "glVertexAttribIPointerEXT",
344         "glVertexAttribLPointer",
345         "glVertexAttribLPointerEXT",
346         
347         #"glMatrixIndexPointerARB",
348     ))
349
350     draw_function_names = set((
351         'glDrawArrays',
352         'glDrawElements',
353         'glDrawRangeElements',
354         'glMultiDrawArrays',
355         'glMultiDrawElements',
356         'glDrawArraysInstanced',
357         "glDrawArraysInstancedBaseInstance",
358         'glDrawElementsInstanced',
359         'glDrawArraysInstancedARB',
360         'glDrawElementsInstancedARB',
361         'glDrawElementsBaseVertex',
362         'glDrawRangeElementsBaseVertex',
363         'glDrawElementsInstancedBaseVertex',
364         "glDrawElementsInstancedBaseInstance",
365         "glDrawElementsInstancedBaseVertexBaseInstance",
366         'glMultiDrawElementsBaseVertex',
367         'glDrawArraysIndirect',
368         'glDrawElementsIndirect',
369         'glDrawArraysEXT',
370         'glDrawRangeElementsEXT',
371         'glDrawRangeElementsEXT_size',
372         'glMultiDrawArraysEXT',
373         'glMultiDrawElementsEXT',
374         'glMultiModeDrawArraysIBM',
375         'glMultiModeDrawElementsIBM',
376         'glDrawArraysInstancedEXT',
377         'glDrawElementsInstancedEXT',
378     ))
379
380     interleaved_formats = [
381          'GL_V2F',
382          'GL_V3F',
383          'GL_C4UB_V2F',
384          'GL_C4UB_V3F',
385          'GL_C3F_V3F',
386          'GL_N3F_V3F',
387          'GL_C4F_N3F_V3F',
388          'GL_T2F_V3F',
389          'GL_T4F_V4F',
390          'GL_T2F_C4UB_V3F',
391          'GL_T2F_C3F_V3F',
392          'GL_T2F_N3F_V3F',
393          'GL_T2F_C4F_N3F_V3F',
394          'GL_T4F_C4F_N3F_V4F',
395     ]
396
397     def traceFunctionImplBody(self, function):
398         # Defer tracing of user array pointers...
399         if function.name in self.array_pointer_function_names:
400             print '    GLint __array_buffer = 0;'
401             print '    __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
402             print '    if (!__array_buffer) {'
403             print '        gltrace::Context *ctx = gltrace::getContext();'
404             print '        ctx->user_arrays = true;'
405             if function.name == "glVertexAttribPointerARB":
406                 print '        ctx->user_arrays_arb = true;'
407             if function.name == "glVertexAttribPointerNV":
408                 print '        ctx->user_arrays_nv = true;'
409             self.invokeFunction(function)
410
411             # And also break down glInterleavedArrays into the individual calls
412             if function.name == 'glInterleavedArrays':
413                 print
414
415                 # Initialize the enable flags
416                 for camelcase_name, uppercase_name in self.arrays:
417                     flag_name = '__' + uppercase_name.lower()
418                     print '        GLboolean %s = GL_FALSE;' % flag_name
419                 print
420
421                 # Switch for the interleaved formats
422                 print '        switch (format) {'
423                 for format in self.interleaved_formats:
424                     print '            case %s:' % format
425                     for camelcase_name, uppercase_name in self.arrays:
426                         flag_name = '__' + uppercase_name.lower()
427                         if format.find('_' + uppercase_name[0]) >= 0:
428                             print '                %s = GL_TRUE;' % flag_name
429                     print '                break;'
430                 print '            default:'
431                 print '               return;'
432                 print '        }'
433                 print
434
435                 # Emit fake glEnableClientState/glDisableClientState flags
436                 for camelcase_name, uppercase_name in self.arrays:
437                     flag_name = '__' + uppercase_name.lower()
438                     enable_name = 'GL_%s_ARRAY' % uppercase_name
439
440                     # Emit a fake function
441                     print '        {'
442                     print '            static const trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
443                     print '            unsigned __call = trace::localWriter.beginEnter(&__sig);'
444                     print '            trace::localWriter.beginArg(0);'
445                     self.serializeValue(glapi.GLenum, enable_name)
446                     print '            trace::localWriter.endArg();'
447                     print '            trace::localWriter.endEnter();'
448                     print '            trace::localWriter.beginLeave(__call);'
449                     print '            trace::localWriter.endLeave();'
450                     print '        }'
451
452             print '        return;'
453             print '    }'
454
455         # ... to the draw calls
456         if function.name in self.draw_function_names:
457             print '    if (__need_user_arrays()) {'
458             arg_names = ', '.join([arg.name for arg in function.args[1:]])
459             print '        GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
460             print '        __trace_user_arrays(maxindex);'
461             print '    }'
462         
463         # Emit a fake memcpy on buffer uploads
464         if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', 'glUnmapBufferOES'):
465             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
466             print '    if (mapping && mapping->write && !mapping->explicit_flush) {'
467             self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
468             print '    }'
469         if function.name == 'glUnmapNamedBufferEXT':
470             print '    GLint access_flags = 0;'
471             print '    __glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
472             print '    if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
473             print '        GLvoid *map = NULL;'
474             print '        __glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
475             print '        GLint length = 0;'
476             print '        __glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
477             print '        if (map && length > 0) {'
478             self.emit_memcpy('map', 'map', 'length')
479             print '        }'
480             print '    }'
481         if function.name == 'glFlushMappedBufferRange':
482             print '    GLvoid *map = NULL;'
483             print '    __glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
484             print '    if (map && length > 0) {'
485             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
486             print '    }'
487         if function.name == 'glFlushMappedBufferRangeAPPLE':
488             print '    GLvoid *map = NULL;'
489             print '    __glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
490             print '    if (map && size > 0) {'
491             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
492             print '    }'
493         if function.name == 'glFlushMappedNamedBufferRangeEXT':
494             print '    GLvoid *map = NULL;'
495             print '    __glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
496             print '    if (map && length > 0) {'
497             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
498             print '    }'
499
500         # Don't leave vertex attrib locations to chance.  Instead emit fake
501         # glBindAttribLocation calls to ensure that the same locations will be
502         # used when retracing.  Trying to remap locations after the fact would
503         # be an herculian task given that vertex attrib locations appear in
504         # many entry-points, including non-shader related ones.
505         if function.name == 'glLinkProgram':
506             Tracer.invokeFunction(self, function)
507             print '    GLint active_attributes = 0;'
508             print '    __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
509             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
510             print '        GLint size = 0;'
511             print '        GLenum type = 0;'
512             print '        GLchar name[256];'
513             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
514             print '        __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
515             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
516             print '            GLint location = __glGetAttribLocation(program, name);'
517             print '            if (location >= 0) {'
518             bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
519             self.fake_call(bind_function, ['program', 'location', 'name'])
520             print '            }'
521             print '        }'
522             print '    }'
523         if function.name == 'glLinkProgramARB':
524             Tracer.invokeFunction(self, function)
525             print '    GLint active_attributes = 0;'
526             print '    __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
527             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
528             print '        GLint size = 0;'
529             print '        GLenum type = 0;'
530             print '        GLcharARB name[256];'
531             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
532             print '        __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
533             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
534             print '            GLint location = __glGetAttribLocationARB(programObj, name);'
535             print '            if (location >= 0) {'
536             bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
537             self.fake_call(bind_function, ['programObj', 'location', 'name'])
538             print '            }'
539             print '        }'
540             print '    }'
541
542         Tracer.traceFunctionImplBody(self, function)
543
544     marker_functions = [
545         # GL_GREMEDY_string_marker
546         'glStringMarkerGREMEDY',
547         # GL_GREMEDY_frame_terminator
548         'glFrameTerminatorGREMEDY',
549         # GL_EXT_debug_marker
550         'glInsertEventMarkerEXT',
551         'glPushGroupMarkerEXT',
552         'glPopGroupMarkerEXT',
553     ]
554
555     def invokeFunction(self, function):
556         if function.name in ('glLinkProgram', 'glLinkProgramARB'):
557             # These functions have been dispatched already
558             return
559
560         # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
561         # driver
562         if function.name in self.marker_functions:
563             return
564
565         if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
566             else_ = ''
567             for marker_function in self.marker_functions:
568                 if self.api.get_function_by_name(marker_function):
569                     print '    %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
570                     print '        __result = (%s)&%s;' % (function.type, marker_function)
571                     print '    }'
572                 else_ = 'else '
573             print '    %s{' % else_
574             Tracer.invokeFunction(self, function)
575             print '    }'
576             return
577
578         # Override GL extensions
579         if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
580             Tracer.invokeFunction(self, function, prefix = 'gltrace::__', suffix = '_override')
581             return
582
583         Tracer.invokeFunction(self, function)
584
585     buffer_targets = [
586         'ARRAY_BUFFER',
587         'ELEMENT_ARRAY_BUFFER',
588         'PIXEL_PACK_BUFFER',
589         'PIXEL_UNPACK_BUFFER',
590         'UNIFORM_BUFFER',
591         'TEXTURE_BUFFER',
592         'TRANSFORM_FEEDBACK_BUFFER',
593         'COPY_READ_BUFFER',
594         'COPY_WRITE_BUFFER',
595         'DRAW_INDIRECT_BUFFER',
596         'ATOMIC_COUNTER_BUFFER',
597     ]
598
599     def wrapRet(self, function, instance):
600         Tracer.wrapRet(self, function, instance)
601
602             
603         if function.name in ('glMapBuffer', 'glMapBufferARB', 'glMapBufferOES'):
604             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
605             print '    if (mapping) {'
606             print '        mapping->map = %s;' % (instance)
607             print '        mapping->length = 0;'
608             print '        __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
609             print '        mapping->write = (access != GL_READ_ONLY);'
610             print '        mapping->explicit_flush = false;'
611             print '    }'
612
613         if function.name == 'glMapBufferRange':
614             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
615             print '    if (mapping) {'
616             print '        mapping->map = %s;' % (instance)
617             print '        mapping->length = length;'
618             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
619             print '        mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
620             print '    }'
621
622     boolean_names = [
623         'GL_FALSE',
624         'GL_TRUE',
625     ]
626
627     def gl_boolean(self, value):
628         return self.boolean_names[int(bool(value))]
629
630     # Names of the functions that unpack from a pixel buffer object.  See the
631     # ARB_pixel_buffer_object specification.
632     unpack_function_names = set([
633         'glBitmap',
634         'glColorSubTable',
635         'glColorTable',
636         'glCompressedTexImage1D',
637         'glCompressedTexImage2D',
638         'glCompressedTexImage3D',
639         'glCompressedTexSubImage1D',
640         'glCompressedTexSubImage2D',
641         'glCompressedTexSubImage3D',
642         'glConvolutionFilter1D',
643         'glConvolutionFilter2D',
644         'glDrawPixels',
645         'glMultiTexImage1DEXT',
646         'glMultiTexImage2DEXT',
647         'glMultiTexImage3DEXT',
648         'glMultiTexSubImage1DEXT',
649         'glMultiTexSubImage2DEXT',
650         'glMultiTexSubImage3DEXT',
651         'glPixelMapfv',
652         'glPixelMapuiv',
653         'glPixelMapusv',
654         'glPolygonStipple',
655         'glSeparableFilter2D',
656         'glTexImage1D',
657         'glTexImage1DEXT',
658         'glTexImage2D',
659         'glTexImage2DEXT',
660         'glTexImage3D',
661         'glTexImage3DEXT',
662         'glTexSubImage1D',
663         'glTexSubImage1DEXT',
664         'glTexSubImage2D',
665         'glTexSubImage2DEXT',
666         'glTexSubImage3D',
667         'glTexSubImage3DEXT',
668         'glTextureImage1DEXT',
669         'glTextureImage2DEXT',
670         'glTextureImage3DEXT',
671         'glTextureSubImage1DEXT',
672         'glTextureSubImage2DEXT',
673         'glTextureSubImage3DEXT',
674     ])
675
676     def serializeArgValue(self, function, arg):
677         if function.name in self.draw_function_names and arg.name == 'indices':
678             print '    GLint __element_array_buffer = 0;'
679             print '    __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
680             print '    if (!__element_array_buffer) {'
681             if isinstance(arg.type, stdapi.Array):
682                 print '        trace::localWriter.beginArray(%s);' % arg.type.length
683                 print '        for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
684                 print '            trace::localWriter.beginElement();'
685                 print '            trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
686                 print '            trace::localWriter.endElement();'
687                 print '        }'
688                 print '        trace::localWriter.endArray();'
689             else:
690                 print '        trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
691             print '    } else {'
692             Tracer.serializeArgValue(self, function, arg)
693             print '    }'
694             return
695
696         # Recognize offsets instead of blobs when a PBO is bound
697         if function.name in self.unpack_function_names \
698            and (isinstance(arg.type, stdapi.Blob) \
699                 or (isinstance(arg.type, stdapi.Const) \
700                     and isinstance(arg.type.type, stdapi.Blob))):
701             print '    {'
702             print '        gltrace::Context *ctx = gltrace::getContext();'
703             print '        GLint __unpack_buffer = 0;'
704             print '        if (ctx->profile == gltrace::PROFILE_COMPAT)'
705             print '            __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
706             print '        if (__unpack_buffer) {'
707             print '            trace::localWriter.writeOpaque(%s);' % arg.name
708             print '        } else {'
709             Tracer.serializeArgValue(self, function, arg)
710             print '        }'
711             print '    }'
712             return
713
714         # Several GL state functions take GLenum symbolic names as
715         # integer/floats; so dump the symbolic name whenever possible
716         if function.name.startswith('gl') \
717            and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
718            and arg.name == 'param':
719             assert arg.index > 0
720             assert function.args[arg.index - 1].name == 'pname'
721             assert function.args[arg.index - 1].type == glapi.GLenum
722             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
723             self.serializeValue(glapi.GLenum, arg.name)
724             print '    } else {'
725             Tracer.serializeArgValue(self, function, arg)
726             print '    }'
727             return
728
729         Tracer.serializeArgValue(self, function, arg)
730
731     def footer(self, api):
732         Tracer.footer(self, api)
733
734         # A simple state tracker to track the pointer values
735         # update the state
736         print 'static void __trace_user_arrays(GLuint maxindex)'
737         print '{'
738         print '    gltrace::Context *ctx = gltrace::getContext();'
739
740         for camelcase_name, uppercase_name in self.arrays:
741             # in which profile is the array available?
742             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
743             if camelcase_name in self.arrays_es1:
744                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
745
746             function_name = 'gl%sPointer' % camelcase_name
747             enable_name = 'GL_%s_ARRAY' % uppercase_name
748             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
749             function = api.get_function_by_name(function_name)
750
751             print '    // %s' % function.prototype()
752             print '  if (%s) {' % profile_check
753             self.array_trace_prolog(api, uppercase_name)
754             self.array_prolog(api, uppercase_name)
755             print '    if (__glIsEnabled(%s)) {' % enable_name
756             print '        GLint __binding = 0;'
757             print '        __glGetIntegerv(%s, &__binding);' % binding_name
758             print '        if (!__binding) {'
759
760             # Get the arguments via glGet*
761             for arg in function.args:
762                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
763                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
764                 print '            %s %s = 0;' % (arg_type, arg.name)
765                 print '            __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
766             
767             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
768             print '            size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
769
770             # Emit a fake function
771             self.array_trace_intermezzo(api, uppercase_name)
772             print '            unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
773             for arg in function.args:
774                 assert not arg.output
775                 print '            trace::localWriter.beginArg(%u);' % (arg.index,)
776                 if arg.name != 'pointer':
777                     self.serializeValue(arg.type, arg.name)
778                 else:
779                     print '            trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
780                 print '            trace::localWriter.endArg();'
781             
782             print '            trace::localWriter.endEnter();'
783             print '            trace::localWriter.beginLeave(__call);'
784             print '            trace::localWriter.endLeave();'
785             print '        }'
786             print '    }'
787             self.array_epilog(api, uppercase_name)
788             self.array_trace_epilog(api, uppercase_name)
789             print '  }'
790             print
791
792         # Samething, but for glVertexAttribPointer*
793         #
794         # Some variants of glVertexAttribPointer alias conventional and generic attributes:
795         # - glVertexAttribPointer: no
796         # - glVertexAttribPointerARB: implementation dependent
797         # - glVertexAttribPointerNV: yes
798         #
799         # This means that the implementations of these functions do not always
800         # alias, and they need to be considered independently.
801         #
802         print '    // ES1 does not support generic vertex attributes'
803         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
804         print '        return;'
805         print
806         print '    vertex_attrib __vertex_attrib = __get_vertex_attrib();'
807         print
808         for suffix in ['', 'ARB', 'NV']:
809             if suffix:
810                 SUFFIX = '_' + suffix
811             else:
812                 SUFFIX = suffix
813             function_name = 'glVertexAttribPointer' + suffix
814             function = api.get_function_by_name(function_name)
815
816             print '    // %s' % function.prototype()
817             print '    if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
818             if suffix == 'NV':
819                 print '        GLint __max_vertex_attribs = 16;'
820             else:
821                 print '        GLint __max_vertex_attribs = 0;'
822                 print '        __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
823             print '        for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
824             print '            GLint __enabled = 0;'
825             if suffix == 'NV':
826                 print '            __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
827             else:
828                 print '            __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
829             print '            if (__enabled) {'
830             print '                GLint __binding = 0;'
831             if suffix != 'NV':
832                 # It doesn't seem possible to use VBOs with NV_vertex_program.
833                 print '                __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
834             print '                if (!__binding) {'
835
836             # Get the arguments via glGet*
837             for arg in function.args[1:]:
838                 if suffix == 'NV':
839                     arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
840                 else:
841                     arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
842                 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
843                 print '                    %s %s = 0;' % (arg_type, arg.name)
844                 print '                    __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
845             
846             arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
847             print '                    size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
848
849             # Emit a fake function
850             print '                    unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
851             for arg in function.args:
852                 assert not arg.output
853                 print '                    trace::localWriter.beginArg(%u);' % (arg.index,)
854                 if arg.name != 'pointer':
855                     self.serializeValue(arg.type, arg.name)
856                 else:
857                     print '                    trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
858                 print '                    trace::localWriter.endArg();'
859             
860             print '                    trace::localWriter.endEnter();'
861             print '                    trace::localWriter.beginLeave(__call);'
862             print '                    trace::localWriter.endLeave();'
863             print '                }'
864             print '            }'
865             print '        }'
866             print '    }'
867             print
868
869         print '}'
870         print
871
872     #
873     # Hooks for glTexCoordPointer, which is identical to the other array
874     # pointers except the fact that it is indexed by glClientActiveTexture.
875     #
876
877     def array_prolog(self, api, uppercase_name):
878         if uppercase_name == 'TEXTURE_COORD':
879             print '    GLint client_active_texture = 0;'
880             print '    __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
881             print '    GLint max_texture_coords = 0;'
882             print '    if (ctx->profile == gltrace::PROFILE_COMPAT)'
883             print '        __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
884             print '    else'
885             print '        __glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
886             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
887             print '        GLint texture = GL_TEXTURE0 + unit;'
888             print '        __glClientActiveTexture(texture);'
889
890     def array_trace_prolog(self, api, uppercase_name):
891         if uppercase_name == 'TEXTURE_COORD':
892             print '    bool client_active_texture_dirty = false;'
893
894     def array_epilog(self, api, uppercase_name):
895         if uppercase_name == 'TEXTURE_COORD':
896             print '    }'
897         self.array_cleanup(api, uppercase_name)
898
899     def array_cleanup(self, api, uppercase_name):
900         if uppercase_name == 'TEXTURE_COORD':
901             print '    __glClientActiveTexture(client_active_texture);'
902         
903     def array_trace_intermezzo(self, api, uppercase_name):
904         if uppercase_name == 'TEXTURE_COORD':
905             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
906             print '        client_active_texture_dirty = true;'
907             self.fake_glClientActiveTexture_call(api, "texture");
908             print '    }'
909
910     def array_trace_epilog(self, api, uppercase_name):
911         if uppercase_name == 'TEXTURE_COORD':
912             print '    if (client_active_texture_dirty) {'
913             self.fake_glClientActiveTexture_call(api, "client_active_texture");
914             print '    }'
915
916     def fake_glClientActiveTexture_call(self, api, texture):
917         function = api.get_function_by_name('glClientActiveTexture')
918         self.fake_call(function, [texture])
919
920     def fake_call(self, function, args):
921         print '            unsigned __fake_call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
922         for arg, instance in zip(function.args, args):
923             assert not arg.output
924             print '            trace::localWriter.beginArg(%u);' % (arg.index,)
925             self.serializeValue(arg.type, instance)
926             print '            trace::localWriter.endArg();'
927         print '            trace::localWriter.endEnter();'
928         print '            trace::localWriter.beginLeave(__fake_call);'
929         print '            trace::localWriter.endLeave();'
930
931
932
933
934
935
936
937
938
939
940