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 ' // glVertexAttribPointer'
128 print ' GLint __max_vertex_attribs = 0;'
129 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
130 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
131 print ' GLint __enabled = 0;'
132 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
133 print ' if (__enabled) {'
134 print ' GLint __binding = 0;'
135 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
136 print ' if (!__binding) {'
137 print ' return true;'
143 print ' return false;'
147 print 'static void __trace_user_arrays(GLuint maxindex);'
150 print 'struct buffer_mapping {'
152 print ' GLint length;'
154 print ' bool explicit_flush;'
157 for target in self.buffer_targets:
158 print 'struct buffer_mapping __%s_mapping;' % target.lower();
160 print 'static inline struct buffer_mapping *'
161 print 'get_buffer_mapping(GLenum target) {'
162 print ' switch(target) {'
163 for target in self.buffer_targets:
164 print ' case GL_%s:' % target
165 print ' return & __%s_mapping;' % target.lower()
167 print ' OS::DebugMessage("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
168 print ' return NULL;'
173 # Generate memcpy's signature
174 self.trace_function_decl(glapi.memcpy)
176 # Generate a helper function to determine whether a parameter name
177 # refers to a symbolic value or not
179 print 'is_symbolic_pname(GLenum pname) {'
180 print ' switch(pname) {'
181 for function, type, count, name in glparams.parameters:
182 if type is glapi.GLenum:
183 print ' case %s:' % name
184 print ' return true;'
186 print ' return false;'
191 # Generate a helper function to determine whether a parameter value is
192 # potentially symbolic or not; i.e., if the value can be represented in
194 print 'template<class T>'
195 print 'static inline bool'
196 print 'is_symbolic_param(T param) {'
197 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
201 # Generate a helper function to know how many elements a parameter has
202 print 'static size_t'
203 print '__gl_param_size(GLenum pname) {'
204 print ' switch(pname) {'
205 for function, type, count, name in glparams.parameters:
207 print ' case %s: return %u;' % (name, count)
208 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
209 print ' GLint num_compressed_texture_formats = 0;'
210 print ' __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
211 print ' return num_compressed_texture_formats;'
214 print r' OS::DebugMessage("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
220 array_pointer_function_names = set((
228 "glSecondaryColorPointer",
230 "glInterleavedArrays",
232 "glVertexPointerEXT",
233 "glNormalPointerEXT",
236 "glTexCoordPointerEXT",
237 "glEdgeFlagPointerEXT",
238 "glFogCoordPointerEXT",
239 "glSecondaryColorPointerEXT",
241 "glVertexAttribPointer",
242 "glVertexAttribPointerARB",
243 "glVertexAttribPointerNV",
244 "glVertexAttribIPointer",
245 "glVertexAttribIPointerEXT",
246 "glVertexAttribLPointer",
247 "glVertexAttribLPointerEXT",
249 #"glMatrixIndexPointerARB",
252 draw_function_names = set((
255 'glDrawRangeElements',
257 'glMultiDrawElements',
258 'glDrawArraysInstanced',
259 'glDrawElementsInstanced',
260 'glDrawArraysInstancedARB',
261 'glDrawElementsInstancedARB',
262 'glDrawElementsBaseVertex',
263 'glDrawRangeElementsBaseVertex',
264 'glDrawElementsInstancedBaseVertex',
265 'glMultiDrawElementsBaseVertex',
266 'glDrawArraysIndirect',
267 'glDrawElementsIndirect',
269 'glDrawRangeElementsEXT',
270 'glDrawRangeElementsEXT_size',
271 'glMultiDrawArraysEXT',
272 'glMultiDrawElementsEXT',
273 'glMultiModeDrawArraysIBM',
274 'glMultiModeDrawElementsIBM',
275 'glDrawArraysInstancedEXT',
276 'glDrawElementsInstancedEXT',
279 interleaved_formats = [
292 'GL_T2F_C4F_N3F_V3F',
293 'GL_T4F_C4F_N3F_V4F',
296 def trace_function_impl_body(self, function):
297 # Defer tracing of user array pointers...
298 if function.name in self.array_pointer_function_names:
299 print ' GLint __array_buffer = 0;'
300 print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
301 print ' if (!__array_buffer) {'
302 print ' __user_arrays = true;'
303 self.dispatch_function(function)
305 # And also break down glInterleavedArrays into the individual calls
306 if function.name == 'glInterleavedArrays':
309 # Initialize the enable flags
310 for camelcase_name, uppercase_name in self.arrays:
311 flag_name = '__' + uppercase_name.lower()
312 print ' GLboolean %s = GL_FALSE;' % flag_name
315 # Switch for the interleaved formats
316 print ' switch (format) {'
317 for format in self.interleaved_formats:
318 print ' case %s:' % format
319 for camelcase_name, uppercase_name in self.arrays:
320 flag_name = '__' + uppercase_name.lower()
321 if format.find('_' + uppercase_name[0]) >= 0:
322 print ' %s = GL_TRUE;' % flag_name
329 # Emit fake glEnableClientState/glDisableClientState flags
330 for camelcase_name, uppercase_name in self.arrays:
331 flag_name = '__' + uppercase_name.lower()
332 enable_name = 'GL_%s_ARRAY' % uppercase_name
334 # Emit a fake function
336 print ' static const Trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
337 print ' unsigned __call = __writer.beginEnter(&__sig);'
338 print ' __writer.beginArg(0);'
339 dump_instance(glapi.GLenum, enable_name)
340 print ' __writer.endArg();'
341 print ' __writer.endEnter();'
342 print ' __writer.beginLeave(__call);'
343 print ' __writer.endLeave();'
349 # ... to the draw calls
350 if function.name in self.draw_function_names:
351 print ' if (__need_user_arrays()) {'
352 arg_names = ', '.join([arg.name for arg in function.args[1:]])
353 print ' GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
354 print ' __trace_user_arrays(maxindex);'
357 # Emit a fake memcpy on buffer uploads
358 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', ):
359 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
360 print ' if (mapping && mapping->write && !mapping->explicit_flush) {'
361 self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
363 if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
364 # TODO: avoid copying [0, offset] bytes
365 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
366 print ' if (mapping) {'
367 if function.name.endswith('APPLE'):
368 print ' GLsizeiptr length = size;'
369 print ' mapping->explicit_flush = true;'
370 print ' //assert(offset + length <= mapping->length);'
371 self.emit_memcpy('mapping->map', 'mapping->map', 'offset + length')
373 # FIXME: glFlushMappedNamedBufferRangeEXT
375 # Don't leave vertex attrib locations to chance. Instead emit fake
376 # glBindAttribLocation calls to ensure that the same locations will be
377 # used when retracing. Trying to remap locations after the fact would
378 # be an herculian task given that vertex attrib locations appear in
379 # many entry-points, including non-shader related ones.
380 if function.name == 'glLinkProgram':
381 Tracer.dispatch_function(self, function)
382 print ' GLint active_attributes = 0;'
383 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
384 print ' for (GLuint attrib = 0; attrib < active_attributes; ++attrib) {'
385 print ' GLint size = 0;'
386 print ' GLenum type = 0;'
387 print ' GLchar name[256];'
388 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
389 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
390 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
391 print ' GLint location = __glGetAttribLocation(program, name);'
392 print ' if (location >= 0) {'
393 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
394 self.fake_call(bind_function, ['program', 'location', 'name'])
398 if function.name == 'glLinkProgramARB':
399 Tracer.dispatch_function(self, function)
400 print ' GLint active_attributes = 0;'
401 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
402 print ' for (GLuint attrib = 0; attrib < active_attributes; ++attrib) {'
403 print ' GLint size = 0;'
404 print ' GLenum type = 0;'
405 print ' GLcharARB name[256];'
406 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
407 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
408 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
409 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
410 print ' if (location >= 0) {'
411 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
412 self.fake_call(bind_function, ['programObj', 'location', 'name'])
417 Tracer.trace_function_impl_body(self, function)
419 def dispatch_function(self, function):
420 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
421 # These functions have been dispatched already
424 Tracer.dispatch_function(self, function)
426 def emit_memcpy(self, dest, src, length):
427 print ' unsigned __call = __writer.beginEnter(&__memcpy_sig);'
428 print ' __writer.beginArg(0);'
429 print ' __writer.writeOpaque(%s);' % dest
430 print ' __writer.endArg();'
431 print ' __writer.beginArg(1);'
432 print ' __writer.writeBlob(%s, %s);' % (src, length)
433 print ' __writer.endArg();'
434 print ' __writer.beginArg(2);'
435 print ' __writer.writeUInt(%s);' % length
436 print ' __writer.endArg();'
437 print ' __writer.endEnter();'
438 print ' __writer.beginLeave(__call);'
439 print ' __writer.endLeave();'
443 'ELEMENT_ARRAY_BUFFER',
445 'PIXEL_UNPACK_BUFFER',
448 def wrap_ret(self, function, instance):
449 Tracer.wrap_ret(self, function, instance)
451 if function.name in ('glMapBuffer', 'glMapBufferARB'):
452 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
453 print ' if (mapping) {'
454 print ' mapping->map = %s;' % (instance)
455 print ' mapping->length = 0;'
456 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
457 print ' mapping->write = (access != GL_READ_ONLY);'
458 print ' mapping->explicit_flush = false;'
461 if function.name == 'glMapBufferRange':
462 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
463 print ' if (mapping) {'
464 print ' mapping->map = %s;' % (instance)
465 print ' mapping->length = length;'
466 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
467 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
475 def gl_boolean(self, value):
476 return self.boolean_names[int(bool(value))]
478 # Names of the functions that unpack from a pixel buffer object. See the
479 # ARB_pixel_buffer_object specification.
480 unpack_function_names = set([
484 'glCompressedTexImage1D',
485 'glCompressedTexImage2D',
486 'glCompressedTexImage3D',
487 'glCompressedTexSubImage1D',
488 'glCompressedTexSubImage2D',
489 'glCompressedTexSubImage3D',
490 'glConvolutionFilter1D',
491 'glConvolutionFilter2D',
493 'glMultiTexImage1DEXT',
494 'glMultiTexImage2DEXT',
495 'glMultiTexImage3DEXT',
496 'glMultiTexSubImage1DEXT',
497 'glMultiTexSubImage2DEXT',
498 'glMultiTexSubImage3DEXT',
503 'glSeparableFilter2D',
511 'glTexSubImage1DEXT',
513 'glTexSubImage2DEXT',
515 'glTexSubImage3DEXT',
516 'glTextureImage1DEXT',
517 'glTextureImage2DEXT',
518 'glTextureImage3DEXT',
519 'glTextureSubImage1DEXT',
520 'glTextureSubImage2DEXT',
521 'glTextureSubImage3DEXT',
524 def dump_arg_instance(self, function, arg):
525 if function.name in self.draw_function_names and arg.name == 'indices':
526 print ' GLint __element_array_buffer = 0;'
527 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
528 print ' if (!__element_array_buffer) {'
529 if isinstance(arg.type, stdapi.Array):
530 print ' __writer.beginArray(%s);' % arg.type.length
531 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
532 print ' __writer.beginElement();'
533 print ' __writer.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
534 print ' __writer.endElement();'
536 print ' __writer.endArray();'
538 print ' __writer.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
540 Tracer.dump_arg_instance(self, function, arg)
544 # Recognize offsets instead of blobs when a PBO is bound
545 if function.name in self.unpack_function_names \
546 and (isinstance(arg.type, stdapi.Blob) \
547 or (isinstance(arg.type, stdapi.Const) \
548 and isinstance(arg.type.type, stdapi.Blob))):
550 print ' GLint __unpack_buffer = 0;'
551 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
552 print ' if (__unpack_buffer) {'
553 print ' __writer.writeOpaque(%s);' % arg.name
555 Tracer.dump_arg_instance(self, function, arg)
560 # Several GL state functions take GLenum symbolic names as
561 # integer/floats; so dump the symbolic name whenever possible
562 if function.name.startswith('gl') \
563 and arg.type in (glapi.GLint, glapi.GLfloat) \
564 and arg.name == 'param':
566 assert function.args[arg.index - 1].name == 'pname'
567 assert function.args[arg.index - 1].type == glapi.GLenum
568 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
569 dump_instance(glapi.GLenum, arg.name)
571 Tracer.dump_arg_instance(self, function, arg)
575 Tracer.dump_arg_instance(self, function, arg)
577 def footer(self, api):
578 Tracer.footer(self, api)
580 # A simple state tracker to track the pointer values
582 print 'static void __trace_user_arrays(GLuint maxindex)'
585 for camelcase_name, uppercase_name in self.arrays:
586 function_name = 'gl%sPointer' % camelcase_name
587 enable_name = 'GL_%s_ARRAY' % uppercase_name
588 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
589 function = api.get_function_by_name(function_name)
591 print ' // %s' % function.name
592 self.array_trace_prolog(api, uppercase_name)
593 self.array_prolog(api, uppercase_name)
594 print ' if (__glIsEnabled(%s)) {' % enable_name
595 print ' GLint __binding = 0;'
596 print ' __glGetIntegerv(%s, &__binding);' % binding_name
597 print ' if (!__binding) {'
599 # Get the arguments via glGet*
600 for arg in function.args:
601 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
602 arg_get_function, arg_type = TypeGetter().visit(arg.type)
603 print ' %s %s = 0;' % (arg_type, arg.name)
604 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
606 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
607 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
609 # Emit a fake function
610 self.array_trace_intermezzo(api, uppercase_name)
611 print ' unsigned __call = __writer.beginEnter(&__%s_sig);' % (function.name,)
612 for arg in function.args:
613 assert not arg.output
614 print ' __writer.beginArg(%u);' % (arg.index,)
615 if arg.name != 'pointer':
616 dump_instance(arg.type, arg.name)
618 print ' __writer.writeBlob((const void *)%s, __size);' % (arg.name)
619 print ' __writer.endArg();'
621 print ' __writer.endEnter();'
622 print ' __writer.beginLeave(__call);'
623 print ' __writer.endLeave();'
626 self.array_epilog(api, uppercase_name)
627 self.array_trace_epilog(api, uppercase_name)
630 # Samething, but for glVertexAttribPointer
631 print ' // glVertexAttribPointer'
632 print ' GLint __max_vertex_attribs = 0;'
633 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
634 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
635 print ' GLint __enabled = 0;'
636 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
637 print ' if (__enabled) {'
638 print ' GLint __binding = 0;'
639 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
640 print ' if (!__binding) {'
642 function = api.get_function_by_name('glVertexAttribPointer')
644 # Get the arguments via glGet*
645 for arg in function.args[1:]:
646 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s' % (arg.name.upper(),)
647 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False).visit(arg.type)
648 print ' %s %s = 0;' % (arg_type, arg.name)
649 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
651 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
652 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
654 # Emit a fake function
655 print ' unsigned __call = __writer.beginEnter(&__%s_sig);' % (function.name,)
656 for arg in function.args:
657 assert not arg.output
658 print ' __writer.beginArg(%u);' % (arg.index,)
659 if arg.name != 'pointer':
660 dump_instance(arg.type, arg.name)
662 print ' __writer.writeBlob((const void *)%s, __size);' % (arg.name)
663 print ' __writer.endArg();'
665 print ' __writer.endEnter();'
666 print ' __writer.beginLeave(__call);'
667 print ' __writer.endLeave();'
677 # Hooks for glTexCoordPointer, which is identical to the other array
678 # pointers except the fact that it is indexed by glClientActiveTexture.
681 def array_prolog(self, api, uppercase_name):
682 if uppercase_name == 'TEXTURE_COORD':
683 print ' GLint client_active_texture = 0;'
684 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
685 print ' GLint max_texture_coords = 0;'
686 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
687 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
688 print ' GLenum texture = GL_TEXTURE0 + unit;'
689 print ' __glClientActiveTexture(texture);'
691 def array_trace_prolog(self, api, uppercase_name):
692 if uppercase_name == 'TEXTURE_COORD':
693 print ' bool client_active_texture_dirty = false;'
695 def array_epilog(self, api, uppercase_name):
696 if uppercase_name == 'TEXTURE_COORD':
698 self.array_cleanup(api, uppercase_name)
700 def array_cleanup(self, api, uppercase_name):
701 if uppercase_name == 'TEXTURE_COORD':
702 print ' __glClientActiveTexture(client_active_texture);'
704 def array_trace_intermezzo(self, api, uppercase_name):
705 if uppercase_name == 'TEXTURE_COORD':
706 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
707 print ' client_active_texture_dirty = true;'
708 self.fake_glClientActiveTexture_call(api, "texture");
711 def array_trace_epilog(self, api, uppercase_name):
712 if uppercase_name == 'TEXTURE_COORD':
713 print ' if (client_active_texture_dirty) {'
714 self.fake_glClientActiveTexture_call(api, "client_active_texture");
717 def fake_glClientActiveTexture_call(self, api, texture):
718 function = api.get_function_by_name('glClientActiveTexture')
719 self.fake_call(function, [texture])
721 def fake_call(self, function, args):
722 print ' unsigned __fake_call = __writer.beginEnter(&__%s_sig);' % (function.name,)
723 for arg, instance in zip(function.args, args):
724 assert not arg.output
725 print ' __writer.beginArg(%u);' % (arg.index,)
726 dump_instance(arg.type, instance)
727 print ' __writer.endArg();'
728 print ' __writer.endEnter();'
729 print ' __writer.beginLeave(__fake_call);'
730 print ' __writer.endLeave();'