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 'static vertex_attrib _get_vertex_attrib(void) {'
125 print ' gltrace::Context *ctx = gltrace::getContext();'
126 print ' if (ctx->user_arrays_arb || ctx->user_arrays_nv) {'
127 print ' GLboolean _vertex_program = GL_FALSE;'
128 print ' _glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &_vertex_program);'
129 print ' if (_vertex_program) {'
130 print ' if (ctx->user_arrays_nv) {'
131 print ' GLint _vertex_program_binding_nv = 0;'
132 print ' _glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &_vertex_program_binding_nv);'
133 print ' if (_vertex_program_binding_nv) {'
134 print ' return VERTEX_ATTRIB_NV;'
137 print ' return VERTEX_ATTRIB_ARB;'
140 print ' return VERTEX_ATTRIB;'
144 # Whether we need user arrays
145 print 'static inline bool _need_user_arrays(void)'
147 print ' gltrace::Context *ctx = gltrace::getContext();'
148 print ' if (!ctx->user_arrays) {'
149 print ' return false;'
153 for camelcase_name, uppercase_name in self.arrays:
154 # in which profile is the array available?
155 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
156 if camelcase_name in self.arrays_es1:
157 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
159 function_name = 'gl%sPointer' % camelcase_name
160 enable_name = 'GL_%s_ARRAY' % uppercase_name
161 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
162 print ' // %s' % function_name
163 print ' if (%s) {' % profile_check
164 self.array_prolog(api, uppercase_name)
165 print ' if (_glIsEnabled(%s)) {' % enable_name
166 print ' GLint _binding = 0;'
167 print ' _glGetIntegerv(%s, &_binding);' % binding_name
168 print ' if (!_binding) {'
169 self.array_cleanup(api, uppercase_name)
170 print ' return true;'
173 self.array_epilog(api, uppercase_name)
177 print ' // ES1 does not support generic vertex attributes'
178 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
179 print ' return false;'
181 print ' vertex_attrib _vertex_attrib = _get_vertex_attrib();'
183 print ' // glVertexAttribPointer'
184 print ' if (_vertex_attrib == VERTEX_ATTRIB) {'
185 print ' GLint _max_vertex_attribs = 0;'
186 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
187 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
188 print ' GLint _enabled = 0;'
189 print ' _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &_enabled);'
190 print ' if (_enabled) {'
191 print ' GLint _binding = 0;'
192 print ' _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &_binding);'
193 print ' if (!_binding) {'
194 print ' return true;'
200 print ' // glVertexAttribPointerARB'
201 print ' if (_vertex_attrib == VERTEX_ATTRIB_ARB) {'
202 print ' GLint _max_vertex_attribs = 0;'
203 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &_max_vertex_attribs);'
204 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
205 print ' GLint _enabled = 0;'
206 print ' _glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &_enabled);'
207 print ' if (_enabled) {'
208 print ' GLint _binding = 0;'
209 print ' _glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &_binding);'
210 print ' if (!_binding) {'
211 print ' return true;'
217 print ' // glVertexAttribPointerNV'
218 print ' if (_vertex_attrib == VERTEX_ATTRIB_NV) {'
219 print ' for (GLint index = 0; index < 16; ++index) {'
220 print ' GLint _enabled = 0;'
221 print ' _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
222 print ' if (_enabled) {'
223 print ' return true;'
229 print ' return false;'
233 print 'static void _trace_user_arrays(GLuint count);'
237 print '// whether glMapBufferRange(GL_MAP_WRITE_BIT) has ever been called'
238 print 'static bool _checkBufferMapRange = false;'
240 print '// whether glBufferParameteriAPPLE(GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE) has ever been called'
241 print 'static bool _checkBufferFlushingUnmapAPPLE = false;'
243 # Buffer mapping information, necessary for old Mesa 2.1 drivers which
244 # do not support glGetBufferParameteriv(GL_BUFFER_ACCESS_FLAGS/GL_BUFFER_MAP_LENGTH)
245 print 'struct buffer_mapping {'
247 print ' GLint length;'
249 print ' bool explicit_flush;'
252 for target in self.buffer_targets:
253 print 'struct buffer_mapping _%s_mapping;' % target.lower();
255 print 'static inline struct buffer_mapping *'
256 print 'get_buffer_mapping(GLenum target) {'
257 print ' switch (target) {'
258 for target in self.buffer_targets:
259 print ' case GL_%s:' % target
260 print ' return & _%s_mapping;' % target.lower()
262 print ' os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
263 print ' return NULL;'
268 # Generate a helper function to determine whether a parameter name
269 # refers to a symbolic value or not
271 print 'is_symbolic_pname(GLenum pname) {'
272 print ' switch (pname) {'
273 for function, type, count, name in glparams.parameters:
274 if type is glapi.GLenum:
275 print ' case %s:' % name
276 print ' return true;'
278 print ' return false;'
283 # Generate a helper function to determine whether a parameter value is
284 # potentially symbolic or not; i.e., if the value can be represented in
286 print 'template<class T>'
287 print 'static inline bool'
288 print 'is_symbolic_param(T param) {'
289 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
293 # Generate a helper function to know how many elements a parameter has
294 print 'static size_t'
295 print '_gl_param_size(GLenum pname) {'
296 print ' switch (pname) {'
297 for function, type, count, name in glparams.parameters:
299 print ' case %s: return %u;' % (name, count)
300 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
301 print ' GLint num_compressed_texture_formats = 0;'
302 print ' _glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
303 print ' return num_compressed_texture_formats;'
306 print r' os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
312 # states such as GL_UNPACK_ROW_LENGTH are not available in GLES
313 print 'static inline bool'
314 print 'can_unpack_subimage(void) {'
315 print ' gltrace::Context *ctx = gltrace::getContext();'
316 print ' return (ctx->profile == gltrace::PROFILE_COMPAT);'
320 getProcAddressFunctionNames = []
322 def traceApi(self, api):
323 if self.getProcAddressFunctionNames:
324 # Generate a function to wrap proc addresses
325 getProcAddressFunction = api.getFunctionByName(self.getProcAddressFunctionNames[0])
326 argType = getProcAddressFunction.args[0].type
327 retType = getProcAddressFunction.type
329 print 'static %s _wrapProcAddress(%s procName, %s procPtr);' % (retType, argType, retType)
332 Tracer.traceApi(self, api)
334 print 'static %s _wrapProcAddress(%s procName, %s procPtr) {' % (retType, argType, retType)
335 print ' if (!procPtr) {'
336 print ' return procPtr;'
338 for function in api.functions:
339 ptype = function_pointer_type(function)
340 pvalue = function_pointer_value(function)
341 print ' if (strcmp("%s", (const char *)procName) == 0) {' % function.name
342 print ' %s = (%s)procPtr;' % (pvalue, ptype)
343 print ' return (%s)&%s;' % (retType, function.name,)
345 print ' os::log("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);'
346 print ' return procPtr;'
350 Tracer.traceApi(self, api)
352 array_pointer_function_names = set((
360 "glSecondaryColorPointer",
362 "glInterleavedArrays",
364 "glVertexPointerEXT",
365 "glNormalPointerEXT",
368 "glTexCoordPointerEXT",
369 "glEdgeFlagPointerEXT",
370 "glFogCoordPointerEXT",
371 "glSecondaryColorPointerEXT",
373 "glVertexAttribPointer",
374 "glVertexAttribPointerARB",
375 "glVertexAttribPointerNV",
376 "glVertexAttribIPointer",
377 "glVertexAttribIPointerEXT",
378 "glVertexAttribLPointer",
379 "glVertexAttribLPointerEXT",
381 #"glMatrixIndexPointerARB",
384 draw_function_names = set((
387 'glDrawRangeElements',
389 'glMultiDrawElements',
390 'glDrawArraysInstanced',
391 "glDrawArraysInstancedBaseInstance",
392 'glDrawElementsInstanced',
393 'glDrawArraysInstancedARB',
394 'glDrawElementsInstancedARB',
395 'glDrawElementsBaseVertex',
396 'glDrawRangeElementsBaseVertex',
397 'glDrawElementsInstancedBaseVertex',
398 "glDrawElementsInstancedBaseInstance",
399 "glDrawElementsInstancedBaseVertexBaseInstance",
400 'glMultiDrawElementsBaseVertex',
401 'glDrawArraysIndirect',
402 'glDrawElementsIndirect',
404 'glDrawRangeElementsEXT',
405 'glDrawRangeElementsEXT_size',
406 'glMultiDrawArraysEXT',
407 'glMultiDrawElementsEXT',
408 'glMultiModeDrawArraysIBM',
409 'glMultiModeDrawElementsIBM',
410 'glDrawArraysInstancedEXT',
411 'glDrawElementsInstancedEXT',
414 interleaved_formats = [
427 'GL_T2F_C4F_N3F_V3F',
428 'GL_T4F_C4F_N3F_V4F',
431 def traceFunctionImplBody(self, function):
432 # Defer tracing of user array pointers...
433 if function.name in self.array_pointer_function_names:
434 print ' GLint _array_buffer = 0;'
435 print ' _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
436 print ' if (!_array_buffer) {'
437 print ' gltrace::Context *ctx = gltrace::getContext();'
438 print ' ctx->user_arrays = true;'
439 if function.name == "glVertexAttribPointerARB":
440 print ' ctx->user_arrays_arb = true;'
441 if function.name == "glVertexAttribPointerNV":
442 print ' ctx->user_arrays_nv = true;'
443 self.invokeFunction(function)
445 # And also break down glInterleavedArrays into the individual calls
446 if function.name == 'glInterleavedArrays':
449 # Initialize the enable flags
450 for camelcase_name, uppercase_name in self.arrays:
451 flag_name = '_' + uppercase_name.lower()
452 print ' GLboolean %s = GL_FALSE;' % flag_name
455 # Switch for the interleaved formats
456 print ' switch (format) {'
457 for format in self.interleaved_formats:
458 print ' case %s:' % format
459 for camelcase_name, uppercase_name in self.arrays:
460 flag_name = '_' + uppercase_name.lower()
461 if format.find('_' + uppercase_name[0]) >= 0:
462 print ' %s = GL_TRUE;' % flag_name
469 # Emit fake glEnableClientState/glDisableClientState flags
470 for camelcase_name, uppercase_name in self.arrays:
471 flag_name = '_' + uppercase_name.lower()
472 enable_name = 'GL_%s_ARRAY' % uppercase_name
474 # Emit a fake function
476 print ' static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
477 print ' unsigned _call = trace::localWriter.beginEnter(&_sig);'
478 print ' trace::localWriter.beginArg(0);'
479 self.serializeValue(glapi.GLenum, enable_name)
480 print ' trace::localWriter.endArg();'
481 print ' trace::localWriter.endEnter();'
482 print ' trace::localWriter.beginLeave(_call);'
483 print ' trace::localWriter.endLeave();'
489 # ... to the draw calls
490 if function.name in self.draw_function_names:
491 print ' if (_need_user_arrays()) {'
492 arg_names = ', '.join([arg.name for arg in function.args[1:]])
493 print ' GLuint _count = _%s_count(%s);' % (function.name, arg_names)
494 print ' _trace_user_arrays(_count);'
497 # Emit a fake memcpy on buffer uploads
498 if function.name == 'glBufferParameteriAPPLE':
499 print ' if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
500 print ' _checkBufferFlushingUnmapAPPLE = true;'
502 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
503 if function.name.endswith('ARB'):
507 print ' GLint access = 0;'
508 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
509 print ' if (access != GL_READ_ONLY) {'
510 print ' GLvoid *map = NULL;'
511 print ' _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);' % suffix
513 print ' GLint length = -1;'
514 print ' bool flush = true;'
515 print ' if (_checkBufferMapRange) {'
516 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
517 print ' GLint access_flags = 0;'
518 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
519 print ' flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
520 print ' if (length == -1) {'
521 print ' // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
522 print ' static bool warned = false;'
523 print ' if (!warned) {'
524 print ' os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
525 print ' warned = true;'
527 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
528 print ' if (mapping) {'
529 print ' length = mapping->length;'
530 print ' flush = flush && !mapping->explicit_flush;'
533 print ' flush = false;'
538 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
540 print ' if (_checkBufferFlushingUnmapAPPLE) {'
541 print ' GLint flushing_unmap = GL_TRUE;'
542 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
543 print ' flush = flush && flushing_unmap;'
545 print ' if (flush && length > 0) {'
546 self.emit_memcpy('map', 'map', 'length')
550 if function.name == 'glUnmapBufferOES':
551 print ' GLint access = 0;'
552 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
553 print ' if (access == GL_WRITE_ONLY_OES) {'
554 print ' GLvoid *map = NULL;'
555 print ' _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
556 print ' GLint size = 0;'
557 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
558 print ' if (map && size > 0) {'
559 self.emit_memcpy('map', 'map', 'size')
562 if function.name == 'glUnmapNamedBufferEXT':
563 print ' GLint access_flags = 0;'
564 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
565 print ' if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
566 print ' GLvoid *map = NULL;'
567 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
568 print ' GLint length = 0;'
569 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
570 print ' if (map && length > 0) {'
571 self.emit_memcpy('map', 'map', 'length')
574 if function.name == 'glFlushMappedBufferRange':
575 print ' GLvoid *map = NULL;'
576 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
577 print ' if (map && length > 0) {'
578 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
580 if function.name == 'glFlushMappedBufferRangeAPPLE':
581 print ' GLvoid *map = NULL;'
582 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
583 print ' if (map && size > 0) {'
584 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
586 if function.name == 'glFlushMappedNamedBufferRangeEXT':
587 print ' GLvoid *map = NULL;'
588 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
589 print ' if (map && length > 0) {'
590 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
593 # Don't leave vertex attrib locations to chance. Instead emit fake
594 # glBindAttribLocation calls to ensure that the same locations will be
595 # used when retracing. Trying to remap locations after the fact would
596 # be an herculian task given that vertex attrib locations appear in
597 # many entry-points, including non-shader related ones.
598 if function.name == 'glLinkProgram':
599 Tracer.invokeFunction(self, function)
600 print ' GLint active_attributes = 0;'
601 print ' _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
602 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
603 print ' GLint size = 0;'
604 print ' GLenum type = 0;'
605 print ' GLchar name[256];'
606 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
607 print ' _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
608 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
609 print ' GLint location = _glGetAttribLocation(program, name);'
610 print ' if (location >= 0) {'
611 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
612 self.fake_call(bind_function, ['program', 'location', 'name'])
616 if function.name == 'glLinkProgramARB':
617 Tracer.invokeFunction(self, function)
618 print ' GLint active_attributes = 0;'
619 print ' _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
620 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
621 print ' GLint size = 0;'
622 print ' GLenum type = 0;'
623 print ' GLcharARB name[256];'
624 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
625 print ' _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
626 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
627 print ' GLint location = _glGetAttribLocationARB(programObj, name);'
628 print ' if (location >= 0) {'
629 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
630 self.fake_call(bind_function, ['programObj', 'location', 'name'])
635 Tracer.traceFunctionImplBody(self, function)
638 # GL_GREMEDY_string_marker
639 'glStringMarkerGREMEDY',
640 # GL_GREMEDY_frame_terminator
641 'glFrameTerminatorGREMEDY',
642 # GL_EXT_debug_marker
643 'glInsertEventMarkerEXT',
644 'glPushGroupMarkerEXT',
645 'glPopGroupMarkerEXT',
648 def invokeFunction(self, function):
649 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
650 # These functions have been dispatched already
653 # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
655 if function.name in self.marker_functions:
658 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
660 for marker_function in self.marker_functions:
661 if self.api.getFunctionByName(marker_function):
662 print ' %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
663 print ' _result = (%s)&%s;' % (function.type, marker_function)
667 Tracer.invokeFunction(self, function)
671 # Override GL extensions
672 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
673 Tracer.invokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
676 Tracer.invokeFunction(self, function)
680 'ELEMENT_ARRAY_BUFFER',
682 'PIXEL_UNPACK_BUFFER',
685 'TRANSFORM_FEEDBACK_BUFFER',
688 'DRAW_INDIRECT_BUFFER',
689 'ATOMIC_COUNTER_BUFFER',
692 def wrapRet(self, function, instance):
693 Tracer.wrapRet(self, function, instance)
695 # Replace function addresses with ours
696 if function.name in self.getProcAddressFunctionNames:
697 print ' %s = _wrapProcAddress(%s, %s);' % (instance, function.args[0].name, instance)
699 # Keep track of buffer mappings
700 if function.name in ('glMapBuffer', 'glMapBufferARB'):
701 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
702 print ' if (mapping) {'
703 print ' mapping->map = %s;' % (instance)
704 print ' mapping->length = 0;'
705 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
706 print ' mapping->write = (access != GL_READ_ONLY);'
707 print ' mapping->explicit_flush = false;'
709 if function.name == 'glMapBufferRange':
710 print ' if (access & GL_MAP_WRITE_BIT) {'
711 print ' _checkBufferMapRange = true;'
713 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
714 print ' if (mapping) {'
715 print ' mapping->map = %s;' % (instance)
716 print ' mapping->length = length;'
717 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
718 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
726 def gl_boolean(self, value):
727 return self.boolean_names[int(bool(value))]
729 # Names of the functions that unpack from a pixel buffer object. See the
730 # ARB_pixel_buffer_object specification.
731 unpack_function_names = set([
735 'glCompressedTexImage1D',
736 'glCompressedTexImage2D',
737 'glCompressedTexImage3D',
738 'glCompressedTexSubImage1D',
739 'glCompressedTexSubImage2D',
740 'glCompressedTexSubImage3D',
741 'glConvolutionFilter1D',
742 'glConvolutionFilter2D',
744 'glMultiTexImage1DEXT',
745 'glMultiTexImage2DEXT',
746 'glMultiTexImage3DEXT',
747 'glMultiTexSubImage1DEXT',
748 'glMultiTexSubImage2DEXT',
749 'glMultiTexSubImage3DEXT',
754 'glSeparableFilter2D',
762 'glTexSubImage1DEXT',
764 'glTexSubImage2DEXT',
766 'glTexSubImage3DEXT',
767 'glTextureImage1DEXT',
768 'glTextureImage2DEXT',
769 'glTextureImage3DEXT',
770 'glTextureSubImage1DEXT',
771 'glTextureSubImage2DEXT',
772 'glTextureSubImage3DEXT',
775 def serializeArgValue(self, function, arg):
776 if function.name in self.draw_function_names and arg.name == 'indices':
777 print ' GLint _element_array_buffer = 0;'
778 print ' _glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &_element_array_buffer);'
779 print ' if (!_element_array_buffer) {'
780 if isinstance(arg.type, stdapi.Array):
781 print ' trace::localWriter.beginArray(%s);' % arg.type.length
782 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
783 print ' trace::localWriter.beginElement();'
784 print ' trace::localWriter.writeBlob(%s[i], count[i]*_gl_type_size(type));' % (arg.name)
785 print ' trace::localWriter.endElement();'
787 print ' trace::localWriter.endArray();'
789 print ' trace::localWriter.writeBlob(%s, count*_gl_type_size(type));' % (arg.name)
791 Tracer.serializeArgValue(self, function, arg)
795 # Recognize offsets instead of blobs when a PBO is bound
796 if function.name in self.unpack_function_names \
797 and (isinstance(arg.type, stdapi.Blob) \
798 or (isinstance(arg.type, stdapi.Const) \
799 and isinstance(arg.type.type, stdapi.Blob))):
801 print ' gltrace::Context *ctx = gltrace::getContext();'
802 print ' GLint _unpack_buffer = 0;'
803 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
804 print ' _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
805 print ' if (_unpack_buffer) {'
806 print ' trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
808 Tracer.serializeArgValue(self, function, arg)
813 # Several GL state functions take GLenum symbolic names as
814 # integer/floats; so dump the symbolic name whenever possible
815 if function.name.startswith('gl') \
816 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
817 and arg.name == 'param':
819 assert function.args[arg.index - 1].name == 'pname'
820 assert function.args[arg.index - 1].type == glapi.GLenum
821 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
822 self.serializeValue(glapi.GLenum, arg.name)
824 Tracer.serializeArgValue(self, function, arg)
828 Tracer.serializeArgValue(self, function, arg)
830 def footer(self, api):
831 Tracer.footer(self, api)
833 # A simple state tracker to track the pointer values
835 print 'static void _trace_user_arrays(GLuint count)'
837 print ' gltrace::Context *ctx = gltrace::getContext();'
839 for camelcase_name, uppercase_name in self.arrays:
840 # in which profile is the array available?
841 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
842 if camelcase_name in self.arrays_es1:
843 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
845 function_name = 'gl%sPointer' % camelcase_name
846 enable_name = 'GL_%s_ARRAY' % uppercase_name
847 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
848 function = api.getFunctionByName(function_name)
850 print ' // %s' % function.prototype()
851 print ' if (%s) {' % profile_check
852 self.array_trace_prolog(api, uppercase_name)
853 self.array_prolog(api, uppercase_name)
854 print ' if (_glIsEnabled(%s)) {' % enable_name
855 print ' GLint _binding = 0;'
856 print ' _glGetIntegerv(%s, &_binding);' % binding_name
857 print ' if (!_binding) {'
859 # Get the arguments via glGet*
860 for arg in function.args:
861 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
862 arg_get_function, arg_type = TypeGetter().visit(arg.type)
863 print ' %s %s = 0;' % (arg_type, arg.name)
864 print ' _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
866 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
867 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
869 # Emit a fake function
870 self.array_trace_intermezzo(api, uppercase_name)
871 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
872 for arg in function.args:
873 assert not arg.output
874 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
875 if arg.name != 'pointer':
876 self.serializeValue(arg.type, arg.name)
878 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
879 print ' trace::localWriter.endArg();'
881 print ' trace::localWriter.endEnter();'
882 print ' trace::localWriter.beginLeave(_call);'
883 print ' trace::localWriter.endLeave();'
886 self.array_epilog(api, uppercase_name)
887 self.array_trace_epilog(api, uppercase_name)
891 # Samething, but for glVertexAttribPointer*
893 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
894 # - glVertexAttribPointer: no
895 # - glVertexAttribPointerARB: implementation dependent
896 # - glVertexAttribPointerNV: yes
898 # This means that the implementations of these functions do not always
899 # alias, and they need to be considered independently.
901 print ' // ES1 does not support generic vertex attributes'
902 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
905 print ' vertex_attrib _vertex_attrib = _get_vertex_attrib();'
907 for suffix in ['', 'ARB', 'NV']:
909 SUFFIX = '_' + suffix
912 function_name = 'glVertexAttribPointer' + suffix
913 function = api.getFunctionByName(function_name)
915 print ' // %s' % function.prototype()
916 print ' if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
918 print ' GLint _max_vertex_attribs = 16;'
920 print ' GLint _max_vertex_attribs = 0;'
921 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
922 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
923 print ' GLint _enabled = 0;'
925 print ' _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
927 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
928 print ' if (_enabled) {'
929 print ' GLint _binding = 0;'
931 # It doesn't seem possible to use VBOs with NV_vertex_program.
932 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
933 print ' if (!_binding) {'
935 # Get the arguments via glGet*
936 for arg in function.args[1:]:
938 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
940 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
941 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
942 print ' %s %s = 0;' % (arg_type, arg.name)
943 print ' _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
945 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
946 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
948 # Emit a fake function
949 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
950 for arg in function.args:
951 assert not arg.output
952 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
953 if arg.name != 'pointer':
954 self.serializeValue(arg.type, arg.name)
956 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
957 print ' trace::localWriter.endArg();'
959 print ' trace::localWriter.endEnter();'
960 print ' trace::localWriter.beginLeave(_call);'
961 print ' trace::localWriter.endLeave();'
972 # Hooks for glTexCoordPointer, which is identical to the other array
973 # pointers except the fact that it is indexed by glClientActiveTexture.
976 def array_prolog(self, api, uppercase_name):
977 if uppercase_name == 'TEXTURE_COORD':
978 print ' GLint client_active_texture = 0;'
979 print ' _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
980 print ' GLint max_texture_coords = 0;'
981 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
982 print ' _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
984 print ' _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
985 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
986 print ' GLint texture = GL_TEXTURE0 + unit;'
987 print ' _glClientActiveTexture(texture);'
989 def array_trace_prolog(self, api, uppercase_name):
990 if uppercase_name == 'TEXTURE_COORD':
991 print ' bool client_active_texture_dirty = false;'
993 def array_epilog(self, api, uppercase_name):
994 if uppercase_name == 'TEXTURE_COORD':
996 self.array_cleanup(api, uppercase_name)
998 def array_cleanup(self, api, uppercase_name):
999 if uppercase_name == 'TEXTURE_COORD':
1000 print ' _glClientActiveTexture(client_active_texture);'
1002 def array_trace_intermezzo(self, api, uppercase_name):
1003 if uppercase_name == 'TEXTURE_COORD':
1004 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
1005 print ' client_active_texture_dirty = true;'
1006 self.fake_glClientActiveTexture_call(api, "texture");
1009 def array_trace_epilog(self, api, uppercase_name):
1010 if uppercase_name == 'TEXTURE_COORD':
1011 print ' if (client_active_texture_dirty) {'
1012 self.fake_glClientActiveTexture_call(api, "client_active_texture");
1015 def fake_glClientActiveTexture_call(self, api, texture):
1016 function = api.getFunctionByName('glClientActiveTexture')
1017 self.fake_call(function, [texture])