Exemple #1
0
    def invokeFunction(self, function):
        if function.name in ('glLinkProgram', 'glLinkProgramARB'):
            # These functions have been dispatched already
            return

        # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
        # driver
        if function.name in self.marker_functions:
            return

        if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
            else_ = ''
            for marker_function in self.marker_functions:
                if self.api.get_function_by_name(marker_function):
                    print '    %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
                    print '        __result = (%s)&%s;' % (function.type, marker_function)
                    print '    }'
                else_ = 'else '
            print '    %s{' % else_
            Tracer.invokeFunction(self, function)
            print '    }'
            return

        # Override GL extensions
        if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
            Tracer.invokeFunction(self, function, prefix = 'gltrace::__', suffix = '_override')
            return

        Tracer.invokeFunction(self, function)
Exemple #2
0
    def invokeFunction(self, function):
        if function.name in ('glLinkProgram', 'glLinkProgramARB'):
            # These functions have been dispatched already
            return

        # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
        # driver
        if function.name in self.marker_functions:
            return

        if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB',
                             'wglGetProcAddress'):
            else_ = ''
            for marker_function in self.marker_functions:
                if self.api.getFunctionByName(marker_function):
                    print '    %sif (strcmp("%s", (const char *)%s) == 0) {' % (
                        else_, marker_function, function.args[0].name)
                    print '        _result = (%s)&%s;' % (function.type,
                                                          marker_function)
                    print '    }'
                else_ = 'else '
            print '    %s{' % else_
            Tracer.invokeFunction(self, function)
            print '    }'
            return

        # Override GL extensions
        if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
            Tracer.invokeFunction(self,
                                  function,
                                  prefix='gltrace::_',
                                  suffix='_override')
            return

        Tracer.invokeFunction(self, function)
Exemple #3
0
    def invokeFunction(self, function):
        if function.name in ('glLinkProgram', 'glLinkProgramARB'):
            # These functions have been dispatched already
            return

        # We implement the GREMEDY extensions, not the driver
        if function.name in self.gremedy_functions:
            return

        if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
            if_ = 'if'
            for gremedy_function in self.gremedy_functions:
                print '    %s (strcmp("%s", (const char *)%s) == 0) {' % (if_, gremedy_function, function.args[0].name)
                print '        __result = (%s)&%s;' % (function.type, gremedy_function)
                print '    }'
                if_ = 'else if'
            print '    else {'
            Tracer.invokeFunction(self, function)
            print '    }'
            return

        # Override GL extensions
        if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
            Tracer.invokeFunction(self, function, prefix = 'gltrace::__', suffix = '_override')
            return

        Tracer.invokeFunction(self, function)
Exemple #4
0
    def invokeFunction(self, function):
        # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
        # driver
        if function.name in self.marker_functions:
            return

        if function.name in self.getProcAddressFunctionNames:
            else_ = ''
            for marker_function in self.marker_functions:
                if self.api.getFunctionByName(marker_function):
                    print '    %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
                    print '        _result = (%s)&%s;' % (function.type, marker_function)
                    print '    }'
                else_ = 'else '
            print '    %s{' % else_
            Tracer.invokeFunction(self, function)
            print '    _result = _wrapProcAddress(%s, _result);' % (function.args[0].name)
            print '    }'
            return

        # Override GL extensions
        if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
            Tracer.invokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
            return

        Tracer.invokeFunction(self, function)
