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):
42 self.long_suffix = long_suffix
44 def visit_const(self, const):
45 return self.visit(const.type)
47 def visit_alias(self, alias):
48 if alias.expr == 'GLboolean':
50 return self.prefix + 'Booleanv', alias.expr
52 return self.prefix + 'iv', 'GLint'
53 elif alias.expr == 'GLdouble':
55 return self.prefix + 'Doublev', alias.expr
57 return self.prefix + 'dv', alias.expr
58 elif alias.expr == 'GLfloat':
60 return self.prefix + 'Floatv', alias.expr
62 return self.prefix + 'fv', alias.expr
63 elif alias.expr in ('GLint', 'GLuint', 'GLsizei'):
65 return self.prefix + 'Integerv', 'GLint'
67 return self.prefix + 'iv', 'GLint'
72 def visit_enum(self, enum):
73 return self.visit(glapi.GLint)
75 def visit_bitmask(self, bitmask):
76 return self.visit(glapi.GLint)
78 def visit_opaque(self, pointer):
79 return self.prefix + 'Pointerv', 'GLvoid *'
82 class GlTracer(Tracer):
89 ("TexCoord", "TEXTURE_COORD"),
90 ("EdgeFlag", "EDGE_FLAG"),
91 ("FogCoord", "FOG_COORD"),
92 ("SecondaryColor", "SECONDARY_COLOR"),
96 def header(self, api):
97 Tracer.header(self, api)
99 print '// Whether user arrays were used'
100 print 'static bool __user_arrays = false;'
102 # Whether we need user arrays
103 print 'static inline bool __need_user_arrays(void)'
105 print ' if (!__user_arrays) {'
106 print ' return false;'
110 for camelcase_name, uppercase_name in self.arrays:
111 function_name = 'gl%sPointer' % camelcase_name
112 enable_name = 'GL_%s_ARRAY' % uppercase_name
113 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
114 print ' // %s' % function_name
115 self.array_prolog(api, uppercase_name)
116 print ' if (__glIsEnabled(%s)) {' % enable_name
117 print ' GLint __binding = 0;'
118 print ' __glGetIntegerv(%s, &__binding);' % binding_name
119 print ' if (!__binding) {'
120 self.array_cleanup(api, uppercase_name)
121 print ' return true;'
124 self.array_epilog(api, uppercase_name)
127 print ' GLboolean __vertex_program = GL_FALSE;'
128 print ' __glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &__vertex_program);'
129 print ' if (__vertex_program) {'
130 print ' // glVertexAttribPointerARB'
131 print ' GLint __max_vertex_attribs = 0;'
132 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &__max_vertex_attribs);'
133 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
134 print ' GLint __enabled = 0;'
135 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &__enabled);'
136 print ' if (__enabled) {'
137 print ' GLint __binding = 0;'
138 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &__binding);'
139 print ' if (!__binding) {'
140 print ' return true;'
145 print ' // glVertexAttribPointer'
146 print ' GLint __max_vertex_attribs = 0;'
147 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
148 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
149 print ' GLint __enabled = 0;'
150 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
151 print ' if (__enabled) {'
152 print ' GLint __binding = 0;'
153 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
154 print ' if (!__binding) {'
155 print ' return true;'
162 print ' return false;'
166 print 'static void __trace_user_arrays(GLuint maxindex);'
169 print 'struct buffer_mapping {'
171 print ' GLint length;'
173 print ' bool explicit_flush;'
176 for target in self.buffer_targets:
177 print 'struct buffer_mapping __%s_mapping;' % target.lower();
179 print 'static inline struct buffer_mapping *'
180 print 'get_buffer_mapping(GLenum target) {'
181 print ' switch(target) {'
182 for target in self.buffer_targets:
183 print ' case GL_%s:' % target
184 print ' return & __%s_mapping;' % target.lower()
186 print ' OS::DebugMessage("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
187 print ' return NULL;'
192 # Generate memcpy's signature
193 self.trace_function_decl(glapi.memcpy)
195 # Generate a helper function to determine whether a parameter name
196 # refers to a symbolic value or not
198 print 'is_symbolic_pname(GLenum pname) {'
199 print ' switch(pname) {'
200 for function, type, count, name in glparams.parameters:
201 if type is glapi.GLenum:
202 print ' case %s:' % name
203 print ' return true;'
205 print ' return false;'
210 # Generate a helper function to determine whether a parameter value is
211 # potentially symbolic or not; i.e., if the value can be represented in
213 print 'template<class T>'
214 print 'static inline bool'
215 print 'is_symbolic_param(T param) {'
216 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
220 # Generate a helper function to know how many elements a parameter has
221 print 'static size_t'
222 print '__gl_param_size(GLenum pname) {'
223 print ' switch(pname) {'
224 for function, type, count, name in glparams.parameters:
226 print ' case %s: return %u;' % (name, count)
227 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
228 print ' GLint num_compressed_texture_formats = 0;'
229 print ' __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
230 print ' return num_compressed_texture_formats;'
233 print r' OS::DebugMessage("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
239 array_pointer_function_names = set((
247 "glSecondaryColorPointer",
249 "glInterleavedArrays",
251 "glVertexPointerEXT",
252 "glNormalPointerEXT",
255 "glTexCoordPointerEXT",
256 "glEdgeFlagPointerEXT",
257 "glFogCoordPointerEXT",
258 "glSecondaryColorPointerEXT",
260 "glVertexAttribPointer",
261 "glVertexAttribPointerARB",
262 "glVertexAttribPointerNV",
263 "glVertexAttribIPointer",
264 "glVertexAttribIPointerEXT",
265 "glVertexAttribLPointer",
266 "glVertexAttribLPointerEXT",
268 #"glMatrixIndexPointerARB",
271 draw_function_names = set((
274 'glDrawRangeElements',
276 'glMultiDrawElements',
277 'glDrawArraysInstanced',
278 'glDrawElementsInstanced',
279 'glDrawArraysInstancedARB',
280 'glDrawElementsInstancedARB',
281 'glDrawElementsBaseVertex',
282 'glDrawRangeElementsBaseVertex',
283 'glDrawElementsInstancedBaseVertex',
284 'glMultiDrawElementsBaseVertex',
285 'glDrawArraysIndirect',
286 'glDrawElementsIndirect',
288 'glDrawRangeElementsEXT',
289 'glDrawRangeElementsEXT_size',
290 'glMultiDrawArraysEXT',
291 'glMultiDrawElementsEXT',
292 'glMultiModeDrawArraysIBM',
293 'glMultiModeDrawElementsIBM',
294 'glDrawArraysInstancedEXT',
295 'glDrawElementsInstancedEXT',
298 interleaved_formats = [
311 'GL_T2F_C4F_N3F_V3F',
312 'GL_T4F_C4F_N3F_V4F',
315 def trace_function_impl_body(self, function):
316 # Defer tracing of user array pointers...
317 if function.name in self.array_pointer_function_names:
318 print ' GLint __array_buffer = 0;'
319 print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
320 print ' if (!__array_buffer) {'
321 print ' __user_arrays = true;'
322 self.dispatch_function(function)
324 # And also break down glInterleavedArrays into the individual calls
325 if function.name == 'glInterleavedArrays':
328 # Initialize the enable flags
329 for camelcase_name, uppercase_name in self.arrays:
330 flag_name = '__' + uppercase_name.lower()
331 print ' GLboolean %s = GL_FALSE;' % flag_name
334 # Switch for the interleaved formats
335 print ' switch (format) {'
336 for format in self.interleaved_formats:
337 print ' case %s:' % format
338 for camelcase_name, uppercase_name in self.arrays:
339 flag_name = '__' + uppercase_name.lower()
340 if format.find('_' + uppercase_name[0]) >= 0:
341 print ' %s = GL_TRUE;' % flag_name
348 # Emit fake glEnableClientState/glDisableClientState flags
349 for camelcase_name, uppercase_name in self.arrays:
350 flag_name = '__' + uppercase_name.lower()
351 enable_name = 'GL_%s_ARRAY' % uppercase_name
353 # Emit a fake function
355 print ' static const Trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
356 print ' unsigned __call = __writer.beginEnter(&__sig);'
357 print ' __writer.beginArg(0);'
358 dump_instance(glapi.GLenum, enable_name)
359 print ' __writer.endArg();'
360 print ' __writer.endEnter();'
361 print ' __writer.beginLeave(__call);'
362 print ' __writer.endLeave();'
368 # ... to the draw calls
369 if function.name in self.draw_function_names:
370 print ' if (__need_user_arrays()) {'
371 arg_names = ', '.join([arg.name for arg in function.args[1:]])
372 print ' GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
373 print ' __trace_user_arrays(maxindex);'
376 # Emit a fake memcpy on buffer uploads
377 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', ):
378 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
379 print ' if (mapping && mapping->write && !mapping->explicit_flush) {'
380 self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
382 if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
383 # TODO: avoid copying [0, offset] bytes
384 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
385 print ' if (mapping) {'
386 if function.name.endswith('APPLE'):
387 print ' GLsizeiptr length = size;'
388 print ' mapping->explicit_flush = true;'
389 print ' //assert(offset + length <= mapping->length);'
390 self.emit_memcpy('mapping->map', 'mapping->map', 'offset + length')
392 # FIXME: glFlushMappedNamedBufferRangeEXT
394 # Don't leave vertex attrib locations to chance. Instead emit fake
395 # glBindAttribLocation calls to ensure that the same locations will be
396 # used when retracing. Trying to remap locations after the fact would
397 # be an herculian task given that vertex attrib locations appear in
398 # many entry-points, including non-shader related ones.
399 if function.name == 'glLinkProgram':
400 Tracer.dispatch_function(self, function)
401 print ' GLint active_attributes = 0;'
402 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
403 print ' for (GLuint attrib = 0; attrib < active_attributes; ++attrib) {'
404 print ' GLint size = 0;'
405 print ' GLenum type = 0;'
406 print ' GLchar name[256];'
407 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
408 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
409 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
410 print ' GLint location = __glGetAttribLocation(program, name);'
411 print ' if (location >= 0) {'
412 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
413 self.fake_call(bind_function, ['program', 'location', 'name'])
417 if function.name == 'glLinkProgramARB':
418 Tracer.dispatch_function(self, function)
419 print ' GLint active_attributes = 0;'
420 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
421 print ' for (GLuint attrib = 0; attrib < active_attributes; ++attrib) {'
422 print ' GLint size = 0;'
423 print ' GLenum type = 0;'
424 print ' GLcharARB name[256];'
425 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
426 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
427 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
428 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
429 print ' if (location >= 0) {'
430 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
431 self.fake_call(bind_function, ['programObj', 'location', 'name'])
436 Tracer.trace_function_impl_body(self, function)
438 def dispatch_function(self, function):
439 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
440 # These functions have been dispatched already
443 Tracer.dispatch_function(self, function)
445 def emit_memcpy(self, dest, src, length):
446 print ' unsigned __call = __writer.beginEnter(&__memcpy_sig);'
447 print ' __writer.beginArg(0);'
448 print ' __writer.writeOpaque(%s);' % dest
449 print ' __writer.endArg();'
450 print ' __writer.beginArg(1);'
451 print ' __writer.writeBlob(%s, %s);' % (src, length)
452 print ' __writer.endArg();'
453 print ' __writer.beginArg(2);'
454 print ' __writer.writeUInt(%s);' % length
455 print ' __writer.endArg();'
456 print ' __writer.endEnter();'
457 print ' __writer.beginLeave(__call);'
458 print ' __writer.endLeave();'
462 'ELEMENT_ARRAY_BUFFER',
464 'PIXEL_UNPACK_BUFFER',
467 def wrap_ret(self, function, instance):
468 Tracer.wrap_ret(self, function, instance)
470 if function.name in ('glMapBuffer', 'glMapBufferARB'):
471 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
472 print ' if (mapping) {'
473 print ' mapping->map = %s;' % (instance)
474 print ' mapping->length = 0;'
475 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
476 print ' mapping->write = (access != GL_READ_ONLY);'
477 print ' mapping->explicit_flush = false;'
480 if function.name == 'glMapBufferRange':
481 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
482 print ' if (mapping) {'
483 print ' mapping->map = %s;' % (instance)
484 print ' mapping->length = length;'
485 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
486 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
494 def gl_boolean(self, value):
495 return self.boolean_names[int(bool(value))]
497 # Names of the functions that unpack from a pixel buffer object. See the
498 # ARB_pixel_buffer_object specification.
499 unpack_function_names = set([
503 'glCompressedTexImage1D',
504 'glCompressedTexImage2D',
505 'glCompressedTexImage3D',
506 'glCompressedTexSubImage1D',
507 'glCompressedTexSubImage2D',
508 'glCompressedTexSubImage3D',
509 'glConvolutionFilter1D',
510 'glConvolutionFilter2D',
512 'glMultiTexImage1DEXT',
513 'glMultiTexImage2DEXT',
514 'glMultiTexImage3DEXT',
515 'glMultiTexSubImage1DEXT',
516 'glMultiTexSubImage2DEXT',
517 'glMultiTexSubImage3DEXT',
522 'glSeparableFilter2D',
530 'glTexSubImage1DEXT',
532 'glTexSubImage2DEXT',
534 'glTexSubImage3DEXT',
535 'glTextureImage1DEXT',
536 'glTextureImage2DEXT',
537 'glTextureImage3DEXT',
538 'glTextureSubImage1DEXT',
539 'glTextureSubImage2DEXT',
540 'glTextureSubImage3DEXT',
543 def dump_arg_instance(self, function, arg):
544 if function.name in self.draw_function_names and arg.name == 'indices':
545 print ' GLint __element_array_buffer = 0;'
546 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
547 print ' if (!__element_array_buffer) {'
548 if isinstance(arg.type, stdapi.Array):
549 print ' __writer.beginArray(%s);' % arg.type.length
550 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
551 print ' __writer.beginElement();'
552 print ' __writer.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
553 print ' __writer.endElement();'
555 print ' __writer.endArray();'
557 print ' __writer.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
559 Tracer.dump_arg_instance(self, function, arg)
563 # Recognize offsets instead of blobs when a PBO is bound
564 if function.name in self.unpack_function_names \
565 and (isinstance(arg.type, stdapi.Blob) \
566 or (isinstance(arg.type, stdapi.Const) \
567 and isinstance(arg.type.type, stdapi.Blob))):
569 print ' GLint __unpack_buffer = 0;'
570 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
571 print ' if (__unpack_buffer) {'
572 print ' __writer.writeOpaque(%s);' % arg.name
574 Tracer.dump_arg_instance(self, function, arg)
579 # Several GL state functions take GLenum symbolic names as
580 # integer/floats; so dump the symbolic name whenever possible
581 if function.name.startswith('gl') \
582 and arg.type in (glapi.GLint, glapi.GLfloat) \
583 and arg.name == 'param':
585 assert function.args[arg.index - 1].name == 'pname'
586 assert function.args[arg.index - 1].type == glapi.GLenum
587 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
588 dump_instance(glapi.GLenum, arg.name)
590 Tracer.dump_arg_instance(self, function, arg)
594 Tracer.dump_arg_instance(self, function, arg)
596 def footer(self, api):
597 Tracer.footer(self, api)
599 # A simple state tracker to track the pointer values
601 print 'static void __trace_user_arrays(GLuint maxindex)'
604 for camelcase_name, uppercase_name in self.arrays:
605 function_name = 'gl%sPointer' % camelcase_name
606 enable_name = 'GL_%s_ARRAY' % uppercase_name
607 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
608 function = api.get_function_by_name(function_name)
610 print ' // %s' % function.name
611 self.array_trace_prolog(api, uppercase_name)
612 self.array_prolog(api, uppercase_name)
613 print ' if (__glIsEnabled(%s)) {' % enable_name
614 print ' GLint __binding = 0;'
615 print ' __glGetIntegerv(%s, &__binding);' % binding_name
616 print ' if (!__binding) {'
618 # Get the arguments via glGet*
619 for arg in function.args:
620 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
621 arg_get_function, arg_type = TypeGetter().visit(arg.type)
622 print ' %s %s = 0;' % (arg_type, arg.name)
623 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
625 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
626 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
628 # Emit a fake function
629 self.array_trace_intermezzo(api, uppercase_name)
630 print ' unsigned __call = __writer.beginEnter(&__%s_sig);' % (function.name,)
631 for arg in function.args:
632 assert not arg.output
633 print ' __writer.beginArg(%u);' % (arg.index,)
634 if arg.name != 'pointer':
635 dump_instance(arg.type, arg.name)
637 print ' __writer.writeBlob((const void *)%s, __size);' % (arg.name)
638 print ' __writer.endArg();'
640 print ' __writer.endEnter();'
641 print ' __writer.beginLeave(__call);'
642 print ' __writer.endLeave();'
645 self.array_epilog(api, uppercase_name)
646 self.array_trace_epilog(api, uppercase_name)
649 # Samething, but for glVertexAttribPointer*
651 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
652 # - glVertexAttribPointer: no
653 # - glVertexAttribPointerARB: implementation dependent
654 # - glVertexAttribPointerNV: yes
656 # This means that the implementations of these functions do not always
657 # alias, and they need to be considered independently.
659 print ' GLboolean __vertex_program = GL_FALSE;'
660 print ' __glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &__vertex_program);'
661 for suffix in ['', 'ARB']:
663 SUFFIX = '_' + suffix
668 print ' if (%s__vertex_program) {' % logic_op
669 function_name = 'glVertexAttribPointer' + suffix
670 print ' // %s' % function_name
671 print ' if (__glVertexAttribPointer%s_ptr &&' % suffix
672 print ' (__glVertexAttribPointer%s_ptr != __glVertexAttribPointer_ptr)) {' % suffix
673 print ' GLint __max_vertex_attribs = 0;'
674 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
675 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
676 print ' GLint __enabled = 0;'
677 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
678 print ' if (__enabled) {'
679 print ' GLint __binding = 0;'
680 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
681 print ' if (!__binding) {'
683 function = api.get_function_by_name(function_name)
685 # Get the arguments via glGet*
686 for arg in function.args[1:]:
687 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
688 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False).visit(arg.type)
689 print ' %s %s = 0;' % (arg_type, arg.name)
690 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
692 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
693 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
695 # Emit a fake function
696 print ' unsigned __call = __writer.beginEnter(&__%s_sig);' % (function.name,)
697 for arg in function.args:
698 assert not arg.output
699 print ' __writer.beginArg(%u);' % (arg.index,)
700 if arg.name != 'pointer':
701 dump_instance(arg.type, arg.name)
703 print ' __writer.writeBlob((const void *)%s, __size);' % (arg.name)
704 print ' __writer.endArg();'
706 print ' __writer.endEnter();'
707 print ' __writer.beginLeave(__call);'
708 print ' __writer.endLeave();'
720 # Hooks for glTexCoordPointer, which is identical to the other array
721 # pointers except the fact that it is indexed by glClientActiveTexture.
724 def array_prolog(self, api, uppercase_name):
725 if uppercase_name == 'TEXTURE_COORD':
726 print ' GLint client_active_texture = 0;'
727 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
728 print ' GLint max_texture_coords = 0;'
729 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
730 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
731 print ' GLenum texture = GL_TEXTURE0 + unit;'
732 print ' __glClientActiveTexture(texture);'
734 def array_trace_prolog(self, api, uppercase_name):
735 if uppercase_name == 'TEXTURE_COORD':
736 print ' bool client_active_texture_dirty = false;'
738 def array_epilog(self, api, uppercase_name):
739 if uppercase_name == 'TEXTURE_COORD':
741 self.array_cleanup(api, uppercase_name)
743 def array_cleanup(self, api, uppercase_name):
744 if uppercase_name == 'TEXTURE_COORD':
745 print ' __glClientActiveTexture(client_active_texture);'
747 def array_trace_intermezzo(self, api, uppercase_name):
748 if uppercase_name == 'TEXTURE_COORD':
749 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
750 print ' client_active_texture_dirty = true;'
751 self.fake_glClientActiveTexture_call(api, "texture");
754 def array_trace_epilog(self, api, uppercase_name):
755 if uppercase_name == 'TEXTURE_COORD':
756 print ' if (client_active_texture_dirty) {'
757 self.fake_glClientActiveTexture_call(api, "client_active_texture");
760 def fake_glClientActiveTexture_call(self, api, texture):
761 function = api.get_function_by_name('glClientActiveTexture')
762 self.fake_call(function, [texture])
764 def fake_call(self, function, args):
765 print ' unsigned __fake_call = __writer.beginEnter(&__%s_sig);' % (function.name,)
766 for arg, instance in zip(function.args, args):
767 assert not arg.output
768 print ' __writer.beginArg(%u);' % (arg.index,)
769 dump_instance(arg.type, instance)
770 print ' __writer.endArg();'
771 print ' __writer.endEnter();'
772 print ' __writer.beginLeave(__fake_call);'
773 print ' __writer.endLeave();'