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
30import re
31import sys
32
33from trace import Tracer
34from dispatch import function_pointer_type, function_pointer_value
35import specs.stdapi as stdapi
36import specs.glapi as glapi
37import specs.glparams as glparams
38from specs.glxapi import glxapi
39
40
41class TypeGetter(stdapi.Visitor):
42    '''Determine which glGet*v function that matches the specified type.'''
43
44    def __init__(self, prefix = 'glGet', long_suffix = True, ext_suffix = ''):
45        self.prefix = prefix
46        self.long_suffix = long_suffix
47        self.ext_suffix = ext_suffix
48
49    def visitConst(self, const):
50        return self.visit(const.type)
51
52    def visitAlias(self, alias):
53        if alias.expr == 'GLboolean':
54            if self.long_suffix:
55                suffix = 'Booleanv'
56                arg_type = alias.expr
57            else:
58                suffix = 'iv'
59                arg_type = 'GLint'
60        elif alias.expr == 'GLdouble':
61            if self.long_suffix:
62                suffix = 'Doublev'
63                arg_type = alias.expr
64            else:
65                suffix = 'dv'
66                arg_type = alias.expr
67        elif alias.expr == 'GLfloat':
68            if self.long_suffix:
69                suffix = 'Floatv'
70                arg_type = alias.expr
71            else:
72                suffix = 'fv'
73                arg_type = alias.expr
74        elif alias.expr in ('GLint', 'GLuint', 'GLsizei'):
75            if self.long_suffix:
76                suffix = 'Integerv'
77                arg_type = 'GLint'
78            else:
79                suffix = 'iv'
80                arg_type = 'GLint'
81        else:
82            print(alias.expr)
83            assert False
84        function_name = self.prefix + suffix + self.ext_suffix
85        return function_name, arg_type
86
87    def visitEnum(self, enum):
88        return self.visit(glapi.GLint)
89
90    def visitBitmask(self, bitmask):
91        return self.visit(glapi.GLint)
92
93    def visitOpaque(self, pointer):
94        return self.prefix + 'Pointerv' + self.ext_suffix, 'GLvoid *'
95
96
97class GlTracer(Tracer):
98
99    arrays = [
100        ("Vertex", "VERTEX"),
101        ("Normal", "NORMAL"),
102        ("Color", "COLOR"),
103        ("Index", "INDEX"),
104        ("TexCoord", "TEXTURE_COORD"),
105        ("EdgeFlag", "EDGE_FLAG"),
106        ("FogCoord", "FOG_COORD"),
107        ("SecondaryColor", "SECONDARY_COLOR"),
108    ]
109    arrays.reverse()
110
111    # arrays available in ES1
112    arrays_es1 = ("Vertex", "Normal", "Color", "TexCoord")
113
114    buffer_targets = [
115        "GL_ARRAY_BUFFER",
116        "GL_ATOMIC_COUNTER_BUFFER",
117        "GL_COPY_READ_BUFFER",
118        "GL_COPY_WRITE_BUFFER",
119        "GL_DRAW_INDIRECT_BUFFER",
120        "GL_DISPATCH_INDIRECT_BUFFER",
121        "GL_ELEMENT_ARRAY_BUFFER",
122        "GL_PIXEL_PACK_BUFFER",
123        "GL_PIXEL_UNPACK_BUFFER",
124        "GL_QUERY_BUFFER",
125        "GL_SHADER_STORAGE_BUFFER",
126        "GL_TEXTURE_BUFFER",
127        "GL_TRANSFORM_FEEDBACK_BUFFER",
128        "GL_UNIFORM_BUFFER",
129    ]
130
131    # Names of the functions that can pack into the current pixel buffer
132    # object.  See also the ARB_pixel_buffer_object specification.
133    pack_function_regex = re.compile(r'^gl(' + r'|'.join([
134        r'Getn?Histogram',
135        r'Getn?PolygonStipple',
136        r'Getn?PixelMap[a-z]+v',
137        r'Getn?Minmax',
138        r'Getn?(Convolution|Separable)Filter',
139        r'Getn?(Compressed)?(Multi)?Tex(ture)?(Sub)?Image',
140        r'Readn?Pixels',
141    ]) + r')[0-9A-Z]*$')
142
143    def header(self, api):
144        Tracer.header(self, api)
145
146        print('#include <algorithm>')
147        print('#include "cxx_compat.hpp"')
148        print()
149        print('#include "gltrace.hpp"')
150        print('#include "gltrace_arrays.hpp"')
151        print('#include "glmemshadow.hpp"')
152        print()
153
154        # Whether we need user arrays
155        print('static inline bool _need_user_arrays(gltrace::Context *_ctx)')
156        print('{')
157        print('    if (!_ctx->user_arrays) {')
158        print('        return false;')
159        print('    }')
160        print()
161        print('    glfeatures::Profile profile = _ctx->profile;')
162        print('    bool es1 = profile.es() && profile.major == 1;')
163        print()
164
165        for camelcase_name, uppercase_name in self.arrays:
166            # in which profile is the array available?
167            profile_check = 'profile.desktop()'
168            if camelcase_name in self.arrays_es1:
169                profile_check = '(' + profile_check + ' || es1)';
170
171            function_name = 'gl%sPointer' % camelcase_name
172            enable_name = 'GL_%s_ARRAY' % uppercase_name
173            binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
174            print('    // %s' % function_name)
175            print('  if (%s) {' % profile_check)
176            self.array_prolog(api, uppercase_name)
177            print('    if (_glIsEnabled(%s) &&' % enable_name)
178            print('        _glGetInteger(%s) == 0) {' % binding_name)
179            self.array_cleanup(api, uppercase_name)
180            print('        return true;')
181            print('    }')
182            self.array_epilog(api, uppercase_name)
183            print('  }')
184            print()
185
186        print('    // ES1 does not support generic vertex attributes')
187        print('    if (es1)')
188        print('        return false;')
189        print()
190        print('    // glVertexAttribPointer')
191        print('    GLint _max_vertex_attribs = _glGetInteger(GL_MAX_VERTEX_ATTRIBS);')
192        print('    for (GLint index = 0; index < _max_vertex_attribs; ++index) {')
193        print('        if (_glGetVertexAttribi(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED) &&')
194        print('            _glGetVertexAttribi(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) == 0) {')
195        print('            return true;')
196        print('        }')
197        print('    }')
198        print()
199
200        print('    return false;')
201        print('}')
202        print()
203
204        print(r'static void _trace_user_arrays(gltrace::Context *_ctx, GLuint count);')
205        print()
206
207        # Declare helper functions to emit fake function calls into the trace
208        for function in api.getAllFunctions():
209            if function.name in self.fake_function_names:
210                print(function.prototype('_fake_' + function.name) + ';')
211        print()
212        print(r'static inline void')
213        print(r'_fakeStringMarker(const std::string &s) {')
214        print(r'    _fake_glStringMarkerGREMEDY(s.length(), s.data());')
215        print(r'}')
216        print()
217
218        # Buffer mappings
219        print('// whether glMapBufferRange(GL_MAP_WRITE_BIT) has ever been called')
220        print('static bool _checkBufferMapRange = false;')
221        print()
222        print('// whether glBufferParameteriAPPLE(GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE) has ever been called')
223        print('static bool _checkBufferFlushingUnmapAPPLE = false;')
224        print()
225
226        # Generate a helper function to determine whether a parameter name
227        # refers to a symbolic value or not
228        print('static bool')
229        print('is_symbolic_pname(GLenum pname) {')
230        print('    switch (pname) {')
231        for function, type, count, name in glparams.parameters:
232            if type is glapi.GLenum:
233                print('    case %s:' % name)
234        print('        return true;')
235        print('    default:')
236        print('        return false;')
237        print('    }')
238        print('}')
239        print()
240
241        # Generate a helper function to determine whether a parameter value is
242        # potentially symbolic or not; i.e., if the value can be represented in
243        # an enum or not
244        print('template<class T>')
245        print('static inline bool')
246        print('is_symbolic_param(T param) {')
247        print('    return static_cast<T>(static_cast<GLenum>(param)) == param;')
248        print('}')
249        print()
250
251        # Generate a helper function to know how many elements a parameter has
252        print('static size_t')
253        print('_gl_param_size(GLenum pname) {')
254        print('    switch (pname) {')
255        for function, type, count, name in glparams.parameters:
256            if name == 'GL_PROGRAM_BINARY_FORMATS':
257                count = 0
258            if type is not None:
259                print('    case %s: return %s;' % (name, count))
260        print('    default:')
261        print(r'        os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);')
262        print('        return 1;')
263        print('    }')
264        print('}')
265        print()
266
267        # Generate a helper function to get buffer binding
268        print('static GLenum')
269        print('getBufferBinding(GLenum target) {')
270        print('    switch (target) {')
271        for target in self.buffer_targets:
272            print('    case %s:' % target)
273            print('        return %s_BINDING;' % target)
274        print('    default:')
275        print('        assert(false);')
276        print('        return 0;')
277        print('    }')
278        print('}')
279        print()
280
281        print('static GLint')
282        print('getBufferName(GLenum target) {')
283        print('    GLint bufferName = 0;')
284        print('    _glGetIntegerv(getBufferBinding(target), &bufferName);')
285        print('    assert(bufferName != 0);')
286        print('    return bufferName;')
287        print('}')
288        print()
289
290        # states such as GL_UNPACK_ROW_LENGTH are not available in GLES
291        print('static inline bool')
292        print('can_unpack_subimage(void) {')
293        print('    gltrace::Context *_ctx = gltrace::getContext();')
294        print('    return _ctx->features.unpack_subimage;')
295        print('}')
296        print()
297
298        # VMWX_map_buffer_debug
299        print(r'extern "C" PUBLIC')
300        print(r'void APIENTRY')
301        print(r'glNotifyMappedBufferRangeVMWX(const void * start, GLsizeiptr length) {')
302        self.emit_memcpy('start', 'length')
303        print(r'}')
304        print()
305
306    getProcAddressFunctionNames = []
307
308    def traceApi(self, api):
309        if self.getProcAddressFunctionNames:
310            # Generate a function to wrap proc addresses
311            getProcAddressFunction = api.getFunctionByName(self.getProcAddressFunctionNames[0])
312            argType = getProcAddressFunction.args[0].type
313            retType = getProcAddressFunction.type
314
315            print('static %s _wrapProcAddress(%s procName, %s procPtr);' % (retType, argType, retType))
316            print()
317
318            Tracer.traceApi(self, api)
319
320            print('static %s _wrapProcAddress(%s procName, %s procPtr) {' % (retType, argType, retType))
321
322            # Provide fallback functions to missing debug functions
323            print('    if (!procPtr) {')
324            else_ = ''
325            for function_name in self.debug_functions:
326                if self.api.getFunctionByName(function_name):
327                    print('        %sif (strcmp("%s", (const char *)procName) == 0) {' % (else_, function_name))
328                    print('            return (%s)&%s;' % (retType, function_name))
329                    print('        }')
330                else_ = 'else '
331            print('        %s{' % else_)
332            print('            return NULL;')
333            print('        }')
334            print('    }')
335
336            for function in api.getAllFunctions():
337                ptype = function_pointer_type(function)
338                pvalue = function_pointer_value(function)
339                print('    if (strcmp("%s", (const char *)procName) == 0) {' % function.name)
340                print('        assert(procPtr != (%s)&%s);' % (retType, function.name))
341                print('        %s = (%s)procPtr;' % (pvalue, ptype))
342                print('        return (%s)&%s;' % (retType, function.name,))
343                print('    }')
344            print('    os::log("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);')
345            print('    return procPtr;')
346            print('}')
347            print()
348        else:
349            Tracer.traceApi(self, api)
350
351    array_pointer_function_names = set((
352        "glVertexPointer",
353        "glNormalPointer",
354        "glColorPointer",
355        "glIndexPointer",
356        "glTexCoordPointer",
357        "glEdgeFlagPointer",
358        "glFogCoordPointer",
359        "glSecondaryColorPointer",
360
361        "glInterleavedArrays",
362
363        "glVertexPointerEXT",
364        "glNormalPointerEXT",
365        "glColorPointerEXT",
366        "glIndexPointerEXT",
367        "glTexCoordPointerEXT",
368        "glEdgeFlagPointerEXT",
369        "glFogCoordPointerEXT",
370        "glSecondaryColorPointerEXT",
371
372        "glVertexAttribPointer",
373        "glVertexAttribPointerARB",
374        "glVertexAttribPointerNV",
375        "glVertexAttribIPointer",
376        "glVertexAttribIPointerEXT",
377        "glVertexAttribLPointer",
378        "glVertexAttribLPointerEXT",
379
380        #"glMatrixIndexPointerARB",
381    ))
382
383    # XXX: We currently ignore the gl*Draw*ElementArray* functions
384    draw_function_regex = re.compile(r'^(?P<radical>gl([A-Z][a-z]+)*Draw(Range)?(Arrays|Elements))(?P<suffix>[A-Z][a-zA-Z]*)?$' )
385
386    interleaved_formats = [
387         'GL_V2F',
388         'GL_V3F',
389         'GL_C4UB_V2F',
390         'GL_C4UB_V3F',
391         'GL_C3F_V3F',
392         'GL_N3F_V3F',
393         'GL_C4F_N3F_V3F',
394         'GL_T2F_V3F',
395         'GL_T4F_V4F',
396         'GL_T2F_C4UB_V3F',
397         'GL_T2F_C3F_V3F',
398         'GL_T2F_N3F_V3F',
399         'GL_T2F_C4F_N3F_V3F',
400         'GL_T4F_C4F_N3F_V4F',
401    ]
402
403    def traceFunctionImplBody(self, function):
404        # Defer tracing of user array pointers...
405        if function.name in self.array_pointer_function_names:
406            print('    GLint _array_buffer = _glGetInteger(GL_ARRAY_BUFFER_BINDING);')
407            print('    if (!_array_buffer) {')
408            print('        static bool warned = false;')
409            print('        if (!warned) {')
410            print('            warned = true;')
411            print('            os::log("apitrace: warning: %s: call will be faked due to pointer to user memory (https://github.com/apitrace/apitrace/blob/master/docs/BUGS.markdown#tracing)\\n", __FUNCTION__);')
412            print('        }')
413            print('        gltrace::Context *_ctx = gltrace::getContext();')
414            print('        _ctx->user_arrays = true;')
415            if function.name == "glVertexAttribPointerNV":
416                print(r'        os::log("apitrace: warning: %s: user memory arrays with NV_vertex_program longer supported\n", __FUNCTION__);')
417            self.invokeFunction(function)
418
419            # And also break down glInterleavedArrays into the individual calls
420            if function.name == 'glInterleavedArrays':
421                print()
422
423                # Initialize the enable flags
424                for camelcase_name, uppercase_name in self.arrays:
425                    flag_name = '_' + uppercase_name.lower()
426                    print('        GLboolean %s = GL_FALSE;' % flag_name)
427                print()
428
429                # Switch for the interleaved formats
430                print('        switch (format) {')
431                for format in self.interleaved_formats:
432                    print('            case %s:' % format)
433                    for camelcase_name, uppercase_name in self.arrays:
434                        flag_name = '_' + uppercase_name.lower()
435                        if format.find('_' + uppercase_name[0]) >= 0:
436                            print('                %s = GL_TRUE;' % flag_name)
437                    print('                break;')
438                print('            default:')
439                print('               return;')
440                print('        }')
441                print()
442
443                # Emit fake glEnableClientState/glDisableClientState flags
444                for camelcase_name, uppercase_name in self.arrays:
445                    flag_name = '_' + uppercase_name.lower()
446                    enable_name = 'GL_%s_ARRAY' % uppercase_name
447
448                    # Emit a fake function
449                    print('        if (%s) {' % flag_name)
450                    print('            _fake_glEnableClientState(%s);' % enable_name)
451                    print('        } else {')
452                    print('            _fake_glDisableClientState(%s);' % enable_name)
453                    print('        }')
454
455            # Warn about buggy glGet(GL_*ARRAY_SIZE) not returning GL_BGRA
456            buggyFunctions = {
457                'glColorPointer':           ('glGetIntegerv',          '',        'GL_COLOR_ARRAY_SIZE'),
458                'glSecondaryColorPointer':  ('glGetIntegerv',          '',        'GL_SECONDARY_COLOR_ARRAY_SIZE'),
459                'glVertexAttribPointer':    ('glGetVertexAttribiv',    'index, ', 'GL_VERTEX_ATTRIB_ARRAY_SIZE'),
460                'glVertexAttribPointerARB': ('glGetVertexAttribivARB', 'index, ', 'GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB'),
461            }
462            if function.name in buggyFunctions:
463                getter, extraArg, pname = buggyFunctions[function.name]
464                print(r'        static bool _checked = false;')
465                print(r'        if (!_checked && size == GL_BGRA) {')
466                print(r'            GLint _size = 0;')
467                print(r'            _%s(%s%s, &_size);' % (getter, extraArg, pname))
468                print(r'            if (_size != GL_BGRA) {')
469                print(r'                os::log("apitrace: warning: %s(%s) does not return GL_BGRA; trace will be incorrect (https://github.com/apitrace/apitrace/issues/261)\n");' % (getter, pname))
470                print(r'            }')
471                print(r'            _checked = true;')
472                print(r'        }')
473
474            print('        return;')
475            print('    }')
476
477        # ... to the draw calls
478        mo = self.draw_function_regex.match(function.name)
479        if mo:
480            functionRadical = mo.group('radical')
481            print('    gltrace::Context *_ctx = gltrace::getContext();')
482
483            print('    GLMemoryShadow::commitAllWrites(_ctx, trace::fakeMemcpy);')
484
485            print('    if (_need_user_arrays(_ctx)) {')
486            if 'Indirect' in function.name:
487                print(r'        os::log("apitrace: warning: %s: indirect user arrays not supported\n");' % (function.name,))
488            else:
489                # Pick the corresponding *Params
490                if 'Arrays' in functionRadical:
491                    paramsType = 'DrawArraysParams'
492                elif 'Elements' in functionRadical:
493                    paramsType = 'DrawElementsParams'
494                else:
495                    assert 0
496                if 'Multi' in functionRadical:
497                    assert 'drawcount' in function.argNames()
498                    paramsType = 'Multi' + paramsType
499                print(r'        %s _params;' % paramsType)
500
501                for arg in function.args:
502                    paramsMember = arg.name.lower()
503                    if paramsMember in ('mode', 'modestride'):
504                        continue
505                    print(r'        _params.%s = %s;' % (paramsMember, arg.name))
506
507                print('        GLuint _count = _glDraw_count(_ctx, _params);')
508                print('        _trace_user_arrays(_ctx, _count);')
509            print('    }')
510
511        if function.name.startswith("glDispatchCompute"):
512            print('    gltrace::Context *_ctx = gltrace::getContext();')
513            print('    GLMemoryShadow::commitAllWrites(_ctx, trace::fakeMemcpy);')
514
515        if function.name == 'glLockArraysEXT':
516            print('    gltrace::Context *_ctx = gltrace::getContext();')
517            print('    if (_ctx) {')
518            print('        _ctx->lockedArrayCount = first + count;')
519            print('    }')
520
521        # Warn if user arrays are used with glBegin/glArrayElement/glEnd.
522        if function.name == 'glBegin':
523            print(r'    gltrace::Context *_ctx = gltrace::getContext();')
524            print(r'    _ctx->userArraysOnBegin = _need_user_arrays(_ctx);')
525        if function.name.startswith('glArrayElement'):
526            print(r'    gltrace::Context *_ctx = gltrace::getContext();')
527            print(r'    if (_ctx->userArraysOnBegin) {')
528            print(r'        os::log("apitrace: warning: user arrays with glArrayElement not supported (https://github.com/apitrace/apitrace/issues/276)\n");')
529            print(r'        _ctx->userArraysOnBegin = false;')
530            print(r'    }')
531
532        # Emit a fake memcpy on buffer uploads
533        if function.name == 'glBufferParameteriAPPLE':
534            print('    if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {')
535            print('        _checkBufferFlushingUnmapAPPLE = true;')
536            print('    }')
537        if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
538            if function.name.endswith('ARB'):
539                suffix = 'ARB'
540            else:
541                suffix = ''
542            print('    GLint access_flags = 0;')
543            print('    GLint access = 0;')
544            print('    bool flush;')
545            print('    // GLES3 does not have GL_BUFFER_ACCESS;')
546            print('    if (_checkBufferMapRange) {')
547            print('        _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);' % suffix)
548            print('        flush = (access_flags & GL_MAP_WRITE_BIT) && !(access_flags & (GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_PERSISTENT_BIT));')
549            print('    } else {')
550            print('        _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix)
551            print('        flush = access != GL_READ_ONLY;')
552            print('    }')
553            print('    if ((access_flags & GL_MAP_COHERENT_BIT) && (access_flags & GL_MAP_WRITE_BIT)) {')
554            print('        gltrace::Context *_ctx = gltrace::getContext();')
555            print('        GLint buffer = getBufferName(target);')
556            print('        auto it = _ctx->bufferToShadowMemory.find(buffer);')
557            print('        if (it != _ctx->bufferToShadowMemory.end()) {')
558            print('            it->second->unmap(trace::fakeMemcpy);')
559            print('        } else {')
560            print(r'            os::log("apitrace: error: %s: cannot find memory shadow\n", __FUNCTION__);')
561            print('        }')
562            print('        flush = false;')
563            print('    }')
564            print('    if (flush) {')
565            print('        GLvoid *map = NULL;')
566            print('        _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);'  % suffix)
567            print('        if (map) {')
568            print('            GLint length = -1;')
569            print('            if (_checkBufferMapRange) {')
570            print('                _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix)
571            print('                if (length == -1) {')
572            print('                    // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0 up-to')
573            print('                    // http://cgit.freedesktop.org/mesa/mesa/commit/?id=ffee498fb848b253a7833373fe5430f8c7ca0c5f')
574            print('                    static bool warned = false;')
575            print('                    if (!warned) {')
576            print('                        os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix)
577            print('                        warned = true;')
578            print('                    }')
579            print('                }')
580            print('            } else {')
581            print('                length = 0;')
582            print('                _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix)
583            print('            }')
584            print('            if (_checkBufferFlushingUnmapAPPLE) {')
585            print('                GLint flushing_unmap = GL_TRUE;')
586            print('                _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix)
587            print('                flush = flush && flushing_unmap;')
588            print('            }')
589            print('            if (flush && length > 0) {')
590            self.emit_memcpy('map', 'length')
591            print('            }')
592            print('        }')
593            print('    }')
594        if function.name == 'glUnmapBufferOES':
595            print('    GLint access_flags = 0;')
596            print('    GLint access = 0;')
597            print('    bool flush;')
598            print('    // GLES3 does not have GL_BUFFER_ACCESS;')
599            print('    if (_checkBufferMapRange) {')
600            print('        _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);')
601            print('        flush = (access_flags & GL_MAP_WRITE_BIT) && !(access_flags & (GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_PERSISTENT_BIT));')
602            print('    } else {')
603            print('        _glGetBufferParameteriv(target, GL_BUFFER_ACCESS, &access);')
604            print('        flush = access != GL_READ_ONLY;')
605            print('    }')
606            print('    if (flush) {')
607            print('        GLvoid *map = NULL;')
608            print('        _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER, &map);')
609            print('        if (map) {')
610            print('            GLint length = 0;')
611            print('            GLint offset = 0;')
612            print('            if (_checkBufferMapRange) {')
613            print('                _glGetBufferParameteriv(target, GL_BUFFER_MAP_LENGTH, &length);')
614            print('                _glGetBufferParameteriv(target, GL_BUFFER_MAP_OFFSET, &offset);')
615            print('            } else {')
616            print('                _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);')
617            print('            }')
618            print('            if (flush && length > 0) {')
619            self.emit_memcpy('map', 'length')
620            print('            }')
621            print('        }')
622            print('    }')
623        if function.name == 'glUnmapNamedBuffer':
624            print('    GLint access_flags = 0;')
625            print('    _glGetNamedBufferParameteriv(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);')
626            print('    if ((access_flags & GL_MAP_COHERENT_BIT) && (access_flags & GL_MAP_WRITE_BIT)) {')
627            print('        gltrace::Context *_ctx = gltrace::getContext();')
628            print('        auto it = _ctx->bufferToShadowMemory.find(buffer);')
629            print('        if (it != _ctx->bufferToShadowMemory.end()) {')
630            print('            it->second->unmap(trace::fakeMemcpy);')
631            print('        } else {')
632            print(r'            os::log("apitrace: error: %s: cannot find memory shadow\n", __FUNCTION__);')
633            print('        }')
634            print('    } else if ((access_flags & GL_MAP_WRITE_BIT) &&')
635            print('               !(access_flags & (GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_PERSISTENT_BIT))) {')
636            print('        GLvoid *map = NULL;')
637            print('        _glGetNamedBufferPointerv(buffer, GL_BUFFER_MAP_POINTER, &map);')
638            print('        GLint length = 0;')
639            print('        _glGetNamedBufferParameteriv(buffer, GL_BUFFER_MAP_LENGTH, &length);')
640            print('        if (map && length > 0) {')
641            self.emit_memcpy('map', 'length')
642            print('        }')
643            print('    }')
644        if function.name == 'glUnmapNamedBufferEXT':
645            print('    GLint access_flags = 0;')
646            print('    _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);')
647            print('    if ((access_flags & GL_MAP_COHERENT_BIT) && (access_flags & GL_MAP_WRITE_BIT)) {')
648            print('        gltrace::Context *_ctx = gltrace::getContext();')
649            print('        auto it = _ctx->bufferToShadowMemory.find(buffer);')
650            print('        if (it != _ctx->bufferToShadowMemory.end()) {')
651            print('            it->second->unmap(trace::fakeMemcpy);')
652            print('        } else {')
653            print(r'            os::log("apitrace: error: %s: cannot find memory shadow\n", __FUNCTION__);')
654            print('        }')
655            print('    } else if ((access_flags & GL_MAP_WRITE_BIT) &&')
656            print('               !(access_flags & (GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_PERSISTENT_BIT))) {')
657            print('        GLvoid *map = NULL;')
658            print('        _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);')
659            print('        GLint length = 0;')
660            print('        _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);')
661            print('        if (map && length > 0) {')
662            self.emit_memcpy('map', 'length')
663            print('        }')
664            print('    }')
665        if function.name == 'glFlushMappedBufferRange':
666            print('    GLvoid *map = NULL;')
667            print('    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);')
668            print('    if (map && length > 0) {')
669            self.emit_memcpy('(const char *)map + offset', 'length')
670            print('    }')
671        if function.name == 'glFlushMappedBufferRangeEXT':
672            print('    GLvoid *map = NULL;')
673            print('    _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);')
674            print('    if (map && length > 0) {')
675            self.emit_memcpy('(const char *)map + offset', 'length')
676            print('    }')
677        if function.name == 'glFlushMappedBufferRangeAPPLE':
678            print('    GLvoid *map = NULL;')
679            print('    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);')
680            print('    if (map && size > 0) {')
681            self.emit_memcpy('(const char *)map + offset', 'size')
682            print('    }')
683        if function.name == 'glFlushMappedNamedBufferRange':
684            print('    GLvoid *map = NULL;')
685            print('    _glGetNamedBufferPointerv(buffer, GL_BUFFER_MAP_POINTER, &map);')
686            print('    if (map && length > 0) {')
687            self.emit_memcpy('(const char *)map + offset', 'length')
688            print('    }')
689        if function.name == 'glFlushMappedNamedBufferRangeEXT':
690            print('    GLvoid *map = NULL;')
691            print('    _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);')
692            print('    if (map && length > 0) {')
693            self.emit_memcpy('(const char *)map + offset', 'length')
694            print('    }')
695
696        # FIXME: We don't support AMD_pinned_memory
697        if function.name in ('glBufferStorage', 'glNamedBufferStorage', 'glNamedBufferStorageEXT'):
698            print(r'    if (flags & GL_MAP_NOTIFY_EXPLICIT_BIT_VMWX) {')
699            print(r'        if (!(flags & GL_MAP_PERSISTENT_BIT)) {')
700            print(r'            os::log("apitrace: warning: %s: MAP_NOTIFY_EXPLICIT_BIT_VMWX set w/o MAP_PERSISTENT_BIT\n", __FUNCTION__);')
701            print(r'        }')
702            print(r'        if (!(flags & GL_MAP_WRITE_BIT)) {')
703            print(r'            os::log("apitrace: warning: %s: MAP_NOTIFY_EXPLICIT_BIT_VMWX set w/o MAP_WRITE_BIT\n", __FUNCTION__);')
704            print(r'        }')
705            print(r'        flags &= ~GL_MAP_NOTIFY_EXPLICIT_BIT_VMWX;')
706            print(r'    }')
707            print(r'')
708            print(r'    if ((flags & GL_MAP_COHERENT_BIT) && (flags & GL_MAP_WRITE_BIT)) {')
709            print(r'        gltrace::Context *_ctx = gltrace::getContext();')
710            if function.name in ('glBufferStorage'):
711                print(r'        GLint buffer = getBufferName(target);')
712            print(r'        auto memoryShadow = std::make_unique<GLMemoryShadow>();')
713            print(r'        const bool success = memoryShadow->init(data, size);')
714            print(r'        if (success) {')
715            print(r'            _ctx->bufferToShadowMemory.insert(std::make_pair(buffer, std::move(memoryShadow)));')
716            print(r'        } else {')
717            print(r'            os::log("apitrace: error: %s: cannot create memory shadow\n", __FUNCTION__);')
718            print(r'        }')
719            print(r'    }')
720        if function.name in ('glMapBufferRange', 'glMapBufferRangeEXT', 'glMapNamedBufferRange', 'glMapNamedBufferRangeEXT'):
721            print(r'    if (access & GL_MAP_NOTIFY_EXPLICIT_BIT_VMWX) {')
722            print(r'        if (!(access & GL_MAP_PERSISTENT_BIT)) {')
723            print(r'            os::log("apitrace: warning: %s: MAP_NOTIFY_EXPLICIT_BIT_VMWX set w/o MAP_PERSISTENT_BIT\n", __FUNCTION__);')
724            print(r'        }')
725            print(r'        if (!(access & GL_MAP_WRITE_BIT)) {')
726            print(r'            os::log("apitrace: warning: %s: MAP_NOTIFY_EXPLICIT_BIT_VMWX set w/o MAP_WRITE_BIT\n", __FUNCTION__);')
727            print(r'        }')
728            print(r'        if (access & GL_MAP_FLUSH_EXPLICIT_BIT) {')
729            print(r'            os::log("apitrace: warning: %s: MAP_NOTIFY_EXPLICIT_BIT_VMWX set w/ MAP_FLUSH_EXPLICIT_BIT\n", __FUNCTION__);')
730            print(r'        }')
731            print(r'        access &= ~GL_MAP_NOTIFY_EXPLICIT_BIT_VMWX;')
732            print(r'    }')
733        if function.name in ('glBufferData', 'glBufferDataARB'):
734            print(r'    if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) {')
735            print(r'        os::log("apitrace: warning: GL_AMD_pinned_memory not fully supported\n");')
736            print(r'    }')
737
738        # TODO: We don't track GL_INTEL_map_texture mappings
739        if function.name == 'glMapTexture2DINTEL':
740            print(r'    if (access & GL_MAP_WRITE_BIT) {')
741            print(r'        os::log("apitrace: warning: GL_INTEL_map_texture not fully supported\n");')
742            print(r'    }')
743
744        # Operations on PBO may use coherent buffers so we must commit them first
745        if self.unpack_function_regex.match(function.name) or self.pack_function_regex.match(function.name):
746            print('    gltrace::Context *_ctx = gltrace::getContext();')
747            print('    GLMemoryShadow::commitAllWrites(_ctx, trace::fakeMemcpy);')
748            print('')
749
750        # Don't leave vertex attrib locations to chance.  Instead emit fake
751        # glBindAttribLocation calls to ensure that the same locations will be
752        # used when retracing.  Trying to remap locations after the fact would
753        # be an herculian task given that vertex attrib locations appear in
754        # many entry-points, including non-shader related ones.
755        if function.name == 'glLinkProgram':
756            Tracer.invokeFunction(self, function)
757            print('    GLint active_attributes = 0;')
758            print('    _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);')
759            print('    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {')
760            print('        GLint size = 0;')
761            print('        GLenum type = 0;')
762            print('        GLchar name[256];')
763            # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
764            print('        _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);')
765            print("        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {")
766            print('            GLint location = _glGetAttribLocation(program, name);')
767            print('            if (location >= 0) {')
768            print('                _fake_glBindAttribLocation(program, location, name);')
769            print('            }')
770            print('        }')
771            print('    }')
772        if function.name == 'glLinkProgramARB':
773            Tracer.invokeFunction(self, function)
774            print('    GLint active_attributes = 0;')
775            print('    _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);')
776            print('    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {')
777            print('        GLint size = 0;')
778            print('        GLenum type = 0;')
779            print('        GLcharARB name[256];')
780            # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
781            print('        _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);')
782            print("        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {")
783            print('            GLint location = _glGetAttribLocationARB(programObj, name);')
784            print('            if (location >= 0) {')
785            print('                _fake_glBindAttribLocationARB(programObj, location, name);')
786            print('            }')
787            print('        }')
788            print('    }')
789
790        Tracer.traceFunctionImplBody(self, function)
791
792    # These entrypoints are only expected to be implemented by tools;
793    # drivers will probably not implement them.
794    marker_functions = [
795        # GL_GREMEDY_string_marker
796        'glStringMarkerGREMEDY',
797        # GL_GREMEDY_frame_terminator
798        'glFrameTerminatorGREMEDY',
799    ]
800
801    # These entrypoints may be implemented by drivers, but are also very useful
802    # for debugging / analysis tools.
803    debug_functions = [
804        # GL_KHR_debug
805        'glDebugMessageControl',
806        'glDebugMessageInsert',
807        'glDebugMessageCallback',
808        'glGetDebugMessageLog',
809        'glPushDebugGroup',
810        'glPopDebugGroup',
811        'glObjectLabel',
812        'glGetObjectLabel',
813        'glObjectPtrLabel',
814        'glGetObjectPtrLabel',
815        # GL_KHR_debug (for OpenGL ES)
816        'glDebugMessageControlKHR',
817        'glDebugMessageInsertKHR',
818        'glDebugMessageCallbackKHR',
819        'glGetDebugMessageLogKHR',
820        'glPushDebugGroupKHR',
821        'glPopDebugGroupKHR',
822        'glObjectLabelKHR',
823        'glGetObjectLabelKHR',
824        'glObjectPtrLabelKHR',
825        'glGetObjectPtrLabelKHR',
826        # GL_ARB_debug_output
827        'glDebugMessageControlARB',
828        'glDebugMessageInsertARB',
829        'glDebugMessageCallbackARB',
830        'glGetDebugMessageLogARB',
831        # GL_AMD_debug_output
832        'glDebugMessageEnableAMD',
833        'glDebugMessageInsertAMD',
834        'glDebugMessageCallbackAMD',
835        'glGetDebugMessageLogAMD',
836        # GL_EXT_debug_label
837        'glLabelObjectEXT',
838        'glGetObjectLabelEXT',
839        # GL_EXT_debug_marker
840        'glInsertEventMarkerEXT',
841        'glPushGroupMarkerEXT',
842        'glPopGroupMarkerEXT',
843    ]
844
845    def invokeFunction(self, function):
846        if function.name in ('glLinkProgram', 'glLinkProgramARB'):
847            # These functions have been dispatched already
848            return
849
850        # Force glProgramBinary to fail.  Per ARB_get_program_binary this
851        # should signal the app that it needs to recompile.
852        if function.name in ('glProgramBinary', 'glProgramBinaryOES'):
853            print(r'   binaryFormat = 0xDEADDEAD;')
854            print(r'   binary = &binaryFormat;')
855            print(r'   length = sizeof binaryFormat;')
856
857        Tracer.invokeFunction(self, function)
858
859    def doInvokeFunction(self, function):
860        # Same as invokeFunction() but called both when trace is enabled or disabled.
861        #
862        # Used to modify the behavior of GL entry-points.
863
864        # Override GL extensions
865        if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
866            Tracer.doInvokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
867            return
868
869        # We implement GL_GREMEDY_*, etc., and not the driver
870        if function.name in self.marker_functions:
871            return
872
873        # We may be faking KHR_debug, so ensure the pointer queries result is
874        # always zeroed to prevent dereference of unitialized pointers
875        if function.name == 'glGetPointerv':
876            print('    if (params &&')
877            print('        (pname == GL_DEBUG_CALLBACK_FUNCTION ||')
878            print('         pname == GL_DEBUG_CALLBACK_USER_PARAM)) {')
879            print('        *params = NULL;')
880            print('    }')
881
882        if function.name in self.getProcAddressFunctionNames:
883            nameArg = function.args[0].name
884            print('    if (strcmp("glNotifyMappedBufferRangeVMWX", (const char *)%s) == 0) {' % (nameArg,))
885            print('        _result = (%s)&glNotifyMappedBufferRangeVMWX;' % (function.type,))
886            for marker_function in self.marker_functions:
887                if self.api.getFunctionByName(marker_function):
888                    print('    } else if (strcmp("%s", (const char *)%s) == 0) {' % (marker_function, nameArg))
889                    print('        _result = (%s)&%s;' % (function.type, marker_function))
890            print('    } else {')
891            Tracer.doInvokeFunction(self, function)
892
893            # Replace function addresses with ours
894            # XXX: Doing this here instead of wrapRet means that the trace will
895            # contain the addresses of the wrapper functions, and not the real
896            # functions, but in practice this should make no difference.
897            if function.name in self.getProcAddressFunctionNames:
898                print('    _result = _wrapProcAddress(%s, _result);' % (nameArg,))
899
900            print('    }')
901            return
902
903        if function.name in ('glGetProgramBinary', 'glGetProgramBinaryOES'):
904            print(r'    bufSize = 0;')
905
906        Tracer.doInvokeFunction(self, function)
907
908        if function.name in ('glMapBufferRange', 'glMapBufferRangeEXT', 'glMapNamedBufferRange', 'glMapNamedBufferRangeEXT'):
909            print(r'    if ((access & GL_MAP_COHERENT_BIT) && (access & GL_MAP_WRITE_BIT)) {')
910            print(r'        gltrace::Context *_ctx = gltrace::getContext();')
911            if function.name in ('glMapBufferRange', 'glMapBufferRangeEXT'):
912                print(r'        GLint buffer = getBufferName(target);')
913            print(r'        auto it = _ctx->bufferToShadowMemory.find(buffer);')
914            print(r'        if (it != _ctx->bufferToShadowMemory.end()) {')
915            print(r'            _result = it->second->map(_ctx, _result, access, offset, length);')
916            print(r'        } else {')
917            print(r'            os::log("apitrace: error: %s: cannot find memory shadow\n", __FUNCTION__);')
918            print(r'        }')
919            print(r'    }')
920
921        # We should sync back readable coherent buffers only when a fence become signaled
922        # because in any other moment application cannot know if changes from operations on
923        # GPU are done and buffers are updated.
924        if function.name == 'glWaitSync':
925            print(r'    gltrace::Context *_ctx = gltrace::getContext();')
926            print(r'    GLMemoryShadow::syncAllForReads(_ctx);')
927
928        if function.name == 'glClientWaitSync':
929            print(r'    if (_result == GL_ALREADY_SIGNALED || _result == GL_CONDITION_SATISFIED) {')
930            print(r'        gltrace::Context *_ctx = gltrace::getContext();')
931            print(r'        GLMemoryShadow::syncAllForReads(_ctx);')
932            print(r'    }')
933
934        if function.name == 'glGetSynciv':
935            print(r'    if (pname == GL_SYNC_STATUS && bufSize > 0 && values[0] == GL_SIGNALED) {')
936            print(r'        gltrace::Context *_ctx = gltrace::getContext();')
937            print(r'        GLMemoryShadow::syncAllForReads(_ctx);')
938            print(r'    }')
939
940        if function.name == 'glGetProgramiv':
941            print(r'    if (params && pname == GL_PROGRAM_BINARY_LENGTH) {')
942            print(r'        *params = 0;')
943            print(r'    }')
944        if function.name in ('glGetProgramBinary', 'glGetProgramBinaryOES'):
945            print(r'    if (length) {')
946            print(r'        *length = 0;')
947            print(r'    }')
948
949    def wrapRet(self, function, instance):
950        Tracer.wrapRet(self, function, instance)
951
952        # Keep track of buffer mappings
953        if function.name in ('glMapBufferRange', 'glMapBufferRangeEXT'):
954            print('    if (access & GL_MAP_WRITE_BIT) {')
955            print('        _checkBufferMapRange = true;')
956            print('    }')
957
958    boolean_names = [
959        'GL_FALSE',
960        'GL_TRUE',
961    ]
962
963    def gl_boolean(self, value):
964        return self.boolean_names[int(bool(value))]
965
966    # Regular expression for the names of the functions that unpack from a
967    # pixel buffer object.  See the ARB_pixel_buffer_object specification.
968    unpack_function_regex = re.compile(r'^gl(' + r'|'.join([
969        r'Bitmap',
970        r'PolygonStipple',
971        r'PixelMap[a-z]+v',
972        r'DrawPixels',
973        r'Color(Sub)?Table',
974        r'(Convolution|Separable)Filter[12]D',
975        r'(Compressed)?(Multi)?Tex(ture)?(Sub)?Image[1-4]D',
976    ]) + r')[0-9A-Z]*$')
977
978    def serializeArgValue(self, function, arg):
979        # Recognize offsets instead of blobs when a PBO is bound
980        if self.unpack_function_regex.match(function.name) \
981           and (isinstance(arg.type, stdapi.Blob) \
982                or (isinstance(arg.type, stdapi.Const) \
983                    and isinstance(arg.type.type, stdapi.Blob))):
984            print('    {')
985            print('        gltrace::Context *_ctx = gltrace::getContext();')
986            print('        GLint _unpack_buffer = 0;')
987            print('        if (_ctx->features.pixel_buffer_object)')
988            print('            _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);')
989            print('        if (_unpack_buffer) {')
990            print('            trace::localWriter.writePointer((uintptr_t)%s);' % arg.name)
991            print('        } else {')
992            Tracer.serializeArgValue(self, function, arg)
993            print('        }')
994            print('    }')
995            return
996
997        # Recognize offsets instead of pointers when query buffer is bound
998        if function.name.startswith('glGetQueryObject') and arg.output:
999            print(r'    gltrace::Context *_ctx = gltrace::getContext();')
1000            print(r'    GLint _query_buffer = 0;')
1001            print(r'    if (_ctx->features.query_buffer_object) {')
1002            print(r'        _query_buffer = _glGetInteger(GL_QUERY_BUFFER_BINDING);')
1003            print(r'    }')
1004            print(r'    if (_query_buffer) {')
1005            print(r'        trace::localWriter.writePointer((uintptr_t)%s);' % arg.name)
1006            print(r'    } else {')
1007            Tracer.serializeArgValue(self, function, arg)
1008            print(r'    }')
1009            return
1010
1011        # Several GL state functions take GLenum symbolic names as
1012        # integer/floats; so dump the symbolic name whenever possible
1013        if function.name.startswith('gl') \
1014           and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
1015           and arg.name == 'param':
1016            assert arg.index > 0
1017            assert function.args[arg.index - 1].name == 'pname'
1018            assert function.args[arg.index - 1].type == glapi.GLenum
1019            print('    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name)
1020            self.serializeValue(glapi.GLenum, arg.name)
1021            print('    } else {')
1022            Tracer.serializeArgValue(self, function, arg)
1023            print('    }')
1024            return
1025
1026        Tracer.serializeArgValue(self, function, arg)
1027
1028    fake_function_names = [
1029        'glBindAttribLocation',
1030        'glBindAttribLocationARB',
1031        'glBindBuffer',
1032        'glBitmap',
1033        'glClientActiveTexture',
1034        'glDisableClientState',
1035        'glEnableClientState',
1036        'glEndList',
1037        'glNewList',
1038        'glScissor',
1039        'glStringMarkerGREMEDY',
1040        'glTexImage2D',
1041        'glViewport',
1042    ]
1043
1044    def footer(self, api):
1045        Tracer.footer(self, api)
1046
1047        # Generate helper functions to emit fake function calls into the trace
1048        for function in api.getAllFunctions():
1049            if function.name in self.fake_function_names:
1050                print(function.prototype('_fake_' + function.name))
1051                print(r'{')
1052                self.fake_call(function, function.argNames())
1053                print(r'}')
1054                print()
1055
1056        # A simple state tracker to track the pointer values
1057        # update the state
1058        print('static void _trace_user_arrays(gltrace::Context *_ctx, GLuint count)')
1059        print('{')
1060        print('    glfeatures::Profile profile = _ctx->profile;')
1061        print('    bool es1 = profile.es() && profile.major == 1;')
1062        print()
1063
1064        # Some apps, in particular Quake3, can tell the driver to lock more
1065        # vertices than those actually required for the draw call.
1066        print('    count = std::max(count, _ctx->lockedArrayCount);')
1067        print()
1068
1069        # Temporarily unbind the array buffer
1070        print('    GLint _array_buffer = _glGetInteger(GL_ARRAY_BUFFER_BINDING);')
1071        print('    if (_array_buffer) {')
1072        print('        _fake_glBindBuffer(GL_ARRAY_BUFFER, 0);')
1073        print('    }')
1074        print()
1075
1076        for camelcase_name, uppercase_name in self.arrays:
1077            # in which profile is the array available?
1078            profile_check = 'profile.desktop()'
1079            if camelcase_name in self.arrays_es1:
1080                profile_check = '(' + profile_check + ' || es1)';
1081
1082            function_name = 'gl%sPointer' % camelcase_name
1083            enable_name = 'GL_%s_ARRAY' % uppercase_name
1084            binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
1085            function = api.getFunctionByName(function_name)
1086
1087            print('    // %s' % function.prototype())
1088            print('  if (%s) {' % profile_check)
1089            self.array_trace_prolog(api, uppercase_name)
1090            self.array_prolog(api, uppercase_name)
1091            print('    if (_glIsEnabled(%s)) {' % enable_name)
1092            print('        GLint _binding = _glGetInteger(%s);' % binding_name)
1093            print('        if (!_binding) {')
1094
1095            # Get the arguments via glGet*
1096            for arg in function.args:
1097                arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
1098                arg_get_function, arg_type = TypeGetter().visit(arg.type)
1099                print('            %s %s = 0;' % (arg_type, arg.name))
1100                print('            _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name))
1101
1102            arg_names = ', '.join([arg.name for arg in function.args[:-1]])
1103            print('            size_t _size = _%s_size(%s, count);' % (function.name, arg_names))
1104
1105            # Emit a fake function
1106            self.array_trace_intermezzo(api, uppercase_name)
1107            print('            unsigned _call = trace::localWriter.beginEnter(&_%s_sig, true);' % (function.name,))
1108            for arg in function.args:
1109                assert not arg.output
1110                print('            trace::localWriter.beginArg(%u);' % (arg.index,))
1111                if arg.name != 'pointer':
1112                    self.serializeValue(arg.type, arg.name)
1113                else:
1114                    print('            trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name))
1115                print('            trace::localWriter.endArg();')
1116
1117            print('            trace::localWriter.endEnter();')
1118            print('            trace::localWriter.beginLeave(_call);')
1119            print('            trace::localWriter.endLeave();')
1120            print('        }')
1121            print('    }')
1122            self.array_epilog(api, uppercase_name)
1123            self.array_trace_epilog(api, uppercase_name)
1124            print('  }')
1125            print()
1126
1127        # Samething, but for glVertexAttribPointer*
1128        #
1129        # Some variants of glVertexAttribPointer alias conventional and generic attributes:
1130        # - glVertexAttribPointer: no
1131        # - glVertexAttribPointerARB: implementation dependent
1132        # - glVertexAttribPointerNV: yes
1133        #
1134        # This means that the implementations of these functions do not always
1135        # alias, and they need to be considered independently.
1136        #
1137        print('    // ES1 does not support generic vertex attributes')
1138        print('    if (es1)')
1139        print('        return;')
1140        print()
1141
1142        function_name = 'glVertexAttribPointer'
1143        function = api.getFunctionByName(function_name)
1144
1145        print('    // %s' % function.prototype())
1146        print('    GLint _max_vertex_attribs = _glGetInteger(GL_MAX_VERTEX_ATTRIBS);')
1147        print('    for (GLint index = 0; index < _max_vertex_attribs; ++index) {')
1148        print('        GLint _enabled = 0;')
1149        print('        _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &_enabled);')
1150        print('        if (_enabled) {')
1151        print('            GLint _binding = 0;')
1152        print('            _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &_binding);')
1153        print('            if (!_binding) {')
1154
1155        # Get the arguments via glGet*
1156        for arg in function.args[1:]:
1157            arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s' % (arg.name.upper())
1158            arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False).visit(arg.type)
1159            print('                %s %s = 0;' % (arg_type, arg.name))
1160            print('                _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name))
1161
1162        arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
1163        print('                size_t _size = _%s_size(%s, count);' % (function.name, arg_names))
1164
1165        # Emit a fake function
1166        print('                unsigned _call = trace::localWriter.beginEnter(&_%s_sig, true);' % (function.name,))
1167        for arg in function.args:
1168            assert not arg.output
1169            print('                trace::localWriter.beginArg(%u);' % (arg.index,))
1170            if arg.name != 'pointer':
1171                self.serializeValue(arg.type, arg.name)
1172            else:
1173                print('                trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name))
1174            print('                trace::localWriter.endArg();')
1175
1176        print('                trace::localWriter.endEnter();')
1177        print('                trace::localWriter.beginLeave(_call);')
1178        print('                trace::localWriter.endLeave();')
1179        print('            }')
1180        print('        }')
1181        print('    }')
1182        print()
1183
1184        # Restore the original array_buffer
1185        print('    if (_array_buffer) {')
1186        print('        _fake_glBindBuffer(GL_ARRAY_BUFFER, _array_buffer);')
1187        print('    }')
1188        print()
1189
1190        print('}')
1191        print()
1192
1193    #
1194    # Hooks for glTexCoordPointer, which is identical to the other array
1195    # pointers except the fact that it is indexed by glClientActiveTexture.
1196    #
1197
1198    def array_prolog(self, api, uppercase_name):
1199        if uppercase_name == 'TEXTURE_COORD':
1200            print('    GLint max_units = 0;')
1201            print('    if (_ctx->profile.desktop())')
1202            print('        _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_units);')
1203            print('    else')
1204            print('        _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_units);')
1205            print('    GLint client_active_texture = GL_TEXTURE0;')
1206            print('    if (max_units > 0) {')
1207            print('        _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);')
1208            print('    }')
1209            print('    GLint unit = 0;')
1210            print('    do {')
1211            print('        GLint texture = GL_TEXTURE0 + unit;')
1212            print('        if (max_units > 0) {')
1213            print('            _glClientActiveTexture(texture);')
1214            print('        }')
1215
1216    def array_trace_prolog(self, api, uppercase_name):
1217        if uppercase_name == 'TEXTURE_COORD':
1218            print('    bool client_active_texture_dirty = false;')
1219
1220    def array_epilog(self, api, uppercase_name):
1221        if uppercase_name == 'TEXTURE_COORD':
1222            print('    } while (++unit < max_units);')
1223        self.array_cleanup(api, uppercase_name)
1224
1225    def array_cleanup(self, api, uppercase_name):
1226        if uppercase_name == 'TEXTURE_COORD':
1227            print('    if (max_units > 0) {')
1228            print('        _glClientActiveTexture(client_active_texture);')
1229            print('    }')
1230
1231    def array_trace_intermezzo(self, api, uppercase_name):
1232        if uppercase_name == 'TEXTURE_COORD':
1233            print('    if (texture != client_active_texture || client_active_texture_dirty) {')
1234            print('        client_active_texture_dirty = true;')
1235            print('        _fake_glClientActiveTexture(texture);')
1236            print('    }')
1237
1238    def array_trace_epilog(self, api, uppercase_name):
1239        if uppercase_name == 'TEXTURE_COORD':
1240            print('    if (client_active_texture_dirty) {')
1241            print('        _fake_glClientActiveTexture(client_active_texture);')
1242            print('    }')
1243
1244    def emitFakeTexture2D(self):
1245        print(r'    _fake_glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);')
1246
1247