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 from trace import Tracer
31 from dispatch import function_pointer_type, function_pointer_value
32 import specs.stdapi as stdapi
33 import specs.glapi as glapi
34 import specs.glparams as glparams
35 from specs.glxapi import glxapi
38 class TypeGetter(stdapi.Visitor):
39 '''Determine which glGet*v function that matches the specified type.'''
41 def __init__(self, prefix = 'glGet', long_suffix = True, ext_suffix = ''):
43 self.long_suffix = long_suffix
44 self.ext_suffix = ext_suffix
46 def visitConst(self, const):
47 return self.visit(const.type)
49 def visitAlias(self, alias):
50 if alias.expr == 'GLboolean':
57 elif alias.expr == 'GLdouble':
64 elif alias.expr == 'GLfloat':
71 elif alias.expr in ('GLint', 'GLuint', 'GLsizei'):
81 function_name = self.prefix + suffix + self.ext_suffix
82 return function_name, arg_type
84 def visitEnum(self, enum):
85 return self.visit(glapi.GLint)
87 def visitBitmask(self, bitmask):
88 return self.visit(glapi.GLint)
90 def visitOpaque(self, pointer):
91 return self.prefix + 'Pointerv' + self.ext_suffix, 'GLvoid *'
94 class GlTracer(Tracer):
101 ("TexCoord", "TEXTURE_COORD"),
102 ("EdgeFlag", "EDGE_FLAG"),
103 ("FogCoord", "FOG_COORD"),
104 ("SecondaryColor", "SECONDARY_COLOR"),
108 # arrays available in PROFILE_ES1
109 arrays_es1 = ("Vertex", "Normal", "Color", "TexCoord")
111 def header(self, api):
112 Tracer.header(self, api)
114 print '#include "gltrace.hpp"'
117 # Which glVertexAttrib* variant to use
118 print 'enum vertex_attrib {'
119 print ' VERTEX_ATTRIB,'
120 print ' VERTEX_ATTRIB_ARB,'
121 print ' VERTEX_ATTRIB_NV,'
124 print 'gltrace::Context *'
125 print 'gltrace::getContext(void)'
127 print ' // TODO return the context set by other APIs (GLX, EGL, and etc.)'
128 print ' static gltrace::Context _ctx = { gltrace::PROFILE_COMPAT, false, false, false };'
129 print ' return &_ctx;'
132 print 'static vertex_attrib _get_vertex_attrib(void) {'
133 print ' gltrace::Context *ctx = gltrace::getContext();'
134 print ' if (ctx->user_arrays_arb || ctx->user_arrays_nv) {'
135 print ' GLboolean _vertex_program = GL_FALSE;'
136 print ' _glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &_vertex_program);'
137 print ' if (_vertex_program) {'
138 print ' if (ctx->user_arrays_nv) {'
139 print ' GLint _vertex_program_binding_nv = 0;'
140 print ' _glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &_vertex_program_binding_nv);'
141 print ' if (_vertex_program_binding_nv) {'
142 print ' return VERTEX_ATTRIB_NV;'
145 print ' return VERTEX_ATTRIB_ARB;'
148 print ' return VERTEX_ATTRIB;'
152 # Whether we need user arrays
153 print 'static inline bool _need_user_arrays(void)'
155 print ' gltrace::Context *ctx = gltrace::getContext();'
156 print ' if (!ctx->user_arrays) {'
157 print ' return false;'
161 for camelcase_name, uppercase_name in self.arrays:
162 # in which profile is the array available?
163 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
164 if camelcase_name in self.arrays_es1:
165 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
167 function_name = 'gl%sPointer' % camelcase_name
168 enable_name = 'GL_%s_ARRAY' % uppercase_name
169 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
170 print ' // %s' % function_name
171 print ' if (%s) {' % profile_check
172 self.array_prolog(api, uppercase_name)
173 print ' if (_glIsEnabled(%s)) {' % enable_name
174 print ' GLint _binding = 0;'
175 print ' _glGetIntegerv(%s, &_binding);' % binding_name
176 print ' if (!_binding) {'
177 self.array_cleanup(api, uppercase_name)
178 print ' return true;'
181 self.array_epilog(api, uppercase_name)
185 print ' // ES1 does not support generic vertex attributes'
186 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
187 print ' return false;'
189 print ' vertex_attrib _vertex_attrib = _get_vertex_attrib();'
191 print ' // glVertexAttribPointer'
192 print ' if (_vertex_attrib == VERTEX_ATTRIB) {'
193 print ' GLint _max_vertex_attribs = 0;'
194 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
195 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
196 print ' GLint _enabled = 0;'
197 print ' _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &_enabled);'
198 print ' if (_enabled) {'
199 print ' GLint _binding = 0;'
200 print ' _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &_binding);'
201 print ' if (!_binding) {'
202 print ' return true;'
208 print ' // glVertexAttribPointerARB'
209 print ' if (_vertex_attrib == VERTEX_ATTRIB_ARB) {'
210 print ' GLint _max_vertex_attribs = 0;'
211 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &_max_vertex_attribs);'
212 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
213 print ' GLint _enabled = 0;'
214 print ' _glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &_enabled);'
215 print ' if (_enabled) {'
216 print ' GLint _binding = 0;'
217 print ' _glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &_binding);'
218 print ' if (!_binding) {'
219 print ' return true;'
225 print ' // glVertexAttribPointerNV'
226 print ' if (_vertex_attrib == VERTEX_ATTRIB_NV) {'
227 print ' for (GLint index = 0; index < 16; ++index) {'
228 print ' GLint _enabled = 0;'
229 print ' _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
230 print ' if (_enabled) {'
231 print ' return true;'
237 print ' return false;'
241 print 'static void _trace_user_arrays(GLuint count);'
245 print '// whether glMapBufferRange(GL_MAP_WRITE_BIT) has ever been called'
246 print 'static bool _checkBufferMapRange = false;'
248 print '// whether glBufferParameteriAPPLE(GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE) has ever been called'
249 print 'static bool _checkBufferFlushingUnmapAPPLE = false;'
251 # Buffer mapping information, necessary for old Mesa 2.1 drivers which
252 # do not support glGetBufferParameteriv(GL_BUFFER_ACCESS_FLAGS/GL_BUFFER_MAP_LENGTH)
253 print 'struct buffer_mapping {'
255 print ' GLint length;'
257 print ' bool explicit_flush;'
260 for target in self.buffer_targets:
261 print 'struct buffer_mapping _%s_mapping;' % target.lower();
263 print 'static inline struct buffer_mapping *'
264 print 'get_buffer_mapping(GLenum target) {'
265 print ' switch (target) {'
266 for target in self.buffer_targets:
267 print ' case GL_%s:' % target
268 print ' return & _%s_mapping;' % target.lower()
270 print ' os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
271 print ' return NULL;'
276 # Generate a helper function to determine whether a parameter name
277 # refers to a symbolic value or not
279 print 'is_symbolic_pname(GLenum pname) {'
280 print ' switch (pname) {'
281 for function, type, count, name in glparams.parameters:
282 if type is glapi.GLenum:
283 print ' case %s:' % name
284 print ' return true;'
286 print ' return false;'
291 # Generate a helper function to determine whether a parameter value is
292 # potentially symbolic or not; i.e., if the value can be represented in
294 print 'template<class T>'
295 print 'static inline bool'
296 print 'is_symbolic_param(T param) {'
297 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
301 # Generate a helper function to know how many elements a parameter has
302 print 'static size_t'
303 print '_gl_param_size(GLenum pname) {'
304 print ' switch (pname) {'
305 for function, type, count, name in glparams.parameters:
307 print ' case %s: return %u;' % (name, count)
308 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
309 print ' GLint num_compressed_texture_formats = 0;'
310 print ' _glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
311 print ' return num_compressed_texture_formats;'
314 print r' os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
320 # states such as GL_UNPACK_ROW_LENGTH are not available in GLES
321 print 'static inline bool'
322 print 'can_unpack_subimage(void) {'
323 print ' gltrace::Context *ctx = gltrace::getContext();'
324 print ' return (ctx->profile == gltrace::PROFILE_COMPAT);'
328 getProcAddressFunctionNames = []
330 def traceApi(self, api):
331 if self.getProcAddressFunctionNames:
332 # Generate a function to wrap proc addresses
333 getProcAddressFunction = api.getFunctionByName(self.getProcAddressFunctionNames[0])
334 argType = getProcAddressFunction.args[0].type
335 retType = getProcAddressFunction.type
337 print 'static %s _wrapProcAddress(%s procName, %s procPtr);' % (retType, argType, retType)
340 Tracer.traceApi(self, api)
342 print 'static %s _wrapProcAddress(%s procName, %s procPtr) {' % (retType, argType, retType)
343 print ' if (!procPtr) {'
344 print ' return procPtr;'
346 for function in api.functions:
347 ptype = function_pointer_type(function)
348 pvalue = function_pointer_value(function)
349 print ' if (strcmp("%s", (const char *)procName) == 0) {' % function.name
350 print ' %s = (%s)procPtr;' % (pvalue, ptype)
351 print ' return (%s)&%s;' % (retType, function.name,)
353 print ' os::log("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);'
354 print ' return procPtr;'
358 Tracer.traceApi(self, api)
360 array_pointer_function_names = set((
368 "glSecondaryColorPointer",
370 "glInterleavedArrays",
372 "glVertexPointerEXT",
373 "glNormalPointerEXT",
376 "glTexCoordPointerEXT",
377 "glEdgeFlagPointerEXT",
378 "glFogCoordPointerEXT",
379 "glSecondaryColorPointerEXT",
381 "glVertexAttribPointer",
382 "glVertexAttribPointerARB",
383 "glVertexAttribPointerNV",
384 "glVertexAttribIPointer",
385 "glVertexAttribIPointerEXT",
386 "glVertexAttribLPointer",
387 "glVertexAttribLPointerEXT",
389 #"glMatrixIndexPointerARB",
392 draw_function_names = set((
395 'glDrawRangeElements',
397 'glMultiDrawElements',
398 'glDrawArraysInstanced',
399 "glDrawArraysInstancedBaseInstance",
400 'glDrawElementsInstanced',
401 'glDrawArraysInstancedARB',
402 'glDrawElementsInstancedARB',
403 'glDrawElementsBaseVertex',
404 'glDrawRangeElementsBaseVertex',
405 'glDrawElementsInstancedBaseVertex',
406 "glDrawElementsInstancedBaseInstance",
407 "glDrawElementsInstancedBaseVertexBaseInstance",
408 'glMultiDrawElementsBaseVertex',
409 'glDrawArraysIndirect',
410 'glDrawElementsIndirect',
412 'glDrawRangeElementsEXT',
413 'glDrawRangeElementsEXT_size',
414 'glMultiDrawArraysEXT',
415 'glMultiDrawElementsEXT',
416 'glMultiModeDrawArraysIBM',
417 'glMultiModeDrawElementsIBM',
418 'glDrawArraysInstancedEXT',
419 'glDrawElementsInstancedEXT',
422 interleaved_formats = [
435 'GL_T2F_C4F_N3F_V3F',
436 'GL_T4F_C4F_N3F_V4F',
439 def traceFunctionImplBody(self, function):
440 # Defer tracing of user array pointers...
441 if function.name in self.array_pointer_function_names:
442 print ' GLint _array_buffer = 0;'
443 print ' _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
444 print ' if (!_array_buffer) {'
445 print ' gltrace::Context *ctx = gltrace::getContext();'
446 print ' ctx->user_arrays = true;'
447 if function.name == "glVertexAttribPointerARB":
448 print ' ctx->user_arrays_arb = true;'
449 if function.name == "glVertexAttribPointerNV":
450 print ' ctx->user_arrays_nv = true;'
451 self.invokeFunction(function)
453 # And also break down glInterleavedArrays into the individual calls
454 if function.name == 'glInterleavedArrays':
457 # Initialize the enable flags
458 for camelcase_name, uppercase_name in self.arrays:
459 flag_name = '_' + uppercase_name.lower()
460 print ' GLboolean %s = GL_FALSE;' % flag_name
463 # Switch for the interleaved formats
464 print ' switch (format) {'
465 for format in self.interleaved_formats:
466 print ' case %s:' % format
467 for camelcase_name, uppercase_name in self.arrays:
468 flag_name = '_' + uppercase_name.lower()
469 if format.find('_' + uppercase_name[0]) >= 0:
470 print ' %s = GL_TRUE;' % flag_name
477 # Emit fake glEnableClientState/glDisableClientState flags
478 for camelcase_name, uppercase_name in self.arrays:
479 flag_name = '_' + uppercase_name.lower()
480 enable_name = 'GL_%s_ARRAY' % uppercase_name
482 # Emit a fake function
484 print ' static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
485 print ' unsigned _call = trace::localWriter.beginEnter(&_sig);'
486 print ' trace::localWriter.beginArg(0);'
487 self.serializeValue(glapi.GLenum, enable_name)
488 print ' trace::localWriter.endArg();'
489 print ' trace::localWriter.endEnter();'
490 print ' trace::localWriter.beginLeave(_call);'
491 print ' trace::localWriter.endLeave();'
497 # ... to the draw calls
498 if function.name in self.draw_function_names:
499 print ' if (_need_user_arrays()) {'
500 arg_names = ', '.join([arg.name for arg in function.args[1:]])
501 print ' GLuint _count = _%s_count(%s);' % (function.name, arg_names)
502 print ' _trace_user_arrays(_count);'
505 # Emit a fake memcpy on buffer uploads
506 if function.name == 'glBufferParameteriAPPLE':
507 print ' if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
508 print ' _checkBufferFlushingUnmapAPPLE = true;'
510 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
511 if function.name.endswith('ARB'):
515 print ' GLint access = 0;'
516 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
517 print ' if (access != GL_READ_ONLY) {'
518 print ' GLvoid *map = NULL;'
519 print ' _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);' % suffix
521 print ' GLint length = -1;'
522 print ' bool flush = true;'
523 print ' if (_checkBufferMapRange) {'
524 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
525 print ' GLint access_flags = 0;'
526 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
527 print ' flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
528 print ' if (length == -1) {'
529 print ' // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
530 print ' static bool warned = false;'
531 print ' if (!warned) {'
532 print ' os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
533 print ' warned = true;'
535 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
536 print ' if (mapping) {'
537 print ' length = mapping->length;'
538 print ' flush = flush && !mapping->explicit_flush;'
541 print ' flush = false;'
546 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
548 print ' if (_checkBufferFlushingUnmapAPPLE) {'
549 print ' GLint flushing_unmap = GL_TRUE;'
550 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
551 print ' flush = flush && flushing_unmap;'
553 print ' if (flush && length > 0) {'
554 self.emit_memcpy('map', 'map', 'length')
558 if function.name == 'glUnmapBufferOES':
559 print ' GLint access = 0;'
560 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
561 print ' if (access == GL_WRITE_ONLY_OES) {'
562 print ' GLvoid *map = NULL;'
563 print ' _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
564 print ' GLint size = 0;'
565 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
566 print ' if (map && size > 0) {'
567 self.emit_memcpy('map', 'map', 'size')
570 if function.name == 'glUnmapNamedBufferEXT':
571 print ' GLint access_flags = 0;'
572 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
573 print ' if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
574 print ' GLvoid *map = NULL;'
575 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
576 print ' GLint length = 0;'
577 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
578 print ' if (map && length > 0) {'
579 self.emit_memcpy('map', 'map', 'length')
582 if function.name == 'glFlushMappedBufferRange':
583 print ' GLvoid *map = NULL;'
584 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
585 print ' if (map && length > 0) {'
586 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
588 if function.name == 'glFlushMappedBufferRangeAPPLE':
589 print ' GLvoid *map = NULL;'
590 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
591 print ' if (map && size > 0) {'
592 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
594 if function.name == 'glFlushMappedNamedBufferRangeEXT':
595 print ' GLvoid *map = NULL;'
596 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
597 print ' if (map && length > 0) {'
598 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
601 # Don't leave vertex attrib locations to chance. Instead emit fake
602 # glBindAttribLocation calls to ensure that the same locations will be
603 # used when retracing. Trying to remap locations after the fact would
604 # be an herculian task given that vertex attrib locations appear in
605 # many entry-points, including non-shader related ones.
606 if function.name == 'glLinkProgram':
607 Tracer.invokeFunction(self, function)
608 print ' GLint active_attributes = 0;'
609 print ' _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
610 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
611 print ' GLint size = 0;'
612 print ' GLenum type = 0;'
613 print ' GLchar name[256];'
614 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
615 print ' _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
616 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
617 print ' GLint location = _glGetAttribLocation(program, name);'
618 print ' if (location >= 0) {'
619 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
620 self.fake_call(bind_function, ['program', 'location', 'name'])
624 if function.name == 'glLinkProgramARB':
625 Tracer.invokeFunction(self, function)
626 print ' GLint active_attributes = 0;'
627 print ' _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
628 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
629 print ' GLint size = 0;'
630 print ' GLenum type = 0;'
631 print ' GLcharARB name[256];'
632 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
633 print ' _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
634 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
635 print ' GLint location = _glGetAttribLocationARB(programObj, name);'
636 print ' if (location >= 0) {'
637 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
638 self.fake_call(bind_function, ['programObj', 'location', 'name'])
643 Tracer.traceFunctionImplBody(self, function)
646 # GL_GREMEDY_string_marker
647 'glStringMarkerGREMEDY',
648 # GL_GREMEDY_frame_terminator
649 'glFrameTerminatorGREMEDY',
650 # GL_EXT_debug_marker
651 'glInsertEventMarkerEXT',
652 'glPushGroupMarkerEXT',
653 'glPopGroupMarkerEXT',
656 def invokeFunction(self, function):
657 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
658 # These functions have been dispatched already
661 # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
663 if function.name in self.marker_functions:
666 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
668 for marker_function in self.marker_functions:
669 if self.api.getFunctionByName(marker_function):
670 print ' %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
671 print ' _result = (%s)&%s;' % (function.type, marker_function)
675 Tracer.invokeFunction(self, function)
679 # Override GL extensions
680 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
681 Tracer.invokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
684 Tracer.invokeFunction(self, function)
688 'ELEMENT_ARRAY_BUFFER',
690 'PIXEL_UNPACK_BUFFER',
693 'TRANSFORM_FEEDBACK_BUFFER',
696 'DRAW_INDIRECT_BUFFER',
697 'ATOMIC_COUNTER_BUFFER',
700 def wrapRet(self, function, instance):
701 Tracer.wrapRet(self, function, instance)
703 # Replace function addresses with ours
704 if function.name in self.getProcAddressFunctionNames:
705 print ' %s = _wrapProcAddress(%s, %s);' % (instance, function.args[0].name, instance)
707 # Keep track of buffer mappings
708 if function.name in ('glMapBuffer', 'glMapBufferARB'):
709 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
710 print ' if (mapping) {'
711 print ' mapping->map = %s;' % (instance)
712 print ' mapping->length = 0;'
713 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
714 print ' mapping->write = (access != GL_READ_ONLY);'
715 print ' mapping->explicit_flush = false;'
717 if function.name == 'glMapBufferRange':
718 print ' if (access & GL_MAP_WRITE_BIT) {'
719 print ' _checkBufferMapRange = true;'
721 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
722 print ' if (mapping) {'
723 print ' mapping->map = %s;' % (instance)
724 print ' mapping->length = length;'
725 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
726 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
734 def gl_boolean(self, value):
735 return self.boolean_names[int(bool(value))]
737 # Names of the functions that unpack from a pixel buffer object. See the
738 # ARB_pixel_buffer_object specification.
739 unpack_function_names = set([
743 'glCompressedTexImage1D',
744 'glCompressedTexImage2D',
745 'glCompressedTexImage3D',
746 'glCompressedTexSubImage1D',
747 'glCompressedTexSubImage2D',
748 'glCompressedTexSubImage3D',
749 'glConvolutionFilter1D',
750 'glConvolutionFilter2D',
752 'glMultiTexImage1DEXT',
753 'glMultiTexImage2DEXT',
754 'glMultiTexImage3DEXT',
755 'glMultiTexSubImage1DEXT',
756 'glMultiTexSubImage2DEXT',
757 'glMultiTexSubImage3DEXT',
762 'glSeparableFilter2D',
770 'glTexSubImage1DEXT',
772 'glTexSubImage2DEXT',
774 'glTexSubImage3DEXT',
775 'glTextureImage1DEXT',
776 'glTextureImage2DEXT',
777 'glTextureImage3DEXT',
778 'glTextureSubImage1DEXT',
779 'glTextureSubImage2DEXT',
780 'glTextureSubImage3DEXT',
783 def serializeArgValue(self, function, arg):
784 if function.name in self.draw_function_names and arg.name == 'indices':
785 print ' GLint _element_array_buffer = 0;'
786 print ' _glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &_element_array_buffer);'
787 print ' if (!_element_array_buffer) {'
788 if isinstance(arg.type, stdapi.Array):
789 print ' trace::localWriter.beginArray(%s);' % arg.type.length
790 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
791 print ' trace::localWriter.beginElement();'
792 print ' trace::localWriter.writeBlob(%s[i], count[i]*_gl_type_size(type));' % (arg.name)
793 print ' trace::localWriter.endElement();'
795 print ' trace::localWriter.endArray();'
797 print ' trace::localWriter.writeBlob(%s, count*_gl_type_size(type));' % (arg.name)
799 Tracer.serializeArgValue(self, function, arg)
803 # Recognize offsets instead of blobs when a PBO is bound
804 if function.name in self.unpack_function_names \
805 and (isinstance(arg.type, stdapi.Blob) \
806 or (isinstance(arg.type, stdapi.Const) \
807 and isinstance(arg.type.type, stdapi.Blob))):
809 print ' gltrace::Context *ctx = gltrace::getContext();'
810 print ' GLint _unpack_buffer = 0;'
811 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
812 print ' _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
813 print ' if (_unpack_buffer) {'
814 print ' trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
816 Tracer.serializeArgValue(self, function, arg)
821 # Several GL state functions take GLenum symbolic names as
822 # integer/floats; so dump the symbolic name whenever possible
823 if function.name.startswith('gl') \
824 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
825 and arg.name == 'param':
827 assert function.args[arg.index - 1].name == 'pname'
828 assert function.args[arg.index - 1].type == glapi.GLenum
829 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
830 self.serializeValue(glapi.GLenum, arg.name)
832 Tracer.serializeArgValue(self, function, arg)
836 Tracer.serializeArgValue(self, function, arg)
838 def footer(self, api):
839 Tracer.footer(self, api)
841 # A simple state tracker to track the pointer values
843 print 'static void _trace_user_arrays(GLuint count)'
845 print ' gltrace::Context *ctx = gltrace::getContext();'
847 for camelcase_name, uppercase_name in self.arrays:
848 # in which profile is the array available?
849 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
850 if camelcase_name in self.arrays_es1:
851 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
853 function_name = 'gl%sPointer' % camelcase_name
854 enable_name = 'GL_%s_ARRAY' % uppercase_name
855 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
856 function = api.getFunctionByName(function_name)
858 print ' // %s' % function.prototype()
859 print ' if (%s) {' % profile_check
860 self.array_trace_prolog(api, uppercase_name)
861 self.array_prolog(api, uppercase_name)
862 print ' if (_glIsEnabled(%s)) {' % enable_name
863 print ' GLint _binding = 0;'
864 print ' _glGetIntegerv(%s, &_binding);' % binding_name
865 print ' if (!_binding) {'
867 # Get the arguments via glGet*
868 for arg in function.args:
869 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
870 arg_get_function, arg_type = TypeGetter().visit(arg.type)
871 print ' %s %s = 0;' % (arg_type, arg.name)
872 print ' _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
874 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
875 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
877 # Emit a fake function
878 self.array_trace_intermezzo(api, uppercase_name)
879 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
880 for arg in function.args:
881 assert not arg.output
882 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
883 if arg.name != 'pointer':
884 self.serializeValue(arg.type, arg.name)
886 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
887 print ' trace::localWriter.endArg();'
889 print ' trace::localWriter.endEnter();'
890 print ' trace::localWriter.beginLeave(_call);'
891 print ' trace::localWriter.endLeave();'
894 self.array_epilog(api, uppercase_name)
895 self.array_trace_epilog(api, uppercase_name)
899 # Samething, but for glVertexAttribPointer*
901 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
902 # - glVertexAttribPointer: no
903 # - glVertexAttribPointerARB: implementation dependent
904 # - glVertexAttribPointerNV: yes
906 # This means that the implementations of these functions do not always
907 # alias, and they need to be considered independently.
909 print ' // ES1 does not support generic vertex attributes'
910 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
913 print ' vertex_attrib _vertex_attrib = _get_vertex_attrib();'
915 for suffix in ['', 'ARB', 'NV']:
917 SUFFIX = '_' + suffix
920 function_name = 'glVertexAttribPointer' + suffix
921 function = api.getFunctionByName(function_name)
923 print ' // %s' % function.prototype()
924 print ' if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
926 print ' GLint _max_vertex_attribs = 16;'
928 print ' GLint _max_vertex_attribs = 0;'
929 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
930 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
931 print ' GLint _enabled = 0;'
933 print ' _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
935 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
936 print ' if (_enabled) {'
937 print ' GLint _binding = 0;'
939 # It doesn't seem possible to use VBOs with NV_vertex_program.
940 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
941 print ' if (!_binding) {'
943 # Get the arguments via glGet*
944 for arg in function.args[1:]:
946 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
948 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
949 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
950 print ' %s %s = 0;' % (arg_type, arg.name)
951 print ' _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
953 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
954 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
956 # Emit a fake function
957 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
958 for arg in function.args:
959 assert not arg.output
960 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
961 if arg.name != 'pointer':
962 self.serializeValue(arg.type, arg.name)
964 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
965 print ' trace::localWriter.endArg();'
967 print ' trace::localWriter.endEnter();'
968 print ' trace::localWriter.beginLeave(_call);'
969 print ' trace::localWriter.endLeave();'
980 # Hooks for glTexCoordPointer, which is identical to the other array
981 # pointers except the fact that it is indexed by glClientActiveTexture.
984 def array_prolog(self, api, uppercase_name):
985 if uppercase_name == 'TEXTURE_COORD':
986 print ' GLint client_active_texture = 0;'
987 print ' _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
988 print ' GLint max_texture_coords = 0;'
989 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
990 print ' _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
992 print ' _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
993 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
994 print ' GLint texture = GL_TEXTURE0 + unit;'
995 print ' _glClientActiveTexture(texture);'
997 def array_trace_prolog(self, api, uppercase_name):
998 if uppercase_name == 'TEXTURE_COORD':
999 print ' bool client_active_texture_dirty = false;'
1001 def array_epilog(self, api, uppercase_name):
1002 if uppercase_name == 'TEXTURE_COORD':
1004 self.array_cleanup(api, uppercase_name)
1006 def array_cleanup(self, api, uppercase_name):
1007 if uppercase_name == 'TEXTURE_COORD':
1008 print ' _glClientActiveTexture(client_active_texture);'
1010 def array_trace_intermezzo(self, api, uppercase_name):
1011 if uppercase_name == 'TEXTURE_COORD':
1012 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
1013 print ' client_active_texture_dirty = true;'
1014 self.fake_glClientActiveTexture_call(api, "texture");
1017 def array_trace_epilog(self, api, uppercase_name):
1018 if uppercase_name == 'TEXTURE_COORD':
1019 print ' if (client_active_texture_dirty) {'
1020 self.fake_glClientActiveTexture_call(api, "client_active_texture");
1023 def fake_glClientActiveTexture_call(self, api, texture):
1024 function = api.getFunctionByName('glClientActiveTexture')
1025 self.fake_call(function, [texture])
1027 def fake_call(self, function, args):
1028 print ' unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1029 for arg, instance in zip(function.args, args):
1030 assert not arg.output
1031 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
1032 self.serializeValue(arg.type, instance)
1033 print ' trace::localWriter.endArg();'
1034 print ' trace::localWriter.endEnter();'
1035 print ' trace::localWriter.beginLeave(_fake_call);'
1036 print ' trace::localWriter.endLeave();'