Exemple #5
0
    def traceFunctionImplBody(self, function):
        # Defer tracing of user array pointers...
        if function.name in self.array_pointer_function_names:
            print '    GLint __array_buffer = 0;'
            print '    __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
            print '    if (!__array_buffer) {'
            print '        gltrace::Context *ctx = gltrace::getContext();'
            print '        ctx->user_arrays = true;'
            if function.name == "glVertexAttribPointerARB":
                print '        ctx->user_arrays_arb = true;'
            if function.name == "glVertexAttribPointerNV":
                print '        ctx->user_arrays_nv = true;'
            self.invokeFunction(function)

            # And also break down glInterleavedArrays into the individual calls
            if function.name == 'glInterleavedArrays':
                print

                # Initialize the enable flags
                for camelcase_name, uppercase_name in self.arrays:
                    flag_name = '__' + uppercase_name.lower()
                    print '        GLboolean %s = GL_FALSE;' % flag_name
                print

                # Switch for the interleaved formats
                print '        switch (format) {'
                for format in self.interleaved_formats:
                    print '            case %s:' % format
                    for camelcase_name, uppercase_name in self.arrays:
                        flag_name = '__' + uppercase_name.lower()
                        if format.find('_' + uppercase_name[0]) >= 0:
                            print '                %s = GL_TRUE;' % flag_name
                    print '                break;'
                print '            default:'
                print '               return;'
                print '        }'
                print

                # Emit fake glEnableClientState/glDisableClientState flags
                for camelcase_name, uppercase_name in self.arrays:
                    flag_name = '__' + uppercase_name.lower()
                    enable_name = 'GL_%s_ARRAY' % uppercase_name

                    # Emit a fake function
                    print '        {'
                    print '            static const trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
                    print '            unsigned __call = trace::localWriter.beginEnter(&__sig);'
                    print '            trace::localWriter.beginArg(0);'
                    self.serializeValue(glapi.GLenum, enable_name)
                    print '            trace::localWriter.endArg();'
                    print '            trace::localWriter.endEnter();'
                    print '            trace::localWriter.beginLeave(__call);'
                    print '            trace::localWriter.endLeave();'
                    print '        }'

            print '        return;'
            print '    }'

        # ... to the draw calls
        if function.name in self.draw_function_names:
            print '    if (__need_user_arrays()) {'
            arg_names = ', '.join([arg.name for arg in function.args[1:]])
            print '        GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
            print '        __trace_user_arrays(maxindex);'
            print '    }'
        
        # Emit a fake memcpy on buffer uploads
        if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', 'glUnmapBufferOES'):
            print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
            print '    if (mapping && mapping->write && !mapping->explicit_flush) {'
            self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
            print '    }'
        if function.name == 'glUnmapNamedBufferEXT':
            print '    GLint access = 0;'
            print '    glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS, &access);'
            print '    if ((access & GL_MAP_WRITE_BIT) & !(access & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
            print '        GLvoid *map = NULL;'
            print '        glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
            print '        GLint length = 0;'
            print '        glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
            self.emit_memcpy('map', 'map', 'length')
            print '    }'
        if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
            print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
            print '    if (mapping) {'
            if function.name.endswith('APPLE'):
                 print '        GLsizeiptr length = size;'
                 print '        mapping->explicit_flush = true;'
            print '        //assert(offset + length <= mapping->length);'
            self.emit_memcpy('(char *)mapping->map + offset', '(const char *)mapping->map + offset', 'length')
            print '    }'
        if function.name == 'glFlushMappedNamedBufferRangeEXT':
            print '    GLvoid *map = NULL;'
            print '    glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
            print '    if (map) {'
            self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
            print '    }'

        # Don't leave vertex attrib locations to chance.  Instead emit fake
        # glBindAttribLocation calls to ensure that the same locations will be
        # used when retracing.  Trying to remap locations after the fact would
        # be an herculian task given that vertex attrib locations appear in
        # many entry-points, including non-shader related ones.
        if function.name == 'glLinkProgram':
            Tracer.invokeFunction(self, function)
            print '    GLint active_attributes = 0;'
            print '    __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
            print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
            print '        GLint size = 0;'
            print '        GLenum type = 0;'
            print '        GLchar name[256];'
            # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
            print '        __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
            print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
            print '            GLint location = __glGetAttribLocation(program, name);'
            print '            if (location >= 0) {'
            bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
            self.fake_call(bind_function, ['program', 'location', 'name'])
            print '            }'
            print '        }'
            print '    }'
        if function.name == 'glLinkProgramARB':
            Tracer.invokeFunction(self, function)
            print '    GLint active_attributes = 0;'
            print '    __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
            print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
            print '        GLint size = 0;'
            print '        GLenum type = 0;'
            print '        GLcharARB name[256];'
            # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
            print '        __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
            print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
            print '            GLint location = __glGetAttribLocationARB(programObj, name);'
            print '            if (location >= 0) {'
            bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
            self.fake_call(bind_function, ['programObj', 'location', 'name'])
            print '            }'
            print '        }'
            print '    }'

        Tracer.traceFunctionImplBody(self, function)
