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'):
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')
468 if function.name == 'glUnmapBufferOES':
469 print ' GLint access = 0;'
470 print ' __glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
471 print ' if (access == GL_WRITE_ONLY_OES) {'
472 print ' GLvoid *map = NULL;'
473 print ' __glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
474 print ' GLint size = 0;'
475 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
476 print ' if (map && size > 0) {'
477 self.emit_memcpy('map', 'map', 'size')
480 if function.name == 'glUnmapNamedBufferEXT':
481 print ' GLint access_flags = 0;'
482 print ' __glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
483 print ' if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
484 print ' GLvoid *map = NULL;'
485 print ' __glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
486 print ' GLint length = 0;'
487 print ' __glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
488 print ' if (map && length > 0) {'
489 self.emit_memcpy('map', 'map', 'length')
492 if function.name == 'glFlushMappedBufferRange':
493 print ' GLvoid *map = NULL;'
494 print ' __glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
495 print ' if (map && length > 0) {'
496 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
498 if function.name == 'glFlushMappedBufferRangeAPPLE':
499 print ' GLvoid *map = NULL;'
500 print ' __glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
501 print ' if (map && size > 0) {'
502 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
504 if function.name == 'glFlushMappedNamedBufferRangeEXT':
505 print ' GLvoid *map = NULL;'
506 print ' __glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
507 print ' if (map && length > 0) {'
508 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
511 # Don't leave vertex attrib locations to chance. Instead emit fake
512 # glBindAttribLocation calls to ensure that the same locations will be
513 # used when retracing. Trying to remap locations after the fact would
514 # be an herculian task given that vertex attrib locations appear in
515 # many entry-points, including non-shader related ones.
516 if function.name == 'glLinkProgram':
517 Tracer.invokeFunction(self, function)
518 print ' GLint active_attributes = 0;'
519 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
520 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
521 print ' GLint size = 0;'
522 print ' GLenum type = 0;'
523 print ' GLchar name[256];'
524 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
525 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
526 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
527 print ' GLint location = __glGetAttribLocation(program, name);'
528 print ' if (location >= 0) {'
529 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
530 self.fake_call(bind_function, ['program', 'location', 'name'])
534 if function.name == 'glLinkProgramARB':
535 Tracer.invokeFunction(self, function)
536 print ' GLint active_attributes = 0;'
537 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
538 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
539 print ' GLint size = 0;'
540 print ' GLenum type = 0;'
541 print ' GLcharARB name[256];'
542 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
543 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
544 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
545 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
546 print ' if (location >= 0) {'
547 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
548 self.fake_call(bind_function, ['programObj', 'location', 'name'])
553 Tracer.traceFunctionImplBody(self, function)
556 # GL_GREMEDY_string_marker
557 'glStringMarkerGREMEDY',
558 # GL_GREMEDY_frame_terminator
559 'glFrameTerminatorGREMEDY',
560 # GL_EXT_debug_marker
561 'glInsertEventMarkerEXT',
562 'glPushGroupMarkerEXT',
563 'glPopGroupMarkerEXT',
566 def invokeFunction(self, function):
567 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
568 # These functions have been dispatched already
571 # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
573 if function.name in self.marker_functions:
576 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
578 for marker_function in self.marker_functions:
579 if self.api.get_function_by_name(marker_function):
580 print ' %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
581 print ' __result = (%s)&%s;' % (function.type, marker_function)
585 Tracer.invokeFunction(self, function)
589 # Override GL extensions
590 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
591 Tracer.invokeFunction(self, function, prefix = 'gltrace::__', suffix = '_override')
594 Tracer.invokeFunction(self, function)
598 'ELEMENT_ARRAY_BUFFER',
600 'PIXEL_UNPACK_BUFFER',
603 'TRANSFORM_FEEDBACK_BUFFER',
606 'DRAW_INDIRECT_BUFFER',
607 'ATOMIC_COUNTER_BUFFER',
610 def wrapRet(self, function, instance):
611 Tracer.wrapRet(self, function, instance)
613 # Keep track of buffer mappings
614 if function.name in ('glMapBuffer', 'glMapBufferARB'):
615 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
616 print ' if (mapping) {'
617 print ' mapping->map = %s;' % (instance)
618 print ' mapping->length = 0;'
619 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
620 print ' mapping->write = (access != GL_READ_ONLY);'
621 print ' mapping->explicit_flush = false;'
623 if function.name == 'glMapBufferRange':
624 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
625 print ' if (mapping) {'
626 print ' mapping->map = %s;' % (instance)
627 print ' mapping->length = length;'
628 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
629 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
637 def gl_boolean(self, value):
638 return self.boolean_names[int(bool(value))]
640 # Names of the functions that unpack from a pixel buffer object. See the
641 # ARB_pixel_buffer_object specification.
642 unpack_function_names = set([
646 'glCompressedTexImage1D',
647 'glCompressedTexImage2D',
648 'glCompressedTexImage3D',
649 'glCompressedTexSubImage1D',
650 'glCompressedTexSubImage2D',
651 'glCompressedTexSubImage3D',
652 'glConvolutionFilter1D',
653 'glConvolutionFilter2D',
655 'glMultiTexImage1DEXT',
656 'glMultiTexImage2DEXT',
657 'glMultiTexImage3DEXT',
658 'glMultiTexSubImage1DEXT',
659 'glMultiTexSubImage2DEXT',
660 'glMultiTexSubImage3DEXT',
665 'glSeparableFilter2D',
673 'glTexSubImage1DEXT',
675 'glTexSubImage2DEXT',
677 'glTexSubImage3DEXT',
678 'glTextureImage1DEXT',
679 'glTextureImage2DEXT',
680 'glTextureImage3DEXT',
681 'glTextureSubImage1DEXT',
682 'glTextureSubImage2DEXT',
683 'glTextureSubImage3DEXT',
686 def serializeArgValue(self, function, arg):
687 if function.name in self.draw_function_names and arg.name == 'indices':
688 print ' GLint __element_array_buffer = 0;'
689 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
690 print ' if (!__element_array_buffer) {'
691 if isinstance(arg.type, stdapi.Array):
692 print ' trace::localWriter.beginArray(%s);' % arg.type.length
693 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
694 print ' trace::localWriter.beginElement();'
695 print ' trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
696 print ' trace::localWriter.endElement();'
698 print ' trace::localWriter.endArray();'
700 print ' trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
702 Tracer.serializeArgValue(self, function, arg)
706 # Recognize offsets instead of blobs when a PBO is bound
707 if function.name in self.unpack_function_names \
708 and (isinstance(arg.type, stdapi.Blob) \
709 or (isinstance(arg.type, stdapi.Const) \
710 and isinstance(arg.type.type, stdapi.Blob))):
712 print ' gltrace::Context *ctx = gltrace::getContext();'
713 print ' GLint __unpack_buffer = 0;'
714 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
715 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
716 print ' if (__unpack_buffer) {'
717 print ' trace::localWriter.writeOpaque(%s);' % arg.name
719 Tracer.serializeArgValue(self, function, arg)
724 # Several GL state functions take GLenum symbolic names as
725 # integer/floats; so dump the symbolic name whenever possible
726 if function.name.startswith('gl') \
727 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
728 and arg.name == 'param':
730 assert function.args[arg.index - 1].name == 'pname'
731 assert function.args[arg.index - 1].type == glapi.GLenum
732 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
733 self.serializeValue(glapi.GLenum, arg.name)
735 Tracer.serializeArgValue(self, function, arg)
739 Tracer.serializeArgValue(self, function, arg)
741 def footer(self, api):
742 Tracer.footer(self, api)
744 # A simple state tracker to track the pointer values
746 print 'static void __trace_user_arrays(GLuint maxindex)'
748 print ' gltrace::Context *ctx = gltrace::getContext();'
750 for camelcase_name, uppercase_name in self.arrays:
751 # in which profile is the array available?
752 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
753 if camelcase_name in self.arrays_es1:
754 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
756 function_name = 'gl%sPointer' % camelcase_name
757 enable_name = 'GL_%s_ARRAY' % uppercase_name
758 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
759 function = api.get_function_by_name(function_name)
761 print ' // %s' % function.prototype()
762 print ' if (%s) {' % profile_check
763 self.array_trace_prolog(api, uppercase_name)
764 self.array_prolog(api, uppercase_name)
765 print ' if (__glIsEnabled(%s)) {' % enable_name
766 print ' GLint __binding = 0;'
767 print ' __glGetIntegerv(%s, &__binding);' % binding_name
768 print ' if (!__binding) {'
770 # Get the arguments via glGet*
771 for arg in function.args:
772 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
773 arg_get_function, arg_type = TypeGetter().visit(arg.type)
774 print ' %s %s = 0;' % (arg_type, arg.name)
775 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
777 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
778 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
780 # Emit a fake function
781 self.array_trace_intermezzo(api, uppercase_name)
782 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
783 for arg in function.args:
784 assert not arg.output
785 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
786 if arg.name != 'pointer':
787 self.serializeValue(arg.type, arg.name)
789 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
790 print ' trace::localWriter.endArg();'
792 print ' trace::localWriter.endEnter();'
793 print ' trace::localWriter.beginLeave(__call);'
794 print ' trace::localWriter.endLeave();'
797 self.array_epilog(api, uppercase_name)
798 self.array_trace_epilog(api, uppercase_name)
802 # Samething, but for glVertexAttribPointer*
804 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
805 # - glVertexAttribPointer: no
806 # - glVertexAttribPointerARB: implementation dependent
807 # - glVertexAttribPointerNV: yes
809 # This means that the implementations of these functions do not always
810 # alias, and they need to be considered independently.
812 print ' // ES1 does not support generic vertex attributes'
813 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
816 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
818 for suffix in ['', 'ARB', 'NV']:
820 SUFFIX = '_' + suffix
823 function_name = 'glVertexAttribPointer' + suffix
824 function = api.get_function_by_name(function_name)
826 print ' // %s' % function.prototype()
827 print ' if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
829 print ' GLint __max_vertex_attribs = 16;'
831 print ' GLint __max_vertex_attribs = 0;'
832 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
833 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
834 print ' GLint __enabled = 0;'
836 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
838 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
839 print ' if (__enabled) {'
840 print ' GLint __binding = 0;'
842 # It doesn't seem possible to use VBOs with NV_vertex_program.
843 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
844 print ' if (!__binding) {'
846 # Get the arguments via glGet*
847 for arg in function.args[1:]:
849 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
851 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
852 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
853 print ' %s %s = 0;' % (arg_type, arg.name)
854 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
856 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
857 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
859 # Emit a fake function
860 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
861 for arg in function.args:
862 assert not arg.output
863 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
864 if arg.name != 'pointer':
865 self.serializeValue(arg.type, arg.name)
867 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
868 print ' trace::localWriter.endArg();'
870 print ' trace::localWriter.endEnter();'
871 print ' trace::localWriter.beginLeave(__call);'
872 print ' trace::localWriter.endLeave();'
883 # Hooks for glTexCoordPointer, which is identical to the other array
884 # pointers except the fact that it is indexed by glClientActiveTexture.
887 def array_prolog(self, api, uppercase_name):
888 if uppercase_name == 'TEXTURE_COORD':
889 print ' GLint client_active_texture = 0;'
890 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
891 print ' GLint max_texture_coords = 0;'
892 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
893 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
895 print ' __glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
896 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
897 print ' GLint texture = GL_TEXTURE0 + unit;'
898 print ' __glClientActiveTexture(texture);'
900 def array_trace_prolog(self, api, uppercase_name):
901 if uppercase_name == 'TEXTURE_COORD':
902 print ' bool client_active_texture_dirty = false;'
904 def array_epilog(self, api, uppercase_name):
905 if uppercase_name == 'TEXTURE_COORD':
907 self.array_cleanup(api, uppercase_name)
909 def array_cleanup(self, api, uppercase_name):
910 if uppercase_name == 'TEXTURE_COORD':
911 print ' __glClientActiveTexture(client_active_texture);'
913 def array_trace_intermezzo(self, api, uppercase_name):
914 if uppercase_name == 'TEXTURE_COORD':
915 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
916 print ' client_active_texture_dirty = true;'
917 self.fake_glClientActiveTexture_call(api, "texture");
920 def array_trace_epilog(self, api, uppercase_name):
921 if uppercase_name == 'TEXTURE_COORD':
922 print ' if (client_active_texture_dirty) {'
923 self.fake_glClientActiveTexture_call(api, "client_active_texture");
926 def fake_glClientActiveTexture_call(self, api, texture):
927 function = api.get_function_by_name('glClientActiveTexture')
928 self.fake_call(function, [texture])
930 def fake_call(self, function, args):
931 print ' unsigned __fake_call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
932 for arg, instance in zip(function.args, args):
933 assert not arg.output
934 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
935 self.serializeValue(arg.type, instance)
936 print ' trace::localWriter.endArg();'
937 print ' trace::localWriter.endEnter();'
938 print ' trace::localWriter.beginLeave(__fake_call);'
939 print ' trace::localWriter.endLeave();'