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"'
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 # states such as GL_UNPACK_ROW_LENGTH are not available in GLES
323 print 'static inline bool'
324 print 'can_unpack_subimage(void) {'
325 print ' tracer_context *ctx = __get_context();'
326 print ' return (ctx->profile == PROFILE_COMPAT);'
330 array_pointer_function_names = set((
338 "glSecondaryColorPointer",
340 "glInterleavedArrays",
342 "glVertexPointerEXT",
343 "glNormalPointerEXT",
346 "glTexCoordPointerEXT",
347 "glEdgeFlagPointerEXT",
348 "glFogCoordPointerEXT",
349 "glSecondaryColorPointerEXT",
351 "glVertexAttribPointer",
352 "glVertexAttribPointerARB",
353 "glVertexAttribPointerNV",
354 "glVertexAttribIPointer",
355 "glVertexAttribIPointerEXT",
356 "glVertexAttribLPointer",
357 "glVertexAttribLPointerEXT",
359 #"glMatrixIndexPointerARB",
362 draw_function_names = set((
365 'glDrawRangeElements',
367 'glMultiDrawElements',
368 'glDrawArraysInstanced',
369 "glDrawArraysInstancedBaseInstance",
370 'glDrawElementsInstanced',
371 'glDrawArraysInstancedARB',
372 'glDrawElementsInstancedARB',
373 'glDrawElementsBaseVertex',
374 'glDrawRangeElementsBaseVertex',
375 'glDrawElementsInstancedBaseVertex',
376 "glDrawElementsInstancedBaseInstance",
377 "glDrawElementsInstancedBaseVertexBaseInstance",
378 'glMultiDrawElementsBaseVertex',
379 'glDrawArraysIndirect',
380 'glDrawElementsIndirect',
382 'glDrawRangeElementsEXT',
383 'glDrawRangeElementsEXT_size',
384 'glMultiDrawArraysEXT',
385 'glMultiDrawElementsEXT',
386 'glMultiModeDrawArraysIBM',
387 'glMultiModeDrawElementsIBM',
388 'glDrawArraysInstancedEXT',
389 'glDrawElementsInstancedEXT',
392 interleaved_formats = [
405 'GL_T2F_C4F_N3F_V3F',
406 'GL_T4F_C4F_N3F_V4F',
409 def traceFunctionImplBody(self, function):
410 # Defer tracing of user array pointers...
411 if function.name in self.array_pointer_function_names:
412 print ' GLint __array_buffer = 0;'
413 print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
414 print ' if (!__array_buffer) {'
415 print ' tracer_context *ctx = __get_context();'
416 print ' ctx->user_arrays = true;'
417 if function.name == "glVertexAttribPointerARB":
418 print ' ctx->user_arrays_arb = true;'
419 if function.name == "glVertexAttribPointerNV":
420 print ' ctx->user_arrays_nv = true;'
421 self.invokeFunction(function)
423 # And also break down glInterleavedArrays into the individual calls
424 if function.name == 'glInterleavedArrays':
427 # Initialize the enable flags
428 for camelcase_name, uppercase_name in self.arrays:
429 flag_name = '__' + uppercase_name.lower()
430 print ' GLboolean %s = GL_FALSE;' % flag_name
433 # Switch for the interleaved formats
434 print ' switch (format) {'
435 for format in self.interleaved_formats:
436 print ' case %s:' % format
437 for camelcase_name, uppercase_name in self.arrays:
438 flag_name = '__' + uppercase_name.lower()
439 if format.find('_' + uppercase_name[0]) >= 0:
440 print ' %s = GL_TRUE;' % flag_name
447 # Emit fake glEnableClientState/glDisableClientState flags
448 for camelcase_name, uppercase_name in self.arrays:
449 flag_name = '__' + uppercase_name.lower()
450 enable_name = 'GL_%s_ARRAY' % uppercase_name
452 # Emit a fake function
454 print ' static const trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
455 print ' unsigned __call = trace::localWriter.beginEnter(&__sig);'
456 print ' trace::localWriter.beginArg(0);'
457 self.serializeValue(glapi.GLenum, enable_name)
458 print ' trace::localWriter.endArg();'
459 print ' trace::localWriter.endEnter();'
460 print ' trace::localWriter.beginLeave(__call);'
461 print ' trace::localWriter.endLeave();'
467 # ... to the draw calls
468 if function.name in self.draw_function_names:
469 print ' if (__need_user_arrays()) {'
470 arg_names = ', '.join([arg.name for arg in function.args[1:]])
471 print ' GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
472 print ' __trace_user_arrays(maxindex);'
475 # Emit a fake memcpy on buffer uploads
476 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB', 'glUnmapBufferOES'):
477 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
478 print ' if (mapping && mapping->write && !mapping->explicit_flush) {'
479 self.emit_memcpy('mapping->map', 'mapping->map', 'mapping->length')
481 if function.name == 'glUnmapNamedBufferEXT':
482 print ' GLint access = 0;'
483 print ' glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS, &access);'
484 print ' if ((access & GL_MAP_WRITE_BIT) & !(access & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
485 print ' GLvoid *map = NULL;'
486 print ' glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
487 print ' GLint length = 0;'
488 print ' glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
489 self.emit_memcpy('map', 'map', 'length')
491 if function.name in ('glFlushMappedBufferRange', 'glFlushMappedBufferRangeAPPLE'):
492 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
493 print ' if (mapping) {'
494 if function.name.endswith('APPLE'):
495 print ' GLsizeiptr length = size;'
496 print ' mapping->explicit_flush = true;'
497 print ' //assert(offset + length <= mapping->length);'
498 self.emit_memcpy('(char *)mapping->map + offset', '(const char *)mapping->map + offset', 'length')
500 if function.name == 'glFlushMappedNamedBufferRangeEXT':
501 print ' GLvoid *map = NULL;'
502 print ' glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
504 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
507 # Don't leave vertex attrib locations to chance. Instead emit fake
508 # glBindAttribLocation calls to ensure that the same locations will be
509 # used when retracing. Trying to remap locations after the fact would
510 # be an herculian task given that vertex attrib locations appear in
511 # many entry-points, including non-shader related ones.
512 if function.name == 'glLinkProgram':
513 Tracer.invokeFunction(self, function)
514 print ' GLint active_attributes = 0;'
515 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
516 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
517 print ' GLint size = 0;'
518 print ' GLenum type = 0;'
519 print ' GLchar name[256];'
520 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
521 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
522 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
523 print ' GLint location = __glGetAttribLocation(program, name);'
524 print ' if (location >= 0) {'
525 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
526 self.fake_call(bind_function, ['program', 'location', 'name'])
530 if function.name == 'glLinkProgramARB':
531 Tracer.invokeFunction(self, function)
532 print ' GLint active_attributes = 0;'
533 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
534 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
535 print ' GLint size = 0;'
536 print ' GLenum type = 0;'
537 print ' GLcharARB name[256];'
538 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
539 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
540 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
541 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
542 print ' if (location >= 0) {'
543 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
544 self.fake_call(bind_function, ['programObj', 'location', 'name'])
549 Tracer.traceFunctionImplBody(self, function)
551 gremedy_functions = [
552 'glStringMarkerGREMEDY',
553 'glFrameTerminatorGREMEDY',
556 def invokeFunction(self, function):
557 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
558 # These functions have been dispatched already
561 # We implement the GREMEDY extensions, not the driver
562 if function.name in self.gremedy_functions:
565 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
567 for gremedy_function in self.gremedy_functions:
568 print ' %s (strcmp("%s", (const char *)%s) == 0) {' % (if_, gremedy_function, function.args[0].name)
569 print ' __result = (%s)&%s;' % (function.type, gremedy_function)
573 Tracer.invokeFunction(self, function)
577 # Override GL extensions
578 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
579 Tracer.invokeFunction(self, function, prefix = 'gltrace::__', suffix = '_override')
582 Tracer.invokeFunction(self, function)
584 def emit_memcpy(self, dest, src, length):
585 print ' unsigned __call = trace::localWriter.beginEnter(&trace::memcpy_sig);'
586 print ' trace::localWriter.beginArg(0);'
587 print ' trace::localWriter.writeOpaque(%s);' % dest
588 print ' trace::localWriter.endArg();'
589 print ' trace::localWriter.beginArg(1);'
590 print ' trace::localWriter.writeBlob(%s, %s);' % (src, length)
591 print ' trace::localWriter.endArg();'
592 print ' trace::localWriter.beginArg(2);'
593 print ' trace::localWriter.writeUInt(%s);' % length
594 print ' trace::localWriter.endArg();'
595 print ' trace::localWriter.endEnter();'
596 print ' trace::localWriter.beginLeave(__call);'
597 print ' trace::localWriter.endLeave();'
601 'ELEMENT_ARRAY_BUFFER',
603 'PIXEL_UNPACK_BUFFER',
606 'TRANSFORM_FEEDBACK_BUFFER',
609 'DRAW_INDIRECT_BUFFER',
610 'ATOMIC_COUNTER_BUFFER',
613 def wrapRet(self, function, instance):
614 Tracer.wrapRet(self, function, instance)
617 if function.name in ('glMapBuffer', 'glMapBufferARB', 'glMapBufferOES'):
618 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
619 print ' if (mapping) {'
620 print ' mapping->map = %s;' % (instance)
621 print ' mapping->length = 0;'
622 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
623 print ' mapping->write = (access != GL_READ_ONLY);'
624 print ' mapping->explicit_flush = false;'
627 if function.name == 'glMapBufferRange':
628 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
629 print ' if (mapping) {'
630 print ' mapping->map = %s;' % (instance)
631 print ' mapping->length = length;'
632 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
633 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
641 def gl_boolean(self, value):
642 return self.boolean_names[int(bool(value))]
644 # Names of the functions that unpack from a pixel buffer object. See the
645 # ARB_pixel_buffer_object specification.
646 unpack_function_names = set([
650 'glCompressedTexImage1D',
651 'glCompressedTexImage2D',
652 'glCompressedTexImage3D',
653 'glCompressedTexSubImage1D',
654 'glCompressedTexSubImage2D',
655 'glCompressedTexSubImage3D',
656 'glConvolutionFilter1D',
657 'glConvolutionFilter2D',
659 'glMultiTexImage1DEXT',
660 'glMultiTexImage2DEXT',
661 'glMultiTexImage3DEXT',
662 'glMultiTexSubImage1DEXT',
663 'glMultiTexSubImage2DEXT',
664 'glMultiTexSubImage3DEXT',
669 'glSeparableFilter2D',
677 'glTexSubImage1DEXT',
679 'glTexSubImage2DEXT',
681 'glTexSubImage3DEXT',
682 'glTextureImage1DEXT',
683 'glTextureImage2DEXT',
684 'glTextureImage3DEXT',
685 'glTextureSubImage1DEXT',
686 'glTextureSubImage2DEXT',
687 'glTextureSubImage3DEXT',
690 def serializeArgValue(self, function, arg):
691 if function.name in self.draw_function_names and arg.name == 'indices':
692 print ' GLint __element_array_buffer = 0;'
693 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
694 print ' if (!__element_array_buffer) {'
695 if isinstance(arg.type, stdapi.Array):
696 print ' trace::localWriter.beginArray(%s);' % arg.type.length
697 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
698 print ' trace::localWriter.beginElement();'
699 print ' trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
700 print ' trace::localWriter.endElement();'
702 print ' trace::localWriter.endArray();'
704 print ' trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
706 Tracer.serializeArgValue(self, function, arg)
710 # Recognize offsets instead of blobs when a PBO is bound
711 if function.name in self.unpack_function_names \
712 and (isinstance(arg.type, stdapi.Blob) \
713 or (isinstance(arg.type, stdapi.Const) \
714 and isinstance(arg.type.type, stdapi.Blob))):
716 print ' tracer_context *ctx = __get_context();'
717 print ' GLint __unpack_buffer = 0;'
718 print ' if (ctx->profile == PROFILE_COMPAT)'
719 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
720 print ' if (__unpack_buffer) {'
721 print ' trace::localWriter.writeOpaque(%s);' % arg.name
723 Tracer.serializeArgValue(self, function, arg)
728 # Several GL state functions take GLenum symbolic names as
729 # integer/floats; so dump the symbolic name whenever possible
730 if function.name.startswith('gl') \
731 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
732 and arg.name == 'param':
734 assert function.args[arg.index - 1].name == 'pname'
735 assert function.args[arg.index - 1].type == glapi.GLenum
736 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
737 self.serializeValue(glapi.GLenum, arg.name)
739 Tracer.serializeArgValue(self, function, arg)
743 Tracer.serializeArgValue(self, function, arg)
745 def footer(self, api):
746 Tracer.footer(self, api)
748 # A simple state tracker to track the pointer values
750 print 'static void __trace_user_arrays(GLuint maxindex)'
752 print ' tracer_context *ctx = __get_context();'
754 for camelcase_name, uppercase_name in self.arrays:
755 # in which profile is the array available?
756 profile_check = 'ctx->profile == PROFILE_COMPAT'
757 if camelcase_name in self.arrays_es1:
758 profile_check = '(' + profile_check + ' || ctx->profile == PROFILE_ES1)';
760 function_name = 'gl%sPointer' % camelcase_name
761 enable_name = 'GL_%s_ARRAY' % uppercase_name
762 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
763 function = api.get_function_by_name(function_name)
765 print ' // %s' % function.prototype()
766 print ' if (%s) {' % profile_check
767 self.array_trace_prolog(api, uppercase_name)
768 self.array_prolog(api, uppercase_name)
769 print ' if (__glIsEnabled(%s)) {' % enable_name
770 print ' GLint __binding = 0;'
771 print ' __glGetIntegerv(%s, &__binding);' % binding_name
772 print ' if (!__binding) {'
774 # Get the arguments via glGet*
775 for arg in function.args:
776 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
777 arg_get_function, arg_type = TypeGetter().visit(arg.type)
778 print ' %s %s = 0;' % (arg_type, arg.name)
779 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
781 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
782 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
784 # Emit a fake function
785 self.array_trace_intermezzo(api, uppercase_name)
786 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
787 for arg in function.args:
788 assert not arg.output
789 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
790 if arg.name != 'pointer':
791 self.serializeValue(arg.type, arg.name)
793 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
794 print ' trace::localWriter.endArg();'
796 print ' trace::localWriter.endEnter();'
797 print ' trace::localWriter.beginLeave(__call);'
798 print ' trace::localWriter.endLeave();'
801 self.array_epilog(api, uppercase_name)
802 self.array_trace_epilog(api, uppercase_name)
806 # Samething, but for glVertexAttribPointer*
808 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
809 # - glVertexAttribPointer: no
810 # - glVertexAttribPointerARB: implementation dependent
811 # - glVertexAttribPointerNV: yes
813 # This means that the implementations of these functions do not always
814 # alias, and they need to be considered independently.
816 print ' // ES1 does not support generic vertex attributes'
817 print ' if (ctx->profile == PROFILE_ES1)'
820 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
822 for suffix in ['', 'ARB', 'NV']:
824 SUFFIX = '_' + suffix
827 function_name = 'glVertexAttribPointer' + suffix
828 function = api.get_function_by_name(function_name)
830 print ' // %s' % function.prototype()
831 print ' if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
833 print ' GLint __max_vertex_attribs = 16;'
835 print ' GLint __max_vertex_attribs = 0;'
836 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
837 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
838 print ' GLint __enabled = 0;'
840 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
842 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
843 print ' if (__enabled) {'
844 print ' GLint __binding = 0;'
846 # It doesn't seem possible to use VBOs with NV_vertex_program.
847 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
848 print ' if (!__binding) {'
850 # Get the arguments via glGet*
851 for arg in function.args[1:]:
853 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
855 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
856 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
857 print ' %s %s = 0;' % (arg_type, arg.name)
858 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
860 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
861 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
863 # Emit a fake function
864 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
865 for arg in function.args:
866 assert not arg.output
867 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
868 if arg.name != 'pointer':
869 self.serializeValue(arg.type, arg.name)
871 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
872 print ' trace::localWriter.endArg();'
874 print ' trace::localWriter.endEnter();'
875 print ' trace::localWriter.beginLeave(__call);'
876 print ' trace::localWriter.endLeave();'
887 # Hooks for glTexCoordPointer, which is identical to the other array
888 # pointers except the fact that it is indexed by glClientActiveTexture.
891 def array_prolog(self, api, uppercase_name):
892 if uppercase_name == 'TEXTURE_COORD':
893 print ' GLint client_active_texture = 0;'
894 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
895 print ' GLint max_texture_coords = 0;'
896 print ' if (ctx->profile == PROFILE_COMPAT)'
897 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
899 print ' __glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
900 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
901 print ' GLint texture = GL_TEXTURE0 + unit;'
902 print ' __glClientActiveTexture(texture);'
904 def array_trace_prolog(self, api, uppercase_name):
905 if uppercase_name == 'TEXTURE_COORD':
906 print ' bool client_active_texture_dirty = false;'
908 def array_epilog(self, api, uppercase_name):
909 if uppercase_name == 'TEXTURE_COORD':
911 self.array_cleanup(api, uppercase_name)
913 def array_cleanup(self, api, uppercase_name):
914 if uppercase_name == 'TEXTURE_COORD':
915 print ' __glClientActiveTexture(client_active_texture);'
917 def array_trace_intermezzo(self, api, uppercase_name):
918 if uppercase_name == 'TEXTURE_COORD':
919 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
920 print ' client_active_texture_dirty = true;'
921 self.fake_glClientActiveTexture_call(api, "texture");
924 def array_trace_epilog(self, api, uppercase_name):
925 if uppercase_name == 'TEXTURE_COORD':
926 print ' if (client_active_texture_dirty) {'
927 self.fake_glClientActiveTexture_call(api, "client_active_texture");
930 def fake_glClientActiveTexture_call(self, api, texture):
931 function = api.get_function_by_name('glClientActiveTexture')
932 self.fake_call(function, [texture])
934 def fake_call(self, function, args):
935 print ' unsigned __fake_call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
936 for arg, instance in zip(function.args, args):
937 assert not arg.output
938 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
939 self.serializeValue(arg.type, instance)
940 print ' trace::localWriter.endArg();'
941 print ' trace::localWriter.endEnter();'
942 print ' trace::localWriter.beginLeave(__fake_call);'
943 print ' trace::localWriter.endLeave();'