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 # arrays available in PROFILE_ES1
108 arrays_es1 = ("Vertex", "Normal", "Color", "TexCoord")
110 def header(self, api):
111 Tracer.header(self, api)
113 print '#include "gltrace.hpp"'
115 print 'enum tracer_context_profile {'
116 print ' PROFILE_COMPAT,'
117 print ' PROFILE_ES1,'
118 print ' PROFILE_ES2,'
121 print 'struct tracer_context {'
122 print ' enum tracer_context_profile profile;'
123 print ' bool user_arrays;'
124 print ' bool user_arrays_arb;'
125 print ' bool user_arrays_nv;'
129 # Which glVertexAttrib* variant to use
130 print 'enum vertex_attrib {'
131 print ' VERTEX_ATTRIB,'
132 print ' VERTEX_ATTRIB_ARB,'
133 print ' VERTEX_ATTRIB_NV,'
136 print 'static tracer_context *__get_context(void)'
138 print ' // TODO return the context set by other APIs (GLX, EGL, and etc.)'
139 print ' static tracer_context __ctx = { PROFILE_COMPAT, false, false, false };'
140 print ' return &__ctx;'
143 print 'static vertex_attrib __get_vertex_attrib(void) {'
144 print ' tracer_context *ctx = __get_context();'
145 print ' if (ctx->user_arrays_arb || ctx->user_arrays_nv) {'
146 print ' GLboolean __vertex_program = GL_FALSE;'
147 print ' __glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &__vertex_program);'
148 print ' if (__vertex_program) {'
149 print ' if (ctx->user_arrays_nv) {'
150 print ' GLint __vertex_program_binding_nv = 0;'
151 print ' __glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &__vertex_program_binding_nv);'
152 print ' if (__vertex_program_binding_nv) {'
153 print ' return VERTEX_ATTRIB_NV;'
156 print ' return VERTEX_ATTRIB_ARB;'
159 print ' return VERTEX_ATTRIB;'
163 # Whether we need user arrays
164 print 'static inline bool __need_user_arrays(void)'
166 print ' tracer_context *ctx = __get_context();'
167 print ' if (!ctx->user_arrays) {'
168 print ' return false;'
172 for camelcase_name, uppercase_name in self.arrays:
173 # in which profile is the array available?
174 profile_check = 'ctx->profile == PROFILE_COMPAT'
175 if camelcase_name in self.arrays_es1:
176 profile_check = '(' + profile_check + ' || ctx->profile == PROFILE_ES1)';
178 function_name = 'gl%sPointer' % camelcase_name
179 enable_name = 'GL_%s_ARRAY' % uppercase_name
180 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
181 print ' // %s' % function_name
182 print ' if (%s) {' % profile_check
183 self.array_prolog(api, uppercase_name)
184 print ' if (__glIsEnabled(%s)) {' % enable_name
185 print ' GLint __binding = 0;'
186 print ' __glGetIntegerv(%s, &__binding);' % binding_name
187 print ' if (!__binding) {'
188 self.array_cleanup(api, uppercase_name)
189 print ' return true;'
192 self.array_epilog(api, uppercase_name)
196 print ' // ES1 does not support generic vertex attributes'
197 print ' if (ctx->profile == PROFILE_ES1)'
198 print ' return false;'
200 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
202 print ' // glVertexAttribPointer'
203 print ' if (__vertex_attrib == VERTEX_ATTRIB) {'
204 print ' GLint __max_vertex_attribs = 0;'
205 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
206 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
207 print ' GLint __enabled = 0;'
208 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
209 print ' if (__enabled) {'
210 print ' GLint __binding = 0;'
211 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
212 print ' if (!__binding) {'
213 print ' return true;'
219 print ' // glVertexAttribPointerARB'
220 print ' if (__vertex_attrib == VERTEX_ATTRIB_ARB) {'
221 print ' GLint __max_vertex_attribs = 0;'
222 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &__max_vertex_attribs);'
223 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
224 print ' GLint __enabled = 0;'
225 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &__enabled);'
226 print ' if (__enabled) {'
227 print ' GLint __binding = 0;'
228 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &__binding);'
229 print ' if (!__binding) {'
230 print ' return true;'
236 print ' // glVertexAttribPointerNV'
237 print ' if (__vertex_attrib == VERTEX_ATTRIB_NV) {'
238 print ' for (GLint index = 0; index < 16; ++index) {'
239 print ' GLint __enabled = 0;'
240 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
241 print ' if (__enabled) {'
242 print ' return true;'
248 print ' return false;'
252 print 'static void __trace_user_arrays(GLuint maxindex);'
255 print 'struct buffer_mapping {'
257 print ' GLint length;'
259 print ' bool explicit_flush;'
262 for target in self.buffer_targets:
263 print 'struct buffer_mapping __%s_mapping;' % target.lower();
265 print 'static inline struct buffer_mapping *'
266 print 'get_buffer_mapping(GLenum target) {'
267 print ' switch (target) {'
268 for target in self.buffer_targets:
269 print ' case GL_%s:' % target
270 print ' return & __%s_mapping;' % target.lower()
272 print ' os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
273 print ' return NULL;'
278 # Generate a helper function to determine whether a parameter name
279 # refers to a symbolic value or not
281 print 'is_symbolic_pname(GLenum pname) {'
282 print ' switch (pname) {'
283 for function, type, count, name in glparams.parameters:
284 if type is glapi.GLenum:
285 print ' case %s:' % name
286 print ' return true;'
288 print ' return false;'
293 # Generate a helper function to determine whether a parameter value is
294 # potentially symbolic or not; i.e., if the value can be represented in
296 print 'template<class T>'
297 print 'static inline bool'
298 print 'is_symbolic_param(T param) {'
299 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
303 # Generate a helper function to know how many elements a parameter has
304 print 'static size_t'
305 print '__gl_param_size(GLenum pname) {'
306 print ' switch (pname) {'
307 for function, type, count, name in glparams.parameters:
309 print ' case %s: return %u;' % (name, count)
310 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
311 print ' GLint num_compressed_texture_formats = 0;'
312 print ' __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
313 print ' return num_compressed_texture_formats;'
316 print r' os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
322 array_pointer_function_names = set((
330 "glSecondaryColorPointer",
332 "glInterleavedArrays",
334 "glVertexPointerEXT",
335 "glNormalPointerEXT",
338 "glTexCoordPointerEXT",
339 "glEdgeFlagPointerEXT",
340 "glFogCoordPointerEXT",
341 "glSecondaryColorPointerEXT",
343 "glVertexAttribPointer",
344 "glVertexAttribPointerARB",
345 "glVertexAttribPointerNV",
346 "glVertexAttribIPointer",
347 "glVertexAttribIPointerEXT",
348 "glVertexAttribLPointer",
349 "glVertexAttribLPointerEXT",
351 #"glMatrixIndexPointerARB",
354 draw_function_names = set((
357 'glDrawRangeElements',
359 'glMultiDrawElements',
360 'glDrawArraysInstanced',
361 "glDrawArraysInstancedBaseInstance",
362 'glDrawElementsInstanced',
363 'glDrawArraysInstancedARB',
364 'glDrawElementsInstancedARB',
365 'glDrawElementsBaseVertex',
366 'glDrawRangeElementsBaseVertex',
367 'glDrawElementsInstancedBaseVertex',
368 "glDrawElementsInstancedBaseInstance",
369 "glDrawElementsInstancedBaseVertexBaseInstance",
370 'glMultiDrawElementsBaseVertex',
371 'glDrawArraysIndirect',
372 'glDrawElementsIndirect',
374 'glDrawRangeElementsEXT',
375 'glDrawRangeElementsEXT_size',
376 'glMultiDrawArraysEXT',
377 'glMultiDrawElementsEXT',
378 'glMultiModeDrawArraysIBM',
379 'glMultiModeDrawElementsIBM',
380 'glDrawArraysInstancedEXT',
381 'glDrawElementsInstancedEXT',
384 interleaved_formats = [
397 'GL_T2F_C4F_N3F_V3F',
398 'GL_T4F_C4F_N3F_V4F',
401 def trace_function_impl_body(self, function):
402 # Defer tracing of user array pointers...
403 if function.name in self.array_pointer_function_names:
404 print ' GLint __array_buffer = 0;'
405 print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
406 print ' if (!__array_buffer) {'
407 print ' tracer_context *ctx = __get_context();'
408 print ' ctx->user_arrays = true;'
409 if function.name == "glVertexAttribPointerARB":
410 print ' ctx->user_arrays_arb = true;'
411 if function.name == "glVertexAttribPointerNV":
412 print ' ctx->user_arrays_nv = true;'
413 self.dispatch_function(function)
415 # And also break down glInterleavedArrays into the individual calls
416 if function.name == 'glInterleavedArrays':
419 # Initialize the enable flags
420 for camelcase_name, uppercase_name in self.arrays:
421 flag_name = '__' + uppercase_name.lower()
422 print ' GLboolean %s = GL_FALSE;' % flag_name
425 # Switch for the interleaved formats
426 print ' switch (format) {'
427 for format in self.interleaved_formats:
428 print ' case %s:' % format
429 for camelcase_name, uppercase_name in self.arrays:
430 flag_name = '__' + uppercase_name.lower()
431 if format.find('_' + uppercase_name[0]) >= 0:
432 print ' %s = GL_TRUE;' % flag_name
439 # Emit fake glEnableClientState/glDisableClientState flags
440 for camelcase_name, uppercase_name in self.arrays:
441 flag_name = '__' + uppercase_name.lower()
442 enable_name = 'GL_%s_ARRAY' % uppercase_name
444 # Emit a fake function
446 print ' static const trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
447 print ' unsigned __call = trace::localWriter.beginEnter(&__sig);'
448 print ' trace::localWriter.beginArg(0);'
449 dump_instance(glapi.GLenum, enable_name)
450 print ' trace::localWriter.endArg();'
451 print ' trace::localWriter.endEnter();'
452 print ' trace::localWriter.beginLeave(__call);'
453 print ' trace::localWriter.endLeave();'
459 # ... to the draw calls
460 if function.name in self.draw_function_names:
461 print ' if (__need_user_arrays()) {'
462 arg_names = ', '.join([arg.name for arg in function.args[1:]])
463 print ' GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
464 print ' __trace_user_arrays(maxindex);'
467 # Emit a fake memcpy on buffer uploads
468 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', ):
469 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
470 print ' if (mapping && mapping->write && !mapping->explicit_flush) {'
471 self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
473 if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
474 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
475 print ' if (mapping) {'
476 if function.name.endswith('APPLE'):
477 print ' GLsizeiptr length = size;'
478 print ' mapping->explicit_flush = true;'
479 print ' //assert(offset + length <= mapping->length);'
480 self.emit_memcpy('(char *)mapping->map + offset', '(const char *)mapping->map + offset', 'length')
482 # FIXME: glFlushMappedNamedBufferRangeEXT
484 # Don't leave vertex attrib locations to chance. Instead emit fake
485 # glBindAttribLocation calls to ensure that the same locations will be
486 # used when retracing. Trying to remap locations after the fact would
487 # be an herculian task given that vertex attrib locations appear in
488 # many entry-points, including non-shader related ones.
489 if function.name == 'glLinkProgram':
490 Tracer.dispatch_function(self, function)
491 print ' GLint active_attributes = 0;'
492 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
493 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
494 print ' GLint size = 0;'
495 print ' GLenum type = 0;'
496 print ' GLchar name[256];'
497 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
498 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
499 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
500 print ' GLint location = __glGetAttribLocation(program, name);'
501 print ' if (location >= 0) {'
502 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
503 self.fake_call(bind_function, ['program', 'location', 'name'])
507 if function.name == 'glLinkProgramARB':
508 Tracer.dispatch_function(self, function)
509 print ' GLint active_attributes = 0;'
510 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
511 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
512 print ' GLint size = 0;'
513 print ' GLenum type = 0;'
514 print ' GLcharARB name[256];'
515 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
516 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
517 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
518 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
519 print ' if (location >= 0) {'
520 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
521 self.fake_call(bind_function, ['programObj', 'location', 'name'])
526 Tracer.trace_function_impl_body(self, function)
528 gremedy_functions = [
529 'glStringMarkerGREMEDY',
530 'glFrameTerminatorGREMEDY',
533 def dispatch_function(self, function):
534 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
535 # These functions have been dispatched already
538 # We implement the GREMEDY extensions, not the driver
539 if function.name in self.gremedy_functions:
542 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
544 for gremedy_function in self.gremedy_functions:
545 print ' %s (strcmp("%s", (const char *)%s) == 0) {' % (if_, gremedy_function, function.args[0].name)
546 print ' __result = (%s)&%s;' % (function.type, gremedy_function)
550 Tracer.dispatch_function(self, function)
554 # Override GL extensions
555 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
556 Tracer.dispatch_function(self, function, prefix = 'gltrace::__', suffix = '_override')
559 Tracer.dispatch_function(self, function)
561 def emit_memcpy(self, dest, src, length):
562 print ' unsigned __call = trace::localWriter.beginEnter(&trace::memcpy_sig);'
563 print ' trace::localWriter.beginArg(0);'
564 print ' trace::localWriter.writeOpaque(%s);' % dest
565 print ' trace::localWriter.endArg();'
566 print ' trace::localWriter.beginArg(1);'
567 print ' trace::localWriter.writeBlob(%s, %s);' % (src, length)
568 print ' trace::localWriter.endArg();'
569 print ' trace::localWriter.beginArg(2);'
570 print ' trace::localWriter.writeUInt(%s);' % length
571 print ' trace::localWriter.endArg();'
572 print ' trace::localWriter.endEnter();'
573 print ' trace::localWriter.beginLeave(__call);'
574 print ' trace::localWriter.endLeave();'
578 'ELEMENT_ARRAY_BUFFER',
580 'PIXEL_UNPACK_BUFFER',
583 def wrap_ret(self, function, instance):
584 Tracer.wrap_ret(self, function, instance)
587 if function.name in ('glMapBuffer', 'glMapBufferARB'):
588 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
589 print ' if (mapping) {'
590 print ' mapping->map = %s;' % (instance)
591 print ' mapping->length = 0;'
592 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
593 print ' mapping->write = (access != GL_READ_ONLY);'
594 print ' mapping->explicit_flush = false;'
597 if function.name == 'glMapBufferRange':
598 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
599 print ' if (mapping) {'
600 print ' mapping->map = %s;' % (instance)
601 print ' mapping->length = length;'
602 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
603 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
611 def gl_boolean(self, value):
612 return self.boolean_names[int(bool(value))]
614 # Names of the functions that unpack from a pixel buffer object. See the
615 # ARB_pixel_buffer_object specification.
616 unpack_function_names = set([
620 'glCompressedTexImage1D',
621 'glCompressedTexImage2D',
622 'glCompressedTexImage3D',
623 'glCompressedTexSubImage1D',
624 'glCompressedTexSubImage2D',
625 'glCompressedTexSubImage3D',
626 'glConvolutionFilter1D',
627 'glConvolutionFilter2D',
629 'glMultiTexImage1DEXT',
630 'glMultiTexImage2DEXT',
631 'glMultiTexImage3DEXT',
632 'glMultiTexSubImage1DEXT',
633 'glMultiTexSubImage2DEXT',
634 'glMultiTexSubImage3DEXT',
639 'glSeparableFilter2D',
647 'glTexSubImage1DEXT',
649 'glTexSubImage2DEXT',
651 'glTexSubImage3DEXT',
652 'glTextureImage1DEXT',
653 'glTextureImage2DEXT',
654 'glTextureImage3DEXT',
655 'glTextureSubImage1DEXT',
656 'glTextureSubImage2DEXT',
657 'glTextureSubImage3DEXT',
660 def dump_arg_instance(self, function, arg):
661 if function.name in self.draw_function_names and arg.name == 'indices':
662 print ' GLint __element_array_buffer = 0;'
663 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
664 print ' if (!__element_array_buffer) {'
665 if isinstance(arg.type, stdapi.Array):
666 print ' trace::localWriter.beginArray(%s);' % arg.type.length
667 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
668 print ' trace::localWriter.beginElement();'
669 print ' trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
670 print ' trace::localWriter.endElement();'
672 print ' trace::localWriter.endArray();'
674 print ' trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
676 Tracer.dump_arg_instance(self, function, arg)
680 # Recognize offsets instead of blobs when a PBO is bound
681 if function.name in self.unpack_function_names \
682 and (isinstance(arg.type, stdapi.Blob) \
683 or (isinstance(arg.type, stdapi.Const) \
684 and isinstance(arg.type.type, stdapi.Blob))):
686 print ' tracer_context *ctx = __get_context();'
687 print ' GLint __unpack_buffer = 0;'
688 print ' if (ctx->profile == PROFILE_COMPAT)'
689 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
690 print ' if (__unpack_buffer) {'
691 print ' trace::localWriter.writeOpaque(%s);' % arg.name
693 Tracer.dump_arg_instance(self, function, arg)
698 # Several GL state functions take GLenum symbolic names as
699 # integer/floats; so dump the symbolic name whenever possible
700 if function.name.startswith('gl') \
701 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
702 and arg.name == 'param':
704 assert function.args[arg.index - 1].name == 'pname'
705 assert function.args[arg.index - 1].type == glapi.GLenum
706 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
707 dump_instance(glapi.GLenum, arg.name)
709 Tracer.dump_arg_instance(self, function, arg)
713 Tracer.dump_arg_instance(self, function, arg)
715 def footer(self, api):
716 Tracer.footer(self, api)
718 # A simple state tracker to track the pointer values
720 print 'static void __trace_user_arrays(GLuint maxindex)'
722 print ' tracer_context *ctx = __get_context();'
724 for camelcase_name, uppercase_name in self.arrays:
725 # in which profile is the array available?
726 profile_check = 'ctx->profile == PROFILE_COMPAT'
727 if camelcase_name in self.arrays_es1:
728 profile_check = '(' + profile_check + ' || ctx->profile == PROFILE_ES1)';
730 function_name = 'gl%sPointer' % camelcase_name
731 enable_name = 'GL_%s_ARRAY' % uppercase_name
732 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
733 function = api.get_function_by_name(function_name)
735 print ' // %s' % function.prototype()
736 print ' if (%s) {' % profile_check
737 self.array_trace_prolog(api, uppercase_name)
738 self.array_prolog(api, uppercase_name)
739 print ' if (__glIsEnabled(%s)) {' % enable_name
740 print ' GLint __binding = 0;'
741 print ' __glGetIntegerv(%s, &__binding);' % binding_name
742 print ' if (!__binding) {'
744 # Get the arguments via glGet*
745 for arg in function.args:
746 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
747 arg_get_function, arg_type = TypeGetter().visit(arg.type)
748 print ' %s %s = 0;' % (arg_type, arg.name)
749 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
751 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
752 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
754 # Emit a fake function
755 self.array_trace_intermezzo(api, uppercase_name)
756 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
757 for arg in function.args:
758 assert not arg.output
759 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
760 if arg.name != 'pointer':
761 dump_instance(arg.type, arg.name)
763 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
764 print ' trace::localWriter.endArg();'
766 print ' trace::localWriter.endEnter();'
767 print ' trace::localWriter.beginLeave(__call);'
768 print ' trace::localWriter.endLeave();'
771 self.array_epilog(api, uppercase_name)
772 self.array_trace_epilog(api, uppercase_name)
776 # Samething, but for glVertexAttribPointer*
778 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
779 # - glVertexAttribPointer: no
780 # - glVertexAttribPointerARB: implementation dependent
781 # - glVertexAttribPointerNV: yes
783 # This means that the implementations of these functions do not always
784 # alias, and they need to be considered independently.
786 print ' // ES1 does not support generic vertex attributes'
787 print ' if (ctx->profile == PROFILE_ES1)'
790 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
792 for suffix in ['', 'ARB', 'NV']:
794 SUFFIX = '_' + suffix
797 function_name = 'glVertexAttribPointer' + suffix
798 function = api.get_function_by_name(function_name)
800 print ' // %s' % function.prototype()
801 print ' if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
803 print ' GLint __max_vertex_attribs = 16;'
805 print ' GLint __max_vertex_attribs = 0;'
806 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
807 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
808 print ' GLint __enabled = 0;'
810 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
812 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
813 print ' if (__enabled) {'
814 print ' GLint __binding = 0;'
816 # It doesn't seem possible to use VBOs with NV_vertex_program.
817 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
818 print ' if (!__binding) {'
820 # Get the arguments via glGet*
821 for arg in function.args[1:]:
823 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
825 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
826 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
827 print ' %s %s = 0;' % (arg_type, arg.name)
828 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
830 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
831 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
833 # Emit a fake function
834 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
835 for arg in function.args:
836 assert not arg.output
837 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
838 if arg.name != 'pointer':
839 dump_instance(arg.type, arg.name)
841 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
842 print ' trace::localWriter.endArg();'
844 print ' trace::localWriter.endEnter();'
845 print ' trace::localWriter.beginLeave(__call);'
846 print ' trace::localWriter.endLeave();'
857 # Hooks for glTexCoordPointer, which is identical to the other array
858 # pointers except the fact that it is indexed by glClientActiveTexture.
861 def array_prolog(self, api, uppercase_name):
862 if uppercase_name == 'TEXTURE_COORD':
863 print ' GLint client_active_texture = 0;'
864 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
865 print ' GLint max_texture_coords = 0;'
866 print ' if (ctx->profile == PROFILE_COMPAT)'
867 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
869 print ' __glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
870 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
871 print ' GLint texture = GL_TEXTURE0 + unit;'
872 print ' __glClientActiveTexture(texture);'
874 def array_trace_prolog(self, api, uppercase_name):
875 if uppercase_name == 'TEXTURE_COORD':
876 print ' bool client_active_texture_dirty = false;'
878 def array_epilog(self, api, uppercase_name):
879 if uppercase_name == 'TEXTURE_COORD':
881 self.array_cleanup(api, uppercase_name)
883 def array_cleanup(self, api, uppercase_name):
884 if uppercase_name == 'TEXTURE_COORD':
885 print ' __glClientActiveTexture(client_active_texture);'
887 def array_trace_intermezzo(self, api, uppercase_name):
888 if uppercase_name == 'TEXTURE_COORD':
889 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
890 print ' client_active_texture_dirty = true;'
891 self.fake_glClientActiveTexture_call(api, "texture");
894 def array_trace_epilog(self, api, uppercase_name):
895 if uppercase_name == 'TEXTURE_COORD':
896 print ' if (client_active_texture_dirty) {'
897 self.fake_glClientActiveTexture_call(api, "client_active_texture");
900 def fake_glClientActiveTexture_call(self, api, texture):
901 function = api.get_function_by_name('glClientActiveTexture')
902 self.fake_call(function, [texture])
904 def fake_call(self, function, args):
905 print ' unsigned __fake_call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
906 for arg, instance in zip(function.args, args):
907 assert not arg.output
908 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
909 dump_instance(arg.type, instance)
910 print ' trace::localWriter.endArg();'
911 print ' trace::localWriter.endEnter();'
912 print ' trace::localWriter.beginLeave(__fake_call);'
913 print ' trace::localWriter.endLeave();'