1 ##########################################################################
3 # Copyright 2008-2010 VMware, Inc.
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:
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
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
24 ##########################################################################/
27 """GL tracing generator."""
30 import specs.stdapi as stdapi
31 import specs.glapi as glapi
32 import specs.glparams as glparams
33 from specs.glxapi import glxapi
34 from trace import Tracer, dump_instance
37 class TypeGetter(stdapi.Visitor):
38 '''Determine which glGet*v function that matches the specified type.'''
40 def __init__(self, prefix = 'glGet', long_suffix = True, ext_suffix = ''):
42 self.long_suffix = long_suffix
43 self.ext_suffix = ext_suffix
45 def visit_const(self, const):
46 return self.visit(const.type)
48 def visit_alias(self, alias):
49 if alias.expr == 'GLboolean':
56 elif alias.expr == 'GLdouble':
63 elif alias.expr == 'GLfloat':
70 elif alias.expr in ('GLint', 'GLuint', 'GLsizei'):
80 function_name = self.prefix + suffix + self.ext_suffix
81 return function_name, arg_type
83 def visit_enum(self, enum):
84 return self.visit(glapi.GLint)
86 def visit_bitmask(self, bitmask):
87 return self.visit(glapi.GLint)
89 def visit_opaque(self, pointer):
90 return self.prefix + 'Pointerv' + self.ext_suffix, 'GLvoid *'
93 class GlTracer(Tracer):
100 ("TexCoord", "TEXTURE_COORD"),
101 ("EdgeFlag", "EDGE_FLAG"),
102 ("FogCoord", "FOG_COORD"),
103 ("SecondaryColor", "SECONDARY_COLOR"),
107 def header(self, api):
108 Tracer.header(self, api)
110 print '#include "gltrace.hpp"'
112 print '// Whether user arrays were used'
113 print 'static bool __user_arrays = false;'
114 print 'static bool __user_arrays_arb = false;'
115 print 'static bool __user_arrays_nv = false;'
118 # Which glVertexAttrib* variant to use
119 print 'enum vertex_attrib {'
120 print ' VERTEX_ATTRIB,'
121 print ' VERTEX_ATTRIB_ARB,'
122 print ' VERTEX_ATTRIB_NV,'
125 print 'static vertex_attrib __get_vertex_attrib(void) {'
126 print ' if (__user_arrays_arb || __user_arrays_nv) {'
127 print ' GLboolean __vertex_program = GL_FALSE;'
128 print ' __glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &__vertex_program);'
129 print ' if (__vertex_program) {'
130 print ' if (__user_arrays_nv) {'
131 print ' GLint __vertex_program_binding_nv = 0;'
132 print ' __glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &__vertex_program_binding_nv);'
133 print ' if (__vertex_program_binding_nv) {'
134 print ' return VERTEX_ATTRIB_NV;'
137 print ' return VERTEX_ATTRIB_ARB;'
140 print ' return VERTEX_ATTRIB;'
144 # Whether we need user arrays
145 print 'static inline bool __need_user_arrays(void)'
147 print ' if (!__user_arrays) {'
148 print ' return false;'
152 for camelcase_name, uppercase_name in self.arrays:
153 function_name = 'gl%sPointer' % camelcase_name
154 enable_name = 'GL_%s_ARRAY' % uppercase_name
155 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
156 print ' // %s' % function_name
157 self.array_prolog(api, uppercase_name)
158 print ' if (__glIsEnabled(%s)) {' % enable_name
159 print ' GLint __binding = 0;'
160 print ' __glGetIntegerv(%s, &__binding);' % binding_name
161 print ' if (!__binding) {'
162 self.array_cleanup(api, uppercase_name)
163 print ' return true;'
166 self.array_epilog(api, uppercase_name)
169 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
171 print ' // glVertexAttribPointer'
172 print ' if (__vertex_attrib == VERTEX_ATTRIB) {'
173 print ' GLint __max_vertex_attribs = 0;'
174 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
175 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
176 print ' GLint __enabled = 0;'
177 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
178 print ' if (__enabled) {'
179 print ' GLint __binding = 0;'
180 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
181 print ' if (!__binding) {'
182 print ' return true;'
188 print ' // glVertexAttribPointerARB'
189 print ' if (__vertex_attrib == VERTEX_ATTRIB_ARB) {'
190 print ' GLint __max_vertex_attribs = 0;'
191 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &__max_vertex_attribs);'
192 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
193 print ' GLint __enabled = 0;'
194 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &__enabled);'
195 print ' if (__enabled) {'
196 print ' GLint __binding = 0;'
197 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &__binding);'
198 print ' if (!__binding) {'
199 print ' return true;'
205 print ' // glVertexAttribPointerNV'
206 print ' if (__vertex_attrib == VERTEX_ATTRIB_NV) {'
207 print ' for (GLint index = 0; index < 16; ++index) {'
208 print ' GLint __enabled = 0;'
209 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
210 print ' if (__enabled) {'
211 print ' return true;'
217 print ' return false;'
221 print 'static void __trace_user_arrays(GLuint maxindex);'
224 print 'struct buffer_mapping {'
226 print ' GLint length;'
228 print ' bool explicit_flush;'
231 for target in self.buffer_targets:
232 print 'struct buffer_mapping __%s_mapping;' % target.lower();
234 print 'static inline struct buffer_mapping *'
235 print 'get_buffer_mapping(GLenum target) {'
236 print ' switch (target) {'
237 for target in self.buffer_targets:
238 print ' case GL_%s:' % target
239 print ' return & __%s_mapping;' % target.lower()
241 print ' os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
242 print ' return NULL;'
247 # Generate a helper function to determine whether a parameter name
248 # refers to a symbolic value or not
250 print 'is_symbolic_pname(GLenum pname) {'
251 print ' switch (pname) {'
252 for function, type, count, name in glparams.parameters:
253 if type is glapi.GLenum:
254 print ' case %s:' % name
255 print ' return true;'
257 print ' return false;'
262 # Generate a helper function to determine whether a parameter value is
263 # potentially symbolic or not; i.e., if the value can be represented in
265 print 'template<class T>'
266 print 'static inline bool'
267 print 'is_symbolic_param(T param) {'
268 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
272 # Generate a helper function to know how many elements a parameter has
273 print 'static size_t'
274 print '__gl_param_size(GLenum pname) {'
275 print ' switch (pname) {'
276 for function, type, count, name in glparams.parameters:
278 print ' case %s: return %u;' % (name, count)
279 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
280 print ' GLint num_compressed_texture_formats = 0;'
281 print ' __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
282 print ' return num_compressed_texture_formats;'
285 print r' os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
291 array_pointer_function_names = set((
299 "glSecondaryColorPointer",
301 "glInterleavedArrays",
303 "glVertexPointerEXT",
304 "glNormalPointerEXT",
307 "glTexCoordPointerEXT",
308 "glEdgeFlagPointerEXT",
309 "glFogCoordPointerEXT",
310 "glSecondaryColorPointerEXT",
312 "glVertexAttribPointer",
313 "glVertexAttribPointerARB",
314 "glVertexAttribPointerNV",
315 "glVertexAttribIPointer",
316 "glVertexAttribIPointerEXT",
317 "glVertexAttribLPointer",
318 "glVertexAttribLPointerEXT",
320 #"glMatrixIndexPointerARB",
323 draw_function_names = set((
326 'glDrawRangeElements',
328 'glMultiDrawElements',
329 'glDrawArraysInstanced',
330 "glDrawArraysInstancedBaseInstance",
331 'glDrawElementsInstanced',
332 'glDrawArraysInstancedARB',
333 'glDrawElementsInstancedARB',
334 'glDrawElementsBaseVertex',
335 'glDrawRangeElementsBaseVertex',
336 'glDrawElementsInstancedBaseVertex',
337 "glDrawElementsInstancedBaseInstance",
338 "glDrawElementsInstancedBaseVertexBaseInstance",
339 'glMultiDrawElementsBaseVertex',
340 'glDrawArraysIndirect',
341 'glDrawElementsIndirect',
343 'glDrawRangeElementsEXT',
344 'glDrawRangeElementsEXT_size',
345 'glMultiDrawArraysEXT',
346 'glMultiDrawElementsEXT',
347 'glMultiModeDrawArraysIBM',
348 'glMultiModeDrawElementsIBM',
349 'glDrawArraysInstancedEXT',
350 'glDrawElementsInstancedEXT',
353 interleaved_formats = [
366 'GL_T2F_C4F_N3F_V3F',
367 'GL_T4F_C4F_N3F_V4F',
370 def trace_function_impl_body(self, function):
371 # Defer tracing of user array pointers...
372 if function.name in self.array_pointer_function_names:
373 print ' GLint __array_buffer = 0;'
374 print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
375 print ' if (!__array_buffer) {'
376 print ' __user_arrays = true;'
377 if function.name == "glVertexAttribPointerARB":
378 print ' __user_arrays_arb = true;'
379 if function.name == "glVertexAttribPointerNV":
380 print ' __user_arrays_nv = true;'
381 self.dispatch_function(function)
383 # And also break down glInterleavedArrays into the individual calls
384 if function.name == 'glInterleavedArrays':
387 # Initialize the enable flags
388 for camelcase_name, uppercase_name in self.arrays:
389 flag_name = '__' + uppercase_name.lower()
390 print ' GLboolean %s = GL_FALSE;' % flag_name
393 # Switch for the interleaved formats
394 print ' switch (format) {'
395 for format in self.interleaved_formats:
396 print ' case %s:' % format
397 for camelcase_name, uppercase_name in self.arrays:
398 flag_name = '__' + uppercase_name.lower()
399 if format.find('_' + uppercase_name[0]) >= 0:
400 print ' %s = GL_TRUE;' % flag_name
407 # Emit fake glEnableClientState/glDisableClientState flags
408 for camelcase_name, uppercase_name in self.arrays:
409 flag_name = '__' + uppercase_name.lower()
410 enable_name = 'GL_%s_ARRAY' % uppercase_name
412 # Emit a fake function
414 print ' static const trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
415 print ' unsigned __call = trace::localWriter.beginEnter(&__sig);'
416 print ' trace::localWriter.beginArg(0);'
417 dump_instance(glapi.GLenum, enable_name)
418 print ' trace::localWriter.endArg();'
419 print ' trace::localWriter.endEnter();'
420 print ' trace::localWriter.beginLeave(__call);'
421 print ' trace::localWriter.endLeave();'
427 # ... to the draw calls
428 if function.name in self.draw_function_names:
429 print ' if (__need_user_arrays()) {'
430 arg_names = ', '.join([arg.name for arg in function.args[1:]])
431 print ' GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
432 print ' __trace_user_arrays(maxindex);'
435 # Emit a fake memcpy on buffer uploads
436 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', ):
437 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
438 print ' if (mapping && mapping->write && !mapping->explicit_flush) {'
439 self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
441 if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
442 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
443 print ' if (mapping) {'
444 if function.name.endswith('APPLE'):
445 print ' GLsizeiptr length = size;'
446 print ' mapping->explicit_flush = true;'
447 print ' //assert(offset + length <= mapping->length);'
448 self.emit_memcpy('(char *)mapping->map + offset', '(const char *)mapping->map + offset', 'length')
450 # FIXME: glFlushMappedNamedBufferRangeEXT
452 # Don't leave vertex attrib locations to chance. Instead emit fake
453 # glBindAttribLocation calls to ensure that the same locations will be
454 # used when retracing. Trying to remap locations after the fact would
455 # be an herculian task given that vertex attrib locations appear in
456 # many entry-points, including non-shader related ones.
457 if function.name == 'glLinkProgram':
458 Tracer.dispatch_function(self, function)
459 print ' GLint active_attributes = 0;'
460 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
461 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
462 print ' GLint size = 0;'
463 print ' GLenum type = 0;'
464 print ' GLchar name[256];'
465 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
466 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
467 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
468 print ' GLint location = __glGetAttribLocation(program, name);'
469 print ' if (location >= 0) {'
470 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
471 self.fake_call(bind_function, ['program', 'location', 'name'])
475 if function.name == 'glLinkProgramARB':
476 Tracer.dispatch_function(self, function)
477 print ' GLint active_attributes = 0;'
478 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
479 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
480 print ' GLint size = 0;'
481 print ' GLenum type = 0;'
482 print ' GLcharARB name[256];'
483 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
484 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
485 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
486 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
487 print ' if (location >= 0) {'
488 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
489 self.fake_call(bind_function, ['programObj', 'location', 'name'])
494 Tracer.trace_function_impl_body(self, function)
496 gremedy_functions = [
497 'glStringMarkerGREMEDY',
498 'glFrameTerminatorGREMEDY',
501 def dispatch_function(self, function):
502 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
503 # These functions have been dispatched already
506 # We implement the GREMEDY extensions, not the driver
507 if function.name in self.gremedy_functions:
510 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
512 for gremedy_function in self.gremedy_functions:
513 print ' %s (strcmp("%s", (const char *)%s) == 0) {' % (if_, gremedy_function, function.args[0].name)
514 print ' __result = (%s)&%s;' % (function.type, gremedy_function)
518 Tracer.dispatch_function(self, function)
522 # Override GL extensions
523 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
524 Tracer.dispatch_function(self, function, prefix = 'gltrace::__', suffix = '_override')
527 Tracer.dispatch_function(self, function)
529 def emit_memcpy(self, dest, src, length):
530 print ' unsigned __call = trace::localWriter.beginEnter(&trace::memcpy_sig);'
531 print ' trace::localWriter.beginArg(0);'
532 print ' trace::localWriter.writeOpaque(%s);' % dest
533 print ' trace::localWriter.endArg();'
534 print ' trace::localWriter.beginArg(1);'
535 print ' trace::localWriter.writeBlob(%s, %s);' % (src, length)
536 print ' trace::localWriter.endArg();'
537 print ' trace::localWriter.beginArg(2);'
538 print ' trace::localWriter.writeUInt(%s);' % length
539 print ' trace::localWriter.endArg();'
540 print ' trace::localWriter.endEnter();'
541 print ' trace::localWriter.beginLeave(__call);'
542 print ' trace::localWriter.endLeave();'
546 'ELEMENT_ARRAY_BUFFER',
548 'PIXEL_UNPACK_BUFFER',
551 def wrap_ret(self, function, instance):
552 Tracer.wrap_ret(self, function, instance)
555 if function.name in ('glMapBuffer', 'glMapBufferARB'):
556 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
557 print ' if (mapping) {'
558 print ' mapping->map = %s;' % (instance)
559 print ' mapping->length = 0;'
560 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
561 print ' mapping->write = (access != GL_READ_ONLY);'
562 print ' mapping->explicit_flush = false;'
565 if function.name == 'glMapBufferRange':
566 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
567 print ' if (mapping) {'
568 print ' mapping->map = %s;' % (instance)
569 print ' mapping->length = length;'
570 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
571 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
579 def gl_boolean(self, value):
580 return self.boolean_names[int(bool(value))]
582 # Names of the functions that unpack from a pixel buffer object. See the
583 # ARB_pixel_buffer_object specification.
584 unpack_function_names = set([
588 'glCompressedTexImage1D',
589 'glCompressedTexImage2D',
590 'glCompressedTexImage3D',
591 'glCompressedTexSubImage1D',
592 'glCompressedTexSubImage2D',
593 'glCompressedTexSubImage3D',
594 'glConvolutionFilter1D',
595 'glConvolutionFilter2D',
597 'glMultiTexImage1DEXT',
598 'glMultiTexImage2DEXT',
599 'glMultiTexImage3DEXT',
600 'glMultiTexSubImage1DEXT',
601 'glMultiTexSubImage2DEXT',
602 'glMultiTexSubImage3DEXT',
607 'glSeparableFilter2D',
615 'glTexSubImage1DEXT',
617 'glTexSubImage2DEXT',
619 'glTexSubImage3DEXT',
620 'glTextureImage1DEXT',
621 'glTextureImage2DEXT',
622 'glTextureImage3DEXT',
623 'glTextureSubImage1DEXT',
624 'glTextureSubImage2DEXT',
625 'glTextureSubImage3DEXT',
628 def dump_arg_instance(self, function, arg):
629 if function.name in self.draw_function_names and arg.name == 'indices':
630 print ' GLint __element_array_buffer = 0;'
631 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
632 print ' if (!__element_array_buffer) {'
633 if isinstance(arg.type, stdapi.Array):
634 print ' trace::localWriter.beginArray(%s);' % arg.type.length
635 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
636 print ' trace::localWriter.beginElement();'
637 print ' trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
638 print ' trace::localWriter.endElement();'
640 print ' trace::localWriter.endArray();'
642 print ' trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
644 Tracer.dump_arg_instance(self, function, arg)
648 # Recognize offsets instead of blobs when a PBO is bound
649 if function.name in self.unpack_function_names \
650 and (isinstance(arg.type, stdapi.Blob) \
651 or (isinstance(arg.type, stdapi.Const) \
652 and isinstance(arg.type.type, stdapi.Blob))):
654 print ' GLint __unpack_buffer = 0;'
655 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
656 print ' if (__unpack_buffer) {'
657 print ' trace::localWriter.writeOpaque(%s);' % arg.name
659 Tracer.dump_arg_instance(self, function, arg)
664 # Several GL state functions take GLenum symbolic names as
665 # integer/floats; so dump the symbolic name whenever possible
666 if function.name.startswith('gl') \
667 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
668 and arg.name == 'param':
670 assert function.args[arg.index - 1].name == 'pname'
671 assert function.args[arg.index - 1].type == glapi.GLenum
672 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
673 dump_instance(glapi.GLenum, arg.name)
675 Tracer.dump_arg_instance(self, function, arg)
679 Tracer.dump_arg_instance(self, function, arg)
681 def footer(self, api):
682 Tracer.footer(self, api)
684 # A simple state tracker to track the pointer values
686 print 'static void __trace_user_arrays(GLuint maxindex)'
689 for camelcase_name, uppercase_name in self.arrays:
690 function_name = 'gl%sPointer' % camelcase_name
691 enable_name = 'GL_%s_ARRAY' % uppercase_name
692 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
693 function = api.get_function_by_name(function_name)
695 print ' // %s' % function.prototype()
696 self.array_trace_prolog(api, uppercase_name)
697 self.array_prolog(api, uppercase_name)
698 print ' if (__glIsEnabled(%s)) {' % enable_name
699 print ' GLint __binding = 0;'
700 print ' __glGetIntegerv(%s, &__binding);' % binding_name
701 print ' if (!__binding) {'
703 # Get the arguments via glGet*
704 for arg in function.args:
705 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
706 arg_get_function, arg_type = TypeGetter().visit(arg.type)
707 print ' %s %s = 0;' % (arg_type, arg.name)
708 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
710 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
711 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
713 # Emit a fake function
714 self.array_trace_intermezzo(api, uppercase_name)
715 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
716 for arg in function.args:
717 assert not arg.output
718 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
719 if arg.name != 'pointer':
720 dump_instance(arg.type, arg.name)
722 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
723 print ' trace::localWriter.endArg();'
725 print ' trace::localWriter.endEnter();'
726 print ' trace::localWriter.beginLeave(__call);'
727 print ' trace::localWriter.endLeave();'
730 self.array_epilog(api, uppercase_name)
731 self.array_trace_epilog(api, uppercase_name)
734 # Samething, but for glVertexAttribPointer*
736 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
737 # - glVertexAttribPointer: no
738 # - glVertexAttribPointerARB: implementation dependent
739 # - glVertexAttribPointerNV: yes
741 # This means that the implementations of these functions do not always
742 # alias, and they need to be considered independently.
744 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
746 for suffix in ['', 'ARB', 'NV']:
748 SUFFIX = '_' + suffix
751 function_name = 'glVertexAttribPointer' + suffix
752 function = api.get_function_by_name(function_name)
754 print ' // %s' % function.prototype()
755 print ' if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
757 print ' GLint __max_vertex_attribs = 16;'
759 print ' GLint __max_vertex_attribs = 0;'
760 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
761 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
762 print ' GLint __enabled = 0;'
764 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
766 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
767 print ' if (__enabled) {'
768 print ' GLint __binding = 0;'
770 # It doesn't seem possible to use VBOs with NV_vertex_program.
771 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
772 print ' if (!__binding) {'
774 # Get the arguments via glGet*
775 for arg in function.args[1:]:
777 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
779 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
780 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
781 print ' %s %s = 0;' % (arg_type, arg.name)
782 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
784 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
785 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
787 # Emit a fake function
788 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
789 for arg in function.args:
790 assert not arg.output
791 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
792 if arg.name != 'pointer':
793 dump_instance(arg.type, arg.name)
795 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
796 print ' trace::localWriter.endArg();'
798 print ' trace::localWriter.endEnter();'
799 print ' trace::localWriter.beginLeave(__call);'
800 print ' trace::localWriter.endLeave();'
811 # Hooks for glTexCoordPointer, which is identical to the other array
812 # pointers except the fact that it is indexed by glClientActiveTexture.
815 def array_prolog(self, api, uppercase_name):
816 if uppercase_name == 'TEXTURE_COORD':
817 print ' GLint client_active_texture = 0;'
818 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
819 print ' GLint max_texture_coords = 0;'
820 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
821 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
822 print ' GLint texture = GL_TEXTURE0 + unit;'
823 print ' __glClientActiveTexture(texture);'
825 def array_trace_prolog(self, api, uppercase_name):
826 if uppercase_name == 'TEXTURE_COORD':
827 print ' bool client_active_texture_dirty = false;'
829 def array_epilog(self, api, uppercase_name):
830 if uppercase_name == 'TEXTURE_COORD':
832 self.array_cleanup(api, uppercase_name)
834 def array_cleanup(self, api, uppercase_name):
835 if uppercase_name == 'TEXTURE_COORD':
836 print ' __glClientActiveTexture(client_active_texture);'
838 def array_trace_intermezzo(self, api, uppercase_name):
839 if uppercase_name == 'TEXTURE_COORD':
840 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
841 print ' client_active_texture_dirty = true;'
842 self.fake_glClientActiveTexture_call(api, "texture");
845 def array_trace_epilog(self, api, uppercase_name):
846 if uppercase_name == 'TEXTURE_COORD':
847 print ' if (client_active_texture_dirty) {'
848 self.fake_glClientActiveTexture_call(api, "client_active_texture");
851 def fake_glClientActiveTexture_call(self, api, texture):
852 function = api.get_function_by_name('glClientActiveTexture')
853 self.fake_call(function, [texture])
855 def fake_call(self, function, args):
856 print ' unsigned __fake_call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
857 for arg, instance in zip(function.args, args):
858 assert not arg.output
859 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
860 dump_instance(arg.type, instance)
861 print ' trace::localWriter.endArg();'
862 print ' trace::localWriter.endEnter();'
863 print ' trace::localWriter.beginLeave(__fake_call);'
864 print ' trace::localWriter.endLeave();'