Exemple #6
0
    def traceFunctionImplBody(self, function):
        # Defer tracing of user array pointers...
        if function.name in self.array_pointer_function_names:
            print '    GLint _array_buffer = 0;'
            print '    _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
            print '    if (!_array_buffer) {'
            print '        gltrace::Context *ctx = gltrace::getContext();'
            print '        ctx->user_arrays = true;'
            if function.name == "glVertexAttribPointerARB":
                print '        ctx->user_arrays_arb = true;'
            if function.name == "glVertexAttribPointerNV":
                print '        ctx->user_arrays_nv = true;'
            self.invokeFunction(function)

            # And also break down glInterleavedArrays into the individual calls
            if function.name == 'glInterleavedArrays':
                print

                # Initialize the enable flags
                for camelcase_name, uppercase_name in self.arrays:
                    flag_name = '_' + uppercase_name.lower()
                    print '        GLboolean %s = GL_FALSE;' % flag_name
                print

                # Switch for the interleaved formats
                print '        switch (format) {'
                for format in self.interleaved_formats:
                    print '            case %s:' % format
                    for camelcase_name, uppercase_name in self.arrays:
                        flag_name = '_' + uppercase_name.lower()
                        if format.find('_' + uppercase_name[0]) >= 0:
                            print '                %s = GL_TRUE;' % flag_name
                    print '                break;'
                print '            default:'
                print '               return;'
                print '        }'
                print

                # Emit fake glEnableClientState/glDisableClientState flags
                for camelcase_name, uppercase_name in self.arrays:
                    flag_name = '_' + uppercase_name.lower()
                    enable_name = 'GL_%s_ARRAY' % uppercase_name

                    # Emit a fake function
                    print '        {'
                    print '            static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
                    print '            unsigned _call = trace::localWriter.beginEnter(&_sig);'
                    print '            trace::localWriter.beginArg(0);'
                    self.serializeValue(glapi.GLenum, enable_name)
                    print '            trace::localWriter.endArg();'
                    print '            trace::localWriter.endEnter();'
                    print '            trace::localWriter.beginLeave(_call);'
                    print '            trace::localWriter.endLeave();'
                    print '        }'

            print '        return;'
            print '    }'

        # ... to the draw calls
        if function.name in self.draw_function_names:
            print '    if (_need_user_arrays()) {'
            arg_names = ', '.join([arg.name for arg in function.args[1:]])
            print '        GLuint _count = _%s_count(%s);' % (function.name,
                                                              arg_names)
            print '        _trace_user_arrays(_count);'
            print '    }'

        # Emit a fake memcpy on buffer uploads
        if function.name == 'glBufferParameteriAPPLE':
            print '    if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
            print '        _checkBufferFlushingUnmapAPPLE = true;'
            print '    }'
        if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
            if function.name.endswith('ARB'):
                suffix = 'ARB'
            else:
                suffix = ''
            print '    GLint access = 0;'
            print '    _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
            print '    if (access != GL_READ_ONLY) {'
            print '        GLvoid *map = NULL;'
            print '        _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);' % suffix
            print '        if (map) {'
            print '            GLint length = -1;'
            print '            bool flush = true;'
            print '            if (_checkBufferMapRange) {'
            print '                _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
            print '                GLint access_flags = 0;'
            print '                _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
            print '                flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
            print '                if (length == -1) {'
            print '                    // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
            print '                    static bool warned = false;'
            print '                    if (!warned) {'
            print '                        os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
            print '                        warned = true;'
            print '                    }'
            print '                    struct buffer_mapping *mapping = get_buffer_mapping(target);'
            print '                    if (mapping) {'
            print '                        length = mapping->length;'
            print '                        flush = flush && !mapping->explicit_flush;'
            print '                    } else {'
            print '                        length = 0;'
            print '                        flush = false;'
            print '                    }'
            print '                }'
            print '            } else {'
            print '                length = 0;'
            print '                _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
            print '            }'
            print '            if (_checkBufferFlushingUnmapAPPLE) {'
            print '                GLint flushing_unmap = GL_TRUE;'
            print '                _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
            print '                flush = flush && flushing_unmap;'
            print '            }'
            print '            if (flush && length > 0) {'
            self.emit_memcpy('map', 'map', 'length')
            print '            }'
            print '        }'
            print '    }'
        if function.name == 'glUnmapBufferOES':
            print '    GLint access = 0;'
            print '    _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
            print '    if (access == GL_WRITE_ONLY_OES) {'
            print '        GLvoid *map = NULL;'
            print '        _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
            print '        GLint size = 0;'
            print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
            print '        if (map && size > 0) {'
            self.emit_memcpy('map', 'map', 'size')
            self.shadowBufferMethod('bufferSubData(0, size, map)')
            print '        }'
            print '    }'
        if function.name == 'glUnmapNamedBufferEXT':
            print '    GLint access_flags = 0;'
            print '    _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
            print '    if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
            print '        GLvoid *map = NULL;'
            print '        _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
            print '        GLint length = 0;'
            print '        _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
            print '        if (map && length > 0) {'
            self.emit_memcpy('map', 'map', 'length')
            print '        }'
            print '    }'
        if function.name == 'glFlushMappedBufferRange':
            print '    GLvoid *map = NULL;'
            print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
            print '    if (map && length > 0) {'
            self.emit_memcpy('(char *)map + offset',
                             '(const char *)map + offset', 'length')
            print '    }'
        if function.name == 'glFlushMappedBufferRangeAPPLE':
            print '    GLvoid *map = NULL;'
            print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
            print '    if (map && size > 0) {'
            self.emit_memcpy('(char *)map + offset',
                             '(const char *)map + offset', 'size')
            print '    }'
        if function.name == 'glFlushMappedNamedBufferRangeEXT':
            print '    GLvoid *map = NULL;'
            print '    _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
            print '    if (map && length > 0) {'
            self.emit_memcpy('(char *)map + offset',
                             '(const char *)map + offset', 'length')
            print '    }'

        # Don't leave vertex attrib locations to chance.  Instead emit fake
        # glBindAttribLocation calls to ensure that the same locations will be
        # used when retracing.  Trying to remap locations after the fact would
        # be an herculian task given that vertex attrib locations appear in
        # many entry-points, including non-shader related ones.
        if function.name == 'glLinkProgram':
            Tracer.invokeFunction(self, function)
            print '    GLint active_attributes = 0;'
            print '    _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
            print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
            print '        GLint size = 0;'
            print '        GLenum type = 0;'
            print '        GLchar name[256];'
            # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
            print '        _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
            print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
            print '            GLint location = _glGetAttribLocation(program, name);'
            print '            if (location >= 0) {'
            bind_function = glapi.glapi.getFunctionByName(
                'glBindAttribLocation')
            self.fake_call(bind_function, ['program', 'location', 'name'])
            print '            }'
            print '        }'
            print '    }'
        if function.name == 'glLinkProgramARB':
            Tracer.invokeFunction(self, function)
            print '    GLint active_attributes = 0;'
            print '    _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
            print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
            print '        GLint size = 0;'
            print '        GLenum type = 0;'
            print '        GLcharARB name[256];'
            # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
            print '        _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
            print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
            print '            GLint location = _glGetAttribLocationARB(programObj, name);'
            print '            if (location >= 0) {'
            bind_function = glapi.glapi.getFunctionByName(
                'glBindAttribLocationARB')
            self.fake_call(bind_function, ['programObj', 'location', 'name'])
            print '            }'
            print '        }'
            print '    }'

        self.shadowBufferProlog(function)

        Tracer.traceFunctionImplBody(self, function)
