]> git.cworth.org Git - apitrace/blob - wrappers/gltrace.py
trace: Protect against uninitialized pointers if debug extensions are not exposed...
[apitrace] / wrappers / 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 from trace import Tracer
31 from dispatch import function_pointer_type, function_pointer_value
32 import specs.stdapi as stdapi
33 import specs.glapi as glapi
34 import specs.glparams as glparams
35 from specs.glxapi import glxapi
36
37
38 class TypeGetter(stdapi.Visitor):
39     '''Determine which glGet*v function that matches the specified type.'''
40
41     def __init__(self, prefix = 'glGet', long_suffix = True, ext_suffix = ''):
42         self.prefix = prefix
43         self.long_suffix = long_suffix
44         self.ext_suffix = ext_suffix
45
46     def visitConst(self, const):
47         return self.visit(const.type)
48
49     def visitAlias(self, alias):
50         if alias.expr == 'GLboolean':
51             if self.long_suffix:
52                 suffix = 'Booleanv'
53                 arg_type = alias.expr
54             else:
55                 suffix = 'iv'
56                 arg_type = 'GLint'
57         elif alias.expr == 'GLdouble':
58             if self.long_suffix:
59                 suffix = 'Doublev'
60                 arg_type = alias.expr
61             else:
62                 suffix = 'dv'
63                 arg_type = alias.expr
64         elif alias.expr == 'GLfloat':
65             if self.long_suffix:
66                 suffix = 'Floatv'
67                 arg_type = alias.expr
68             else:
69                 suffix = 'fv'
70                 arg_type = alias.expr
71         elif alias.expr in ('GLint', 'GLuint', 'GLsizei'):
72             if self.long_suffix:
73                 suffix = 'Integerv'
74                 arg_type = 'GLint'
75             else:
76                 suffix = 'iv'
77                 arg_type = 'GLint'
78         else:
79             print alias.expr
80             assert False
81         function_name = self.prefix + suffix + self.ext_suffix
82         return function_name, arg_type
83     
84     def visitEnum(self, enum):
85         return self.visit(glapi.GLint)
86
87     def visitBitmask(self, bitmask):
88         return self.visit(glapi.GLint)
89
90     def visitOpaque(self, pointer):
91         return self.prefix + 'Pointerv' + self.ext_suffix, 'GLvoid *'
92
93
94 class GlTracer(Tracer):
95
96     arrays = [
97         ("Vertex", "VERTEX"),
98         ("Normal", "NORMAL"),
99         ("Color", "COLOR"),
100         ("Index", "INDEX"),
101         ("TexCoord", "TEXTURE_COORD"),
102         ("EdgeFlag", "EDGE_FLAG"),
103         ("FogCoord", "FOG_COORD"),
104         ("SecondaryColor", "SECONDARY_COLOR"),
105     ]
106     arrays.reverse()
107
108     # arrays available in PROFILE_ES1
109     arrays_es1 = ("Vertex", "Normal", "Color", "TexCoord")
110
111     def header(self, api):
112         Tracer.header(self, api)
113
114         print '#include "gltrace.hpp"'
115         print
116         
117         # Which glVertexAttrib* variant to use
118         print 'enum vertex_attrib {'
119         print '    VERTEX_ATTRIB,'
120         print '    VERTEX_ATTRIB_ARB,'
121         print '    VERTEX_ATTRIB_NV,'
122         print '};'
123         print
124         print 'static vertex_attrib _get_vertex_attrib(void) {'
125         print '    gltrace::Context *ctx = gltrace::getContext();'
126         print '    if (ctx->user_arrays_arb || ctx->user_arrays_nv) {'
127         print '        GLboolean _vertex_program = GL_FALSE;'
128         print '        _glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &_vertex_program);'
129         print '        if (_vertex_program) {'
130         print '            if (ctx->user_arrays_nv) {'
131         print '                GLint _vertex_program_binding_nv = 0;'
132         print '                _glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &_vertex_program_binding_nv);'
133         print '                if (_vertex_program_binding_nv) {'
134         print '                    return VERTEX_ATTRIB_NV;'
135         print '                }'
136         print '            }'
137         print '            return VERTEX_ATTRIB_ARB;'
138         print '        }'
139         print '    }'
140         print '    return VERTEX_ATTRIB;'
141         print '}'
142         print
143
144         self.defineShadowBufferHelper()
145
146         # Whether we need user arrays
147         print 'static inline bool _need_user_arrays(void)'
148         print '{'
149         print '    gltrace::Context *ctx = gltrace::getContext();'
150         print '    if (!ctx->user_arrays) {'
151         print '        return false;'
152         print '    }'
153         print
154
155         for camelcase_name, uppercase_name in self.arrays:
156             # in which profile is the array available?
157             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
158             if camelcase_name in self.arrays_es1:
159                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
160
161             function_name = 'gl%sPointer' % camelcase_name
162             enable_name = 'GL_%s_ARRAY' % uppercase_name
163             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
164             print '    // %s' % function_name
165             print '  if (%s) {' % profile_check
166             self.array_prolog(api, uppercase_name)
167             print '    if (_glIsEnabled(%s)) {' % enable_name
168             print '        GLint _binding = 0;'
169             print '        _glGetIntegerv(%s, &_binding);' % binding_name
170             print '        if (!_binding) {'
171             self.array_cleanup(api, uppercase_name)
172             print '            return true;'
173             print '        }'
174             print '    }'
175             self.array_epilog(api, uppercase_name)
176             print '  }'
177             print
178
179         print '    // ES1 does not support generic vertex attributes'
180         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
181         print '        return false;'
182         print
183         print '    vertex_attrib _vertex_attrib = _get_vertex_attrib();'
184         print
185         print '    // glVertexAttribPointer'
186         print '    if (_vertex_attrib == VERTEX_ATTRIB) {'
187         print '        GLint _max_vertex_attribs = 0;'
188         print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
189         print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
190         print '            GLint _enabled = 0;'
191         print '            _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &_enabled);'
192         print '            if (_enabled) {'
193         print '                GLint _binding = 0;'
194         print '                _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &_binding);'
195         print '                if (!_binding) {'
196         print '                    return true;'
197         print '                }'
198         print '            }'
199         print '        }'
200         print '    }'
201         print
202         print '    // glVertexAttribPointerARB'
203         print '    if (_vertex_attrib == VERTEX_ATTRIB_ARB) {'
204         print '        GLint _max_vertex_attribs = 0;'
205         print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &_max_vertex_attribs);'
206         print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
207         print '            GLint _enabled = 0;'
208         print '            _glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &_enabled);'
209         print '            if (_enabled) {'
210         print '                GLint _binding = 0;'
211         print '                _glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &_binding);'
212         print '                if (!_binding) {'
213         print '                    return true;'
214         print '                }'
215         print '            }'
216         print '        }'
217         print '    }'
218         print
219         print '    // glVertexAttribPointerNV'
220         print '    if (_vertex_attrib == VERTEX_ATTRIB_NV) {'
221         print '        for (GLint index = 0; index < 16; ++index) {'
222         print '            GLint _enabled = 0;'
223         print '            _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
224         print '            if (_enabled) {'
225         print '                return true;'
226         print '            }'
227         print '        }'
228         print '    }'
229         print
230
231         print '    return false;'
232         print '}'
233         print
234
235         print 'static void _trace_user_arrays(GLuint count);'
236         print
237
238         # Buffer mappings
239         print '// whether glMapBufferRange(GL_MAP_WRITE_BIT) has ever been called'
240         print 'static bool _checkBufferMapRange = false;'
241         print
242         print '// whether glBufferParameteriAPPLE(GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE) has ever been called'
243         print 'static bool _checkBufferFlushingUnmapAPPLE = false;'
244         print
245         # Buffer mapping information, necessary for old Mesa 2.1 drivers which
246         # do not support glGetBufferParameteriv(GL_BUFFER_ACCESS_FLAGS/GL_BUFFER_MAP_LENGTH)
247         print 'struct buffer_mapping {'
248         print '    void *map;'
249         print '    GLint length;'
250         print '    bool write;'
251         print '    bool explicit_flush;'
252         print '};'
253         print
254         for target in self.buffer_targets:
255             print 'struct buffer_mapping _%s_mapping;' % target.lower();
256         print
257         print 'static inline struct buffer_mapping *'
258         print 'get_buffer_mapping(GLenum target) {'
259         print '    switch (target) {'
260         for target in self.buffer_targets:
261             print '    case GL_%s:' % target
262             print '        return & _%s_mapping;' % target.lower()
263         print '    default:'
264         print '        os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
265         print '        return NULL;'
266         print '    }'
267         print '}'
268         print
269
270         # Generate a helper function to determine whether a parameter name
271         # refers to a symbolic value or not
272         print 'static bool'
273         print 'is_symbolic_pname(GLenum pname) {'
274         print '    switch (pname) {'
275         for function, type, count, name in glparams.parameters:
276             if type is glapi.GLenum:
277                 print '    case %s:' % name
278         print '        return true;'
279         print '    default:'
280         print '        return false;'
281         print '    }'
282         print '}'
283         print
284         
285         # Generate a helper function to determine whether a parameter value is
286         # potentially symbolic or not; i.e., if the value can be represented in
287         # an enum or not
288         print 'template<class T>'
289         print 'static inline bool'
290         print 'is_symbolic_param(T param) {'
291         print '    return static_cast<T>(static_cast<GLenum>(param)) == param;'
292         print '}'
293         print
294
295         # Generate a helper function to know how many elements a parameter has
296         print 'static size_t'
297         print '_gl_param_size(GLenum pname) {'
298         print '    switch (pname) {'
299         for function, type, count, name in glparams.parameters:
300             if type is not None:
301                 print '    case %s: return %s;' % (name, count)
302         print '    default:'
303         print r'        os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
304         print '        return 1;'
305         print '    }'
306         print '}'
307         print
308
309         # states such as GL_UNPACK_ROW_LENGTH are not available in GLES
310         print 'static inline bool'
311         print 'can_unpack_subimage(void) {'
312         print '    gltrace::Context *ctx = gltrace::getContext();'
313         print '    return (ctx->profile == gltrace::PROFILE_COMPAT);'
314         print '}'
315         print
316
317     getProcAddressFunctionNames = []
318
319     def traceApi(self, api):
320         if self.getProcAddressFunctionNames:
321             # Generate a function to wrap proc addresses
322             getProcAddressFunction = api.getFunctionByName(self.getProcAddressFunctionNames[0])
323             argType = getProcAddressFunction.args[0].type
324             retType = getProcAddressFunction.type
325             
326             print 'static %s _wrapProcAddress(%s procName, %s procPtr);' % (retType, argType, retType)
327             print
328             
329             Tracer.traceApi(self, api)
330             
331             print 'static %s _wrapProcAddress(%s procName, %s procPtr) {' % (retType, argType, retType)
332
333             # Provide fallback functions to missing debug functions
334             print '    if (!procPtr) {'
335             else_ = ''
336             for function_name in self.debug_functions:
337                 if self.api.getFunctionByName(function_name):
338                     print '        %sif (strcmp("%s", (const char *)procName) == 0) {' % (else_, function_name)
339                     print '            return (%s)&%s;' % (retType, function_name)
340                     print '        }'
341                 else_ = 'else '
342             print '        %s{' % else_
343             print '            return NULL;'
344             print '        }'
345             print '    }'
346
347             for function in api.getAllFunctions():
348                 ptype = function_pointer_type(function)
349                 pvalue = function_pointer_value(function)
350                 print '    if (strcmp("%s", (const char *)procName) == 0) {' % function.name
351                 print '        %s = (%s)procPtr;' % (pvalue, ptype)
352                 print '        return (%s)&%s;' % (retType, function.name,)
353                 print '    }'
354             print '    os::log("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);'
355             print '    return procPtr;'
356             print '}'
357             print
358         else:
359             Tracer.traceApi(self, api)
360
361     def defineShadowBufferHelper(self):
362         print 'void _shadow_glGetBufferSubData(GLenum target, GLintptr offset,'
363         print '                                GLsizeiptr size, GLvoid *data)'
364         print '{'
365         print '    gltrace::Context *ctx = gltrace::getContext();'
366         print '    if (!ctx->needsShadowBuffers() || target != GL_ELEMENT_ARRAY_BUFFER) {'
367         print '        _glGetBufferSubData(target, offset, size, data);'
368         print '        return;'
369         print '    }'
370         print
371         print '    GLint buffer_binding = 0;'
372         print '    _glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buffer_binding);'
373         print '    if (buffer_binding > 0) {'
374         print '        gltrace::Buffer & buf = ctx->buffers[buffer_binding];'
375         print '        buf.getSubData(offset, size, data);'
376         print '    }'
377         print '}'
378
379     def shadowBufferMethod(self, method):
380         # Emit code to fetch the shadow buffer, and invoke a method
381         print '    gltrace::Context *ctx = gltrace::getContext();'
382         print '    if (ctx->needsShadowBuffers() && target == GL_ELEMENT_ARRAY_BUFFER) {'
383         print '        GLint buffer_binding = 0;'
384         print '        _glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buffer_binding);'
385         print '        if (buffer_binding > 0) {'
386         print '            gltrace::Buffer & buf = ctx->buffers[buffer_binding];'
387         print '            buf.' + method + ';'
388         print '        }'
389         print '    }'
390         print
391
392     def shadowBufferProlog(self, function):
393         if function.name == 'glBufferData':
394             self.shadowBufferMethod('bufferData(size, data)')
395
396         if function.name == 'glBufferSubData':
397             self.shadowBufferMethod('bufferSubData(offset, size, data)')
398
399         if function.name == 'glDeleteBuffers':
400             print '    gltrace::Context *ctx = gltrace::getContext();'
401             print '    if (ctx->needsShadowBuffers()) {'
402             print '        for (GLsizei i = 0; i < n; i++) {'
403             print '            ctx->buffers.erase(buffer[i]);'
404             print '        }'
405             print '    }'
406
407     array_pointer_function_names = set((
408         "glVertexPointer",
409         "glNormalPointer",
410         "glColorPointer",
411         "glIndexPointer",
412         "glTexCoordPointer",
413         "glEdgeFlagPointer",
414         "glFogCoordPointer",
415         "glSecondaryColorPointer",
416         
417         "glInterleavedArrays",
418
419         "glVertexPointerEXT",
420         "glNormalPointerEXT",
421         "glColorPointerEXT",
422         "glIndexPointerEXT",
423         "glTexCoordPointerEXT",
424         "glEdgeFlagPointerEXT",
425         "glFogCoordPointerEXT",
426         "glSecondaryColorPointerEXT",
427
428         "glVertexAttribPointer",
429         "glVertexAttribPointerARB",
430         "glVertexAttribPointerNV",
431         "glVertexAttribIPointer",
432         "glVertexAttribIPointerEXT",
433         "glVertexAttribLPointer",
434         "glVertexAttribLPointerEXT",
435         
436         #"glMatrixIndexPointerARB",
437     ))
438
439     draw_function_names = set((
440         'glDrawArrays',
441         'glDrawElements',
442         'glDrawRangeElements',
443         'glMultiDrawArrays',
444         'glMultiDrawElements',
445         'glDrawArraysInstanced',
446         "glDrawArraysInstancedBaseInstance",
447         'glDrawElementsInstanced',
448         'glDrawArraysInstancedARB',
449         'glDrawElementsInstancedARB',
450         'glDrawElementsBaseVertex',
451         'glDrawRangeElementsBaseVertex',
452         'glDrawElementsInstancedBaseVertex',
453         "glDrawElementsInstancedBaseInstance",
454         "glDrawElementsInstancedBaseVertexBaseInstance",
455         'glMultiDrawElementsBaseVertex',
456         'glDrawArraysIndirect',
457         'glDrawElementsIndirect',
458         'glMultiDrawArraysIndirect',
459         'glMultiDrawArraysIndirectAMD',
460         'glMultiDrawElementsIndirect',
461         'glMultiDrawElementsIndirectAMD',
462         'glDrawArraysEXT',
463         'glDrawRangeElementsEXT',
464         'glDrawRangeElementsEXT_size',
465         'glMultiDrawArraysEXT',
466         'glMultiDrawElementsEXT',
467         'glMultiModeDrawArraysIBM',
468         'glMultiModeDrawElementsIBM',
469         'glDrawArraysInstancedEXT',
470         'glDrawElementsInstancedEXT',
471     ))
472
473     interleaved_formats = [
474          'GL_V2F',
475          'GL_V3F',
476          'GL_C4UB_V2F',
477          'GL_C4UB_V3F',
478          'GL_C3F_V3F',
479          'GL_N3F_V3F',
480          'GL_C4F_N3F_V3F',
481          'GL_T2F_V3F',
482          'GL_T4F_V4F',
483          'GL_T2F_C4UB_V3F',
484          'GL_T2F_C3F_V3F',
485          'GL_T2F_N3F_V3F',
486          'GL_T2F_C4F_N3F_V3F',
487          'GL_T4F_C4F_N3F_V4F',
488     ]
489
490     def traceFunctionImplBody(self, function):
491         # Defer tracing of user array pointers...
492         if function.name in self.array_pointer_function_names:
493             print '    GLint _array_buffer = 0;'
494             print '    _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
495             print '    if (!_array_buffer) {'
496             print '        gltrace::Context *ctx = gltrace::getContext();'
497             print '        ctx->user_arrays = true;'
498             if function.name == "glVertexAttribPointerARB":
499                 print '        ctx->user_arrays_arb = true;'
500             if function.name == "glVertexAttribPointerNV":
501                 print '        ctx->user_arrays_nv = true;'
502             self.invokeFunction(function)
503
504             # And also break down glInterleavedArrays into the individual calls
505             if function.name == 'glInterleavedArrays':
506                 print
507
508                 # Initialize the enable flags
509                 for camelcase_name, uppercase_name in self.arrays:
510                     flag_name = '_' + uppercase_name.lower()
511                     print '        GLboolean %s = GL_FALSE;' % flag_name
512                 print
513
514                 # Switch for the interleaved formats
515                 print '        switch (format) {'
516                 for format in self.interleaved_formats:
517                     print '            case %s:' % format
518                     for camelcase_name, uppercase_name in self.arrays:
519                         flag_name = '_' + uppercase_name.lower()
520                         if format.find('_' + uppercase_name[0]) >= 0:
521                             print '                %s = GL_TRUE;' % flag_name
522                     print '                break;'
523                 print '            default:'
524                 print '               return;'
525                 print '        }'
526                 print
527
528                 # Emit fake glEnableClientState/glDisableClientState flags
529                 for camelcase_name, uppercase_name in self.arrays:
530                     flag_name = '_' + uppercase_name.lower()
531                     enable_name = 'GL_%s_ARRAY' % uppercase_name
532
533                     # Emit a fake function
534                     print '        {'
535                     print '            static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
536                     print '            unsigned _call = trace::localWriter.beginEnter(&_sig);'
537                     print '            trace::localWriter.beginArg(0);'
538                     self.serializeValue(glapi.GLenum, enable_name)
539                     print '            trace::localWriter.endArg();'
540                     print '            trace::localWriter.endEnter();'
541                     print '            trace::localWriter.beginLeave(_call);'
542                     print '            trace::localWriter.endLeave();'
543                     print '        }'
544
545             print '        return;'
546             print '    }'
547
548         # ... to the draw calls
549         if function.name in self.draw_function_names:
550             print '    if (_need_user_arrays()) {'
551             arg_names = ', '.join([arg.name for arg in function.args[1:]])
552             print '        GLuint _count = _%s_count(%s);' % (function.name, arg_names)
553             print '        _trace_user_arrays(_count);'
554             print '    }'
555         
556         # Emit a fake memcpy on buffer uploads
557         if function.name == 'glBufferParameteriAPPLE':
558             print '    if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
559             print '        _checkBufferFlushingUnmapAPPLE = true;'
560             print '    }'
561         if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
562             if function.name.endswith('ARB'):
563                 suffix = 'ARB'
564             else:
565                 suffix = ''
566             print '    GLint access = 0;'
567             print '    _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
568             print '    if (access != GL_READ_ONLY) {'
569             print '        GLvoid *map = NULL;'
570             print '        _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);'  % suffix
571             print '        if (map) {'
572             print '            GLint length = -1;'
573             print '            bool flush = true;'
574             print '            if (_checkBufferMapRange) {'
575             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
576             print '                GLint access_flags = 0;'
577             print '                _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
578             print '                flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
579             print '                if (length == -1) {'
580             print '                    // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
581             print '                    static bool warned = false;'
582             print '                    if (!warned) {'
583             print '                        os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
584             print '                        warned = true;'
585             print '                    }'
586             print '                    struct buffer_mapping *mapping = get_buffer_mapping(target);'
587             print '                    if (mapping) {'
588             print '                        length = mapping->length;'
589             print '                        flush = flush && !mapping->explicit_flush;'
590             print '                    } else {'
591             print '                        length = 0;'
592             print '                        flush = false;'
593             print '                    }'
594             print '                }'
595             print '            } else {'
596             print '                length = 0;'
597             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
598             print '            }'
599             print '            if (_checkBufferFlushingUnmapAPPLE) {'
600             print '                GLint flushing_unmap = GL_TRUE;'
601             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
602             print '                flush = flush && flushing_unmap;'
603             print '            }'
604             print '            if (flush && length > 0) {'
605             self.emit_memcpy('map', 'map', 'length')
606             print '            }'
607             print '        }'
608             print '    }'
609         if function.name == 'glUnmapBufferOES':
610             print '    GLint access = 0;'
611             print '    _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
612             print '    if (access == GL_WRITE_ONLY_OES) {'
613             print '        GLvoid *map = NULL;'
614             print '        _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
615             print '        GLint size = 0;'
616             print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
617             print '        if (map && size > 0) {'
618             self.emit_memcpy('map', 'map', 'size')
619             self.shadowBufferMethod('bufferSubData(0, size, map)')
620             print '        }'
621             print '    }'
622         if function.name == 'glUnmapNamedBufferEXT':
623             print '    GLint access_flags = 0;'
624             print '    _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
625             print '    if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
626             print '        GLvoid *map = NULL;'
627             print '        _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
628             print '        GLint length = 0;'
629             print '        _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
630             print '        if (map && length > 0) {'
631             self.emit_memcpy('map', 'map', 'length')
632             print '        }'
633             print '    }'
634         if function.name == 'glFlushMappedBufferRange':
635             print '    GLvoid *map = NULL;'
636             print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
637             print '    if (map && length > 0) {'
638             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
639             print '    }'
640         if function.name == 'glFlushMappedBufferRangeAPPLE':
641             print '    GLvoid *map = NULL;'
642             print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
643             print '    if (map && size > 0) {'
644             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
645             print '    }'
646         if function.name == 'glFlushMappedNamedBufferRangeEXT':
647             print '    GLvoid *map = NULL;'
648             print '    _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
649             print '    if (map && length > 0) {'
650             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
651             print '    }'
652
653         # Don't leave vertex attrib locations to chance.  Instead emit fake
654         # glBindAttribLocation calls to ensure that the same locations will be
655         # used when retracing.  Trying to remap locations after the fact would
656         # be an herculian task given that vertex attrib locations appear in
657         # many entry-points, including non-shader related ones.
658         if function.name == 'glLinkProgram':
659             Tracer.invokeFunction(self, function)
660             print '    GLint active_attributes = 0;'
661             print '    _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
662             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
663             print '        GLint size = 0;'
664             print '        GLenum type = 0;'
665             print '        GLchar name[256];'
666             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
667             print '        _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
668             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
669             print '            GLint location = _glGetAttribLocation(program, name);'
670             print '            if (location >= 0) {'
671             bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
672             self.fake_call(bind_function, ['program', 'location', 'name'])
673             print '            }'
674             print '        }'
675             print '    }'
676         if function.name == 'glLinkProgramARB':
677             Tracer.invokeFunction(self, function)
678             print '    GLint active_attributes = 0;'
679             print '    _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
680             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
681             print '        GLint size = 0;'
682             print '        GLenum type = 0;'
683             print '        GLcharARB name[256];'
684             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
685             print '        _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
686             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
687             print '            GLint location = _glGetAttribLocationARB(programObj, name);'
688             print '            if (location >= 0) {'
689             bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
690             self.fake_call(bind_function, ['programObj', 'location', 'name'])
691             print '            }'
692             print '        }'
693             print '    }'
694
695         self.shadowBufferProlog(function)
696
697         Tracer.traceFunctionImplBody(self, function)
698
699     # These entrypoints are only expected to be implemented by tools;
700     # drivers will probably not implement them.
701     marker_functions = [
702         # GL_GREMEDY_string_marker
703         'glStringMarkerGREMEDY',
704         # GL_GREMEDY_frame_terminator
705         'glFrameTerminatorGREMEDY',
706         # GL_EXT_debug_marker
707         'glInsertEventMarkerEXT',
708         'glPushGroupMarkerEXT',
709         'glPopGroupMarkerEXT',
710     ]
711
712     # These entrypoints may be implemented by drivers, but are also very useful
713     # for debugging / analysis tools.
714     debug_functions = [
715         # GL_KHR_debug
716         'glDebugMessageControl',
717         'glDebugMessageInsert',
718         'glDebugMessageCallback',
719         'glGetDebugMessageLog',
720         'glPushDebugGroup',
721         'glPopDebugGroup',
722         'glObjectLabel',
723         'glGetObjectLabel',
724         'glObjectPtrLabel',
725         'glGetObjectPtrLabel',
726         # GL_ARB_debug_output
727         'glDebugMessageControlARB',
728         'glDebugMessageInsertARB',
729         'glDebugMessageCallbackARB',
730         'glGetDebugMessageLogARB',
731         # GL_AMD_debug_output
732         'glDebugMessageEnableAMD',
733         'glDebugMessageInsertAMD',
734         'glDebugMessageCallbackAMD',
735         'glGetDebugMessageLogAMD',
736     ]
737
738     def invokeFunction(self, function):
739         if function.name in ('glLinkProgram', 'glLinkProgramARB'):
740             # These functions have been dispatched already
741             return
742
743         Tracer.invokeFunction(self, function)
744
745     def doInvokeFunction(self, function):
746         # Same as invokeFunction() but called both when trace is enabled or disabled.
747         #
748         # Used to modify the behavior of GL entry-points.
749
750         # Override GL extensions
751         if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
752             Tracer.doInvokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
753             return
754
755         # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
756         # driver
757         if function.name in self.marker_functions:
758             return
759
760         # We may be faking KHR_debug, so ensure the pointer queries result is
761         # always zeroed to prevent dereference of unitialized pointers
762         if function.name == 'glGetPointerv':
763             print '    if (params &&'
764             print '        (pname == GL_DEBUG_CALLBACK_FUNCTION ||'
765             print '         pname == GL_DEBUG_CALLBACK_USER_PARAM)) {'
766             print '        *params = NULL;'
767             print '    }'
768
769         if function.name in self.getProcAddressFunctionNames:
770             else_ = ''
771             for marker_function in self.marker_functions:
772                 if self.api.getFunctionByName(marker_function):
773                     print '    %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
774                     print '        _result = (%s)&%s;' % (function.type, marker_function)
775                     print '    }'
776                 else_ = 'else '
777             print '    %s{' % else_
778             Tracer.doInvokeFunction(self, function)
779
780             # Replace function addresses with ours
781             # XXX: Doing this here instead of wrapRet means that the trace will
782             # contain the addresses of the wrapper functions, and not the real
783             # functions, but in practice this should make no difference.
784             if function.name in self.getProcAddressFunctionNames:
785                 print '    _result = _wrapProcAddress(%s, _result);' % (function.args[0].name,)
786
787             print '    }'
788             return
789
790         Tracer.doInvokeFunction(self, function)
791
792     buffer_targets = [
793         'ARRAY_BUFFER',
794         'ELEMENT_ARRAY_BUFFER',
795         'PIXEL_PACK_BUFFER',
796         'PIXEL_UNPACK_BUFFER',
797         'UNIFORM_BUFFER',
798         'TEXTURE_BUFFER',
799         'TRANSFORM_FEEDBACK_BUFFER',
800         'COPY_READ_BUFFER',
801         'COPY_WRITE_BUFFER',
802         'DRAW_INDIRECT_BUFFER',
803         'ATOMIC_COUNTER_BUFFER',
804     ]
805
806     def wrapRet(self, function, instance):
807         Tracer.wrapRet(self, function, instance)
808
809         # Keep track of buffer mappings
810         if function.name in ('glMapBuffer', 'glMapBufferARB'):
811             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
812             print '    if (mapping) {'
813             print '        mapping->map = %s;' % (instance)
814             print '        mapping->length = 0;'
815             print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
816             print '        mapping->write = (access != GL_READ_ONLY);'
817             print '        mapping->explicit_flush = false;'
818             print '    }'
819         if function.name == 'glMapBufferRange':
820             print '    if (access & GL_MAP_WRITE_BIT) {'
821             print '        _checkBufferMapRange = true;'
822             print '    }'
823             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
824             print '    if (mapping) {'
825             print '        mapping->map = %s;' % (instance)
826             print '        mapping->length = length;'
827             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
828             print '        mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
829             print '    }'
830
831     boolean_names = [
832         'GL_FALSE',
833         'GL_TRUE',
834     ]
835
836     def gl_boolean(self, value):
837         return self.boolean_names[int(bool(value))]
838
839     # Names of the functions that unpack from a pixel buffer object.  See the
840     # ARB_pixel_buffer_object specification.
841     unpack_function_names = set([
842         'glBitmap',
843         'glColorSubTable',
844         'glColorTable',
845         'glCompressedMultiTexImage1DEXT',
846         'glCompressedMultiTexImage2DEXT',
847         'glCompressedMultiTexImage3DEXT',
848         'glCompressedMultiTexSubImage1DEXT',
849         'glCompressedMultiTexSubImage2DEXT',
850         'glCompressedMultiTexSubImage3DEXT',
851         'glCompressedTexImage1D',
852         'glCompressedTexImage2D',
853         'glCompressedTexImage3D',
854         'glCompressedTexSubImage1D',
855         'glCompressedTexSubImage2D',
856         'glCompressedTexSubImage3D',
857         'glCompressedTextureImage1DEXT',
858         'glCompressedTextureImage2DEXT',
859         'glCompressedTextureImage3DEXT',
860         'glCompressedTextureSubImage1DEXT',
861         'glCompressedTextureSubImage2DEXT',
862         'glCompressedTextureSubImage3DEXT',
863         'glConvolutionFilter1D',
864         'glConvolutionFilter2D',
865         'glDrawPixels',
866         'glMultiTexImage1DEXT',
867         'glMultiTexImage2DEXT',
868         'glMultiTexImage3DEXT',
869         'glMultiTexSubImage1DEXT',
870         'glMultiTexSubImage2DEXT',
871         'glMultiTexSubImage3DEXT',
872         'glPixelMapfv',
873         'glPixelMapuiv',
874         'glPixelMapusv',
875         'glPolygonStipple',
876         'glSeparableFilter2D',
877         'glTexImage1D',
878         'glTexImage1DEXT',
879         'glTexImage2D',
880         'glTexImage2DEXT',
881         'glTexImage3D',
882         'glTexImage3DEXT',
883         'glTexSubImage1D',
884         'glTexSubImage1DEXT',
885         'glTexSubImage2D',
886         'glTexSubImage2DEXT',
887         'glTexSubImage3D',
888         'glTexSubImage3DEXT',
889         'glTextureImage1DEXT',
890         'glTextureImage2DEXT',
891         'glTextureImage3DEXT',
892         'glTextureSubImage1DEXT',
893         'glTextureSubImage2DEXT',
894         'glTextureSubImage3DEXT',
895     ])
896
897     def serializeArgValue(self, function, arg):
898         # Recognize offsets instead of blobs when a PBO is bound
899         if function.name in self.unpack_function_names \
900            and (isinstance(arg.type, stdapi.Blob) \
901                 or (isinstance(arg.type, stdapi.Const) \
902                     and isinstance(arg.type.type, stdapi.Blob))):
903             print '    {'
904             print '        gltrace::Context *ctx = gltrace::getContext();'
905             print '        GLint _unpack_buffer = 0;'
906             print '        if (ctx->profile == gltrace::PROFILE_COMPAT)'
907             print '            _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
908             print '        if (_unpack_buffer) {'
909             print '            trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
910             print '        } else {'
911             Tracer.serializeArgValue(self, function, arg)
912             print '        }'
913             print '    }'
914             return
915
916         # Several GL state functions take GLenum symbolic names as
917         # integer/floats; so dump the symbolic name whenever possible
918         if function.name.startswith('gl') \
919            and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
920            and arg.name == 'param':
921             assert arg.index > 0
922             assert function.args[arg.index - 1].name == 'pname'
923             assert function.args[arg.index - 1].type == glapi.GLenum
924             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
925             self.serializeValue(glapi.GLenum, arg.name)
926             print '    } else {'
927             Tracer.serializeArgValue(self, function, arg)
928             print '    }'
929             return
930
931         Tracer.serializeArgValue(self, function, arg)
932
933     def footer(self, api):
934         Tracer.footer(self, api)
935
936         # A simple state tracker to track the pointer values
937         # update the state
938         print 'static void _trace_user_arrays(GLuint count)'
939         print '{'
940         print '    gltrace::Context *ctx = gltrace::getContext();'
941
942         for camelcase_name, uppercase_name in self.arrays:
943             # in which profile is the array available?
944             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
945             if camelcase_name in self.arrays_es1:
946                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
947
948             function_name = 'gl%sPointer' % camelcase_name
949             enable_name = 'GL_%s_ARRAY' % uppercase_name
950             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
951             function = api.getFunctionByName(function_name)
952
953             print '    // %s' % function.prototype()
954             print '  if (%s) {' % profile_check
955             self.array_trace_prolog(api, uppercase_name)
956             self.array_prolog(api, uppercase_name)
957             print '    if (_glIsEnabled(%s)) {' % enable_name
958             print '        GLint _binding = 0;'
959             print '        _glGetIntegerv(%s, &_binding);' % binding_name
960             print '        if (!_binding) {'
961
962             # Get the arguments via glGet*
963             for arg in function.args:
964                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
965                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
966                 print '            %s %s = 0;' % (arg_type, arg.name)
967                 print '            _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
968             
969             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
970             print '            size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
971
972             # Emit a fake function
973             self.array_trace_intermezzo(api, uppercase_name)
974             print '            unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
975             for arg in function.args:
976                 assert not arg.output
977                 print '            trace::localWriter.beginArg(%u);' % (arg.index,)
978                 if arg.name != 'pointer':
979                     self.serializeValue(arg.type, arg.name)
980                 else:
981                     print '            trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
982                 print '            trace::localWriter.endArg();'
983             
984             print '            trace::localWriter.endEnter();'
985             print '            trace::localWriter.beginLeave(_call);'
986             print '            trace::localWriter.endLeave();'
987             print '        }'
988             print '    }'
989             self.array_epilog(api, uppercase_name)
990             self.array_trace_epilog(api, uppercase_name)
991             print '  }'
992             print
993
994         # Samething, but for glVertexAttribPointer*
995         #
996         # Some variants of glVertexAttribPointer alias conventional and generic attributes:
997         # - glVertexAttribPointer: no
998         # - glVertexAttribPointerARB: implementation dependent
999         # - glVertexAttribPointerNV: yes
1000         #
1001         # This means that the implementations of these functions do not always
1002         # alias, and they need to be considered independently.
1003         #
1004         print '    // ES1 does not support generic vertex attributes'
1005         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
1006         print '        return;'
1007         print
1008         print '    vertex_attrib _vertex_attrib = _get_vertex_attrib();'
1009         print
1010         for suffix in ['', 'ARB', 'NV']:
1011             if suffix:
1012                 SUFFIX = '_' + suffix
1013             else:
1014                 SUFFIX = suffix
1015             function_name = 'glVertexAttribPointer' + suffix
1016             function = api.getFunctionByName(function_name)
1017
1018             print '    // %s' % function.prototype()
1019             print '    if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
1020             if suffix == 'NV':
1021                 print '        GLint _max_vertex_attribs = 16;'
1022             else:
1023                 print '        GLint _max_vertex_attribs = 0;'
1024                 print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
1025             print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
1026             print '            GLint _enabled = 0;'
1027             if suffix == 'NV':
1028                 print '            _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
1029             else:
1030                 print '            _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
1031             print '            if (_enabled) {'
1032             print '                GLint _binding = 0;'
1033             if suffix != 'NV':
1034                 # It doesn't seem possible to use VBOs with NV_vertex_program.
1035                 print '                _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
1036             print '                if (!_binding) {'
1037
1038             # Get the arguments via glGet*
1039             for arg in function.args[1:]:
1040                 if suffix == 'NV':
1041                     arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
1042                 else:
1043                     arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
1044                 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
1045                 print '                    %s %s = 0;' % (arg_type, arg.name)
1046                 print '                    _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
1047             
1048             arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
1049             print '                    size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
1050
1051             # Emit a fake function
1052             print '                    unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1053             for arg in function.args:
1054                 assert not arg.output
1055                 print '                    trace::localWriter.beginArg(%u);' % (arg.index,)
1056                 if arg.name != 'pointer':
1057                     self.serializeValue(arg.type, arg.name)
1058                 else:
1059                     print '                    trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
1060                 print '                    trace::localWriter.endArg();'
1061             
1062             print '                    trace::localWriter.endEnter();'
1063             print '                    trace::localWriter.beginLeave(_call);'
1064             print '                    trace::localWriter.endLeave();'
1065             print '                }'
1066             print '            }'
1067             print '        }'
1068             print '    }'
1069             print
1070
1071         print '}'
1072         print
1073
1074     #
1075     # Hooks for glTexCoordPointer, which is identical to the other array
1076     # pointers except the fact that it is indexed by glClientActiveTexture.
1077     #
1078
1079     def array_prolog(self, api, uppercase_name):
1080         if uppercase_name == 'TEXTURE_COORD':
1081             print '    GLint client_active_texture = 0;'
1082             print '    _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1083             print '    GLint max_texture_coords = 0;'
1084             print '    if (ctx->profile == gltrace::PROFILE_COMPAT)'
1085             print '        _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1086             print '    else'
1087             print '        _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1088             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1089             print '        GLint texture = GL_TEXTURE0 + unit;'
1090             print '        _glClientActiveTexture(texture);'
1091
1092     def array_trace_prolog(self, api, uppercase_name):
1093         if uppercase_name == 'TEXTURE_COORD':
1094             print '    bool client_active_texture_dirty = false;'
1095
1096     def array_epilog(self, api, uppercase_name):
1097         if uppercase_name == 'TEXTURE_COORD':
1098             print '    }'
1099         self.array_cleanup(api, uppercase_name)
1100
1101     def array_cleanup(self, api, uppercase_name):
1102         if uppercase_name == 'TEXTURE_COORD':
1103             print '    _glClientActiveTexture(client_active_texture);'
1104         
1105     def array_trace_intermezzo(self, api, uppercase_name):
1106         if uppercase_name == 'TEXTURE_COORD':
1107             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
1108             print '        client_active_texture_dirty = true;'
1109             self.fake_glClientActiveTexture_call(api, "texture");
1110             print '    }'
1111
1112     def array_trace_epilog(self, api, uppercase_name):
1113         if uppercase_name == 'TEXTURE_COORD':
1114             print '    if (client_active_texture_dirty) {'
1115             self.fake_glClientActiveTexture_call(api, "client_active_texture");
1116             print '    }'
1117
1118     def fake_glClientActiveTexture_call(self, api, texture):
1119         function = api.getFunctionByName('glClientActiveTexture')
1120         self.fake_call(function, [texture])
1121
1122     def emitFakeTexture2D(self):
1123         function = glapi.glapi.getFunctionByName('glTexImage2D')
1124         instances = function.argNames()
1125         print '        unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1126         for arg in function.args:
1127             assert not arg.output
1128             self.serializeArg(function, arg)
1129         print '        trace::localWriter.endEnter();'
1130         print '        trace::localWriter.beginLeave(_fake_call);'
1131         print '        trace::localWriter.endLeave();'
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142