def dump_arg_instance(self, function, arg): if function.name in self.draw_function_names and arg.name == 'indices': print ' GLint __element_array_buffer = 0;' print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);' print ' if (!__element_array_buffer) {' print ' Trace::LiteralBlob((const void *)%s, count*__gl_type_size(type));' % (arg.name) print ' } else {' print ' Trace::LiteralOpaque((const void *)%s);' % (arg.name) print ' }' return # Several GL state functions take GLenum symbolic names as # integer/floats; so dump the symbolic name whenever possible if arg.type in (glapi.GLint, glapi.GLfloat) and arg.name == 'param': assert arg.index > 0 assert function.args[arg.index - 1].name == 'pname' assert function.args[arg.index - 1].type == glapi.GLenum print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name dump_instance(glapi.GLenum, arg.name) print ' } else {' Tracer.dump_arg_instance(self, function, arg) print ' }' return Tracer.dump_arg_instance(self, function, arg)
def fake_call(self, function, args): print ' unsigned __fake_call = Trace::BeginEnter(__%s_sig);' % (function.name,) for arg, instance in zip(function.args, args): assert not arg.output print ' Trace::BeginArg(%u);' % (arg.index,) dump_instance(arg.type, instance) print ' Trace::EndArg();' print ' Trace::EndEnter();' print ' Trace::BeginLeave(__fake_call);' print ' Trace::EndLeave();'
def dump_arg_instance(self, function, arg): if function.name in self.draw_function_names and arg.name == 'indices': print ' GLint __element_array_buffer = 0;' print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);' print ' if (!__element_array_buffer) {' if isinstance(arg.type, stdapi.Array): print ' trace::localWriter.beginArray(%s);' % arg.type.length print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length print ' trace::localWriter.beginElement();' print ' trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name) print ' trace::localWriter.endElement();' print ' }' print ' trace::localWriter.endArray();' else: print ' trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name) print ' } else {' Tracer.dump_arg_instance(self, function, arg) print ' }' return # Recognize offsets instead of blobs when a PBO is bound if function.name in self.unpack_function_names \ and (isinstance(arg.type, stdapi.Blob) \ or (isinstance(arg.type, stdapi.Const) \ and isinstance(arg.type.type, stdapi.Blob))): print ' {' print ' tracer_context *ctx = __get_context();' print ' GLint __unpack_buffer = 0;' print ' if (ctx->profile == PROFILE_COMPAT)' print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);' print ' if (__unpack_buffer) {' print ' trace::localWriter.writeOpaque(%s);' % arg.name print ' } else {' Tracer.dump_arg_instance(self, function, arg) print ' }' print ' }' return # Several GL state functions take GLenum symbolic names as # integer/floats; so dump the symbolic name whenever possible if function.name.startswith('gl') \ and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \ and arg.name == 'param': assert arg.index > 0 assert function.args[arg.index - 1].name == 'pname' assert function.args[arg.index - 1].type == glapi.GLenum print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name dump_instance(glapi.GLenum, arg.name) print ' } else {' Tracer.dump_arg_instance(self, function, arg) print ' }' return Tracer.dump_arg_instance(self, function, arg)
def footer(self, api): Tracer.footer(self, api) # A simple state tracker to track the pointer values # update the state print 'static void __trace_user_arrays(GLuint maxindex)' print '{' for camelcase_name, uppercase_name in self.arrays: function_name = 'gl%sPointer' % camelcase_name enable_name = 'GL_%s_ARRAY' % uppercase_name binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name function = api.get_function_by_name(function_name) print ' // %s' % function.name self.array_trace_prolog(api, uppercase_name) self.array_prolog(api, uppercase_name) print ' if (__glIsEnabled(%s)) {' % enable_name print ' GLint __binding = 0;' print ' __glGetIntegerv(%s, &__binding);' % binding_name print ' if (!__binding) {' # Get the arguments via glGet* for arg in function.args: arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper()) arg_get_function, arg_type = TypeGetter().visit(arg.type) print ' %s %s = 0;' % (arg_type, arg.name) print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name) arg_names = ', '.join([arg.name for arg in function.args[:-1]]) print ' size_t __size = __%s_size(%s, maxindex);' % ( function.name, arg_names) # Emit a fake function self.array_trace_intermezzo(api, uppercase_name) print ' unsigned __call = Trace::BeginEnter(__%s_sig);' % ( function.name, ) for arg in function.args: assert not arg.output print ' Trace::BeginArg(%u);' % (arg.index, ) if arg.name != 'pointer': dump_instance(arg.type, arg.name) else: print ' Trace::LiteralBlob((const void *)%s, __size);' % ( arg.name) print ' Trace::EndArg();' print ' Trace::EndEnter();' print ' Trace::BeginLeave(__call);' print ' Trace::EndLeave();' print ' }' print ' }' self.array_epilog(api, uppercase_name) self.array_trace_epilog(api, uppercase_name) print # Samething, but for glVertexAttribPointer print ' // glVertexAttribPointer' print ' GLint __max_vertex_attribs = 0;' print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);' print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {' print ' GLint __enabled = 0;' print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);' print ' if (__enabled) {' print ' GLint __binding = 0;' print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);' print ' if (!__binding) {' function = api.get_function_by_name('glVertexAttribPointer') # Get the arguments via glGet* for arg in function.args[1:]: arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s' % (arg.name.upper(), ) arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False).visit(arg.type) print ' %s %s = 0;' % (arg_type, arg.name) print ' __%s(index, %s, &%s);' % ( arg_get_function, arg_get_enum, arg.name) arg_names = ', '.join([arg.name for arg in function.args[1:-1]]) print ' size_t __size = __%s_size(%s, maxindex);' % ( function.name, arg_names) # Emit a fake function print ' unsigned __call = Trace::BeginEnter(__%s_sig);' % ( function.name, ) for arg in function.args: assert not arg.output print ' Trace::BeginArg(%u);' % (arg.index, ) if arg.name != 'pointer': dump_instance(arg.type, arg.name) else: print ' Trace::LiteralBlob((const void *)%s, __size);' % ( arg.name) print ' Trace::EndArg();' print ' Trace::EndEnter();' print ' Trace::BeginLeave(__call);' print ' Trace::EndLeave();' print ' }' print ' }' print ' }' print print '}' print
def trace_function_impl_body(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 ' __user_arrays = true;' self.dispatch_function(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::BeginEnter(__sig);' print ' Trace::BeginArg(0);' dump_instance(glapi.GLenum, enable_name) print ' Trace::EndArg();' print ' Trace::EndEnter();' print ' Trace::BeginLeave(__call);' print ' Trace::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', ): 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 in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'): # TODO: avoid copying [0, offset] bytes 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('mapping->map', 'mapping->map', 'offset + length') print ' }' # FIXME: glFlushMappedNamedBufferRangeEXT # 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.dispatch_function(self, function) print ' GLint active_attributes = 0;' print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);' print ' for (GLuint 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 ' 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 ' }' if function.name == 'glLinkProgramARB': Tracer.dispatch_function(self, function) print ' GLint active_attributes = 0;' print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);' print ' for (GLuint 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 ' 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 ' }' Tracer.trace_function_impl_body(self, function)
def trace_function_impl_body(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 ' __user_arrays = true;' self.dispatch_function(function) 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 ' }' # And also break down glInterleavedArrays into the individual calls if function.name == 'glInterleavedArrays': print ' GLint __array_buffer = 0;' print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);' print ' if (!__array_buffer) {' print ' __user_arrays = true;' self.dispatch_function(function) 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 # Swicth 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::BeginEnter(__sig);' print ' Trace::BeginArg(0);' dump_instance(glapi.GLenum, enable_name) print ' Trace::EndArg();' print ' Trace::EndEnter();' print ' Trace::BeginLeave(__call);' print ' Trace::EndLeave();' print ' }' print ' return;' print ' }' # Emit a fake memcpy on if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'): print ' struct buffer_mapping *mapping = get_buffer_mapping(target);' print ' if (mapping && mapping->write) {' print ' unsigned __call = Trace::BeginEnter(__memcpy_sig);' print ' Trace::BeginArg(0);' print ' Trace::LiteralOpaque(mapping->map);' print ' Trace::EndArg();' print ' Trace::BeginArg(1);' print ' Trace::LiteralBlob(mapping->map, mapping->length);' print ' Trace::EndArg();' print ' Trace::BeginArg(2);' print ' Trace::LiteralUInt(mapping->length);' print ' Trace::EndArg();' print ' Trace::EndEnter();' print ' Trace::BeginLeave(__call);' print ' Trace::EndLeave();' print ' }' Tracer.trace_function_impl_body(self, function)
def footer(self, api): Tracer.footer(self, api) # A simple state tracker to track the pointer values # update the state print 'static void __trace_user_arrays(GLuint maxindex)' print '{' for camelcase_name, uppercase_name in self.arrays: function_name = 'gl%sPointer' % camelcase_name enable_name = 'GL_%s_ARRAY' % uppercase_name binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name function = api.get_function_by_name(function_name) print ' // %s' % function.name self.array_trace_prolog(api, uppercase_name) self.array_prolog(api, uppercase_name) print ' if (__glIsEnabled(%s)) {' % enable_name print ' GLint __binding = 0;' print ' __glGetIntegerv(%s, &__binding);' % binding_name print ' if (!__binding) {' # Get the arguments via glGet* for arg in function.args: arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper()) arg_get_function, arg_type = TypeGetter().visit(arg.type) print ' %s %s = 0;' % (arg_type, arg.name) print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name) arg_names = ', '.join([arg.name for arg in function.args[:-1]]) print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names) # Emit a fake function self.array_trace_intermezzo(api, uppercase_name) print ' unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name,) for arg in function.args: assert not arg.output print ' Trace::BeginArg(%u);' % (arg.index,) if arg.name != 'pointer': dump_instance(arg.type, arg.name) else: print ' Trace::LiteralBlob((const void *)%s, __size);' % (arg.name) print ' Trace::EndArg();' print ' Trace::EndEnter();' print ' Trace::BeginLeave(__call);' print ' Trace::EndLeave();' print ' }' print ' }' self.array_epilog(api, uppercase_name) self.array_trace_epilog(api, uppercase_name) print # Samething, but for glVertexAttribPointer print ' // glVertexAttribPointer' print ' GLint __max_vertex_attribs = 0;' print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);' print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {' print ' GLint __enabled = 0;' print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);' print ' if (__enabled) {' print ' GLint __binding = 0;' print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);' print ' if (!__binding) {' function = api.get_function_by_name('glVertexAttribPointer') # Get the arguments via glGet* for arg in function.args[1:]: arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s' % (arg.name.upper(),) arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False).visit(arg.type) print ' %s %s = 0;' % (arg_type, arg.name) print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name) arg_names = ', '.join([arg.name for arg in function.args[1:-1]]) print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names) # Emit a fake function print ' unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name,) for arg in function.args: assert not arg.output print ' Trace::BeginArg(%u);' % (arg.index,) if arg.name != 'pointer': dump_instance(arg.type, arg.name) else: print ' Trace::LiteralBlob((const void *)%s, __size);' % (arg.name) print ' Trace::EndArg();' print ' Trace::EndEnter();' print ' Trace::BeginLeave(__call);' print ' Trace::EndLeave();' print ' }' print ' }' print ' }' print print '}' print
def trace_function_impl_body(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 ' __user_arrays = true;' self.dispatch_function(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::BeginEnter(__sig);' print ' Trace::BeginArg(0);' dump_instance(glapi.GLenum, enable_name) print ' Trace::EndArg();' print ' Trace::EndEnter();' print ' Trace::BeginLeave(__call);' print ' Trace::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 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'): print ' struct buffer_mapping *mapping = get_buffer_mapping(target);' print ' if (mapping && mapping->write) {' print ' unsigned __call = Trace::BeginEnter(__memcpy_sig);' print ' Trace::BeginArg(0);' print ' Trace::LiteralOpaque(mapping->map);' print ' Trace::EndArg();' print ' Trace::BeginArg(1);' print ' Trace::LiteralBlob(mapping->map, mapping->length);' print ' Trace::EndArg();' print ' Trace::BeginArg(2);' print ' Trace::LiteralUInt(mapping->length);' print ' Trace::EndArg();' print ' Trace::EndEnter();' print ' Trace::BeginLeave(__call);' print ' Trace::EndLeave();' print ' }' Tracer.trace_function_impl_body(self, function)
def state_tracker_impl(self, api): # A simple state tracker to track the pointer values # update the state print "static void __trace_user_arrays(GLuint maxindex)" print "{" for camelcase_name, uppercase_name in self.arrays: function_name = "gl%sPointer" % camelcase_name enable_name = "GL_%s_ARRAY" % uppercase_name binding_name = "GL_%s_ARRAY_BUFFER_BINDING" % uppercase_name function = api.get_function_by_name(function_name) print " // %s" % function.name self.array_trace_prolog(api, uppercase_name) self.array_prolog(api, uppercase_name) print " if (__glIsEnabled(%s)) {" % enable_name print " GLint __binding = 0;" print " __glGetIntegerv(%s, &__binding);" % binding_name print " if (!__binding) {" # Get the arguments via glGet* for arg in function.args: arg_get_enum = "GL_%s_ARRAY_%s" % (uppercase_name, arg.name.upper()) arg_get_function, arg_type = TypeGetter().visit(arg.type) print " %s %s = 0;" % (arg_type, arg.name) print " __%s(%s, &%s);" % (arg_get_function, arg_get_enum, arg.name) arg_names = ", ".join([arg.name for arg in function.args[:-1]]) print " size_t __size = __%s_size(%s, maxindex);" % (function.name, arg_names) # Emit a fake function self.array_trace_intermezzo(api, uppercase_name) print " unsigned __call = Trace::BeginEnter(__%s_sig);" % (function.name,) for arg in function.args: assert not arg.output print " Trace::BeginArg(%u);" % (arg.index,) if arg.name != "pointer": dump_instance(arg.type, arg.name) else: print " Trace::LiteralBlob((const void *)%s, __size);" % (arg.name) print " Trace::EndArg();" print " Trace::EndEnter();" print " Trace::BeginLeave(__call);" print " Trace::EndLeave();" print " }" print " }" self.array_epilog(api, uppercase_name) self.array_trace_epilog(api, uppercase_name) print # Samething, but for glVertexAttribPointer print " // glVertexAttribPointer" print " GLint __max_vertex_attribs = 0;" print " __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);" print " for (GLint index = 0; index < __max_vertex_attribs; ++index) {" print " GLint __enabled = 0;" print " __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);" print " if (__enabled) {" print " GLint __binding = 0;" print " __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);" print " if (!__binding) {" function = api.get_function_by_name("glVertexAttribPointer") # Get the arguments via glGet* for arg in function.args[1:]: arg_get_enum = "GL_VERTEX_ATTRIB_ARRAY_%s" % (arg.name.upper(),) arg_get_function, arg_type = TypeGetter("glGetVertexAttrib", False).visit(arg.type) print " %s %s = 0;" % (arg_type, arg.name) print " __%s(index, %s, &%s);" % (arg_get_function, arg_get_enum, arg.name) arg_names = ", ".join([arg.name for arg in function.args[1:-1]]) print " size_t __size = __%s_size(%s, maxindex);" % (function.name, arg_names) # Emit a fake function print " unsigned __call = Trace::BeginEnter(__%s_sig);" % (function.name,) for arg in function.args: assert not arg.output print " Trace::BeginArg(%u);" % (arg.index,) if arg.name != "pointer": dump_instance(arg.type, arg.name) else: print " Trace::LiteralBlob((const void *)%s, __size);" % (arg.name) print " Trace::EndArg();" print " Trace::EndEnter();" print " Trace::BeginLeave(__call);" print " Trace::EndLeave();" print " }" print " }" print " }" print print "}" print
def trace_function_impl_body(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 " __user_arrays = true;" self.dispatch_function(function) 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 " }" # And also break down glInterleavedArrays into the individual calls if function.name == "glInterleavedArrays": print " GLint __array_buffer = 0;" print " __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);" print " if (!__array_buffer) {" print " __user_arrays = true;" self.dispatch_function(function) 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 # Swicth 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::BeginEnter(__sig);" print " Trace::BeginArg(0);" dump_instance(glapi.GLenum, enable_name) print " Trace::EndArg();" print " Trace::EndEnter();" print " Trace::BeginLeave(__call);" print " Trace::EndLeave();" print " }" print " return;" print " }" # Emit a fake memcpy on if function.name in ("glUnmapBuffer", "glUnmapBufferARB"): print " struct buffer_mapping *mapping = get_buffer_mapping(target);" print " if (mapping && mapping->write) {" print " unsigned __call = Trace::BeginEnter(__memcpy_sig);" print " Trace::BeginArg(0);" print " Trace::LiteralOpaque(mapping->map);" print " Trace::EndArg();" print " Trace::BeginArg(1);" print " Trace::LiteralBlob(mapping->map, mapping->length);" print " Trace::EndArg();" print " Trace::BeginArg(2);" print " Trace::LiteralUInt(mapping->length);" print " Trace::EndArg();" print " Trace::EndEnter();" print " Trace::BeginLeave(__call);" print " Trace::EndLeave();" print " }" Tracer.trace_function_impl_body(self, function)
def footer(self, api): Tracer.footer(self, api) # A simple state tracker to track the pointer values # update the state print 'static void __trace_user_arrays(GLuint maxindex)' print '{' print ' tracer_context *ctx = __get_context();' for camelcase_name, uppercase_name in self.arrays: # in which profile is the array available? profile_check = 'ctx->profile == PROFILE_COMPAT' if camelcase_name in self.arrays_es1: profile_check = '(' + profile_check + ' || ctx->profile == PROFILE_ES1)'; function_name = 'gl%sPointer' % camelcase_name enable_name = 'GL_%s_ARRAY' % uppercase_name binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name function = api.get_function_by_name(function_name) print ' // %s' % function.prototype() print ' if (%s) {' % profile_check self.array_trace_prolog(api, uppercase_name) self.array_prolog(api, uppercase_name) print ' if (__glIsEnabled(%s)) {' % enable_name print ' GLint __binding = 0;' print ' __glGetIntegerv(%s, &__binding);' % binding_name print ' if (!__binding) {' # Get the arguments via glGet* for arg in function.args: arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper()) arg_get_function, arg_type = TypeGetter().visit(arg.type) print ' %s %s = 0;' % (arg_type, arg.name) print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name) arg_names = ', '.join([arg.name for arg in function.args[:-1]]) print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names) # Emit a fake function self.array_trace_intermezzo(api, uppercase_name) print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,) for arg in function.args: assert not arg.output print ' trace::localWriter.beginArg(%u);' % (arg.index,) if arg.name != 'pointer': dump_instance(arg.type, arg.name) else: print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name) print ' trace::localWriter.endArg();' print ' trace::localWriter.endEnter();' print ' trace::localWriter.beginLeave(__call);' print ' trace::localWriter.endLeave();' print ' }' print ' }' self.array_epilog(api, uppercase_name) self.array_trace_epilog(api, uppercase_name) print ' }' print # Samething, but for glVertexAttribPointer* # # Some variants of glVertexAttribPointer alias conventional and generic attributes: # - glVertexAttribPointer: no # - glVertexAttribPointerARB: implementation dependent # - glVertexAttribPointerNV: yes # # This means that the implementations of these functions do not always # alias, and they need to be considered independently. # print ' // ES1 does not support generic vertex attributes' print ' if (ctx->profile == PROFILE_ES1)' print ' return;' print print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();' print for suffix in ['', 'ARB', 'NV']: if suffix: SUFFIX = '_' + suffix else: SUFFIX = suffix function_name = 'glVertexAttribPointer' + suffix function = api.get_function_by_name(function_name) print ' // %s' % function.prototype() print ' if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX if suffix == 'NV': print ' GLint __max_vertex_attribs = 16;' else: print ' GLint __max_vertex_attribs = 0;' print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);' print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {' print ' GLint __enabled = 0;' if suffix == 'NV': print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);' else: print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX) print ' if (__enabled) {' print ' GLint __binding = 0;' if suffix != 'NV': # It doesn't seem possible to use VBOs with NV_vertex_program. print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX) print ' if (!__binding) {' # Get the arguments via glGet* for arg in function.args[1:]: if suffix == 'NV': arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX) else: arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX) arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type) print ' %s %s = 0;' % (arg_type, arg.name) print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name) arg_names = ', '.join([arg.name for arg in function.args[1:-1]]) print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names) # Emit a fake function print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,) for arg in function.args: assert not arg.output print ' trace::localWriter.beginArg(%u);' % (arg.index,) if arg.name != 'pointer': dump_instance(arg.type, arg.name) else: print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name) print ' trace::localWriter.endArg();' print ' trace::localWriter.endEnter();' print ' trace::localWriter.beginLeave(__call);' print ' trace::localWriter.endLeave();' print ' }' print ' }' print ' }' print ' }' print print '}' print
def trace_function_impl_body(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 ' tracer_context *ctx = __get_context();' 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.dispatch_function(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);' dump_instance(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', ): 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 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 ' }' # FIXME: glFlushMappedNamedBufferRangeEXT # 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.dispatch_function(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.dispatch_function(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.trace_function_impl_body(self, function)