Exemple #7
0
    def invokeFunction(self, function):
        if function.name in ('glLinkProgram', 'glLinkProgramARB'):
            # These functions have been dispatched already
            return

        Tracer.invokeFunction(self, function)
Exemple #8
0
    def traceFunctionImplBody(self, function):
        # Defer tracing of user array pointers...
        if function.name in self.array_pointer_function_names:
            print '    GLint _array_buffer = 0;'
            print '    _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
            print '    if (!_array_buffer) {'
            print '        gltrace::Context *ctx = gltrace::getContext();'
            print '        ctx->user_arrays = true;'
            if function.name == "glVertexAttribPointerARB":
                print '        ctx->user_arrays_arb = true;'
            if function.name == "glVertexAttribPointerNV":
                print '        ctx->user_arrays_nv = true;'
            self.invokeFunction(function)

            # And also break down glInterleavedArrays into the individual calls
            if function.name == 'glInterleavedArrays':
                print

                # Initialize the enable flags
                for camelcase_name, uppercase_name in self.arrays:
                    flag_name = '_' + uppercase_name.lower()
                    print '        GLboolean %s = GL_FALSE;' % flag_name
                print

                # Switch for the interleaved formats
                print '        switch (format) {'
                for format in self.interleaved_formats:
                    print '            case %s:' % format
                    for camelcase_name, uppercase_name in self.arrays:
                        flag_name = '_' + uppercase_name.lower()
                        if format.find('_' + uppercase_name[0]) >= 0:
                            print '                %s = GL_TRUE;' % flag_name
                    print '                break;'
                print '            default:'
                print '               return;'
                print '        }'
                print

                # Emit fake glEnableClientState/glDisableClientState flags
                for camelcase_name, uppercase_name in self.arrays:
                    flag_name = '_' + uppercase_name.lower()
                    enable_name = 'GL_%s_ARRAY' % uppercase_name

                    # Emit a fake function
                    print '        {'
                    print '            static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
                    print '            unsigned _call = trace::localWriter.beginEnter(&_sig);'
                    print '            trace::localWriter.beginArg(0);'
                    self.serializeValue(glapi.GLenum, enable_name)
                    print '            trace::localWriter.endArg();'
                    print '            trace::localWriter.endEnter();'
                    print '            trace::localWriter.beginLeave(_call);'
                    print '            trace::localWriter.endLeave();'
                    print '        }'

            print '        return;'
            print '    }'

        # ... to the draw calls
        if function.name in self.draw_function_names:
            print '    if (_need_user_arrays()) {'
            arg_names = ', '.join([arg.name for arg in function.args[1:]])
            print '        GLuint _count = _%s_count(%s);' % (function.name, arg_names)
            print '        _trace_user_arrays(_count);'
            print '    }'
        
        # Emit a fake memcpy on buffer uploads
        if function.name == 'glBufferParameteriAPPLE':
            print '    if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
            print '        _checkBufferFlushingUnmapAPPLE = true;'
            print '    }'
        if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
            if function.name.endswith('ARB'):
                suffix = 'ARB'
            else:
                suffix = ''
            print '    GLint access = 0;'
            print '    _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
            print '    if (access != GL_READ_ONLY) {'
            print '        GLvoid *map = NULL;'
            print '        _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);'  % suffix
            print '        if (map) {'
            print '            GLint length = -1;'
            print '            bool flush = true;'
            print '            if (_checkBufferMapRange) {'
            print '                _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
            print '                GLint access_flags = 0;'
            print '                _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
            print '                flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
            print '                if (length == -1) {'
            print '                    // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0 up-to'
            print '                    // http://cgit.freedesktop.org/mesa/mesa/commit/?id=ffee498fb848b253a7833373fe5430f8c7ca0c5f'
            print '                    static bool warned = false;'
            print '                    if (!warned) {'
            print '                        os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
            print '                        warned = true;'
            print '                    }'
            print '                    struct buffer_mapping *mapping = get_buffer_mapping(target);'
            print '                    if (mapping) {'
            print '                        length = mapping->length;'
            print '                        flush = flush && !mapping->explicit_flush;'
            print '                    } else {'
            print '                        length = 0;'
            print '                        flush = false;'
            print '                    }'
            print '                }'
            print '            } else {'
            print '                length = 0;'
            print '                _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
            print '            }'
            print '            if (_checkBufferFlushingUnmapAPPLE) {'
            print '                GLint flushing_unmap = GL_TRUE;'
            print '                _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
            print '                flush = flush && flushing_unmap;'
            print '            }'
            print '            if (flush && length > 0) {'
            self.emit_memcpy('map', 'map', 'length')
            print '            }'
            print '        }'
            print '    }'
        if function.name == 'glUnmapBufferOES':
            print '    GLint access = 0;'
            print '    _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
            print '    if (access == GL_WRITE_ONLY_OES) {'
            print '        GLvoid *map = NULL;'
            print '        _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
            print '        GLint size = 0;'
            print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
            print '        if (map && size > 0) {'
            self.emit_memcpy('map', 'map', 'size')
            self.shadowBufferMethod('bufferSubData(0, size, map)')
            print '        }'
            print '    }'
        if function.name == 'glUnmapNamedBufferEXT':
            print '    GLint access_flags = 0;'
            print '    _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
            print '    if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
            print '        GLvoid *map = NULL;'
            print '        _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
            print '        GLint length = 0;'
            print '        _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
            print '        if (map && length > 0) {'
            self.emit_memcpy('map', 'map', 'length')
            print '        }'
            print '    }'
        if function.name == 'glFlushMappedBufferRange':
            print '    GLvoid *map = NULL;'
            print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
            print '    if (map && length > 0) {'
            self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
            print '    }'
        if function.name == 'glFlushMappedBufferRangeAPPLE':
            print '    GLvoid *map = NULL;'
            print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
            print '    if (map && size > 0) {'
            self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
            print '    }'
        if function.name == 'glFlushMappedNamedBufferRangeEXT':
            print '    GLvoid *map = NULL;'
            print '    _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
            print '    if (map && length > 0) {'
            self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
            print '    }'

        # Don't leave vertex attrib locations to chance.  Instead emit fake
        # glBindAttribLocation calls to ensure that the same locations will be
        # used when retracing.  Trying to remap locations after the fact would
        # be an herculian task given that vertex attrib locations appear in
        # many entry-points, including non-shader related ones.
        if function.name == 'glLinkProgram':
            Tracer.invokeFunction(self, function)
            print '    GLint active_attributes = 0;'
            print '    _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
            print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
            print '        GLint size = 0;'
            print '        GLenum type = 0;'
            print '        GLchar name[256];'
            # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
            print '        _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
            print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
            print '            GLint location = _glGetAttribLocation(program, name);'
            print '            if (location >= 0) {'
            bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
            self.fake_call(bind_function, ['program', 'location', 'name'])
            print '            }'
            print '        }'
            print '    }'
        if function.name == 'glLinkProgramARB':
            Tracer.invokeFunction(self, function)
            print '    GLint active_attributes = 0;'
            print '    _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
            print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
            print '        GLint size = 0;'
            print '        GLenum type = 0;'
            print '        GLcharARB name[256];'
            # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
            print '        _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
            print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
            print '            GLint location = _glGetAttribLocationARB(programObj, name);'
            print '            if (location >= 0) {'
            bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
            self.fake_call(bind_function, ['programObj', 'location', 'name'])
            print '            }'
            print '        }'
            print '    }'

        self.shadowBufferProlog(function)

        Tracer.traceFunctionImplBody(self, function)