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."""
33 from 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 '// Whether user arrays were used'
111 print 'static bool __user_arrays = false;'
112 print 'static bool __user_arrays_arb = false;'
113 print 'static bool __user_arrays_nv = false;'
116 # Which glVertexAttrib* variant to use
117 print 'enum vertex_attrib {'
118 print ' VERTEX_ATTRIB,'
119 print ' VERTEX_ATTRIB_ARB,'
120 print ' VERTEX_ATTRIB_NV,'
123 print 'static vertex_attrib __get_vertex_attrib(void) {'
124 print ' if (__user_arrays_arb) {'
125 print ' GLboolean __vertex_program = GL_FALSE;'
126 print ' __glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &__vertex_program);'
127 print ' if (__vertex_program) {'
128 print ' if (__user_arrays_nv) {'
129 print ' GLint __vertex_program_binding_nv = 0;'
130 print ' __glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &__vertex_program_binding_nv);'
131 print ' if (__vertex_program_binding_nv) {'
132 print ' return VERTEX_ATTRIB_NV;'
135 print ' return VERTEX_ATTRIB_ARB;'
138 print ' return VERTEX_ATTRIB;'
142 # Whether we need user arrays
143 print 'static inline bool __need_user_arrays(void)'
145 print ' if (!__user_arrays) {'
146 print ' return false;'
150 for camelcase_name, uppercase_name in self.arrays:
151 function_name = 'gl%sPointer' % camelcase_name
152 enable_name = 'GL_%s_ARRAY' % uppercase_name
153 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
154 print ' // %s' % function_name
155 self.array_prolog(api, uppercase_name)
156 print ' if (__glIsEnabled(%s)) {' % enable_name
157 print ' GLint __binding = 0;'
158 print ' __glGetIntegerv(%s, &__binding);' % binding_name
159 print ' if (!__binding) {'
160 self.array_cleanup(api, uppercase_name)
161 print ' return true;'
164 self.array_epilog(api, uppercase_name)
167 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
169 print ' // glVertexAttribPointer'
170 print ' if (__vertex_attrib == VERTEX_ATTRIB) {'
171 print ' GLint __max_vertex_attribs = 0;'
172 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
173 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
174 print ' GLint __enabled = 0;'
175 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
176 print ' if (__enabled) {'
177 print ' GLint __binding = 0;'
178 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
179 print ' if (!__binding) {'
180 print ' return true;'
186 print ' // glVertexAttribPointerARB'
187 print ' if (__vertex_attrib == VERTEX_ATTRIB_ARB) {'
188 print ' GLint __max_vertex_attribs = 0;'
189 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &__max_vertex_attribs);'
190 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
191 print ' GLint __enabled = 0;'
192 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &__enabled);'
193 print ' if (__enabled) {'
194 print ' GLint __binding = 0;'
195 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &__binding);'
196 print ' if (!__binding) {'
197 print ' return true;'
203 print ' // glVertexAttribPointerNV'
204 print ' if (__vertex_attrib == VERTEX_ATTRIB_NV) {'
205 print ' for (GLint index = 0; index < 16; ++index) {'
206 print ' GLint __enabled = 0;'
207 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
208 print ' if (__enabled) {'
209 print ' return true;'
215 print ' return false;'
219 print 'static void __trace_user_arrays(GLuint maxindex);'
222 print 'struct buffer_mapping {'
224 print ' GLint length;'
226 print ' bool explicit_flush;'
229 for target in self.buffer_targets:
230 print 'struct buffer_mapping __%s_mapping;' % target.lower();
232 print 'static inline struct buffer_mapping *'
233 print 'get_buffer_mapping(GLenum target) {'
234 print ' switch(target) {'
235 for target in self.buffer_targets:
236 print ' case GL_%s:' % target
237 print ' return & __%s_mapping;' % target.lower()
239 print ' OS::DebugMessage("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
240 print ' return NULL;'
245 # Generate memcpy's signature
246 self.trace_function_decl(glapi.memcpy)
248 # Generate a helper function to determine whether a parameter name
249 # refers to a symbolic value or not
251 print 'is_symbolic_pname(GLenum pname) {'
252 print ' switch(pname) {'
253 for function, type, count, name in glparams.parameters:
254 if type is glapi.GLenum:
255 print ' case %s:' % name
256 print ' return true;'
258 print ' return false;'
263 # Generate a helper function to determine whether a parameter value is
264 # potentially symbolic or not; i.e., if the value can be represented in
266 print 'template<class T>'
267 print 'static inline bool'
268 print 'is_symbolic_param(T param) {'
269 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
273 # Generate a helper function to know how many elements a parameter has
274 print 'static size_t'
275 print '__gl_param_size(GLenum pname) {'
276 print ' switch(pname) {'
277 for function, type, count, name in glparams.parameters:
279 print ' case %s: return %u;' % (name, count)
280 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
281 print ' GLint num_compressed_texture_formats = 0;'
282 print ' __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
283 print ' return num_compressed_texture_formats;'
286 print r' OS::DebugMessage("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
292 array_pointer_function_names = set((
300 "glSecondaryColorPointer",
302 "glInterleavedArrays",
304 "glVertexPointerEXT",
305 "glNormalPointerEXT",
308 "glTexCoordPointerEXT",
309 "glEdgeFlagPointerEXT",
310 "glFogCoordPointerEXT",
311 "glSecondaryColorPointerEXT",
313 "glVertexAttribPointer",
314 "glVertexAttribPointerARB",
315 "glVertexAttribPointerNV",
316 "glVertexAttribIPointer",
317 "glVertexAttribIPointerEXT",
318 "glVertexAttribLPointer",
319 "glVertexAttribLPointerEXT",
321 #"glMatrixIndexPointerARB",
324 draw_function_names = set((
327 'glDrawRangeElements',
329 'glMultiDrawElements',
330 'glDrawArraysInstanced',
331 'glDrawElementsInstanced',
332 'glDrawArraysInstancedARB',
333 'glDrawElementsInstancedARB',
334 'glDrawElementsBaseVertex',
335 'glDrawRangeElementsBaseVertex',
336 'glDrawElementsInstancedBaseVertex',
337 'glMultiDrawElementsBaseVertex',
338 'glDrawArraysIndirect',
339 'glDrawElementsIndirect',
341 'glDrawRangeElementsEXT',
342 'glDrawRangeElementsEXT_size',
343 'glMultiDrawArraysEXT',
344 'glMultiDrawElementsEXT',
345 'glMultiModeDrawArraysIBM',
346 'glMultiModeDrawElementsIBM',
347 'glDrawArraysInstancedEXT',
348 'glDrawElementsInstancedEXT',
351 interleaved_formats = [
364 'GL_T2F_C4F_N3F_V3F',
365 'GL_T4F_C4F_N3F_V4F',
368 def trace_function_impl_body(self, function):
369 # Defer tracing of user array pointers...
370 if function.name in self.array_pointer_function_names:
371 print ' GLint __array_buffer = 0;'
372 print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
373 print ' if (!__array_buffer) {'
374 print ' __user_arrays = true;'
375 if function.name == "glVertexAttribPointerARB":
376 print ' __user_arrays_arb = true;'
377 if function.name == "glVertexAttribPointerNV":
378 print ' __user_arrays_nv = true;'
379 self.dispatch_function(function)
381 # And also break down glInterleavedArrays into the individual calls
382 if function.name == 'glInterleavedArrays':
385 # Initialize the enable flags
386 for camelcase_name, uppercase_name in self.arrays:
387 flag_name = '__' + uppercase_name.lower()
388 print ' GLboolean %s = GL_FALSE;' % flag_name
391 # Switch for the interleaved formats
392 print ' switch (format) {'
393 for format in self.interleaved_formats:
394 print ' case %s:' % format
395 for camelcase_name, uppercase_name in self.arrays:
396 flag_name = '__' + uppercase_name.lower()
397 if format.find('_' + uppercase_name[0]) >= 0:
398 print ' %s = GL_TRUE;' % flag_name
405 # Emit fake glEnableClientState/glDisableClientState flags
406 for camelcase_name, uppercase_name in self.arrays:
407 flag_name = '__' + uppercase_name.lower()
408 enable_name = 'GL_%s_ARRAY' % uppercase_name
410 # Emit a fake function
412 print ' static const Trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
413 print ' unsigned __call = __writer.beginEnter(&__sig);'
414 print ' __writer.beginArg(0);'
415 dump_instance(glapi.GLenum, enable_name)
416 print ' __writer.endArg();'
417 print ' __writer.endEnter();'
418 print ' __writer.beginLeave(__call);'
419 print ' __writer.endLeave();'
425 # ... to the draw calls
426 if function.name in self.draw_function_names:
427 print ' if (__need_user_arrays()) {'
428 arg_names = ', '.join([arg.name for arg in function.args[1:]])
429 print ' GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
430 print ' __trace_user_arrays(maxindex);'
433 # Emit a fake memcpy on buffer uploads
434 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', ):
435 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
436 print ' if (mapping && mapping->write && !mapping->explicit_flush) {'
437 self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
439 if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
440 # TODO: avoid copying [0, offset] bytes
441 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
442 print ' if (mapping) {'
443 if function.name.endswith('APPLE'):
444 print ' GLsizeiptr length = size;'
445 print ' mapping->explicit_flush = true;'
446 print ' //assert(offset + length <= mapping->length);'
447 self.emit_memcpy('mapping->map', 'mapping->map', 'offset + length')
449 # FIXME: glFlushMappedNamedBufferRangeEXT
451 # Don't leave vertex attrib locations to chance. Instead emit fake
452 # glBindAttribLocation calls to ensure that the same locations will be
453 # used when retracing. Trying to remap locations after the fact would
454 # be an herculian task given that vertex attrib locations appear in
455 # many entry-points, including non-shader related ones.
456 if function.name == 'glLinkProgram':
457 Tracer.dispatch_function(self, function)
458 print ' GLint active_attributes = 0;'
459 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
460 print ' for (GLuint attrib = 0; attrib < active_attributes; ++attrib) {'
461 print ' GLint size = 0;'
462 print ' GLenum type = 0;'
463 print ' GLchar name[256];'
464 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
465 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
466 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
467 print ' GLint location = __glGetAttribLocation(program, name);'
468 print ' if (location >= 0) {'
469 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
470 self.fake_call(bind_function, ['program', 'location', 'name'])
474 if function.name == 'glLinkProgramARB':
475 Tracer.dispatch_function(self, function)
476 print ' GLint active_attributes = 0;'
477 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
478 print ' for (GLuint attrib = 0; attrib < active_attributes; ++attrib) {'
479 print ' GLint size = 0;'
480 print ' GLenum type = 0;'
481 print ' GLcharARB name[256];'
482 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
483 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
484 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
485 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
486 print ' if (location >= 0) {'
487 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
488 self.fake_call(bind_function, ['programObj', 'location', 'name'])
493 Tracer.trace_function_impl_body(self, function)
495 def dispatch_function(self, function):
496 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
497 # These functions have been dispatched already
500 Tracer.dispatch_function(self, function)
502 def emit_memcpy(self, dest, src, length):
503 print ' unsigned __call = __writer.beginEnter(&__memcpy_sig);'
504 print ' __writer.beginArg(0);'
505 print ' __writer.writeOpaque(%s);' % dest
506 print ' __writer.endArg();'
507 print ' __writer.beginArg(1);'
508 print ' __writer.writeBlob(%s, %s);' % (src, length)
509 print ' __writer.endArg();'
510 print ' __writer.beginArg(2);'
511 print ' __writer.writeUInt(%s);' % length
512 print ' __writer.endArg();'
513 print ' __writer.endEnter();'
514 print ' __writer.beginLeave(__call);'
515 print ' __writer.endLeave();'
519 'ELEMENT_ARRAY_BUFFER',
521 'PIXEL_UNPACK_BUFFER',
524 def wrap_ret(self, function, instance):
525 Tracer.wrap_ret(self, function, instance)
527 if function.name in ('glMapBuffer', 'glMapBufferARB'):
528 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
529 print ' if (mapping) {'
530 print ' mapping->map = %s;' % (instance)
531 print ' mapping->length = 0;'
532 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
533 print ' mapping->write = (access != GL_READ_ONLY);'
534 print ' mapping->explicit_flush = false;'
537 if function.name == 'glMapBufferRange':
538 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
539 print ' if (mapping) {'
540 print ' mapping->map = %s;' % (instance)
541 print ' mapping->length = length;'
542 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
543 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
551 def gl_boolean(self, value):
552 return self.boolean_names[int(bool(value))]
554 # Names of the functions that unpack from a pixel buffer object. See the
555 # ARB_pixel_buffer_object specification.
556 unpack_function_names = set([
560 'glCompressedTexImage1D',
561 'glCompressedTexImage2D',
562 'glCompressedTexImage3D',
563 'glCompressedTexSubImage1D',
564 'glCompressedTexSubImage2D',
565 'glCompressedTexSubImage3D',
566 'glConvolutionFilter1D',
567 'glConvolutionFilter2D',
569 'glMultiTexImage1DEXT',
570 'glMultiTexImage2DEXT',
571 'glMultiTexImage3DEXT',
572 'glMultiTexSubImage1DEXT',
573 'glMultiTexSubImage2DEXT',
574 'glMultiTexSubImage3DEXT',
579 'glSeparableFilter2D',
587 'glTexSubImage1DEXT',
589 'glTexSubImage2DEXT',
591 'glTexSubImage3DEXT',
592 'glTextureImage1DEXT',
593 'glTextureImage2DEXT',
594 'glTextureImage3DEXT',
595 'glTextureSubImage1DEXT',
596 'glTextureSubImage2DEXT',
597 'glTextureSubImage3DEXT',
600 def dump_arg_instance(self, function, arg):
601 if function.name in self.draw_function_names and arg.name == 'indices':
602 print ' GLint __element_array_buffer = 0;'
603 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
604 print ' if (!__element_array_buffer) {'
605 if isinstance(arg.type, stdapi.Array):
606 print ' __writer.beginArray(%s);' % arg.type.length
607 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
608 print ' __writer.beginElement();'
609 print ' __writer.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
610 print ' __writer.endElement();'
612 print ' __writer.endArray();'
614 print ' __writer.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
616 Tracer.dump_arg_instance(self, function, arg)
620 # Recognize offsets instead of blobs when a PBO is bound
621 if function.name in self.unpack_function_names \
622 and (isinstance(arg.type, stdapi.Blob) \
623 or (isinstance(arg.type, stdapi.Const) \
624 and isinstance(arg.type.type, stdapi.Blob))):
626 print ' GLint __unpack_buffer = 0;'
627 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
628 print ' if (__unpack_buffer) {'
629 print ' __writer.writeOpaque(%s);' % arg.name
631 Tracer.dump_arg_instance(self, function, arg)
636 # Several GL state functions take GLenum symbolic names as
637 # integer/floats; so dump the symbolic name whenever possible
638 if function.name.startswith('gl') \
639 and arg.type in (glapi.GLint, glapi.GLfloat) \
640 and arg.name == 'param':
642 assert function.args[arg.index - 1].name == 'pname'
643 assert function.args[arg.index - 1].type == glapi.GLenum
644 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
645 dump_instance(glapi.GLenum, arg.name)
647 Tracer.dump_arg_instance(self, function, arg)
651 Tracer.dump_arg_instance(self, function, arg)
653 def footer(self, api):
654 Tracer.footer(self, api)
656 # A simple state tracker to track the pointer values
658 print 'static void __trace_user_arrays(GLuint maxindex)'
661 for camelcase_name, uppercase_name in self.arrays:
662 function_name = 'gl%sPointer' % camelcase_name
663 enable_name = 'GL_%s_ARRAY' % uppercase_name
664 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
665 function = api.get_function_by_name(function_name)
667 print ' // %s' % function.name
668 self.array_trace_prolog(api, uppercase_name)
669 self.array_prolog(api, uppercase_name)
670 print ' if (__glIsEnabled(%s)) {' % enable_name
671 print ' GLint __binding = 0;'
672 print ' __glGetIntegerv(%s, &__binding);' % binding_name
673 print ' if (!__binding) {'
675 # Get the arguments via glGet*
676 for arg in function.args:
677 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
678 arg_get_function, arg_type = TypeGetter().visit(arg.type)
679 print ' %s %s = 0;' % (arg_type, arg.name)
680 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
682 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
683 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
685 # Emit a fake function
686 self.array_trace_intermezzo(api, uppercase_name)
687 print ' unsigned __call = __writer.beginEnter(&__%s_sig);' % (function.name,)
688 for arg in function.args:
689 assert not arg.output
690 print ' __writer.beginArg(%u);' % (arg.index,)
691 if arg.name != 'pointer':
692 dump_instance(arg.type, arg.name)
694 print ' __writer.writeBlob((const void *)%s, __size);' % (arg.name)
695 print ' __writer.endArg();'
697 print ' __writer.endEnter();'
698 print ' __writer.beginLeave(__call);'
699 print ' __writer.endLeave();'
702 self.array_epilog(api, uppercase_name)
703 self.array_trace_epilog(api, uppercase_name)
706 # Samething, but for glVertexAttribPointer*
708 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
709 # - glVertexAttribPointer: no
710 # - glVertexAttribPointerARB: implementation dependent
711 # - glVertexAttribPointerNV: yes
713 # This means that the implementations of these functions do not always
714 # alias, and they need to be considered independently.
716 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
718 for suffix in ['', 'ARB', 'NV']:
720 SUFFIX = '_' + suffix
723 function_name = 'glVertexAttribPointer' + suffix
724 print ' // %s' % function_name
725 print ' if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
727 print ' GLint __max_vertex_attribs = 16;'
729 print ' GLint __max_vertex_attribs = 0;'
730 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
731 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
732 print ' GLint __enabled = 0;'
734 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
736 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
737 print ' if (__enabled) {'
738 print ' GLint __binding = 0;'
740 # It doesn't seem possible to use VBOs with NV_vertex_program.
741 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
742 print ' if (!__binding) {'
744 function = api.get_function_by_name(function_name)
746 # Get the arguments via glGet*
747 for arg in function.args[1:]:
749 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
751 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
752 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
753 print ' %s %s = 0;' % (arg_type, arg.name)
754 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
756 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
757 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
759 # Emit a fake function
760 print ' unsigned __call = __writer.beginEnter(&__%s_sig);' % (function.name,)
761 for arg in function.args:
762 assert not arg.output
763 print ' __writer.beginArg(%u);' % (arg.index,)
764 if arg.name != 'pointer':
765 dump_instance(arg.type, arg.name)
767 print ' __writer.writeBlob((const void *)%s, __size);' % (arg.name)
768 print ' __writer.endArg();'
770 print ' __writer.endEnter();'
771 print ' __writer.beginLeave(__call);'
772 print ' __writer.endLeave();'
783 # Hooks for glTexCoordPointer, which is identical to the other array
784 # pointers except the fact that it is indexed by glClientActiveTexture.
787 def array_prolog(self, api, uppercase_name):
788 if uppercase_name == 'TEXTURE_COORD':
789 print ' GLint client_active_texture = 0;'
790 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
791 print ' GLint max_texture_coords = 0;'
792 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
793 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
794 print ' GLenum texture = GL_TEXTURE0 + unit;'
795 print ' __glClientActiveTexture(texture);'
797 def array_trace_prolog(self, api, uppercase_name):
798 if uppercase_name == 'TEXTURE_COORD':
799 print ' bool client_active_texture_dirty = false;'
801 def array_epilog(self, api, uppercase_name):
802 if uppercase_name == 'TEXTURE_COORD':
804 self.array_cleanup(api, uppercase_name)
806 def array_cleanup(self, api, uppercase_name):
807 if uppercase_name == 'TEXTURE_COORD':
808 print ' __glClientActiveTexture(client_active_texture);'
810 def array_trace_intermezzo(self, api, uppercase_name):
811 if uppercase_name == 'TEXTURE_COORD':
812 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
813 print ' client_active_texture_dirty = true;'
814 self.fake_glClientActiveTexture_call(api, "texture");
817 def array_trace_epilog(self, api, uppercase_name):
818 if uppercase_name == 'TEXTURE_COORD':
819 print ' if (client_active_texture_dirty) {'
820 self.fake_glClientActiveTexture_call(api, "client_active_texture");
823 def fake_glClientActiveTexture_call(self, api, texture):
824 function = api.get_function_by_name('glClientActiveTexture')
825 self.fake_call(function, [texture])
827 def fake_call(self, function, args):
828 print ' unsigned __fake_call = __writer.beginEnter(&__%s_sig);' % (function.name,)
829 for arg, instance in zip(function.args, args):
830 assert not arg.output
831 print ' __writer.beginArg(%u);' % (arg.index,)
832 dump_instance(arg.type, instance)
833 print ' __writer.endArg();'
834 print ' __writer.endEnter();'
835 print ' __writer.beginLeave(__fake_call);'
836 print ' __writer.endLeave();'