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
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 visitConst(self, const):
46 return self.visit(const.type)
48 def visitAlias(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 visitEnum(self, enum):
84 return self.visit(glapi.GLint)
86 def visitBitmask(self, bitmask):
87 return self.visit(glapi.GLint)
89 def visitOpaque(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"'
116 # Which glVertexAttrib* variant to use
117 print 'enum vertex_attrib {'
118 print ' VERTEX_ATTRIB,'
119 print ' VERTEX_ATTRIB_ARB,'
120 print ' VERTEX_ATTRIB_NV,'
123 print 'gltrace::Context *'
124 print 'gltrace::getContext(void)'
126 print ' // TODO return the context set by other APIs (GLX, EGL, and etc.)'
127 print ' static gltrace::Context __ctx = { gltrace::PROFILE_COMPAT, false, false, false };'
128 print ' return &__ctx;'
131 print 'static vertex_attrib __get_vertex_attrib(void) {'
132 print ' gltrace::Context *ctx = gltrace::getContext();'
133 print ' if (ctx->user_arrays_arb || ctx->user_arrays_nv) {'
134 print ' GLboolean __vertex_program = GL_FALSE;'
135 print ' __glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &__vertex_program);'
136 print ' if (__vertex_program) {'
137 print ' if (ctx->user_arrays_nv) {'
138 print ' GLint __vertex_program_binding_nv = 0;'
139 print ' __glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &__vertex_program_binding_nv);'
140 print ' if (__vertex_program_binding_nv) {'
141 print ' return VERTEX_ATTRIB_NV;'
144 print ' return VERTEX_ATTRIB_ARB;'
147 print ' return VERTEX_ATTRIB;'
151 # Whether we need user arrays
152 print 'static inline bool __need_user_arrays(void)'
154 print ' gltrace::Context *ctx = gltrace::getContext();'
155 print ' if (!ctx->user_arrays) {'
156 print ' return false;'
160 for camelcase_name, uppercase_name in self.arrays:
161 # in which profile is the array available?
162 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
163 if camelcase_name in self.arrays_es1:
164 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
166 function_name = 'gl%sPointer' % camelcase_name
167 enable_name = 'GL_%s_ARRAY' % uppercase_name
168 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
169 print ' // %s' % function_name
170 print ' if (%s) {' % profile_check
171 self.array_prolog(api, uppercase_name)
172 print ' if (__glIsEnabled(%s)) {' % enable_name
173 print ' GLint __binding = 0;'
174 print ' __glGetIntegerv(%s, &__binding);' % binding_name
175 print ' if (!__binding) {'
176 self.array_cleanup(api, uppercase_name)
177 print ' return true;'
180 self.array_epilog(api, uppercase_name)
184 print ' // ES1 does not support generic vertex attributes'
185 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
186 print ' return false;'
188 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
190 print ' // glVertexAttribPointer'
191 print ' if (__vertex_attrib == VERTEX_ATTRIB) {'
192 print ' GLint __max_vertex_attribs = 0;'
193 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
194 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
195 print ' GLint __enabled = 0;'
196 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
197 print ' if (__enabled) {'
198 print ' GLint __binding = 0;'
199 print ' __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
200 print ' if (!__binding) {'
201 print ' return true;'
207 print ' // glVertexAttribPointerARB'
208 print ' if (__vertex_attrib == VERTEX_ATTRIB_ARB) {'
209 print ' GLint __max_vertex_attribs = 0;'
210 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &__max_vertex_attribs);'
211 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
212 print ' GLint __enabled = 0;'
213 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &__enabled);'
214 print ' if (__enabled) {'
215 print ' GLint __binding = 0;'
216 print ' __glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &__binding);'
217 print ' if (!__binding) {'
218 print ' return true;'
224 print ' // glVertexAttribPointerNV'
225 print ' if (__vertex_attrib == VERTEX_ATTRIB_NV) {'
226 print ' for (GLint index = 0; index < 16; ++index) {'
227 print ' GLint __enabled = 0;'
228 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
229 print ' if (__enabled) {'
230 print ' return true;'
236 print ' return false;'
240 print 'static void __trace_user_arrays(GLuint maxindex);'
243 print 'struct buffer_mapping {'
245 print ' GLint length;'
247 print ' bool explicit_flush;'
250 for target in self.buffer_targets:
251 print 'struct buffer_mapping __%s_mapping;' % target.lower();
253 print 'static inline struct buffer_mapping *'
254 print 'get_buffer_mapping(GLenum target) {'
255 print ' switch (target) {'
256 for target in self.buffer_targets:
257 print ' case GL_%s:' % target
258 print ' return & __%s_mapping;' % target.lower()
260 print ' os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
261 print ' return NULL;'
266 # Generate a helper function to determine whether a parameter name
267 # refers to a symbolic value or not
269 print 'is_symbolic_pname(GLenum pname) {'
270 print ' switch (pname) {'
271 for function, type, count, name in glparams.parameters:
272 if type is glapi.GLenum:
273 print ' case %s:' % name
274 print ' return true;'
276 print ' return false;'
281 # Generate a helper function to determine whether a parameter value is
282 # potentially symbolic or not; i.e., if the value can be represented in
284 print 'template<class T>'
285 print 'static inline bool'
286 print 'is_symbolic_param(T param) {'
287 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
291 # Generate a helper function to know how many elements a parameter has
292 print 'static size_t'
293 print '__gl_param_size(GLenum pname) {'
294 print ' switch (pname) {'
295 for function, type, count, name in glparams.parameters:
297 print ' case %s: return %u;' % (name, count)
298 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
299 print ' GLint num_compressed_texture_formats = 0;'
300 print ' __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
301 print ' return num_compressed_texture_formats;'
304 print r' os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
310 # states such as GL_UNPACK_ROW_LENGTH are not available in GLES
311 print 'static inline bool'
312 print 'can_unpack_subimage(void) {'
313 print ' gltrace::Context *ctx = gltrace::getContext();'
314 print ' return (ctx->profile == gltrace::PROFILE_COMPAT);'
318 array_pointer_function_names = set((
326 "glSecondaryColorPointer",
328 "glInterleavedArrays",
330 "glVertexPointerEXT",
331 "glNormalPointerEXT",
334 "glTexCoordPointerEXT",
335 "glEdgeFlagPointerEXT",
336 "glFogCoordPointerEXT",
337 "glSecondaryColorPointerEXT",
339 "glVertexAttribPointer",
340 "glVertexAttribPointerARB",
341 "glVertexAttribPointerNV",
342 "glVertexAttribIPointer",
343 "glVertexAttribIPointerEXT",
344 "glVertexAttribLPointer",
345 "glVertexAttribLPointerEXT",
347 #"glMatrixIndexPointerARB",
350 draw_function_names = set((
353 'glDrawRangeElements',
355 'glMultiDrawElements',
356 'glDrawArraysInstanced',
357 "glDrawArraysInstancedBaseInstance",
358 'glDrawElementsInstanced',
359 'glDrawArraysInstancedARB',
360 'glDrawElementsInstancedARB',
361 'glDrawElementsBaseVertex',
362 'glDrawRangeElementsBaseVertex',
363 'glDrawElementsInstancedBaseVertex',
364 "glDrawElementsInstancedBaseInstance",
365 "glDrawElementsInstancedBaseVertexBaseInstance",
366 'glMultiDrawElementsBaseVertex',
367 'glDrawArraysIndirect',
368 'glDrawElementsIndirect',
370 'glDrawRangeElementsEXT',
371 'glDrawRangeElementsEXT_size',
372 'glMultiDrawArraysEXT',
373 'glMultiDrawElementsEXT',
374 'glMultiModeDrawArraysIBM',
375 'glMultiModeDrawElementsIBM',
376 'glDrawArraysInstancedEXT',
377 'glDrawElementsInstancedEXT',
380 interleaved_formats = [
393 'GL_T2F_C4F_N3F_V3F',
394 'GL_T4F_C4F_N3F_V4F',
397 def traceFunctionImplBody(self, function):
398 # Defer tracing of user array pointers...
399 if function.name in self.array_pointer_function_names:
400 print ' GLint __array_buffer = 0;'
401 print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
402 print ' if (!__array_buffer) {'
403 print ' gltrace::Context *ctx = gltrace::getContext();'
404 print ' ctx->user_arrays = true;'
405 if function.name == "glVertexAttribPointerARB":
406 print ' ctx->user_arrays_arb = true;'
407 if function.name == "glVertexAttribPointerNV":
408 print ' ctx->user_arrays_nv = true;'
409 self.invokeFunction(function)
411 # And also break down glInterleavedArrays into the individual calls
412 if function.name == 'glInterleavedArrays':
415 # Initialize the enable flags
416 for camelcase_name, uppercase_name in self.arrays:
417 flag_name = '__' + uppercase_name.lower()
418 print ' GLboolean %s = GL_FALSE;' % flag_name
421 # Switch for the interleaved formats
422 print ' switch (format) {'
423 for format in self.interleaved_formats:
424 print ' case %s:' % format
425 for camelcase_name, uppercase_name in self.arrays:
426 flag_name = '__' + uppercase_name.lower()
427 if format.find('_' + uppercase_name[0]) >= 0:
428 print ' %s = GL_TRUE;' % flag_name
435 # Emit fake glEnableClientState/glDisableClientState flags
436 for camelcase_name, uppercase_name in self.arrays:
437 flag_name = '__' + uppercase_name.lower()
438 enable_name = 'GL_%s_ARRAY' % uppercase_name
440 # Emit a fake function
442 print ' static const trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
443 print ' unsigned __call = trace::localWriter.beginEnter(&__sig);'
444 print ' trace::localWriter.beginArg(0);'
445 self.serializeValue(glapi.GLenum, enable_name)
446 print ' trace::localWriter.endArg();'
447 print ' trace::localWriter.endEnter();'
448 print ' trace::localWriter.beginLeave(__call);'
449 print ' trace::localWriter.endLeave();'
455 # ... to the draw calls
456 if function.name in self.draw_function_names:
457 print ' if (__need_user_arrays()) {'
458 arg_names = ', '.join([arg.name for arg in function.args[1:]])
459 print ' GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
460 print ' __trace_user_arrays(maxindex);'
463 # Emit a fake memcpy on buffer uploads
464 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', 'glUnmapBufferOES'):
465 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
466 print ' if (mapping && mapping->write && !mapping->explicit_flush) {'
467 self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
469 if function.name == 'glUnmapNamedBufferEXT':
470 print ' GLint access = 0;'
471 print ' glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS, &access);'
472 print ' if ((access & GL_MAP_WRITE_BIT) & !(access & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
473 print ' GLvoid *map = NULL;'
474 print ' glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
475 print ' GLint length = 0;'
476 print ' glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
477 self.emit_memcpy('map', 'map', 'length')
479 if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
480 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
481 print ' if (mapping) {'
482 if function.name.endswith('APPLE'):
483 print ' GLsizeiptr length = size;'
484 print ' mapping->explicit_flush = true;'
485 print ' //assert(offset + length <= mapping->length);'
486 self.emit_memcpy('(char *)mapping->map + offset', '(const char *)mapping->map + offset', 'length')
488 if function.name == 'glFlushMappedNamedBufferRangeEXT':
489 print ' GLvoid *map = NULL;'
490 print ' glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
492 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
495 # Don't leave vertex attrib locations to chance. Instead emit fake
496 # glBindAttribLocation calls to ensure that the same locations will be
497 # used when retracing. Trying to remap locations after the fact would
498 # be an herculian task given that vertex attrib locations appear in
499 # many entry-points, including non-shader related ones.
500 if function.name == 'glLinkProgram':
501 Tracer.invokeFunction(self, function)
502 print ' GLint active_attributes = 0;'
503 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
504 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
505 print ' GLint size = 0;'
506 print ' GLenum type = 0;'
507 print ' GLchar name[256];'
508 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
509 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
510 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
511 print ' GLint location = __glGetAttribLocation(program, name);'
512 print ' if (location >= 0) {'
513 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
514 self.fake_call(bind_function, ['program', 'location', 'name'])
518 if function.name == 'glLinkProgramARB':
519 Tracer.invokeFunction(self, function)
520 print ' GLint active_attributes = 0;'
521 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
522 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
523 print ' GLint size = 0;'
524 print ' GLenum type = 0;'
525 print ' GLcharARB name[256];'
526 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
527 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
528 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
529 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
530 print ' if (location >= 0) {'
531 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
532 self.fake_call(bind_function, ['programObj', 'location', 'name'])
537 Tracer.traceFunctionImplBody(self, function)
540 # GL_GREMEDY_string_marker
541 'glStringMarkerGREMEDY',
542 # GL_GREMEDY_frame_terminator
543 'glFrameTerminatorGREMEDY',
544 # GL_EXT_debug_marker
545 'glInsertEventMarkerEXT',
546 'glPushGroupMarkerEXT',
547 'glPopGroupMarkerEXT',
550 def invokeFunction(self, function):
551 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
552 # These functions have been dispatched already
555 # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
557 if function.name in self.marker_functions:
560 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
562 for marker_function in self.marker_functions:
563 if self.api.get_function_by_name(marker_function):
564 print ' %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
565 print ' __result = (%s)&%s;' % (function.type, marker_function)
569 Tracer.invokeFunction(self, function)
573 # Override GL extensions
574 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
575 Tracer.invokeFunction(self, function, prefix = 'gltrace::__', suffix = '_override')
578 Tracer.invokeFunction(self, function)
582 'ELEMENT_ARRAY_BUFFER',
584 'PIXEL_UNPACK_BUFFER',
587 'TRANSFORM_FEEDBACK_BUFFER',
590 'DRAW_INDIRECT_BUFFER',
591 'ATOMIC_COUNTER_BUFFER',
594 def wrapRet(self, function, instance):
595 Tracer.wrapRet(self, function, instance)
598 if function.name in ('glMapBuffer', 'glMapBufferARB', 'glMapBufferOES'):
599 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
600 print ' if (mapping) {'
601 print ' mapping->map = %s;' % (instance)
602 print ' mapping->length = 0;'
603 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
604 print ' mapping->write = (access != GL_READ_ONLY);'
605 print ' mapping->explicit_flush = false;'
608 if function.name == 'glMapBufferRange':
609 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
610 print ' if (mapping) {'
611 print ' mapping->map = %s;' % (instance)
612 print ' mapping->length = length;'
613 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
614 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
622 def gl_boolean(self, value):
623 return self.boolean_names[int(bool(value))]
625 # Names of the functions that unpack from a pixel buffer object. See the
626 # ARB_pixel_buffer_object specification.
627 unpack_function_names = set([
631 'glCompressedTexImage1D',
632 'glCompressedTexImage2D',
633 'glCompressedTexImage3D',
634 'glCompressedTexSubImage1D',
635 'glCompressedTexSubImage2D',
636 'glCompressedTexSubImage3D',
637 'glConvolutionFilter1D',
638 'glConvolutionFilter2D',
640 'glMultiTexImage1DEXT',
641 'glMultiTexImage2DEXT',
642 'glMultiTexImage3DEXT',
643 'glMultiTexSubImage1DEXT',
644 'glMultiTexSubImage2DEXT',
645 'glMultiTexSubImage3DEXT',
650 'glSeparableFilter2D',
658 'glTexSubImage1DEXT',
660 'glTexSubImage2DEXT',
662 'glTexSubImage3DEXT',
663 'glTextureImage1DEXT',
664 'glTextureImage2DEXT',
665 'glTextureImage3DEXT',
666 'glTextureSubImage1DEXT',
667 'glTextureSubImage2DEXT',
668 'glTextureSubImage3DEXT',
671 def serializeArgValue(self, function, arg):
672 if function.name in self.draw_function_names and arg.name == 'indices':
673 print ' GLint __element_array_buffer = 0;'
674 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
675 print ' if (!__element_array_buffer) {'
676 if isinstance(arg.type, stdapi.Array):
677 print ' trace::localWriter.beginArray(%s);' % arg.type.length
678 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
679 print ' trace::localWriter.beginElement();'
680 print ' trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
681 print ' trace::localWriter.endElement();'
683 print ' trace::localWriter.endArray();'
685 print ' trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
687 Tracer.serializeArgValue(self, function, arg)
691 # Recognize offsets instead of blobs when a PBO is bound
692 if function.name in self.unpack_function_names \
693 and (isinstance(arg.type, stdapi.Blob) \
694 or (isinstance(arg.type, stdapi.Const) \
695 and isinstance(arg.type.type, stdapi.Blob))):
697 print ' gltrace::Context *ctx = gltrace::getContext();'
698 print ' GLint __unpack_buffer = 0;'
699 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
700 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
701 print ' if (__unpack_buffer) {'
702 print ' trace::localWriter.writeOpaque(%s);' % arg.name
704 Tracer.serializeArgValue(self, function, arg)
709 # Several GL state functions take GLenum symbolic names as
710 # integer/floats; so dump the symbolic name whenever possible
711 if function.name.startswith('gl') \
712 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
713 and arg.name == 'param':
715 assert function.args[arg.index - 1].name == 'pname'
716 assert function.args[arg.index - 1].type == glapi.GLenum
717 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
718 self.serializeValue(glapi.GLenum, arg.name)
720 Tracer.serializeArgValue(self, function, arg)
724 Tracer.serializeArgValue(self, function, arg)
726 def footer(self, api):
727 Tracer.footer(self, api)
729 # A simple state tracker to track the pointer values
731 print 'static void __trace_user_arrays(GLuint maxindex)'
733 print ' gltrace::Context *ctx = gltrace::getContext();'
735 for camelcase_name, uppercase_name in self.arrays:
736 # in which profile is the array available?
737 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
738 if camelcase_name in self.arrays_es1:
739 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
741 function_name = 'gl%sPointer' % camelcase_name
742 enable_name = 'GL_%s_ARRAY' % uppercase_name
743 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
744 function = api.get_function_by_name(function_name)
746 print ' // %s' % function.prototype()
747 print ' if (%s) {' % profile_check
748 self.array_trace_prolog(api, uppercase_name)
749 self.array_prolog(api, uppercase_name)
750 print ' if (__glIsEnabled(%s)) {' % enable_name
751 print ' GLint __binding = 0;'
752 print ' __glGetIntegerv(%s, &__binding);' % binding_name
753 print ' if (!__binding) {'
755 # Get the arguments via glGet*
756 for arg in function.args:
757 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
758 arg_get_function, arg_type = TypeGetter().visit(arg.type)
759 print ' %s %s = 0;' % (arg_type, arg.name)
760 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
762 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
763 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
765 # Emit a fake function
766 self.array_trace_intermezzo(api, uppercase_name)
767 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
768 for arg in function.args:
769 assert not arg.output
770 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
771 if arg.name != 'pointer':
772 self.serializeValue(arg.type, arg.name)
774 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
775 print ' trace::localWriter.endArg();'
777 print ' trace::localWriter.endEnter();'
778 print ' trace::localWriter.beginLeave(__call);'
779 print ' trace::localWriter.endLeave();'
782 self.array_epilog(api, uppercase_name)
783 self.array_trace_epilog(api, uppercase_name)
787 # Samething, but for glVertexAttribPointer*
789 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
790 # - glVertexAttribPointer: no
791 # - glVertexAttribPointerARB: implementation dependent
792 # - glVertexAttribPointerNV: yes
794 # This means that the implementations of these functions do not always
795 # alias, and they need to be considered independently.
797 print ' // ES1 does not support generic vertex attributes'
798 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
801 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
803 for suffix in ['', 'ARB', 'NV']:
805 SUFFIX = '_' + suffix
808 function_name = 'glVertexAttribPointer' + suffix
809 function = api.get_function_by_name(function_name)
811 print ' // %s' % function.prototype()
812 print ' if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
814 print ' GLint __max_vertex_attribs = 16;'
816 print ' GLint __max_vertex_attribs = 0;'
817 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
818 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
819 print ' GLint __enabled = 0;'
821 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
823 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
824 print ' if (__enabled) {'
825 print ' GLint __binding = 0;'
827 # It doesn't seem possible to use VBOs with NV_vertex_program.
828 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
829 print ' if (!__binding) {'
831 # Get the arguments via glGet*
832 for arg in function.args[1:]:
834 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
836 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
837 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
838 print ' %s %s = 0;' % (arg_type, arg.name)
839 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
841 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
842 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
844 # Emit a fake function
845 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
846 for arg in function.args:
847 assert not arg.output
848 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
849 if arg.name != 'pointer':
850 self.serializeValue(arg.type, arg.name)
852 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
853 print ' trace::localWriter.endArg();'
855 print ' trace::localWriter.endEnter();'
856 print ' trace::localWriter.beginLeave(__call);'
857 print ' trace::localWriter.endLeave();'
868 # Hooks for glTexCoordPointer, which is identical to the other array
869 # pointers except the fact that it is indexed by glClientActiveTexture.
872 def array_prolog(self, api, uppercase_name):
873 if uppercase_name == 'TEXTURE_COORD':
874 print ' GLint client_active_texture = 0;'
875 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
876 print ' GLint max_texture_coords = 0;'
877 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
878 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
880 print ' __glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
881 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
882 print ' GLint texture = GL_TEXTURE0 + unit;'
883 print ' __glClientActiveTexture(texture);'
885 def array_trace_prolog(self, api, uppercase_name):
886 if uppercase_name == 'TEXTURE_COORD':
887 print ' bool client_active_texture_dirty = false;'
889 def array_epilog(self, api, uppercase_name):
890 if uppercase_name == 'TEXTURE_COORD':
892 self.array_cleanup(api, uppercase_name)
894 def array_cleanup(self, api, uppercase_name):
895 if uppercase_name == 'TEXTURE_COORD':
896 print ' __glClientActiveTexture(client_active_texture);'
898 def array_trace_intermezzo(self, api, uppercase_name):
899 if uppercase_name == 'TEXTURE_COORD':
900 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
901 print ' client_active_texture_dirty = true;'
902 self.fake_glClientActiveTexture_call(api, "texture");
905 def array_trace_epilog(self, api, uppercase_name):
906 if uppercase_name == 'TEXTURE_COORD':
907 print ' if (client_active_texture_dirty) {'
908 self.fake_glClientActiveTexture_call(api, "client_active_texture");
911 def fake_glClientActiveTexture_call(self, api, texture):
912 function = api.get_function_by_name('glClientActiveTexture')
913 self.fake_call(function, [texture])
915 def fake_call(self, function, args):
916 print ' unsigned __fake_call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
917 for arg, instance in zip(function.args, args):
918 assert not arg.output
919 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
920 self.serializeValue(arg.type, instance)
921 print ' trace::localWriter.endArg();'
922 print ' trace::localWriter.endEnter();'
923 print ' trace::localWriter.beginLeave(__fake_call);'
924 print ' trace::localWriter.endLeave();'