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::DebugMessage("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
242 print ' return NULL;'
247 # Generate memcpy's signature
248 self.trace_function_decl(glapi.memcpy)
250 # Generate a helper function to determine whether a parameter name
251 # refers to a symbolic value or not
253 print 'is_symbolic_pname(GLenum pname) {'
254 print ' switch(pname) {'
255 for function, type, count, name in glparams.parameters:
256 if type is glapi.GLenum:
257 print ' case %s:' % name
258 print ' return true;'
260 print ' return false;'
265 # Generate a helper function to determine whether a parameter value is
266 # potentially symbolic or not; i.e., if the value can be represented in
268 print 'template<class T>'
269 print 'static inline bool'
270 print 'is_symbolic_param(T param) {'
271 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
275 # Generate a helper function to know how many elements a parameter has
276 print 'static size_t'
277 print '__gl_param_size(GLenum pname) {'
278 print ' switch(pname) {'
279 for function, type, count, name in glparams.parameters:
281 print ' case %s: return %u;' % (name, count)
282 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
283 print ' GLint num_compressed_texture_formats = 0;'
284 print ' __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
285 print ' return num_compressed_texture_formats;'
288 print r' OS::DebugMessage("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
294 array_pointer_function_names = set((
302 "glSecondaryColorPointer",
304 "glInterleavedArrays",
306 "glVertexPointerEXT",
307 "glNormalPointerEXT",
310 "glTexCoordPointerEXT",
311 "glEdgeFlagPointerEXT",
312 "glFogCoordPointerEXT",
313 "glSecondaryColorPointerEXT",
315 "glVertexAttribPointer",
316 "glVertexAttribPointerARB",
317 "glVertexAttribPointerNV",
318 "glVertexAttribIPointer",
319 "glVertexAttribIPointerEXT",
320 "glVertexAttribLPointer",
321 "glVertexAttribLPointerEXT",
323 #"glMatrixIndexPointerARB",
326 draw_function_names = set((
329 'glDrawRangeElements',
331 'glMultiDrawElements',
332 'glDrawArraysInstanced',
333 "glDrawArraysInstancedBaseInstance",
334 'glDrawElementsInstanced',
335 'glDrawArraysInstancedARB',
336 'glDrawElementsInstancedARB',
337 'glDrawElementsBaseVertex',
338 'glDrawRangeElementsBaseVertex',
339 'glDrawElementsInstancedBaseVertex',
340 "glDrawElementsInstancedBaseInstance",
341 "glDrawElementsInstancedBaseVertexBaseInstance",
342 'glMultiDrawElementsBaseVertex',
343 'glDrawArraysIndirect',
344 'glDrawElementsIndirect',
346 'glDrawRangeElementsEXT',
347 'glDrawRangeElementsEXT_size',
348 'glMultiDrawArraysEXT',
349 'glMultiDrawElementsEXT',
350 'glMultiModeDrawArraysIBM',
351 'glMultiModeDrawElementsIBM',
352 'glDrawArraysInstancedEXT',
353 'glDrawElementsInstancedEXT',
356 interleaved_formats = [
369 'GL_T2F_C4F_N3F_V3F',
370 'GL_T4F_C4F_N3F_V4F',
373 def trace_function_impl_body(self, function):
374 # Defer tracing of user array pointers...
375 if function.name in self.array_pointer_function_names:
376 print ' GLint __array_buffer = 0;'
377 print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
378 print ' if (!__array_buffer) {'
379 print ' __user_arrays = true;'
380 if function.name == "glVertexAttribPointerARB":
381 print ' __user_arrays_arb = true;'
382 if function.name == "glVertexAttribPointerNV":
383 print ' __user_arrays_nv = true;'
384 self.dispatch_function(function)
386 # And also break down glInterleavedArrays into the individual calls
387 if function.name == 'glInterleavedArrays':
390 # Initialize the enable flags
391 for camelcase_name, uppercase_name in self.arrays:
392 flag_name = '__' + uppercase_name.lower()
393 print ' GLboolean %s = GL_FALSE;' % flag_name
396 # Switch for the interleaved formats
397 print ' switch (format) {'
398 for format in self.interleaved_formats:
399 print ' case %s:' % format
400 for camelcase_name, uppercase_name in self.arrays:
401 flag_name = '__' + uppercase_name.lower()
402 if format.find('_' + uppercase_name[0]) >= 0:
403 print ' %s = GL_TRUE;' % flag_name
410 # Emit fake glEnableClientState/glDisableClientState flags
411 for camelcase_name, uppercase_name in self.arrays:
412 flag_name = '__' + uppercase_name.lower()
413 enable_name = 'GL_%s_ARRAY' % uppercase_name
415 # Emit a fake function
417 print ' static const Trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
418 print ' unsigned __call = Trace::localWriter.beginEnter(&__sig);'
419 print ' Trace::localWriter.beginArg(0);'
420 dump_instance(glapi.GLenum, enable_name)
421 print ' Trace::localWriter.endArg();'
422 print ' Trace::localWriter.endEnter();'
423 print ' Trace::localWriter.beginLeave(__call);'
424 print ' Trace::localWriter.endLeave();'
430 # ... to the draw calls
431 if function.name in self.draw_function_names:
432 print ' if (__need_user_arrays()) {'
433 arg_names = ', '.join([arg.name for arg in function.args[1:]])
434 print ' GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
435 print ' __trace_user_arrays(maxindex);'
438 # Emit a fake memcpy on buffer uploads
439 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', ):
440 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
441 print ' if (mapping && mapping->write && !mapping->explicit_flush) {'
442 self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
444 if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
445 # TODO: avoid copying [0, offset] bytes
446 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
447 print ' if (mapping) {'
448 if function.name.endswith('APPLE'):
449 print ' GLsizeiptr length = size;'
450 print ' mapping->explicit_flush = true;'
451 print ' //assert(offset + length <= mapping->length);'
452 self.emit_memcpy('mapping->map', 'mapping->map', 'offset + length')
454 # FIXME: glFlushMappedNamedBufferRangeEXT
456 # Don't leave vertex attrib locations to chance. Instead emit fake
457 # glBindAttribLocation calls to ensure that the same locations will be
458 # used when retracing. Trying to remap locations after the fact would
459 # be an herculian task given that vertex attrib locations appear in
460 # many entry-points, including non-shader related ones.
461 if function.name == 'glLinkProgram':
462 Tracer.dispatch_function(self, function)
463 print ' GLint active_attributes = 0;'
464 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
465 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
466 print ' GLint size = 0;'
467 print ' GLenum type = 0;'
468 print ' GLchar name[256];'
469 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
470 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
471 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
472 print ' GLint location = __glGetAttribLocation(program, name);'
473 print ' if (location >= 0) {'
474 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
475 self.fake_call(bind_function, ['program', 'location', 'name'])
479 if function.name == 'glLinkProgramARB':
480 Tracer.dispatch_function(self, function)
481 print ' GLint active_attributes = 0;'
482 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
483 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
484 print ' GLint size = 0;'
485 print ' GLenum type = 0;'
486 print ' GLcharARB name[256];'
487 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
488 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
489 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
490 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
491 print ' if (location >= 0) {'
492 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
493 self.fake_call(bind_function, ['programObj', 'location', 'name'])
498 Tracer.trace_function_impl_body(self, function)
500 gremedy_functions = [
501 'glStringMarkerGREMEDY',
502 'glFrameTerminatorGREMEDY',
505 def dispatch_function(self, function):
506 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
507 # These functions have been dispatched already
510 # We implement the GREMEDY extensions, not the driver
511 if function.name in self.gremedy_functions:
514 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
516 for gremedy_function in self.gremedy_functions:
517 print ' %s (strcmp("%s", (const char *)%s) == 0) {' % (if_, gremedy_function, function.args[0].name)
518 print ' __result = (%s)&%s;' % (function.type, gremedy_function)
522 Tracer.dispatch_function(self, function)
526 # Override GL extensions
527 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
528 Tracer.dispatch_function(self, function, prefix = 'gltrace::__', suffix = '_override')
531 Tracer.dispatch_function(self, function)
533 def emit_memcpy(self, dest, src, length):
534 print ' unsigned __call = Trace::localWriter.beginEnter(&__memcpy_sig);'
535 print ' Trace::localWriter.beginArg(0);'
536 print ' Trace::localWriter.writeOpaque(%s);' % dest
537 print ' Trace::localWriter.endArg();'
538 print ' Trace::localWriter.beginArg(1);'
539 print ' Trace::localWriter.writeBlob(%s, %s);' % (src, length)
540 print ' Trace::localWriter.endArg();'
541 print ' Trace::localWriter.beginArg(2);'
542 print ' Trace::localWriter.writeUInt(%s);' % length
543 print ' Trace::localWriter.endArg();'
544 print ' Trace::localWriter.endEnter();'
545 print ' Trace::localWriter.beginLeave(__call);'
546 print ' Trace::localWriter.endLeave();'
550 'ELEMENT_ARRAY_BUFFER',
552 'PIXEL_UNPACK_BUFFER',
555 def wrap_ret(self, function, instance):
556 Tracer.wrap_ret(self, function, instance)
559 if function.name in ('glMapBuffer', 'glMapBufferARB'):
560 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
561 print ' if (mapping) {'
562 print ' mapping->map = %s;' % (instance)
563 print ' mapping->length = 0;'
564 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
565 print ' mapping->write = (access != GL_READ_ONLY);'
566 print ' mapping->explicit_flush = false;'
569 if function.name == 'glMapBufferRange':
570 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
571 print ' if (mapping) {'
572 print ' mapping->map = %s;' % (instance)
573 print ' mapping->length = length;'
574 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
575 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
583 def gl_boolean(self, value):
584 return self.boolean_names[int(bool(value))]
586 # Names of the functions that unpack from a pixel buffer object. See the
587 # ARB_pixel_buffer_object specification.
588 unpack_function_names = set([
592 'glCompressedTexImage1D',
593 'glCompressedTexImage2D',
594 'glCompressedTexImage3D',
595 'glCompressedTexSubImage1D',
596 'glCompressedTexSubImage2D',
597 'glCompressedTexSubImage3D',
598 'glConvolutionFilter1D',
599 'glConvolutionFilter2D',
601 'glMultiTexImage1DEXT',
602 'glMultiTexImage2DEXT',
603 'glMultiTexImage3DEXT',
604 'glMultiTexSubImage1DEXT',
605 'glMultiTexSubImage2DEXT',
606 'glMultiTexSubImage3DEXT',
611 'glSeparableFilter2D',
619 'glTexSubImage1DEXT',
621 'glTexSubImage2DEXT',
623 'glTexSubImage3DEXT',
624 'glTextureImage1DEXT',
625 'glTextureImage2DEXT',
626 'glTextureImage3DEXT',
627 'glTextureSubImage1DEXT',
628 'glTextureSubImage2DEXT',
629 'glTextureSubImage3DEXT',
632 def dump_arg_instance(self, function, arg):
633 if function.name in self.draw_function_names and arg.name == 'indices':
634 print ' GLint __element_array_buffer = 0;'
635 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
636 print ' if (!__element_array_buffer) {'
637 if isinstance(arg.type, stdapi.Array):
638 print ' Trace::localWriter.beginArray(%s);' % arg.type.length
639 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
640 print ' Trace::localWriter.beginElement();'
641 print ' Trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
642 print ' Trace::localWriter.endElement();'
644 print ' Trace::localWriter.endArray();'
646 print ' Trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
648 Tracer.dump_arg_instance(self, function, arg)
652 # Recognize offsets instead of blobs when a PBO is bound
653 if function.name in self.unpack_function_names \
654 and (isinstance(arg.type, stdapi.Blob) \
655 or (isinstance(arg.type, stdapi.Const) \
656 and isinstance(arg.type.type, stdapi.Blob))):
658 print ' GLint __unpack_buffer = 0;'
659 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
660 print ' if (__unpack_buffer) {'
661 print ' Trace::localWriter.writeOpaque(%s);' % arg.name
663 Tracer.dump_arg_instance(self, function, arg)
668 # Several GL state functions take GLenum symbolic names as
669 # integer/floats; so dump the symbolic name whenever possible
670 if function.name.startswith('gl') \
671 and arg.type in (glapi.GLint, glapi.GLfloat) \
672 and arg.name == 'param':
674 assert function.args[arg.index - 1].name == 'pname'
675 assert function.args[arg.index - 1].type == glapi.GLenum
676 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
677 dump_instance(glapi.GLenum, arg.name)
679 Tracer.dump_arg_instance(self, function, arg)
683 Tracer.dump_arg_instance(self, function, arg)
685 def footer(self, api):
686 Tracer.footer(self, api)
688 # A simple state tracker to track the pointer values
690 print 'static void __trace_user_arrays(GLuint maxindex)'
693 for camelcase_name, uppercase_name in self.arrays:
694 function_name = 'gl%sPointer' % camelcase_name
695 enable_name = 'GL_%s_ARRAY' % uppercase_name
696 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
697 function = api.get_function_by_name(function_name)
699 print ' // %s' % function.name
700 self.array_trace_prolog(api, uppercase_name)
701 self.array_prolog(api, uppercase_name)
702 print ' if (__glIsEnabled(%s)) {' % enable_name
703 print ' GLint __binding = 0;'
704 print ' __glGetIntegerv(%s, &__binding);' % binding_name
705 print ' if (!__binding) {'
707 # Get the arguments via glGet*
708 for arg in function.args:
709 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
710 arg_get_function, arg_type = TypeGetter().visit(arg.type)
711 print ' %s %s = 0;' % (arg_type, arg.name)
712 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
714 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
715 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
717 # Emit a fake function
718 self.array_trace_intermezzo(api, uppercase_name)
719 print ' unsigned __call = Trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
720 for arg in function.args:
721 assert not arg.output
722 print ' Trace::localWriter.beginArg(%u);' % (arg.index,)
723 if arg.name != 'pointer':
724 dump_instance(arg.type, arg.name)
726 print ' Trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
727 print ' Trace::localWriter.endArg();'
729 print ' Trace::localWriter.endEnter();'
730 print ' Trace::localWriter.beginLeave(__call);'
731 print ' Trace::localWriter.endLeave();'
734 self.array_epilog(api, uppercase_name)
735 self.array_trace_epilog(api, uppercase_name)
738 # Samething, but for glVertexAttribPointer*
740 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
741 # - glVertexAttribPointer: no
742 # - glVertexAttribPointerARB: implementation dependent
743 # - glVertexAttribPointerNV: yes
745 # This means that the implementations of these functions do not always
746 # alias, and they need to be considered independently.
748 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
750 for suffix in ['', 'ARB', 'NV']:
752 SUFFIX = '_' + suffix
755 function_name = 'glVertexAttribPointer' + suffix
756 print ' // %s' % function_name
757 print ' if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
759 print ' GLint __max_vertex_attribs = 16;'
761 print ' GLint __max_vertex_attribs = 0;'
762 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
763 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
764 print ' GLint __enabled = 0;'
766 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
768 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
769 print ' if (__enabled) {'
770 print ' GLint __binding = 0;'
772 # It doesn't seem possible to use VBOs with NV_vertex_program.
773 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
774 print ' if (!__binding) {'
776 function = api.get_function_by_name(function_name)
778 # Get the arguments via glGet*
779 for arg in function.args[1:]:
781 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
783 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
784 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
785 print ' %s %s = 0;' % (arg_type, arg.name)
786 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
788 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
789 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
791 # Emit a fake function
792 print ' unsigned __call = Trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
793 for arg in function.args:
794 assert not arg.output
795 print ' Trace::localWriter.beginArg(%u);' % (arg.index,)
796 if arg.name != 'pointer':
797 dump_instance(arg.type, arg.name)
799 print ' Trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
800 print ' Trace::localWriter.endArg();'
802 print ' Trace::localWriter.endEnter();'
803 print ' Trace::localWriter.beginLeave(__call);'
804 print ' Trace::localWriter.endLeave();'
815 # Hooks for glTexCoordPointer, which is identical to the other array
816 # pointers except the fact that it is indexed by glClientActiveTexture.
819 def array_prolog(self, api, uppercase_name):
820 if uppercase_name == 'TEXTURE_COORD':
821 print ' GLint client_active_texture = 0;'
822 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
823 print ' GLint max_texture_coords = 0;'
824 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
825 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
826 print ' GLint texture = GL_TEXTURE0 + unit;'
827 print ' __glClientActiveTexture(texture);'
829 def array_trace_prolog(self, api, uppercase_name):
830 if uppercase_name == 'TEXTURE_COORD':
831 print ' bool client_active_texture_dirty = false;'
833 def array_epilog(self, api, uppercase_name):
834 if uppercase_name == 'TEXTURE_COORD':
836 self.array_cleanup(api, uppercase_name)
838 def array_cleanup(self, api, uppercase_name):
839 if uppercase_name == 'TEXTURE_COORD':
840 print ' __glClientActiveTexture(client_active_texture);'
842 def array_trace_intermezzo(self, api, uppercase_name):
843 if uppercase_name == 'TEXTURE_COORD':
844 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
845 print ' client_active_texture_dirty = true;'
846 self.fake_glClientActiveTexture_call(api, "texture");
849 def array_trace_epilog(self, api, uppercase_name):
850 if uppercase_name == 'TEXTURE_COORD':
851 print ' if (client_active_texture_dirty) {'
852 self.fake_glClientActiveTexture_call(api, "client_active_texture");
855 def fake_glClientActiveTexture_call(self, api, texture):
856 function = api.get_function_by_name('glClientActiveTexture')
857 self.fake_call(function, [texture])
859 def fake_call(self, function, args):
860 print ' unsigned __fake_call = Trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
861 for arg, instance in zip(function.args, args):
862 assert not arg.output
863 print ' Trace::localWriter.beginArg(%u);' % (arg.index,)
864 dump_instance(arg.type, instance)
865 print ' Trace::localWriter.endArg();'
866 print ' Trace::localWriter.endEnter();'
867 print ' Trace::localWriter.beginLeave(__fake_call);'
868 print ' Trace::localWriter.endLeave();'