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 '#include "gltrace.hpp"'
112 print '// Whether user arrays were used'
113 print 'static bool __user_arrays = false;'
114 print 'static bool __user_arrays_arb = false;'
115 print 'static bool __user_arrays_nv = false;'
118 # Which glVertexAttrib* variant to use
119 print 'enum vertex_attrib {'
120 print ' VERTEX_ATTRIB,'
121 print ' VERTEX_ATTRIB_ARB,'
122 print ' VERTEX_ATTRIB_NV,'
125 print 'static vertex_attrib __get_vertex_attrib(void) {'
126 print ' if (__user_arrays_arb || __user_arrays_nv) {'
127 print ' GLboolean __vertex_program = GL_FALSE;'
128 print ' __glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &__vertex_program);'
129 print ' if (__vertex_program) {'
130 print ' if (__user_arrays_nv) {'
131 print ' GLint __vertex_program_binding_nv = 0;'
132 print ' __glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &__vertex_program_binding_nv);'
133 print ' if (__vertex_program_binding_nv) {'
134 print ' return VERTEX_ATTRIB_NV;'
137 print ' return VERTEX_ATTRIB_ARB;'
140 print ' return VERTEX_ATTRIB;'
144 # Whether we need user arrays
145 print 'static inline bool __need_user_arrays(void)'
147 print ' if (!__user_arrays) {'
148 print ' return false;'
152 for camelcase_name, uppercase_name in self.arrays:
153 function_name = 'gl%sPointer' % camelcase_name
154 enable_name = 'GL_%s_ARRAY' % uppercase_name
155 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
156 print ' // %s' % function_name
157 self.array_prolog(api, uppercase_name)
158 print ' if (__glIsEnabled(%s)) {' % enable_name
159 print ' GLint __binding = 0;'
160 print ' __glGetIntegerv(%s, &__binding);' % binding_name
161 print ' if (!__binding) {'
162 self.array_cleanup(api, uppercase_name)
163 print ' return true;'
166 self.array_epilog(api, uppercase_name)
169 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
171 print ' // glVertexAttribPointer'
172 print ' if (__vertex_attrib == VERTEX_ATTRIB) {'
173 print ' GLint __max_vertex_attribs = 0;'
174 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
175 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
176 print ' GLint __enabled = 0;'
177 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
178 print ' if (__enabled) {'
179 print ' GLint __binding = 0;'
180 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
181 print ' if (!__binding) {'
182 print ' return true;'
188 print ' // glVertexAttribPointerARB'
189 print ' if (__vertex_attrib == VERTEX_ATTRIB_ARB) {'
190 print ' GLint __max_vertex_attribs = 0;'
191 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &__max_vertex_attribs);'
192 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
193 print ' GLint __enabled = 0;'
194 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &__enabled);'
195 print ' if (__enabled) {'
196 print ' GLint __binding = 0;'
197 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &__binding);'
198 print ' if (!__binding) {'
199 print ' return true;'
205 print ' // glVertexAttribPointerNV'
206 print ' if (__vertex_attrib == VERTEX_ATTRIB_NV) {'
207 print ' for (GLint index = 0; index < 16; ++index) {'
208 print ' GLint __enabled = 0;'
209 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
210 print ' if (__enabled) {'
211 print ' return true;'
217 print ' return false;'
221 print 'static void __trace_user_arrays(GLuint maxindex);'
224 print 'struct buffer_mapping {'
226 print ' GLint length;'
228 print ' bool explicit_flush;'
231 for target in self.buffer_targets:
232 print 'struct buffer_mapping __%s_mapping;' % target.lower();
234 print 'static inline struct buffer_mapping *'
235 print 'get_buffer_mapping(GLenum target) {'
236 print ' switch(target) {'
237 for target in self.buffer_targets:
238 print ' case GL_%s:' % target
239 print ' return & __%s_mapping;' % target.lower()
241 print ' OS::DebugMessage("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
242 print ' return NULL;'
247 # Generate memcpy's signature
248 self.trace_function_decl(glapi.memcpy)
250 # Generate a helper function to determine whether a parameter name
251 # refers to a symbolic value or not
253 print 'is_symbolic_pname(GLenum pname) {'
254 print ' switch(pname) {'
255 for function, type, count, name in glparams.parameters:
256 if type is glapi.GLenum:
257 print ' case %s:' % name
258 print ' return true;'
260 print ' return false;'
265 # Generate a helper function to determine whether a parameter value is
266 # potentially symbolic or not; i.e., if the value can be represented in
268 print 'template<class T>'
269 print 'static inline bool'
270 print 'is_symbolic_param(T param) {'
271 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
275 # Generate a helper function to know how many elements a parameter has
276 print 'static size_t'
277 print '__gl_param_size(GLenum pname) {'
278 print ' switch(pname) {'
279 for function, type, count, name in glparams.parameters:
281 print ' case %s: return %u;' % (name, count)
282 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
283 print ' GLint num_compressed_texture_formats = 0;'
284 print ' __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
285 print ' return num_compressed_texture_formats;'
288 print r' OS::DebugMessage("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
294 array_pointer_function_names = set((
302 "glSecondaryColorPointer",
304 "glInterleavedArrays",
306 "glVertexPointerEXT",
307 "glNormalPointerEXT",
310 "glTexCoordPointerEXT",
311 "glEdgeFlagPointerEXT",
312 "glFogCoordPointerEXT",
313 "glSecondaryColorPointerEXT",
315 "glVertexAttribPointer",
316 "glVertexAttribPointerARB",
317 "glVertexAttribPointerNV",
318 "glVertexAttribIPointer",
319 "glVertexAttribIPointerEXT",
320 "glVertexAttribLPointer",
321 "glVertexAttribLPointerEXT",
323 #"glMatrixIndexPointerARB",
326 draw_function_names = set((
329 'glDrawRangeElements',
331 'glMultiDrawElements',
332 'glDrawArraysInstanced',
333 'glDrawElementsInstanced',
334 'glDrawArraysInstancedARB',
335 'glDrawElementsInstancedARB',
336 'glDrawElementsBaseVertex',
337 'glDrawRangeElementsBaseVertex',
338 'glDrawElementsInstancedBaseVertex',
339 'glMultiDrawElementsBaseVertex',
340 'glDrawArraysIndirect',
341 'glDrawElementsIndirect',
343 'glDrawRangeElementsEXT',
344 'glDrawRangeElementsEXT_size',
345 'glMultiDrawArraysEXT',
346 'glMultiDrawElementsEXT',
347 'glMultiModeDrawArraysIBM',
348 'glMultiModeDrawElementsIBM',
349 'glDrawArraysInstancedEXT',
350 'glDrawElementsInstancedEXT',
353 interleaved_formats = [
366 'GL_T2F_C4F_N3F_V3F',
367 'GL_T4F_C4F_N3F_V4F',
370 def trace_function_impl_body(self, function):
371 # Defer tracing of user array pointers...
372 if function.name in self.array_pointer_function_names:
373 print ' GLint __array_buffer = 0;'
374 print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
375 print ' if (!__array_buffer) {'
376 print ' __user_arrays = true;'
377 if function.name == "glVertexAttribPointerARB":
378 print ' __user_arrays_arb = true;'
379 if function.name == "glVertexAttribPointerNV":
380 print ' __user_arrays_nv = true;'
381 self.dispatch_function(function)
383 # And also break down glInterleavedArrays into the individual calls
384 if function.name == 'glInterleavedArrays':
387 # Initialize the enable flags
388 for camelcase_name, uppercase_name in self.arrays:
389 flag_name = '__' + uppercase_name.lower()
390 print ' GLboolean %s = GL_FALSE;' % flag_name
393 # Switch for the interleaved formats
394 print ' switch (format) {'
395 for format in self.interleaved_formats:
396 print ' case %s:' % format
397 for camelcase_name, uppercase_name in self.arrays:
398 flag_name = '__' + uppercase_name.lower()
399 if format.find('_' + uppercase_name[0]) >= 0:
400 print ' %s = GL_TRUE;' % flag_name
407 # Emit fake glEnableClientState/glDisableClientState flags
408 for camelcase_name, uppercase_name in self.arrays:
409 flag_name = '__' + uppercase_name.lower()
410 enable_name = 'GL_%s_ARRAY' % uppercase_name
412 # Emit a fake function
414 print ' static const Trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
415 print ' unsigned __call = __writer.beginEnter(&__sig);'
416 print ' __writer.beginArg(0);'
417 dump_instance(glapi.GLenum, enable_name)
418 print ' __writer.endArg();'
419 print ' __writer.endEnter();'
420 print ' __writer.beginLeave(__call);'
421 print ' __writer.endLeave();'
427 # ... to the draw calls
428 if function.name in self.draw_function_names:
429 print ' if (__need_user_arrays()) {'
430 arg_names = ', '.join([arg.name for arg in function.args[1:]])
431 print ' GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
432 print ' __trace_user_arrays(maxindex);'
435 # Emit a fake memcpy on buffer uploads
436 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', ):
437 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
438 print ' if (mapping && mapping->write && !mapping->explicit_flush) {'
439 self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
441 if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
442 # TODO: avoid copying [0, offset] bytes
443 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
444 print ' if (mapping) {'
445 if function.name.endswith('APPLE'):
446 print ' GLsizeiptr length = size;'
447 print ' mapping->explicit_flush = true;'
448 print ' //assert(offset + length <= mapping->length);'
449 self.emit_memcpy('mapping->map', 'mapping->map', 'offset + length')
451 # FIXME: glFlushMappedNamedBufferRangeEXT
453 # Don't leave vertex attrib locations to chance. Instead emit fake
454 # glBindAttribLocation calls to ensure that the same locations will be
455 # used when retracing. Trying to remap locations after the fact would
456 # be an herculian task given that vertex attrib locations appear in
457 # many entry-points, including non-shader related ones.
458 if function.name == 'glLinkProgram':
459 Tracer.dispatch_function(self, function)
460 print ' GLint active_attributes = 0;'
461 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
462 print ' for (GLuint attrib = 0; attrib < active_attributes; ++attrib) {'
463 print ' GLint size = 0;'
464 print ' GLenum type = 0;'
465 print ' GLchar name[256];'
466 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
467 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
468 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
469 print ' GLint location = __glGetAttribLocation(program, name);'
470 print ' if (location >= 0) {'
471 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
472 self.fake_call(bind_function, ['program', 'location', 'name'])
476 if function.name == 'glLinkProgramARB':
477 Tracer.dispatch_function(self, function)
478 print ' GLint active_attributes = 0;'
479 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
480 print ' for (GLuint attrib = 0; attrib < active_attributes; ++attrib) {'
481 print ' GLint size = 0;'
482 print ' GLenum type = 0;'
483 print ' GLcharARB name[256];'
484 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
485 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
486 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
487 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
488 print ' if (location >= 0) {'
489 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
490 self.fake_call(bind_function, ['programObj', 'location', 'name'])
495 Tracer.trace_function_impl_body(self, function)
497 gremedy_functions = [
498 'glStringMarkerGREMEDY',
499 'glFrameTerminatorGREMEDY',
502 def dispatch_function(self, function):
503 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
504 # These functions have been dispatched already
507 # We implement the GREMEDY extensions, not the driver
508 if function.name in self.gremedy_functions:
511 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
513 for gremedy_function in self.gremedy_functions:
514 print ' %s (strcmp("%s", (const char *)%s) == 0) {' % (if_, gremedy_function, function.args[0].name)
515 print ' __result = (%s)&%s;' % (function.type, gremedy_function)
519 Tracer.dispatch_function(self, function)
523 Tracer.dispatch_function(self, function)
525 def emit_memcpy(self, dest, src, length):
526 print ' unsigned __call = __writer.beginEnter(&__memcpy_sig);'
527 print ' __writer.beginArg(0);'
528 print ' __writer.writeOpaque(%s);' % dest
529 print ' __writer.endArg();'
530 print ' __writer.beginArg(1);'
531 print ' __writer.writeBlob(%s, %s);' % (src, length)
532 print ' __writer.endArg();'
533 print ' __writer.beginArg(2);'
534 print ' __writer.writeUInt(%s);' % length
535 print ' __writer.endArg();'
536 print ' __writer.endEnter();'
537 print ' __writer.beginLeave(__call);'
538 print ' __writer.endLeave();'
542 'ELEMENT_ARRAY_BUFFER',
544 'PIXEL_UNPACK_BUFFER',
547 def wrap_ret(self, function, instance):
548 Tracer.wrap_ret(self, function, instance)
550 if function.name == 'glGetString':
551 print ' if (__result) {'
552 print ' switch (name) {'
553 print ' case GL_EXTENSIONS:'
554 print ' __result = gltrace::translateExtensionsString(__result);'
561 if function.name in ('glMapBuffer', 'glMapBufferARB'):
562 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
563 print ' if (mapping) {'
564 print ' mapping->map = %s;' % (instance)
565 print ' mapping->length = 0;'
566 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
567 print ' mapping->write = (access != GL_READ_ONLY);'
568 print ' mapping->explicit_flush = false;'
571 if function.name == 'glMapBufferRange':
572 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
573 print ' if (mapping) {'
574 print ' mapping->map = %s;' % (instance)
575 print ' mapping->length = length;'
576 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
577 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
585 def gl_boolean(self, value):
586 return self.boolean_names[int(bool(value))]
588 # Names of the functions that unpack from a pixel buffer object. See the
589 # ARB_pixel_buffer_object specification.
590 unpack_function_names = set([
594 'glCompressedTexImage1D',
595 'glCompressedTexImage2D',
596 'glCompressedTexImage3D',
597 'glCompressedTexSubImage1D',
598 'glCompressedTexSubImage2D',
599 'glCompressedTexSubImage3D',
600 'glConvolutionFilter1D',
601 'glConvolutionFilter2D',
603 'glMultiTexImage1DEXT',
604 'glMultiTexImage2DEXT',
605 'glMultiTexImage3DEXT',
606 'glMultiTexSubImage1DEXT',
607 'glMultiTexSubImage2DEXT',
608 'glMultiTexSubImage3DEXT',
613 'glSeparableFilter2D',
621 'glTexSubImage1DEXT',
623 'glTexSubImage2DEXT',
625 'glTexSubImage3DEXT',
626 'glTextureImage1DEXT',
627 'glTextureImage2DEXT',
628 'glTextureImage3DEXT',
629 'glTextureSubImage1DEXT',
630 'glTextureSubImage2DEXT',
631 'glTextureSubImage3DEXT',
634 def dump_arg_instance(self, function, arg):
635 if function.name in self.draw_function_names and arg.name == 'indices':
636 print ' GLint __element_array_buffer = 0;'
637 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
638 print ' if (!__element_array_buffer) {'
639 if isinstance(arg.type, stdapi.Array):
640 print ' __writer.beginArray(%s);' % arg.type.length
641 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
642 print ' __writer.beginElement();'
643 print ' __writer.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
644 print ' __writer.endElement();'
646 print ' __writer.endArray();'
648 print ' __writer.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
650 Tracer.dump_arg_instance(self, function, arg)
654 # Recognize offsets instead of blobs when a PBO is bound
655 if function.name in self.unpack_function_names \
656 and (isinstance(arg.type, stdapi.Blob) \
657 or (isinstance(arg.type, stdapi.Const) \
658 and isinstance(arg.type.type, stdapi.Blob))):
660 print ' GLint __unpack_buffer = 0;'
661 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
662 print ' if (__unpack_buffer) {'
663 print ' __writer.writeOpaque(%s);' % arg.name
665 Tracer.dump_arg_instance(self, function, arg)
670 # Several GL state functions take GLenum symbolic names as
671 # integer/floats; so dump the symbolic name whenever possible
672 if function.name.startswith('gl') \
673 and arg.type in (glapi.GLint, glapi.GLfloat) \
674 and arg.name == 'param':
676 assert function.args[arg.index - 1].name == 'pname'
677 assert function.args[arg.index - 1].type == glapi.GLenum
678 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
679 dump_instance(glapi.GLenum, arg.name)
681 Tracer.dump_arg_instance(self, function, arg)
685 Tracer.dump_arg_instance(self, function, arg)
687 def footer(self, api):
688 Tracer.footer(self, api)
690 # A simple state tracker to track the pointer values
692 print 'static void __trace_user_arrays(GLuint maxindex)'
695 for camelcase_name, uppercase_name in self.arrays:
696 function_name = 'gl%sPointer' % camelcase_name
697 enable_name = 'GL_%s_ARRAY' % uppercase_name
698 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
699 function = api.get_function_by_name(function_name)
701 print ' // %s' % function.name
702 self.array_trace_prolog(api, uppercase_name)
703 self.array_prolog(api, uppercase_name)
704 print ' if (__glIsEnabled(%s)) {' % enable_name
705 print ' GLint __binding = 0;'
706 print ' __glGetIntegerv(%s, &__binding);' % binding_name
707 print ' if (!__binding) {'
709 # Get the arguments via glGet*
710 for arg in function.args:
711 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
712 arg_get_function, arg_type = TypeGetter().visit(arg.type)
713 print ' %s %s = 0;' % (arg_type, arg.name)
714 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
716 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
717 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
719 # Emit a fake function
720 self.array_trace_intermezzo(api, uppercase_name)
721 print ' unsigned __call = __writer.beginEnter(&__%s_sig);' % (function.name,)
722 for arg in function.args:
723 assert not arg.output
724 print ' __writer.beginArg(%u);' % (arg.index,)
725 if arg.name != 'pointer':
726 dump_instance(arg.type, arg.name)
728 print ' __writer.writeBlob((const void *)%s, __size);' % (arg.name)
729 print ' __writer.endArg();'
731 print ' __writer.endEnter();'
732 print ' __writer.beginLeave(__call);'
733 print ' __writer.endLeave();'
736 self.array_epilog(api, uppercase_name)
737 self.array_trace_epilog(api, uppercase_name)
740 # Samething, but for glVertexAttribPointer*
742 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
743 # - glVertexAttribPointer: no
744 # - glVertexAttribPointerARB: implementation dependent
745 # - glVertexAttribPointerNV: yes
747 # This means that the implementations of these functions do not always
748 # alias, and they need to be considered independently.
750 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
752 for suffix in ['', 'ARB', 'NV']:
754 SUFFIX = '_' + suffix
757 function_name = 'glVertexAttribPointer' + suffix
758 print ' // %s' % function_name
759 print ' if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
761 print ' GLint __max_vertex_attribs = 16;'
763 print ' GLint __max_vertex_attribs = 0;'
764 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
765 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
766 print ' GLint __enabled = 0;'
768 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
770 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
771 print ' if (__enabled) {'
772 print ' GLint __binding = 0;'
774 # It doesn't seem possible to use VBOs with NV_vertex_program.
775 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
776 print ' if (!__binding) {'
778 function = api.get_function_by_name(function_name)
780 # Get the arguments via glGet*
781 for arg in function.args[1:]:
783 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
785 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
786 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
787 print ' %s %s = 0;' % (arg_type, arg.name)
788 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
790 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
791 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
793 # Emit a fake function
794 print ' unsigned __call = __writer.beginEnter(&__%s_sig);' % (function.name,)
795 for arg in function.args:
796 assert not arg.output
797 print ' __writer.beginArg(%u);' % (arg.index,)
798 if arg.name != 'pointer':
799 dump_instance(arg.type, arg.name)
801 print ' __writer.writeBlob((const void *)%s, __size);' % (arg.name)
802 print ' __writer.endArg();'
804 print ' __writer.endEnter();'
805 print ' __writer.beginLeave(__call);'
806 print ' __writer.endLeave();'
817 # Hooks for glTexCoordPointer, which is identical to the other array
818 # pointers except the fact that it is indexed by glClientActiveTexture.
821 def array_prolog(self, api, uppercase_name):
822 if uppercase_name == 'TEXTURE_COORD':
823 print ' GLint client_active_texture = 0;'
824 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
825 print ' GLint max_texture_coords = 0;'
826 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
827 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
828 print ' GLenum texture = GL_TEXTURE0 + unit;'
829 print ' __glClientActiveTexture(texture);'
831 def array_trace_prolog(self, api, uppercase_name):
832 if uppercase_name == 'TEXTURE_COORD':
833 print ' bool client_active_texture_dirty = false;'
835 def array_epilog(self, api, uppercase_name):
836 if uppercase_name == 'TEXTURE_COORD':
838 self.array_cleanup(api, uppercase_name)
840 def array_cleanup(self, api, uppercase_name):
841 if uppercase_name == 'TEXTURE_COORD':
842 print ' __glClientActiveTexture(client_active_texture);'
844 def array_trace_intermezzo(self, api, uppercase_name):
845 if uppercase_name == 'TEXTURE_COORD':
846 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
847 print ' client_active_texture_dirty = true;'
848 self.fake_glClientActiveTexture_call(api, "texture");
851 def array_trace_epilog(self, api, uppercase_name):
852 if uppercase_name == 'TEXTURE_COORD':
853 print ' if (client_active_texture_dirty) {'
854 self.fake_glClientActiveTexture_call(api, "client_active_texture");
857 def fake_glClientActiveTexture_call(self, api, texture):
858 function = api.get_function_by_name('glClientActiveTexture')
859 self.fake_call(function, [texture])
861 def fake_call(self, function, args):
862 print ' unsigned __fake_call = __writer.beginEnter(&__%s_sig);' % (function.name,)
863 for arg, instance in zip(function.args, args):
864 assert not arg.output
865 print ' __writer.beginArg(%u);' % (arg.index,)
866 dump_instance(arg.type, instance)
867 print ' __writer.endArg();'
868 print ' __writer.endEnter();'
869 print ' __writer.beginLeave(__fake_call);'
870 print ' __writer.endLeave();'