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;'
113 # Whether we need user arrays
114 print 'static inline bool __need_user_arrays(void)'
116 print ' if (!__user_arrays) {'
117 print ' return false;'
121 for camelcase_name, uppercase_name in self.arrays:
122 function_name = 'gl%sPointer' % camelcase_name
123 enable_name = 'GL_%s_ARRAY' % uppercase_name
124 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
125 print ' // %s' % function_name
126 self.array_prolog(api, uppercase_name)
127 print ' if (__glIsEnabled(%s)) {' % enable_name
128 print ' GLint __binding = 0;'
129 print ' __glGetIntegerv(%s, &__binding);' % binding_name
130 print ' if (!__binding) {'
131 self.array_cleanup(api, uppercase_name)
132 print ' return true;'
135 self.array_epilog(api, uppercase_name)
138 print ' GLboolean __vertex_program = GL_FALSE;'
139 print ' __glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &__vertex_program);'
140 print ' if (__vertex_program) {'
141 print ' // glVertexAttribPointerARB'
142 print ' GLint __max_vertex_attribs = 0;'
143 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &__max_vertex_attribs);'
144 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
145 print ' GLint __enabled = 0;'
146 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &__enabled);'
147 print ' if (__enabled) {'
148 print ' GLint __binding = 0;'
149 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &__binding);'
150 print ' if (!__binding) {'
151 print ' return true;'
156 print ' // glVertexAttribPointer'
157 print ' GLint __max_vertex_attribs = 0;'
158 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
159 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
160 print ' GLint __enabled = 0;'
161 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
162 print ' if (__enabled) {'
163 print ' GLint __binding = 0;'
164 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
165 print ' if (!__binding) {'
166 print ' return true;'
173 print ' return false;'
177 print 'static void __trace_user_arrays(GLuint maxindex);'
180 print 'struct buffer_mapping {'
182 print ' GLint length;'
184 print ' bool explicit_flush;'
187 for target in self.buffer_targets:
188 print 'struct buffer_mapping __%s_mapping;' % target.lower();
190 print 'static inline struct buffer_mapping *'
191 print 'get_buffer_mapping(GLenum target) {'
192 print ' switch(target) {'
193 for target in self.buffer_targets:
194 print ' case GL_%s:' % target
195 print ' return & __%s_mapping;' % target.lower()
197 print ' OS::DebugMessage("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
198 print ' return NULL;'
203 # Generate memcpy's signature
204 self.trace_function_decl(glapi.memcpy)
206 # Generate a helper function to determine whether a parameter name
207 # refers to a symbolic value or not
209 print 'is_symbolic_pname(GLenum pname) {'
210 print ' switch(pname) {'
211 for function, type, count, name in glparams.parameters:
212 if type is glapi.GLenum:
213 print ' case %s:' % name
214 print ' return true;'
216 print ' return false;'
221 # Generate a helper function to determine whether a parameter value is
222 # potentially symbolic or not; i.e., if the value can be represented in
224 print 'template<class T>'
225 print 'static inline bool'
226 print 'is_symbolic_param(T param) {'
227 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
231 # Generate a helper function to know how many elements a parameter has
232 print 'static size_t'
233 print '__gl_param_size(GLenum pname) {'
234 print ' switch(pname) {'
235 for function, type, count, name in glparams.parameters:
237 print ' case %s: return %u;' % (name, count)
238 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
239 print ' GLint num_compressed_texture_formats = 0;'
240 print ' __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
241 print ' return num_compressed_texture_formats;'
244 print r' OS::DebugMessage("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
250 array_pointer_function_names = set((
258 "glSecondaryColorPointer",
260 "glInterleavedArrays",
262 "glVertexPointerEXT",
263 "glNormalPointerEXT",
266 "glTexCoordPointerEXT",
267 "glEdgeFlagPointerEXT",
268 "glFogCoordPointerEXT",
269 "glSecondaryColorPointerEXT",
271 "glVertexAttribPointer",
272 "glVertexAttribPointerARB",
273 "glVertexAttribPointerNV",
274 "glVertexAttribIPointer",
275 "glVertexAttribIPointerEXT",
276 "glVertexAttribLPointer",
277 "glVertexAttribLPointerEXT",
279 #"glMatrixIndexPointerARB",
282 draw_function_names = set((
285 'glDrawRangeElements',
287 'glMultiDrawElements',
288 'glDrawArraysInstanced',
289 'glDrawElementsInstanced',
290 'glDrawArraysInstancedARB',
291 'glDrawElementsInstancedARB',
292 'glDrawElementsBaseVertex',
293 'glDrawRangeElementsBaseVertex',
294 'glDrawElementsInstancedBaseVertex',
295 'glMultiDrawElementsBaseVertex',
296 'glDrawArraysIndirect',
297 'glDrawElementsIndirect',
299 'glDrawRangeElementsEXT',
300 'glDrawRangeElementsEXT_size',
301 'glMultiDrawArraysEXT',
302 'glMultiDrawElementsEXT',
303 'glMultiModeDrawArraysIBM',
304 'glMultiModeDrawElementsIBM',
305 'glDrawArraysInstancedEXT',
306 'glDrawElementsInstancedEXT',
309 interleaved_formats = [
322 'GL_T2F_C4F_N3F_V3F',
323 'GL_T4F_C4F_N3F_V4F',
326 def trace_function_impl_body(self, function):
327 # Defer tracing of user array pointers...
328 if function.name in self.array_pointer_function_names:
329 print ' GLint __array_buffer = 0;'
330 print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
331 print ' if (!__array_buffer) {'
332 print ' __user_arrays = true;'
333 self.dispatch_function(function)
335 # And also break down glInterleavedArrays into the individual calls
336 if function.name == 'glInterleavedArrays':
339 # Initialize the enable flags
340 for camelcase_name, uppercase_name in self.arrays:
341 flag_name = '__' + uppercase_name.lower()
342 print ' GLboolean %s = GL_FALSE;' % flag_name
345 # Switch for the interleaved formats
346 print ' switch (format) {'
347 for format in self.interleaved_formats:
348 print ' case %s:' % format
349 for camelcase_name, uppercase_name in self.arrays:
350 flag_name = '__' + uppercase_name.lower()
351 if format.find('_' + uppercase_name[0]) >= 0:
352 print ' %s = GL_TRUE;' % flag_name
359 # Emit fake glEnableClientState/glDisableClientState flags
360 for camelcase_name, uppercase_name in self.arrays:
361 flag_name = '__' + uppercase_name.lower()
362 enable_name = 'GL_%s_ARRAY' % uppercase_name
364 # Emit a fake function
366 print ' static const Trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
367 print ' unsigned __call = __writer.beginEnter(&__sig);'
368 print ' __writer.beginArg(0);'
369 dump_instance(glapi.GLenum, enable_name)
370 print ' __writer.endArg();'
371 print ' __writer.endEnter();'
372 print ' __writer.beginLeave(__call);'
373 print ' __writer.endLeave();'
379 # ... to the draw calls
380 if function.name in self.draw_function_names:
381 print ' if (__need_user_arrays()) {'
382 arg_names = ', '.join([arg.name for arg in function.args[1:]])
383 print ' GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
384 print ' __trace_user_arrays(maxindex);'
387 # Emit a fake memcpy on buffer uploads
388 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', ):
389 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
390 print ' if (mapping && mapping->write && !mapping->explicit_flush) {'
391 self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
393 if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
394 # TODO: avoid copying [0, offset] bytes
395 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
396 print ' if (mapping) {'
397 if function.name.endswith('APPLE'):
398 print ' GLsizeiptr length = size;'
399 print ' mapping->explicit_flush = true;'
400 print ' //assert(offset + length <= mapping->length);'
401 self.emit_memcpy('mapping->map', 'mapping->map', 'offset + length')
403 # FIXME: glFlushMappedNamedBufferRangeEXT
405 # Don't leave vertex attrib locations to chance. Instead emit fake
406 # glBindAttribLocation calls to ensure that the same locations will be
407 # used when retracing. Trying to remap locations after the fact would
408 # be an herculian task given that vertex attrib locations appear in
409 # many entry-points, including non-shader related ones.
410 if function.name == 'glLinkProgram':
411 Tracer.dispatch_function(self, function)
412 print ' GLint active_attributes = 0;'
413 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
414 print ' for (GLuint attrib = 0; attrib < active_attributes; ++attrib) {'
415 print ' GLint size = 0;'
416 print ' GLenum type = 0;'
417 print ' GLchar name[256];'
418 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
419 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
420 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
421 print ' GLint location = __glGetAttribLocation(program, name);'
422 print ' if (location >= 0) {'
423 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
424 self.fake_call(bind_function, ['program', 'location', 'name'])
428 if function.name == 'glLinkProgramARB':
429 Tracer.dispatch_function(self, function)
430 print ' GLint active_attributes = 0;'
431 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
432 print ' for (GLuint attrib = 0; attrib < active_attributes; ++attrib) {'
433 print ' GLint size = 0;'
434 print ' GLenum type = 0;'
435 print ' GLcharARB name[256];'
436 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
437 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
438 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
439 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
440 print ' if (location >= 0) {'
441 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
442 self.fake_call(bind_function, ['programObj', 'location', 'name'])
447 Tracer.trace_function_impl_body(self, function)
449 def dispatch_function(self, function):
450 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
451 # These functions have been dispatched already
454 Tracer.dispatch_function(self, function)
456 def emit_memcpy(self, dest, src, length):
457 print ' unsigned __call = __writer.beginEnter(&__memcpy_sig);'
458 print ' __writer.beginArg(0);'
459 print ' __writer.writeOpaque(%s);' % dest
460 print ' __writer.endArg();'
461 print ' __writer.beginArg(1);'
462 print ' __writer.writeBlob(%s, %s);' % (src, length)
463 print ' __writer.endArg();'
464 print ' __writer.beginArg(2);'
465 print ' __writer.writeUInt(%s);' % length
466 print ' __writer.endArg();'
467 print ' __writer.endEnter();'
468 print ' __writer.beginLeave(__call);'
469 print ' __writer.endLeave();'
473 'ELEMENT_ARRAY_BUFFER',
475 'PIXEL_UNPACK_BUFFER',
478 def wrap_ret(self, function, instance):
479 Tracer.wrap_ret(self, function, instance)
481 if function.name in ('glMapBuffer', 'glMapBufferARB'):
482 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
483 print ' if (mapping) {'
484 print ' mapping->map = %s;' % (instance)
485 print ' mapping->length = 0;'
486 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
487 print ' mapping->write = (access != GL_READ_ONLY);'
488 print ' mapping->explicit_flush = false;'
491 if function.name == 'glMapBufferRange':
492 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
493 print ' if (mapping) {'
494 print ' mapping->map = %s;' % (instance)
495 print ' mapping->length = length;'
496 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
497 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
505 def gl_boolean(self, value):
506 return self.boolean_names[int(bool(value))]
508 # Names of the functions that unpack from a pixel buffer object. See the
509 # ARB_pixel_buffer_object specification.
510 unpack_function_names = set([
514 'glCompressedTexImage1D',
515 'glCompressedTexImage2D',
516 'glCompressedTexImage3D',
517 'glCompressedTexSubImage1D',
518 'glCompressedTexSubImage2D',
519 'glCompressedTexSubImage3D',
520 'glConvolutionFilter1D',
521 'glConvolutionFilter2D',
523 'glMultiTexImage1DEXT',
524 'glMultiTexImage2DEXT',
525 'glMultiTexImage3DEXT',
526 'glMultiTexSubImage1DEXT',
527 'glMultiTexSubImage2DEXT',
528 'glMultiTexSubImage3DEXT',
533 'glSeparableFilter2D',
541 'glTexSubImage1DEXT',
543 'glTexSubImage2DEXT',
545 'glTexSubImage3DEXT',
546 'glTextureImage1DEXT',
547 'glTextureImage2DEXT',
548 'glTextureImage3DEXT',
549 'glTextureSubImage1DEXT',
550 'glTextureSubImage2DEXT',
551 'glTextureSubImage3DEXT',
554 def dump_arg_instance(self, function, arg):
555 if function.name in self.draw_function_names and arg.name == 'indices':
556 print ' GLint __element_array_buffer = 0;'
557 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
558 print ' if (!__element_array_buffer) {'
559 if isinstance(arg.type, stdapi.Array):
560 print ' __writer.beginArray(%s);' % arg.type.length
561 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
562 print ' __writer.beginElement();'
563 print ' __writer.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
564 print ' __writer.endElement();'
566 print ' __writer.endArray();'
568 print ' __writer.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
570 Tracer.dump_arg_instance(self, function, arg)
574 # Recognize offsets instead of blobs when a PBO is bound
575 if function.name in self.unpack_function_names \
576 and (isinstance(arg.type, stdapi.Blob) \
577 or (isinstance(arg.type, stdapi.Const) \
578 and isinstance(arg.type.type, stdapi.Blob))):
580 print ' GLint __unpack_buffer = 0;'
581 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
582 print ' if (__unpack_buffer) {'
583 print ' __writer.writeOpaque(%s);' % arg.name
585 Tracer.dump_arg_instance(self, function, arg)
590 # Several GL state functions take GLenum symbolic names as
591 # integer/floats; so dump the symbolic name whenever possible
592 if function.name.startswith('gl') \
593 and arg.type in (glapi.GLint, glapi.GLfloat) \
594 and arg.name == 'param':
596 assert function.args[arg.index - 1].name == 'pname'
597 assert function.args[arg.index - 1].type == glapi.GLenum
598 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
599 dump_instance(glapi.GLenum, arg.name)
601 Tracer.dump_arg_instance(self, function, arg)
605 Tracer.dump_arg_instance(self, function, arg)
607 def footer(self, api):
608 Tracer.footer(self, api)
610 # A simple state tracker to track the pointer values
612 print 'static void __trace_user_arrays(GLuint maxindex)'
615 for camelcase_name, uppercase_name in self.arrays:
616 function_name = 'gl%sPointer' % camelcase_name
617 enable_name = 'GL_%s_ARRAY' % uppercase_name
618 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
619 function = api.get_function_by_name(function_name)
621 print ' // %s' % function.name
622 self.array_trace_prolog(api, uppercase_name)
623 self.array_prolog(api, uppercase_name)
624 print ' if (__glIsEnabled(%s)) {' % enable_name
625 print ' GLint __binding = 0;'
626 print ' __glGetIntegerv(%s, &__binding);' % binding_name
627 print ' if (!__binding) {'
629 # Get the arguments via glGet*
630 for arg in function.args:
631 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
632 arg_get_function, arg_type = TypeGetter().visit(arg.type)
633 print ' %s %s = 0;' % (arg_type, arg.name)
634 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
636 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
637 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
639 # Emit a fake function
640 self.array_trace_intermezzo(api, uppercase_name)
641 print ' unsigned __call = __writer.beginEnter(&__%s_sig);' % (function.name,)
642 for arg in function.args:
643 assert not arg.output
644 print ' __writer.beginArg(%u);' % (arg.index,)
645 if arg.name != 'pointer':
646 dump_instance(arg.type, arg.name)
648 print ' __writer.writeBlob((const void *)%s, __size);' % (arg.name)
649 print ' __writer.endArg();'
651 print ' __writer.endEnter();'
652 print ' __writer.beginLeave(__call);'
653 print ' __writer.endLeave();'
656 self.array_epilog(api, uppercase_name)
657 self.array_trace_epilog(api, uppercase_name)
660 # Samething, but for glVertexAttribPointer*
662 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
663 # - glVertexAttribPointer: no
664 # - glVertexAttribPointerARB: implementation dependent
665 # - glVertexAttribPointerNV: yes
667 # This means that the implementations of these functions do not always
668 # alias, and they need to be considered independently.
670 print ' GLboolean __vertex_program = GL_FALSE;'
671 print ' __glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &__vertex_program);'
672 for suffix in ['', 'ARB']:
674 SUFFIX = '_' + suffix
679 print ' if (%s__vertex_program) {' % logic_op
680 function_name = 'glVertexAttribPointer' + suffix
681 print ' // %s' % function_name
682 print ' if (__glVertexAttribPointer%s_ptr &&' % suffix
683 print ' (__glVertexAttribPointer%s_ptr != __glVertexAttribPointer_ptr)) {' % suffix
684 print ' GLint __max_vertex_attribs = 0;'
685 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
686 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
687 print ' GLint __enabled = 0;'
688 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
689 print ' if (__enabled) {'
690 print ' GLint __binding = 0;'
691 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
692 print ' if (!__binding) {'
694 function = api.get_function_by_name(function_name)
696 # Get the arguments via glGet*
697 for arg in function.args[1:]:
698 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
699 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
700 print ' %s %s = 0;' % (arg_type, arg.name)
701 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
703 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
704 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
706 # Emit a fake function
707 print ' unsigned __call = __writer.beginEnter(&__%s_sig);' % (function.name,)
708 for arg in function.args:
709 assert not arg.output
710 print ' __writer.beginArg(%u);' % (arg.index,)
711 if arg.name != 'pointer':
712 dump_instance(arg.type, arg.name)
714 print ' __writer.writeBlob((const void *)%s, __size);' % (arg.name)
715 print ' __writer.endArg();'
717 print ' __writer.endEnter();'
718 print ' __writer.beginLeave(__call);'
719 print ' __writer.endLeave();'
731 # Hooks for glTexCoordPointer, which is identical to the other array
732 # pointers except the fact that it is indexed by glClientActiveTexture.
735 def array_prolog(self, api, uppercase_name):
736 if uppercase_name == 'TEXTURE_COORD':
737 print ' GLint client_active_texture = 0;'
738 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
739 print ' GLint max_texture_coords = 0;'
740 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
741 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
742 print ' GLenum texture = GL_TEXTURE0 + unit;'
743 print ' __glClientActiveTexture(texture);'
745 def array_trace_prolog(self, api, uppercase_name):
746 if uppercase_name == 'TEXTURE_COORD':
747 print ' bool client_active_texture_dirty = false;'
749 def array_epilog(self, api, uppercase_name):
750 if uppercase_name == 'TEXTURE_COORD':
752 self.array_cleanup(api, uppercase_name)
754 def array_cleanup(self, api, uppercase_name):
755 if uppercase_name == 'TEXTURE_COORD':
756 print ' __glClientActiveTexture(client_active_texture);'
758 def array_trace_intermezzo(self, api, uppercase_name):
759 if uppercase_name == 'TEXTURE_COORD':
760 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
761 print ' client_active_texture_dirty = true;'
762 self.fake_glClientActiveTexture_call(api, "texture");
765 def array_trace_epilog(self, api, uppercase_name):
766 if uppercase_name == 'TEXTURE_COORD':
767 print ' if (client_active_texture_dirty) {'
768 self.fake_glClientActiveTexture_call(api, "client_active_texture");
771 def fake_glClientActiveTexture_call(self, api, texture):
772 function = api.get_function_by_name('glClientActiveTexture')
773 self.fake_call(function, [texture])
775 def fake_call(self, function, args):
776 print ' unsigned __fake_call = __writer.beginEnter(&__%s_sig);' % (function.name,)
777 for arg, instance in zip(function.args, args):
778 assert not arg.output
779 print ' __writer.beginArg(%u);' % (arg.index,)
780 dump_instance(arg.type, instance)
781 print ' __writer.endArg();'
782 print ' __writer.endEnter();'
783 print ' __writer.beginLeave(__fake_call);'
784 print ' __writer.endLeave();'