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);'
244 print '// whether glMapBufferRange(GL_MAP_WRITE_BIT) has ever been called'
245 print 'static bool __checkBufferMapRange = false;'
247 print '// whether glBufferParameteriAPPLE(GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE) has ever been called'
248 print 'static bool __checkBufferFlushingUnmapAPPLE = false;'
250 # Buffer mapping information, necessary for old Mesa 2.1 drivers which
251 # do not support glGetBufferParameteriv(GL_BUFFER_ACCESS_FLAGS/GL_BUFFER_MAP_LENGTH)
252 print 'struct buffer_mapping {'
254 print ' GLint length;'
256 print ' bool explicit_flush;'
259 for target in self.buffer_targets:
260 print 'struct buffer_mapping __%s_mapping;' % target.lower();
262 print 'static inline struct buffer_mapping *'
263 print 'get_buffer_mapping(GLenum target) {'
264 print ' switch (target) {'
265 for target in self.buffer_targets:
266 print ' case GL_%s:' % target
267 print ' return & __%s_mapping;' % target.lower()
269 print ' os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
270 print ' return NULL;'
275 # Generate a helper function to determine whether a parameter name
276 # refers to a symbolic value or not
278 print 'is_symbolic_pname(GLenum pname) {'
279 print ' switch (pname) {'
280 for function, type, count, name in glparams.parameters:
281 if type is glapi.GLenum:
282 print ' case %s:' % name
283 print ' return true;'
285 print ' return false;'
290 # Generate a helper function to determine whether a parameter value is
291 # potentially symbolic or not; i.e., if the value can be represented in
293 print 'template<class T>'
294 print 'static inline bool'
295 print 'is_symbolic_param(T param) {'
296 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
300 # Generate a helper function to know how many elements a parameter has
301 print 'static size_t'
302 print '__gl_param_size(GLenum pname) {'
303 print ' switch (pname) {'
304 for function, type, count, name in glparams.parameters:
306 print ' case %s: return %u;' % (name, count)
307 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
308 print ' GLint num_compressed_texture_formats = 0;'
309 print ' __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
310 print ' return num_compressed_texture_formats;'
313 print r' os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
319 # states such as GL_UNPACK_ROW_LENGTH are not available in GLES
320 print 'static inline bool'
321 print 'can_unpack_subimage(void) {'
322 print ' gltrace::Context *ctx = gltrace::getContext();'
323 print ' return (ctx->profile == gltrace::PROFILE_COMPAT);'
327 array_pointer_function_names = set((
335 "glSecondaryColorPointer",
337 "glInterleavedArrays",
339 "glVertexPointerEXT",
340 "glNormalPointerEXT",
343 "glTexCoordPointerEXT",
344 "glEdgeFlagPointerEXT",
345 "glFogCoordPointerEXT",
346 "glSecondaryColorPointerEXT",
348 "glVertexAttribPointer",
349 "glVertexAttribPointerARB",
350 "glVertexAttribPointerNV",
351 "glVertexAttribIPointer",
352 "glVertexAttribIPointerEXT",
353 "glVertexAttribLPointer",
354 "glVertexAttribLPointerEXT",
356 #"glMatrixIndexPointerARB",
359 draw_function_names = set((
362 'glDrawRangeElements',
364 'glMultiDrawElements',
365 'glDrawArraysInstanced',
366 "glDrawArraysInstancedBaseInstance",
367 'glDrawElementsInstanced',
368 'glDrawArraysInstancedARB',
369 'glDrawElementsInstancedARB',
370 'glDrawElementsBaseVertex',
371 'glDrawRangeElementsBaseVertex',
372 'glDrawElementsInstancedBaseVertex',
373 "glDrawElementsInstancedBaseInstance",
374 "glDrawElementsInstancedBaseVertexBaseInstance",
375 'glMultiDrawElementsBaseVertex',
376 'glDrawArraysIndirect',
377 'glDrawElementsIndirect',
379 'glDrawRangeElementsEXT',
380 'glDrawRangeElementsEXT_size',
381 'glMultiDrawArraysEXT',
382 'glMultiDrawElementsEXT',
383 'glMultiModeDrawArraysIBM',
384 'glMultiModeDrawElementsIBM',
385 'glDrawArraysInstancedEXT',
386 'glDrawElementsInstancedEXT',
389 interleaved_formats = [
402 'GL_T2F_C4F_N3F_V3F',
403 'GL_T4F_C4F_N3F_V4F',
406 def traceFunctionImplBody(self, function):
407 # Defer tracing of user array pointers...
408 if function.name in self.array_pointer_function_names:
409 print ' GLint __array_buffer = 0;'
410 print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
411 print ' if (!__array_buffer) {'
412 print ' gltrace::Context *ctx = gltrace::getContext();'
413 print ' ctx->user_arrays = true;'
414 if function.name == "glVertexAttribPointerARB":
415 print ' ctx->user_arrays_arb = true;'
416 if function.name == "glVertexAttribPointerNV":
417 print ' ctx->user_arrays_nv = true;'
418 self.invokeFunction(function)
420 # And also break down glInterleavedArrays into the individual calls
421 if function.name == 'glInterleavedArrays':
424 # Initialize the enable flags
425 for camelcase_name, uppercase_name in self.arrays:
426 flag_name = '__' + uppercase_name.lower()
427 print ' GLboolean %s = GL_FALSE;' % flag_name
430 # Switch for the interleaved formats
431 print ' switch (format) {'
432 for format in self.interleaved_formats:
433 print ' case %s:' % format
434 for camelcase_name, uppercase_name in self.arrays:
435 flag_name = '__' + uppercase_name.lower()
436 if format.find('_' + uppercase_name[0]) >= 0:
437 print ' %s = GL_TRUE;' % flag_name
444 # Emit fake glEnableClientState/glDisableClientState flags
445 for camelcase_name, uppercase_name in self.arrays:
446 flag_name = '__' + uppercase_name.lower()
447 enable_name = 'GL_%s_ARRAY' % uppercase_name
449 # Emit a fake function
451 print ' static const trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
452 print ' unsigned __call = trace::localWriter.beginEnter(&__sig);'
453 print ' trace::localWriter.beginArg(0);'
454 self.serializeValue(glapi.GLenum, enable_name)
455 print ' trace::localWriter.endArg();'
456 print ' trace::localWriter.endEnter();'
457 print ' trace::localWriter.beginLeave(__call);'
458 print ' trace::localWriter.endLeave();'
464 # ... to the draw calls
465 if function.name in self.draw_function_names:
466 print ' if (__need_user_arrays()) {'
467 arg_names = ', '.join([arg.name for arg in function.args[1:]])
468 print ' GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
469 print ' __trace_user_arrays(maxindex);'
472 # Emit a fake memcpy on buffer uploads
473 if function.name == 'glBufferParameteriAPPLE':
474 print ' if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
475 print ' __checkBufferFlushingUnmapAPPLE = true;'
477 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
478 if function.name.endswith('ARB'):
482 print ' GLint access = 0;'
483 print ' __glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
484 print ' if (access != GL_READ_ONLY) {'
485 print ' GLvoid *map = NULL;'
486 print ' __glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);' % suffix
488 print ' GLint length = -1;'
489 print ' bool flush = true;'
490 print ' if (__checkBufferMapRange) {'
491 print ' __glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
492 print ' GLint access_flags = 0;'
493 print ' __glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
494 print ' flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
495 print ' if (length == -1) {'
496 print ' // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
497 print ' static bool warned = false;'
498 print ' if (!warned) {'
499 print ' os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
500 print ' warned = true;'
502 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
503 print ' if (mapping) {'
504 print ' length = mapping->length;'
505 print ' flush = flush && !mapping->explicit_flush;'
508 print ' flush = false;'
513 print ' __glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
515 print ' if (__checkBufferFlushingUnmapAPPLE) {'
516 print ' GLint flushing_unmap = GL_TRUE;'
517 print ' __glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
518 print ' flush = flush && flushing_unmap;'
520 print ' if (flush && length > 0) {'
521 self.emit_memcpy('map', 'map', 'length')
525 if function.name == 'glUnmapBufferOES':
526 print ' GLint access = 0;'
527 print ' __glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
528 print ' if (access == GL_WRITE_ONLY_OES) {'
529 print ' GLvoid *map = NULL;'
530 print ' __glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
531 print ' GLint size = 0;'
532 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
533 print ' if (map && size > 0) {'
534 self.emit_memcpy('map', 'map', 'size')
537 if function.name == 'glUnmapNamedBufferEXT':
538 print ' GLint access_flags = 0;'
539 print ' __glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
540 print ' if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
541 print ' GLvoid *map = NULL;'
542 print ' __glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
543 print ' GLint length = 0;'
544 print ' __glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
545 print ' if (map && length > 0) {'
546 self.emit_memcpy('map', 'map', 'length')
549 if function.name == 'glFlushMappedBufferRange':
550 print ' GLvoid *map = NULL;'
551 print ' __glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
552 print ' if (map && length > 0) {'
553 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
555 if function.name == 'glFlushMappedBufferRangeAPPLE':
556 print ' GLvoid *map = NULL;'
557 print ' __glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
558 print ' if (map && size > 0) {'
559 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
561 if function.name == 'glFlushMappedNamedBufferRangeEXT':
562 print ' GLvoid *map = NULL;'
563 print ' __glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
564 print ' if (map && length > 0) {'
565 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
568 # Don't leave vertex attrib locations to chance. Instead emit fake
569 # glBindAttribLocation calls to ensure that the same locations will be
570 # used when retracing. Trying to remap locations after the fact would
571 # be an herculian task given that vertex attrib locations appear in
572 # many entry-points, including non-shader related ones.
573 if function.name == 'glLinkProgram':
574 Tracer.invokeFunction(self, function)
575 print ' GLint active_attributes = 0;'
576 print ' __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
577 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
578 print ' GLint size = 0;'
579 print ' GLenum type = 0;'
580 print ' GLchar name[256];'
581 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
582 print ' __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
583 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
584 print ' GLint location = __glGetAttribLocation(program, name);'
585 print ' if (location >= 0) {'
586 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
587 self.fake_call(bind_function, ['program', 'location', 'name'])
591 if function.name == 'glLinkProgramARB':
592 Tracer.invokeFunction(self, function)
593 print ' GLint active_attributes = 0;'
594 print ' __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
595 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
596 print ' GLint size = 0;'
597 print ' GLenum type = 0;'
598 print ' GLcharARB name[256];'
599 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
600 print ' __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
601 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
602 print ' GLint location = __glGetAttribLocationARB(programObj, name);'
603 print ' if (location >= 0) {'
604 bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
605 self.fake_call(bind_function, ['programObj', 'location', 'name'])
610 Tracer.traceFunctionImplBody(self, function)
613 # GL_GREMEDY_string_marker
614 'glStringMarkerGREMEDY',
615 # GL_GREMEDY_frame_terminator
616 'glFrameTerminatorGREMEDY',
617 # GL_EXT_debug_marker
618 'glInsertEventMarkerEXT',
619 'glPushGroupMarkerEXT',
620 'glPopGroupMarkerEXT',
623 def invokeFunction(self, function):
624 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
625 # These functions have been dispatched already
628 # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
630 if function.name in self.marker_functions:
633 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
635 for marker_function in self.marker_functions:
636 if self.api.get_function_by_name(marker_function):
637 print ' %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
638 print ' __result = (%s)&%s;' % (function.type, marker_function)
642 Tracer.invokeFunction(self, function)
646 # Override GL extensions
647 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
648 Tracer.invokeFunction(self, function, prefix = 'gltrace::__', suffix = '_override')
651 Tracer.invokeFunction(self, function)
655 'ELEMENT_ARRAY_BUFFER',
657 'PIXEL_UNPACK_BUFFER',
660 'TRANSFORM_FEEDBACK_BUFFER',
663 'DRAW_INDIRECT_BUFFER',
664 'ATOMIC_COUNTER_BUFFER',
667 def wrapRet(self, function, instance):
668 Tracer.wrapRet(self, function, instance)
670 # Keep track of buffer mappings
671 if function.name in ('glMapBuffer', 'glMapBufferARB'):
672 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
673 print ' if (mapping) {'
674 print ' mapping->map = %s;' % (instance)
675 print ' mapping->length = 0;'
676 print ' __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
677 print ' mapping->write = (access != GL_READ_ONLY);'
678 print ' mapping->explicit_flush = false;'
680 if function.name == 'glMapBufferRange':
681 print ' if (access & GL_MAP_WRITE_BIT) {'
682 print ' __checkBufferMapRange = true;'
684 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
685 print ' if (mapping) {'
686 print ' mapping->map = %s;' % (instance)
687 print ' mapping->length = length;'
688 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
689 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
697 def gl_boolean(self, value):
698 return self.boolean_names[int(bool(value))]
700 # Names of the functions that unpack from a pixel buffer object. See the
701 # ARB_pixel_buffer_object specification.
702 unpack_function_names = set([
706 'glCompressedTexImage1D',
707 'glCompressedTexImage2D',
708 'glCompressedTexImage3D',
709 'glCompressedTexSubImage1D',
710 'glCompressedTexSubImage2D',
711 'glCompressedTexSubImage3D',
712 'glConvolutionFilter1D',
713 'glConvolutionFilter2D',
715 'glMultiTexImage1DEXT',
716 'glMultiTexImage2DEXT',
717 'glMultiTexImage3DEXT',
718 'glMultiTexSubImage1DEXT',
719 'glMultiTexSubImage2DEXT',
720 'glMultiTexSubImage3DEXT',
725 'glSeparableFilter2D',
733 'glTexSubImage1DEXT',
735 'glTexSubImage2DEXT',
737 'glTexSubImage3DEXT',
738 'glTextureImage1DEXT',
739 'glTextureImage2DEXT',
740 'glTextureImage3DEXT',
741 'glTextureSubImage1DEXT',
742 'glTextureSubImage2DEXT',
743 'glTextureSubImage3DEXT',
746 def serializeArgValue(self, function, arg):
747 if function.name in self.draw_function_names and arg.name == 'indices':
748 print ' GLint __element_array_buffer = 0;'
749 print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
750 print ' if (!__element_array_buffer) {'
751 if isinstance(arg.type, stdapi.Array):
752 print ' trace::localWriter.beginArray(%s);' % arg.type.length
753 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
754 print ' trace::localWriter.beginElement();'
755 print ' trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
756 print ' trace::localWriter.endElement();'
758 print ' trace::localWriter.endArray();'
760 print ' trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
762 Tracer.serializeArgValue(self, function, arg)
766 # Recognize offsets instead of blobs when a PBO is bound
767 if function.name in self.unpack_function_names \
768 and (isinstance(arg.type, stdapi.Blob) \
769 or (isinstance(arg.type, stdapi.Const) \
770 and isinstance(arg.type.type, stdapi.Blob))):
772 print ' gltrace::Context *ctx = gltrace::getContext();'
773 print ' GLint __unpack_buffer = 0;'
774 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
775 print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
776 print ' if (__unpack_buffer) {'
777 print ' trace::localWriter.writeOpaque(%s);' % arg.name
779 Tracer.serializeArgValue(self, function, arg)
784 # Several GL state functions take GLenum symbolic names as
785 # integer/floats; so dump the symbolic name whenever possible
786 if function.name.startswith('gl') \
787 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
788 and arg.name == 'param':
790 assert function.args[arg.index - 1].name == 'pname'
791 assert function.args[arg.index - 1].type == glapi.GLenum
792 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
793 self.serializeValue(glapi.GLenum, arg.name)
795 Tracer.serializeArgValue(self, function, arg)
799 Tracer.serializeArgValue(self, function, arg)
801 def footer(self, api):
802 Tracer.footer(self, api)
804 # A simple state tracker to track the pointer values
806 print 'static void __trace_user_arrays(GLuint maxindex)'
808 print ' gltrace::Context *ctx = gltrace::getContext();'
810 for camelcase_name, uppercase_name in self.arrays:
811 # in which profile is the array available?
812 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
813 if camelcase_name in self.arrays_es1:
814 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
816 function_name = 'gl%sPointer' % camelcase_name
817 enable_name = 'GL_%s_ARRAY' % uppercase_name
818 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
819 function = api.get_function_by_name(function_name)
821 print ' // %s' % function.prototype()
822 print ' if (%s) {' % profile_check
823 self.array_trace_prolog(api, uppercase_name)
824 self.array_prolog(api, uppercase_name)
825 print ' if (__glIsEnabled(%s)) {' % enable_name
826 print ' GLint __binding = 0;'
827 print ' __glGetIntegerv(%s, &__binding);' % binding_name
828 print ' if (!__binding) {'
830 # Get the arguments via glGet*
831 for arg in function.args:
832 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
833 arg_get_function, arg_type = TypeGetter().visit(arg.type)
834 print ' %s %s = 0;' % (arg_type, arg.name)
835 print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
837 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
838 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
840 # Emit a fake function
841 self.array_trace_intermezzo(api, uppercase_name)
842 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
843 for arg in function.args:
844 assert not arg.output
845 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
846 if arg.name != 'pointer':
847 self.serializeValue(arg.type, arg.name)
849 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
850 print ' trace::localWriter.endArg();'
852 print ' trace::localWriter.endEnter();'
853 print ' trace::localWriter.beginLeave(__call);'
854 print ' trace::localWriter.endLeave();'
857 self.array_epilog(api, uppercase_name)
858 self.array_trace_epilog(api, uppercase_name)
862 # Samething, but for glVertexAttribPointer*
864 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
865 # - glVertexAttribPointer: no
866 # - glVertexAttribPointerARB: implementation dependent
867 # - glVertexAttribPointerNV: yes
869 # This means that the implementations of these functions do not always
870 # alias, and they need to be considered independently.
872 print ' // ES1 does not support generic vertex attributes'
873 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
876 print ' vertex_attrib __vertex_attrib = __get_vertex_attrib();'
878 for suffix in ['', 'ARB', 'NV']:
880 SUFFIX = '_' + suffix
883 function_name = 'glVertexAttribPointer' + suffix
884 function = api.get_function_by_name(function_name)
886 print ' // %s' % function.prototype()
887 print ' if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
889 print ' GLint __max_vertex_attribs = 16;'
891 print ' GLint __max_vertex_attribs = 0;'
892 print ' __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
893 print ' for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
894 print ' GLint __enabled = 0;'
896 print ' __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
898 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
899 print ' if (__enabled) {'
900 print ' GLint __binding = 0;'
902 # It doesn't seem possible to use VBOs with NV_vertex_program.
903 print ' __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
904 print ' if (!__binding) {'
906 # Get the arguments via glGet*
907 for arg in function.args[1:]:
909 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
911 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
912 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
913 print ' %s %s = 0;' % (arg_type, arg.name)
914 print ' __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
916 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
917 print ' size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
919 # Emit a fake function
920 print ' unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
921 for arg in function.args:
922 assert not arg.output
923 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
924 if arg.name != 'pointer':
925 self.serializeValue(arg.type, arg.name)
927 print ' trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
928 print ' trace::localWriter.endArg();'
930 print ' trace::localWriter.endEnter();'
931 print ' trace::localWriter.beginLeave(__call);'
932 print ' trace::localWriter.endLeave();'
943 # Hooks for glTexCoordPointer, which is identical to the other array
944 # pointers except the fact that it is indexed by glClientActiveTexture.
947 def array_prolog(self, api, uppercase_name):
948 if uppercase_name == 'TEXTURE_COORD':
949 print ' GLint client_active_texture = 0;'
950 print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
951 print ' GLint max_texture_coords = 0;'
952 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
953 print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
955 print ' __glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
956 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
957 print ' GLint texture = GL_TEXTURE0 + unit;'
958 print ' __glClientActiveTexture(texture);'
960 def array_trace_prolog(self, api, uppercase_name):
961 if uppercase_name == 'TEXTURE_COORD':
962 print ' bool client_active_texture_dirty = false;'
964 def array_epilog(self, api, uppercase_name):
965 if uppercase_name == 'TEXTURE_COORD':
967 self.array_cleanup(api, uppercase_name)
969 def array_cleanup(self, api, uppercase_name):
970 if uppercase_name == 'TEXTURE_COORD':
971 print ' __glClientActiveTexture(client_active_texture);'
973 def array_trace_intermezzo(self, api, uppercase_name):
974 if uppercase_name == 'TEXTURE_COORD':
975 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
976 print ' client_active_texture_dirty = true;'
977 self.fake_glClientActiveTexture_call(api, "texture");
980 def array_trace_epilog(self, api, uppercase_name):
981 if uppercase_name == 'TEXTURE_COORD':
982 print ' if (client_active_texture_dirty) {'
983 self.fake_glClientActiveTexture_call(api, "client_active_texture");
986 def fake_glClientActiveTexture_call(self, api, texture):
987 function = api.get_function_by_name('glClientActiveTexture')
988 self.fake_call(function, [texture])
990 def fake_call(self, function, args):
991 print ' unsigned __fake_call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
992 for arg, instance in zip(function.args, args):
993 assert not arg.output
994 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
995 self.serializeValue(arg.type, instance)
996 print ' trace::localWriter.endArg();'
997 print ' trace::localWriter.endEnter();'
998 print ' trace::localWriter.beginLeave(__fake_call);'
999 print ' trace::localWriter.endLeave();'