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."""
30 import specs.stdapi as stdapi
31 import specs.glapi as glapi
32 import specs.glparams as glparams
33 from specs.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 'enum gl_context_profile {'
113 print ' PROFILE_COMPAT,'
116 print 'struct tracer_context {'
117 print ' enum gl_context_profile profile;'
118 print ' bool user_arrays;'
119 print ' bool user_arrays_arb;'
120 print ' bool user_arrays_nv;'
124 # Which glVertexAttrib* variant to use
125 print 'enum vertex_attrib {'
126 print ' VERTEX_ATTRIB,'
127 print ' VERTEX_ATTRIB_ARB,'
128 print ' VERTEX_ATTRIB_NV,'
131 print 'static tracer_context *__get_context(void)'
133 print ' // TODO return the context set by other APIs (GLX, EGL, and etc.)'
134 print ' static tracer_context __ctx = { PROFILE_COMPAT, false, false, false };'
135 print ' return &__ctx;'
138 print 'static vertex_attrib __get_vertex_attrib(void) {'
139 print ' tracer_context *ctx = __get_context();'
140 print ' if (ctx->user_arrays_arb || ctx->user_arrays_nv) {'
141 print ' GLboolean __vertex_program = GL_FALSE;'
142 print ' __glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &__vertex_program);'
143 print ' if (__vertex_program) {'
144 print ' if (ctx->user_arrays_nv) {'
145 print ' GLint __vertex_program_binding_nv = 0;'
146 print ' __glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &__vertex_program_binding_nv);'
147 print ' if (__vertex_program_binding_nv) {'
148 print ' return VERTEX_ATTRIB_NV;'
151 print ' return VERTEX_ATTRIB_ARB;'
154 print ' return VERTEX_ATTRIB;'
158 # Whether we need user arrays
159 print 'static inline bool __need_user_arrays(void)'
161 print ' tracer_context *ctx = __get_context();'
162 print ' if (!ctx->user_arrays) {'
163 print ' return false;'
167 for camelcase_name, uppercase_name in self.arrays:
168 function_name = 'gl%sPointer' % camelcase_name
169 enable_name = 'GL_%s_ARRAY' % uppercase_name
170 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
171 print ' // %s' % function_name
172 self.array_prolog(api, uppercase_name)
173 print ' if (__glIsEnabled(%s)) {' % enable_name
174 print ' GLint __binding = 0;'
175 print ' __glGetIntegerv(%s, &__binding);' % binding_name
176 print ' if (!__binding) {'
177 self.array_cleanup(api, uppercase_name)
178 print ' return true;'
181 self.array_epilog(api, uppercase_name)
184 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
186 print ' // glVertexAttribPointer'
187 print ' if (__vertex_attrib == VERTEX_ATTRIB) {'
188 print ' GLint __max_vertex_attribs = 0;'
189 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
190 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
191 print ' GLint __enabled = 0;'
192 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
193 print ' if (__enabled) {'
194 print ' GLint __binding = 0;'
195 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
196 print ' if (!__binding) {'
197 print ' return true;'
203 print ' // glVertexAttribPointerARB'
204 print ' if (__vertex_attrib == VERTEX_ATTRIB_ARB) {'
205 print ' GLint __max_vertex_attribs = 0;'
206 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &__max_vertex_attribs);'
207 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
208 print ' GLint __enabled = 0;'
209 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &__enabled);'
210 print ' if (__enabled) {'
211 print ' GLint __binding = 0;'
212 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &__binding);'
213 print ' if (!__binding) {'
214 print ' return true;'
220 print ' // glVertexAttribPointerNV'
221 print ' if (__vertex_attrib == VERTEX_ATTRIB_NV) {'
222 print ' for (GLint index = 0; index < 16; ++index) {'
223 print ' GLint __enabled = 0;'
224 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
225 print ' if (__enabled) {'
226 print ' return true;'
232 print ' return false;'
236 print 'static void __trace_user_arrays(GLuint maxindex);'
239 print 'struct buffer_mapping {'
241 print ' GLint length;'
243 print ' bool explicit_flush;'
246 for target in self.buffer_targets:
247 print 'struct buffer_mapping __%s_mapping;' % target.lower();
249 print 'static inline struct buffer_mapping *'
250 print 'get_buffer_mapping(GLenum target) {'
251 print ' switch (target) {'
252 for target in self.buffer_targets:
253 print ' case GL_%s:' % target
254 print ' return & __%s_mapping;' % target.lower()
256 print ' os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
257 print ' return NULL;'
262 # Generate a helper function to determine whether a parameter name
263 # refers to a symbolic value or not
265 print 'is_symbolic_pname(GLenum pname) {'
266 print ' switch (pname) {'
267 for function, type, count, name in glparams.parameters:
268 if type is glapi.GLenum:
269 print ' case %s:' % name
270 print ' return true;'
272 print ' return false;'
277 # Generate a helper function to determine whether a parameter value is
278 # potentially symbolic or not; i.e., if the value can be represented in
280 print 'template<class T>'
281 print 'static inline bool'
282 print 'is_symbolic_param(T param) {'
283 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
287 # Generate a helper function to know how many elements a parameter has
288 print 'static size_t'
289 print '__gl_param_size(GLenum pname) {'
290 print ' switch (pname) {'
291 for function, type, count, name in glparams.parameters:
293 print ' case %s: return %u;' % (name, count)
294 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
295 print ' GLint num_compressed_texture_formats = 0;'
296 print ' __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
297 print ' return num_compressed_texture_formats;'
300 print r' os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
306 array_pointer_function_names = set((
314 "glSecondaryColorPointer",
316 "glInterleavedArrays",
318 "glVertexPointerEXT",
319 "glNormalPointerEXT",
322 "glTexCoordPointerEXT",
323 "glEdgeFlagPointerEXT",
324 "glFogCoordPointerEXT",
325 "glSecondaryColorPointerEXT",
327 "glVertexAttribPointer",
328 "glVertexAttribPointerARB",
329 "glVertexAttribPointerNV",
330 "glVertexAttribIPointer",
331 "glVertexAttribIPointerEXT",
332 "glVertexAttribLPointer",
333 "glVertexAttribLPointerEXT",
335 #"glMatrixIndexPointerARB",
338 draw_function_names = set((
341 'glDrawRangeElements',
343 'glMultiDrawElements',
344 'glDrawArraysInstanced',
345 "glDrawArraysInstancedBaseInstance",
346 'glDrawElementsInstanced',
347 'glDrawArraysInstancedARB',
348 'glDrawElementsInstancedARB',
349 'glDrawElementsBaseVertex',
350 'glDrawRangeElementsBaseVertex',
351 'glDrawElementsInstancedBaseVertex',
352 "glDrawElementsInstancedBaseInstance",
353 "glDrawElementsInstancedBaseVertexBaseInstance",
354 'glMultiDrawElementsBaseVertex',
355 'glDrawArraysIndirect',
356 'glDrawElementsIndirect',
358 'glDrawRangeElementsEXT',
359 'glDrawRangeElementsEXT_size',
360 'glMultiDrawArraysEXT',
361 'glMultiDrawElementsEXT',
362 'glMultiModeDrawArraysIBM',
363 'glMultiModeDrawElementsIBM',
364 'glDrawArraysInstancedEXT',
365 'glDrawElementsInstancedEXT',
368 interleaved_formats = [
381 'GL_T2F_C4F_N3F_V3F',
382 'GL_T4F_C4F_N3F_V4F',
385 def trace_function_impl_body(self, function):
386 # Defer tracing of user array pointers...
387 if function.name in self.array_pointer_function_names:
388 print ' GLint __array_buffer = 0;'
389 print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
390 print ' if (!__array_buffer) {'
391 print ' tracer_context *ctx = __get_context();'
392 print ' ctx->user_arrays = true;'
393 if function.name == "glVertexAttribPointerARB":
394 print ' ctx->user_arrays_arb = true;'
395 if function.name == "glVertexAttribPointerNV":
396 print ' ctx->user_arrays_nv = true;'
397 self.dispatch_function(function)
399 # And also break down glInterleavedArrays into the individual calls
400 if function.name == 'glInterleavedArrays':
403 # Initialize the enable flags
404 for camelcase_name, uppercase_name in self.arrays:
405 flag_name = '__' + uppercase_name.lower()
406 print ' GLboolean %s = GL_FALSE;' % flag_name
409 # Switch for the interleaved formats
410 print ' switch (format) {'
411 for format in self.interleaved_formats:
412 print ' case %s:' % format
413 for camelcase_name, uppercase_name in self.arrays:
414 flag_name = '__' + uppercase_name.lower()
415 if format.find('_' + uppercase_name[0]) >= 0:
416 print ' %s = GL_TRUE;' % flag_name
423 # Emit fake glEnableClientState/glDisableClientState flags
424 for camelcase_name, uppercase_name in self.arrays:
425 flag_name = '__' + uppercase_name.lower()
426 enable_name = 'GL_%s_ARRAY' % uppercase_name
428 # Emit a fake function
430 print ' static const trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
431 print ' unsigned __call = trace::localWriter.beginEnter(&__sig);'
432 print ' trace::localWriter.beginArg(0);'
433 dump_instance(glapi.GLenum, enable_name)
434 print ' trace::localWriter.endArg();'
435 print ' trace::localWriter.endEnter();'
436 print ' trace::localWriter.beginLeave(__call);'
437 print ' trace::localWriter.endLeave();'
443 # ... to the draw calls
444 if function.name in self.draw_function_names:
445 print ' if (__need_user_arrays()) {'
446 arg_names = ', '.join([arg.name for arg in function.args[1:]])
447 print ' GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
448 print ' __trace_user_arrays(maxindex);'
451 # Emit a fake memcpy on buffer uploads
452 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', ):
453 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
454 print ' if (mapping && mapping->write && !mapping->explicit_flush) {'
455 self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
457 if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
458 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
459 print ' if (mapping) {'
460 if function.name.endswith('APPLE'):
461 print ' GLsizeiptr length = size;'
462 print ' mapping->explicit_flush = true;'
463 print ' //assert(offset + length <= mapping->length);'
464 self.emit_memcpy('(char *)mapping->map + offset', '(const char *)mapping->map + offset', 'length')
466 # FIXME: glFlushMappedNamedBufferRangeEXT
468 # Don't leave vertex attrib locations to chance. Instead emit fake
469 # glBindAttribLocation calls to ensure that the same locations will be
470 # used when retracing. Trying to remap locations after the fact would
471 # be an herculian task given that vertex attrib locations appear in
472 # many entry-points, including non-shader related ones.
473 if function.name == 'glLinkProgram':
474 Tracer.dispatch_function(self, function)
475 print ' GLint active_attributes = 0;'
476 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
477 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
478 print ' GLint size = 0;'
479 print ' GLenum type = 0;'
480 print ' GLchar name[256];'
481 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
482 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
483 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
484 print ' GLint location = __glGetAttribLocation(program, name);'
485 print ' if (location >= 0) {'
486 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
487 self.fake_call(bind_function, ['program', 'location', 'name'])
491 if function.name == 'glLinkProgramARB':
492 Tracer.dispatch_function(self, function)
493 print ' GLint active_attributes = 0;'
494 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
495 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
496 print ' GLint size = 0;'
497 print ' GLenum type = 0;'
498 print ' GLcharARB name[256];'
499 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
500 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
501 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
502 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
503 print ' if (location >= 0) {'
504 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
505 self.fake_call(bind_function, ['programObj', 'location', 'name'])
510 Tracer.trace_function_impl_body(self, function)
512 gremedy_functions = [
513 'glStringMarkerGREMEDY',
514 'glFrameTerminatorGREMEDY',
517 def dispatch_function(self, function):
518 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
519 # These functions have been dispatched already
522 # We implement the GREMEDY extensions, not the driver
523 if function.name in self.gremedy_functions:
526 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
528 for gremedy_function in self.gremedy_functions:
529 print ' %s (strcmp("%s", (const char *)%s) == 0) {' % (if_, gremedy_function, function.args[0].name)
530 print ' __result = (%s)&%s;' % (function.type, gremedy_function)
534 Tracer.dispatch_function(self, function)
538 # Override GL extensions
539 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
540 Tracer.dispatch_function(self, function, prefix = 'gltrace::__', suffix = '_override')
543 Tracer.dispatch_function(self, function)
545 def emit_memcpy(self, dest, src, length):
546 print ' unsigned __call = trace::localWriter.beginEnter(&trace::memcpy_sig);'
547 print ' trace::localWriter.beginArg(0);'
548 print ' trace::localWriter.writeOpaque(%s);' % dest
549 print ' trace::localWriter.endArg();'
550 print ' trace::localWriter.beginArg(1);'
551 print ' trace::localWriter.writeBlob(%s, %s);' % (src, length)
552 print ' trace::localWriter.endArg();'
553 print ' trace::localWriter.beginArg(2);'
554 print ' trace::localWriter.writeUInt(%s);' % length
555 print ' trace::localWriter.endArg();'
556 print ' trace::localWriter.endEnter();'
557 print ' trace::localWriter.beginLeave(__call);'
558 print ' trace::localWriter.endLeave();'
562 'ELEMENT_ARRAY_BUFFER',
564 'PIXEL_UNPACK_BUFFER',
567 def wrap_ret(self, function, instance):
568 Tracer.wrap_ret(self, function, instance)
571 if function.name in ('glMapBuffer', 'glMapBufferARB'):
572 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
573 print ' if (mapping) {'
574 print ' mapping->map = %s;' % (instance)
575 print ' mapping->length = 0;'
576 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
577 print ' mapping->write = (access != GL_READ_ONLY);'
578 print ' mapping->explicit_flush = false;'
581 if function.name == 'glMapBufferRange':
582 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
583 print ' if (mapping) {'
584 print ' mapping->map = %s;' % (instance)
585 print ' mapping->length = length;'
586 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
587 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
595 def gl_boolean(self, value):
596 return self.boolean_names[int(bool(value))]
598 # Names of the functions that unpack from a pixel buffer object. See the
599 # ARB_pixel_buffer_object specification.
600 unpack_function_names = set([
604 'glCompressedTexImage1D',
605 'glCompressedTexImage2D',
606 'glCompressedTexImage3D',
607 'glCompressedTexSubImage1D',
608 'glCompressedTexSubImage2D',
609 'glCompressedTexSubImage3D',
610 'glConvolutionFilter1D',
611 'glConvolutionFilter2D',
613 'glMultiTexImage1DEXT',
614 'glMultiTexImage2DEXT',
615 'glMultiTexImage3DEXT',
616 'glMultiTexSubImage1DEXT',
617 'glMultiTexSubImage2DEXT',
618 'glMultiTexSubImage3DEXT',
623 'glSeparableFilter2D',
631 'glTexSubImage1DEXT',
633 'glTexSubImage2DEXT',
635 'glTexSubImage3DEXT',
636 'glTextureImage1DEXT',
637 'glTextureImage2DEXT',
638 'glTextureImage3DEXT',
639 'glTextureSubImage1DEXT',
640 'glTextureSubImage2DEXT',
641 'glTextureSubImage3DEXT',
644 def dump_arg_instance(self, function, arg):
645 if function.name in self.draw_function_names and arg.name == 'indices':
646 print ' GLint __element_array_buffer = 0;'
647 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
648 print ' if (!__element_array_buffer) {'
649 if isinstance(arg.type, stdapi.Array):
650 print ' trace::localWriter.beginArray(%s);' % arg.type.length
651 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
652 print ' trace::localWriter.beginElement();'
653 print ' trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
654 print ' trace::localWriter.endElement();'
656 print ' trace::localWriter.endArray();'
658 print ' trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
660 Tracer.dump_arg_instance(self, function, arg)
664 # Recognize offsets instead of blobs when a PBO is bound
665 if function.name in self.unpack_function_names \
666 and (isinstance(arg.type, stdapi.Blob) \
667 or (isinstance(arg.type, stdapi.Const) \
668 and isinstance(arg.type.type, stdapi.Blob))):
670 print ' GLint __unpack_buffer = 0;'
671 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
672 print ' if (__unpack_buffer) {'
673 print ' trace::localWriter.writeOpaque(%s);' % arg.name
675 Tracer.dump_arg_instance(self, function, arg)
680 # Several GL state functions take GLenum symbolic names as
681 # integer/floats; so dump the symbolic name whenever possible
682 if function.name.startswith('gl') \
683 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
684 and arg.name == 'param':
686 assert function.args[arg.index - 1].name == 'pname'
687 assert function.args[arg.index - 1].type == glapi.GLenum
688 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
689 dump_instance(glapi.GLenum, arg.name)
691 Tracer.dump_arg_instance(self, function, arg)
695 Tracer.dump_arg_instance(self, function, arg)
697 def footer(self, api):
698 Tracer.footer(self, api)
700 # A simple state tracker to track the pointer values
702 print 'static void __trace_user_arrays(GLuint maxindex)'
705 for camelcase_name, uppercase_name in self.arrays:
706 function_name = 'gl%sPointer' % camelcase_name
707 enable_name = 'GL_%s_ARRAY' % uppercase_name
708 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
709 function = api.get_function_by_name(function_name)
711 print ' // %s' % function.prototype()
712 self.array_trace_prolog(api, uppercase_name)
713 self.array_prolog(api, uppercase_name)
714 print ' if (__glIsEnabled(%s)) {' % enable_name
715 print ' GLint __binding = 0;'
716 print ' __glGetIntegerv(%s, &__binding);' % binding_name
717 print ' if (!__binding) {'
719 # Get the arguments via glGet*
720 for arg in function.args:
721 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
722 arg_get_function, arg_type = TypeGetter().visit(arg.type)
723 print ' %s %s = 0;' % (arg_type, arg.name)
724 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
726 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
727 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
729 # Emit a fake function
730 self.array_trace_intermezzo(api, uppercase_name)
731 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
732 for arg in function.args:
733 assert not arg.output
734 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
735 if arg.name != 'pointer':
736 dump_instance(arg.type, arg.name)
738 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
739 print ' trace::localWriter.endArg();'
741 print ' trace::localWriter.endEnter();'
742 print ' trace::localWriter.beginLeave(__call);'
743 print ' trace::localWriter.endLeave();'
746 self.array_epilog(api, uppercase_name)
747 self.array_trace_epilog(api, uppercase_name)
750 # Samething, but for glVertexAttribPointer*
752 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
753 # - glVertexAttribPointer: no
754 # - glVertexAttribPointerARB: implementation dependent
755 # - glVertexAttribPointerNV: yes
757 # This means that the implementations of these functions do not always
758 # alias, and they need to be considered independently.
760 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
762 for suffix in ['', 'ARB', 'NV']:
764 SUFFIX = '_' + suffix
767 function_name = 'glVertexAttribPointer' + suffix
768 function = api.get_function_by_name(function_name)
770 print ' // %s' % function.prototype()
771 print ' if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
773 print ' GLint __max_vertex_attribs = 16;'
775 print ' GLint __max_vertex_attribs = 0;'
776 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
777 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
778 print ' GLint __enabled = 0;'
780 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
782 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
783 print ' if (__enabled) {'
784 print ' GLint __binding = 0;'
786 # It doesn't seem possible to use VBOs with NV_vertex_program.
787 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
788 print ' if (!__binding) {'
790 # Get the arguments via glGet*
791 for arg in function.args[1:]:
793 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
795 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
796 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
797 print ' %s %s = 0;' % (arg_type, arg.name)
798 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
800 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
801 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
803 # Emit a fake function
804 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
805 for arg in function.args:
806 assert not arg.output
807 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
808 if arg.name != 'pointer':
809 dump_instance(arg.type, arg.name)
811 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
812 print ' trace::localWriter.endArg();'
814 print ' trace::localWriter.endEnter();'
815 print ' trace::localWriter.beginLeave(__call);'
816 print ' trace::localWriter.endLeave();'
827 # Hooks for glTexCoordPointer, which is identical to the other array
828 # pointers except the fact that it is indexed by glClientActiveTexture.
831 def array_prolog(self, api, uppercase_name):
832 if uppercase_name == 'TEXTURE_COORD':
833 print ' GLint client_active_texture = 0;'
834 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
835 print ' GLint max_texture_coords = 0;'
836 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
837 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
838 print ' GLint texture = GL_TEXTURE0 + unit;'
839 print ' __glClientActiveTexture(texture);'
841 def array_trace_prolog(self, api, uppercase_name):
842 if uppercase_name == 'TEXTURE_COORD':
843 print ' bool client_active_texture_dirty = false;'
845 def array_epilog(self, api, uppercase_name):
846 if uppercase_name == 'TEXTURE_COORD':
848 self.array_cleanup(api, uppercase_name)
850 def array_cleanup(self, api, uppercase_name):
851 if uppercase_name == 'TEXTURE_COORD':
852 print ' __glClientActiveTexture(client_active_texture);'
854 def array_trace_intermezzo(self, api, uppercase_name):
855 if uppercase_name == 'TEXTURE_COORD':
856 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
857 print ' client_active_texture_dirty = true;'
858 self.fake_glClientActiveTexture_call(api, "texture");
861 def array_trace_epilog(self, api, uppercase_name):
862 if uppercase_name == 'TEXTURE_COORD':
863 print ' if (client_active_texture_dirty) {'
864 self.fake_glClientActiveTexture_call(api, "client_active_texture");
867 def fake_glClientActiveTexture_call(self, api, texture):
868 function = api.get_function_by_name('glClientActiveTexture')
869 self.fake_call(function, [texture])
871 def fake_call(self, function, args):
872 print ' unsigned __fake_call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
873 for arg, instance in zip(function.args, args):
874 assert not arg.output
875 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
876 dump_instance(arg.type, instance)
877 print ' trace::localWriter.endArg();'
878 print ' trace::localWriter.endEnter();'
879 print ' trace::localWriter.beginLeave(__fake_call);'
880 print ' trace::localWriter.endLeave();'