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 self.defineShadowBufferHelper()
146 # Whether we need user arrays
147 print 'static inline bool _need_user_arrays(void)'
149 print ' gltrace::Context *ctx = gltrace::getContext();'
150 print ' if (!ctx->user_arrays) {'
151 print ' return false;'
155 for camelcase_name, uppercase_name in self.arrays:
156 # in which profile is the array available?
157 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
158 if camelcase_name in self.arrays_es1:
159 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
161 function_name = 'gl%sPointer' % camelcase_name
162 enable_name = 'GL_%s_ARRAY' % uppercase_name
163 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
164 print ' // %s' % function_name
165 print ' if (%s) {' % profile_check
166 self.array_prolog(api, uppercase_name)
167 print ' if (_glIsEnabled(%s)) {' % enable_name
168 print ' GLint _binding = 0;'
169 print ' _glGetIntegerv(%s, &_binding);' % binding_name
170 print ' if (!_binding) {'
171 self.array_cleanup(api, uppercase_name)
172 print ' return true;'
175 self.array_epilog(api, uppercase_name)
179 print ' // ES1 does not support generic vertex attributes'
180 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
181 print ' return false;'
183 print ' vertex_attrib _vertex_attrib = _get_vertex_attrib();'
185 print ' // glVertexAttribPointer'
186 print ' if (_vertex_attrib == VERTEX_ATTRIB) {'
187 print ' GLint _max_vertex_attribs = 0;'
188 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
189 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
190 print ' GLint _enabled = 0;'
191 print ' _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &_enabled);'
192 print ' if (_enabled) {'
193 print ' GLint _binding = 0;'
194 print ' _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &_binding);'
195 print ' if (!_binding) {'
196 print ' return true;'
202 print ' // glVertexAttribPointerARB'
203 print ' if (_vertex_attrib == VERTEX_ATTRIB_ARB) {'
204 print ' GLint _max_vertex_attribs = 0;'
205 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &_max_vertex_attribs);'
206 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
207 print ' GLint _enabled = 0;'
208 print ' _glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &_enabled);'
209 print ' if (_enabled) {'
210 print ' GLint _binding = 0;'
211 print ' _glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &_binding);'
212 print ' if (!_binding) {'
213 print ' return true;'
219 print ' // glVertexAttribPointerNV'
220 print ' if (_vertex_attrib == VERTEX_ATTRIB_NV) {'
221 print ' for (GLint index = 0; index < 16; ++index) {'
222 print ' GLint _enabled = 0;'
223 print ' _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
224 print ' if (_enabled) {'
225 print ' return true;'
231 print ' return false;'
235 print 'static void _trace_user_arrays(GLuint count);'
239 print '// whether glMapBufferRange(GL_MAP_WRITE_BIT) has ever been called'
240 print 'static bool _checkBufferMapRange = false;'
242 print '// whether glBufferParameteriAPPLE(GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE) has ever been called'
243 print 'static bool _checkBufferFlushingUnmapAPPLE = false;'
245 # Buffer mapping information, necessary for old Mesa 2.1 drivers which
246 # do not support glGetBufferParameteriv(GL_BUFFER_ACCESS_FLAGS/GL_BUFFER_MAP_LENGTH)
247 print 'struct buffer_mapping {'
249 print ' GLint length;'
251 print ' bool explicit_flush;'
254 for target in self.buffer_targets:
255 print 'struct buffer_mapping _%s_mapping;' % target.lower();
257 print 'static inline struct buffer_mapping *'
258 print 'get_buffer_mapping(GLenum target) {'
259 print ' switch (target) {'
260 for target in self.buffer_targets:
261 print ' case GL_%s:' % target
262 print ' return & _%s_mapping;' % target.lower()
264 print ' os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
265 print ' return NULL;'
270 # Generate a helper function to determine whether a parameter name
271 # refers to a symbolic value or not
273 print 'is_symbolic_pname(GLenum pname) {'
274 print ' switch (pname) {'
275 for function, type, count, name in glparams.parameters:
276 if type is glapi.GLenum:
277 print ' case %s:' % name
278 print ' return true;'
280 print ' return false;'
285 # Generate a helper function to determine whether a parameter value is
286 # potentially symbolic or not; i.e., if the value can be represented in
288 print 'template<class T>'
289 print 'static inline bool'
290 print 'is_symbolic_param(T param) {'
291 print ' return static_cast<T>(static_cast<GLenum>(param)) == param;'
295 # Generate a helper function to know how many elements a parameter has
296 print 'static size_t'
297 print '_gl_param_size(GLenum pname) {'
298 print ' switch (pname) {'
299 for function, type, count, name in glparams.parameters:
301 print ' case %s: return %s;' % (name, count)
303 print r' os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
309 # states such as GL_UNPACK_ROW_LENGTH are not available in GLES
310 print 'static inline bool'
311 print 'can_unpack_subimage(void) {'
312 print ' gltrace::Context *ctx = gltrace::getContext();'
313 print ' return (ctx->profile == gltrace::PROFILE_COMPAT);'
317 getProcAddressFunctionNames = []
319 def traceApi(self, api):
320 if self.getProcAddressFunctionNames:
321 # Generate a function to wrap proc addresses
322 getProcAddressFunction = api.getFunctionByName(self.getProcAddressFunctionNames[0])
323 argType = getProcAddressFunction.args[0].type
324 retType = getProcAddressFunction.type
326 print 'static %s _wrapProcAddress(%s procName, %s procPtr);' % (retType, argType, retType)
329 Tracer.traceApi(self, api)
331 print 'static %s _wrapProcAddress(%s procName, %s procPtr) {' % (retType, argType, retType)
332 print ' if (!procPtr) {'
333 print ' return procPtr;'
335 for function in api.getAllFunctions():
336 ptype = function_pointer_type(function)
337 pvalue = function_pointer_value(function)
338 print ' if (strcmp("%s", (const char *)procName) == 0) {' % function.name
339 print ' %s = (%s)procPtr;' % (pvalue, ptype)
340 print ' return (%s)&%s;' % (retType, function.name,)
342 print ' os::log("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);'
343 print ' return procPtr;'
347 Tracer.traceApi(self, api)
349 def defineShadowBufferHelper(self):
350 print 'void _shadow_glGetBufferSubData(GLenum target, GLintptr offset,'
351 print ' GLsizeiptr size, GLvoid *data)'
353 print ' gltrace::Context *ctx = gltrace::getContext();'
354 print ' if (!ctx->needsShadowBuffers() || target != GL_ELEMENT_ARRAY_BUFFER) {'
355 print ' _glGetBufferSubData(target, offset, size, data);'
359 print ' GLint buffer_binding = 0;'
360 print ' _glGetIntegerv(target, &buffer_binding);'
361 print ' if (buffer_binding > 0) {'
362 print ' gltrace::Buffer & buf = ctx->buffers[buffer_binding];'
363 print ' buf.getSubData(offset, size, data);'
367 def shadowBufferMethod(self, method):
368 # Emit code to fetch the shadow buffer, and invoke a method
369 print ' gltrace::Context *ctx = gltrace::getContext();'
370 print ' if (ctx->needsShadowBuffers() && target == GL_ELEMENT_ARRAY_BUFFER) {'
371 print ' GLint buffer_binding = 0;'
372 print ' _glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buffer_binding);'
373 print ' if (buffer_binding > 0) {'
374 print ' gltrace::Buffer & buf = ctx->buffers[buffer_binding];'
375 print ' buf.' + method + ';'
380 def shadowBufferProlog(self, function):
381 if function.name == 'glBufferData':
382 self.shadowBufferMethod('bufferData(size, data)')
384 if function.name == 'glBufferSubData':
385 self.shadowBufferMethod('bufferSubData(offset, size, data)')
387 if function.name == 'glDeleteBuffers':
388 print ' gltrace::Context *ctx = gltrace::getContext();'
389 print ' if (ctx->needsShadowBuffers()) {'
390 print ' for (GLsizei i = 0; i < n; i++) {'
391 print ' ctx->buffers.erase(buffer[i]);'
395 array_pointer_function_names = set((
403 "glSecondaryColorPointer",
405 "glInterleavedArrays",
407 "glVertexPointerEXT",
408 "glNormalPointerEXT",
411 "glTexCoordPointerEXT",
412 "glEdgeFlagPointerEXT",
413 "glFogCoordPointerEXT",
414 "glSecondaryColorPointerEXT",
416 "glVertexAttribPointer",
417 "glVertexAttribPointerARB",
418 "glVertexAttribPointerNV",
419 "glVertexAttribIPointer",
420 "glVertexAttribIPointerEXT",
421 "glVertexAttribLPointer",
422 "glVertexAttribLPointerEXT",
424 #"glMatrixIndexPointerARB",
427 draw_function_names = set((
430 'glDrawRangeElements',
432 'glMultiDrawElements',
433 'glDrawArraysInstanced',
434 "glDrawArraysInstancedBaseInstance",
435 'glDrawElementsInstanced',
436 'glDrawArraysInstancedARB',
437 'glDrawElementsInstancedARB',
438 'glDrawElementsBaseVertex',
439 'glDrawRangeElementsBaseVertex',
440 'glDrawElementsInstancedBaseVertex',
441 "glDrawElementsInstancedBaseInstance",
442 "glDrawElementsInstancedBaseVertexBaseInstance",
443 'glMultiDrawElementsBaseVertex',
444 'glDrawArraysIndirect',
445 'glDrawElementsIndirect',
447 'glDrawRangeElementsEXT',
448 'glDrawRangeElementsEXT_size',
449 'glMultiDrawArraysEXT',
450 'glMultiDrawElementsEXT',
451 'glMultiModeDrawArraysIBM',
452 'glMultiModeDrawElementsIBM',
453 'glDrawArraysInstancedEXT',
454 'glDrawElementsInstancedEXT',
457 interleaved_formats = [
470 'GL_T2F_C4F_N3F_V3F',
471 'GL_T4F_C4F_N3F_V4F',
474 def traceFunctionImplBody(self, function):
475 # Defer tracing of user array pointers...
476 if function.name in self.array_pointer_function_names:
477 print ' GLint _array_buffer = 0;'
478 print ' _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
479 print ' if (!_array_buffer) {'
480 print ' gltrace::Context *ctx = gltrace::getContext();'
481 print ' ctx->user_arrays = true;'
482 if function.name == "glVertexAttribPointerARB":
483 print ' ctx->user_arrays_arb = true;'
484 if function.name == "glVertexAttribPointerNV":
485 print ' ctx->user_arrays_nv = true;'
486 self.invokeFunction(function)
488 # And also break down glInterleavedArrays into the individual calls
489 if function.name == 'glInterleavedArrays':
492 # Initialize the enable flags
493 for camelcase_name, uppercase_name in self.arrays:
494 flag_name = '_' + uppercase_name.lower()
495 print ' GLboolean %s = GL_FALSE;' % flag_name
498 # Switch for the interleaved formats
499 print ' switch (format) {'
500 for format in self.interleaved_formats:
501 print ' case %s:' % format
502 for camelcase_name, uppercase_name in self.arrays:
503 flag_name = '_' + uppercase_name.lower()
504 if format.find('_' + uppercase_name[0]) >= 0:
505 print ' %s = GL_TRUE;' % flag_name
512 # Emit fake glEnableClientState/glDisableClientState flags
513 for camelcase_name, uppercase_name in self.arrays:
514 flag_name = '_' + uppercase_name.lower()
515 enable_name = 'GL_%s_ARRAY' % uppercase_name
517 # Emit a fake function
519 print ' static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
520 print ' unsigned _call = trace::localWriter.beginEnter(&_sig);'
521 print ' trace::localWriter.beginArg(0);'
522 self.serializeValue(glapi.GLenum, enable_name)
523 print ' trace::localWriter.endArg();'
524 print ' trace::localWriter.endEnter();'
525 print ' trace::localWriter.beginLeave(_call);'
526 print ' trace::localWriter.endLeave();'
532 # ... to the draw calls
533 if function.name in self.draw_function_names:
534 print ' if (_need_user_arrays()) {'
535 arg_names = ', '.join([arg.name for arg in function.args[1:]])
536 print ' GLuint _count = _%s_count(%s);' % (function.name, arg_names)
537 print ' _trace_user_arrays(_count);'
540 # Emit a fake memcpy on buffer uploads
541 if function.name == 'glBufferParameteriAPPLE':
542 print ' if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
543 print ' _checkBufferFlushingUnmapAPPLE = true;'
545 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
546 if function.name.endswith('ARB'):
550 print ' GLint access = 0;'
551 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
552 print ' if (access != GL_READ_ONLY) {'
553 print ' GLvoid *map = NULL;'
554 print ' _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);' % suffix
556 print ' GLint length = -1;'
557 print ' bool flush = true;'
558 print ' if (_checkBufferMapRange) {'
559 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
560 print ' GLint access_flags = 0;'
561 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
562 print ' flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
563 print ' if (length == -1) {'
564 print ' // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
565 print ' static bool warned = false;'
566 print ' if (!warned) {'
567 print ' os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
568 print ' warned = true;'
570 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
571 print ' if (mapping) {'
572 print ' length = mapping->length;'
573 print ' flush = flush && !mapping->explicit_flush;'
576 print ' flush = false;'
581 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
583 print ' if (_checkBufferFlushingUnmapAPPLE) {'
584 print ' GLint flushing_unmap = GL_TRUE;'
585 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
586 print ' flush = flush && flushing_unmap;'
588 print ' if (flush && length > 0) {'
589 self.emit_memcpy('map', 'map', 'length')
593 if function.name == 'glUnmapBufferOES':
594 print ' GLint access = 0;'
595 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
596 print ' if (access == GL_WRITE_ONLY_OES) {'
597 print ' GLvoid *map = NULL;'
598 print ' _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
599 print ' GLint size = 0;'
600 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
601 print ' if (map && size > 0) {'
602 self.emit_memcpy('map', 'map', 'size')
603 self.shadowBufferMethod('bufferSubData(0, size, map)')
606 if function.name == 'glUnmapNamedBufferEXT':
607 print ' GLint access_flags = 0;'
608 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
609 print ' if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
610 print ' GLvoid *map = NULL;'
611 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
612 print ' GLint length = 0;'
613 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
614 print ' if (map && length > 0) {'
615 self.emit_memcpy('map', 'map', 'length')
618 if function.name == 'glFlushMappedBufferRange':
619 print ' GLvoid *map = NULL;'
620 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
621 print ' if (map && length > 0) {'
622 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
624 if function.name == 'glFlushMappedBufferRangeAPPLE':
625 print ' GLvoid *map = NULL;'
626 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
627 print ' if (map && size > 0) {'
628 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
630 if function.name == 'glFlushMappedNamedBufferRangeEXT':
631 print ' GLvoid *map = NULL;'
632 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
633 print ' if (map && length > 0) {'
634 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
637 # Don't leave vertex attrib locations to chance. Instead emit fake
638 # glBindAttribLocation calls to ensure that the same locations will be
639 # used when retracing. Trying to remap locations after the fact would
640 # be an herculian task given that vertex attrib locations appear in
641 # many entry-points, including non-shader related ones.
642 if function.name == 'glLinkProgram':
643 Tracer.invokeFunction(self, function)
644 print ' GLint active_attributes = 0;'
645 print ' _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
646 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
647 print ' GLint size = 0;'
648 print ' GLenum type = 0;'
649 print ' GLchar name[256];'
650 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
651 print ' _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
652 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
653 print ' GLint location = _glGetAttribLocation(program, name);'
654 print ' if (location >= 0) {'
655 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
656 self.fake_call(bind_function, ['program', 'location', 'name'])
660 if function.name == 'glLinkProgramARB':
661 Tracer.invokeFunction(self, function)
662 print ' GLint active_attributes = 0;'
663 print ' _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
664 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
665 print ' GLint size = 0;'
666 print ' GLenum type = 0;'
667 print ' GLcharARB name[256];'
668 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
669 print ' _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
670 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
671 print ' GLint location = _glGetAttribLocationARB(programObj, name);'
672 print ' if (location >= 0) {'
673 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
674 self.fake_call(bind_function, ['programObj', 'location', 'name'])
679 self.shadowBufferProlog(function)
681 Tracer.traceFunctionImplBody(self, function)
684 # GL_GREMEDY_string_marker
685 'glStringMarkerGREMEDY',
686 # GL_GREMEDY_frame_terminator
687 'glFrameTerminatorGREMEDY',
688 # GL_EXT_debug_marker
689 'glInsertEventMarkerEXT',
690 'glPushGroupMarkerEXT',
691 'glPopGroupMarkerEXT',
694 def invokeFunction(self, function):
695 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
696 # These functions have been dispatched already
699 # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
701 if function.name in self.marker_functions:
704 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
706 for marker_function in self.marker_functions:
707 if self.api.getFunctionByName(marker_function):
708 print ' %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
709 print ' _result = (%s)&%s;' % (function.type, marker_function)
713 Tracer.invokeFunction(self, function)
717 # Override GL extensions
718 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
719 Tracer.invokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
722 Tracer.invokeFunction(self, function)
726 'ELEMENT_ARRAY_BUFFER',
728 'PIXEL_UNPACK_BUFFER',
731 'TRANSFORM_FEEDBACK_BUFFER',
734 'DRAW_INDIRECT_BUFFER',
735 'ATOMIC_COUNTER_BUFFER',
738 def wrapRet(self, function, instance):
739 Tracer.wrapRet(self, function, instance)
741 # Replace function addresses with ours
742 if function.name in self.getProcAddressFunctionNames:
743 print ' %s = _wrapProcAddress(%s, %s);' % (instance, function.args[0].name, instance)
745 # Keep track of buffer mappings
746 if function.name in ('glMapBuffer', 'glMapBufferARB'):
747 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
748 print ' if (mapping) {'
749 print ' mapping->map = %s;' % (instance)
750 print ' mapping->length = 0;'
751 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
752 print ' mapping->write = (access != GL_READ_ONLY);'
753 print ' mapping->explicit_flush = false;'
755 if function.name == 'glMapBufferRange':
756 print ' if (access & GL_MAP_WRITE_BIT) {'
757 print ' _checkBufferMapRange = true;'
759 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
760 print ' if (mapping) {'
761 print ' mapping->map = %s;' % (instance)
762 print ' mapping->length = length;'
763 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
764 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
772 def gl_boolean(self, value):
773 return self.boolean_names[int(bool(value))]
775 # Names of the functions that unpack from a pixel buffer object. See the
776 # ARB_pixel_buffer_object specification.
777 unpack_function_names = set([
781 'glCompressedMultiTexImage1DEXT',
782 'glCompressedMultiTexImage2DEXT',
783 'glCompressedMultiTexImage3DEXT',
784 'glCompressedMultiTexSubImage1DEXT',
785 'glCompressedMultiTexSubImage2DEXT',
786 'glCompressedMultiTexSubImage3DEXT',
787 'glCompressedTexImage1D',
788 'glCompressedTexImage2D',
789 'glCompressedTexImage3D',
790 'glCompressedTexSubImage1D',
791 'glCompressedTexSubImage2D',
792 'glCompressedTexSubImage3D',
793 'glCompressedTextureImage1DEXT',
794 'glCompressedTextureImage2DEXT',
795 'glCompressedTextureImage3DEXT',
796 'glCompressedTextureSubImage1DEXT',
797 'glCompressedTextureSubImage2DEXT',
798 'glCompressedTextureSubImage3DEXT',
799 'glConvolutionFilter1D',
800 'glConvolutionFilter2D',
802 'glMultiTexImage1DEXT',
803 'glMultiTexImage2DEXT',
804 'glMultiTexImage3DEXT',
805 'glMultiTexSubImage1DEXT',
806 'glMultiTexSubImage2DEXT',
807 'glMultiTexSubImage3DEXT',
812 'glSeparableFilter2D',
820 'glTexSubImage1DEXT',
822 'glTexSubImage2DEXT',
824 'glTexSubImage3DEXT',
825 'glTextureImage1DEXT',
826 'glTextureImage2DEXT',
827 'glTextureImage3DEXT',
828 'glTextureSubImage1DEXT',
829 'glTextureSubImage2DEXT',
830 'glTextureSubImage3DEXT',
833 def serializeArgValue(self, function, arg):
834 # Recognize offsets instead of blobs when a PBO is bound
835 if function.name in self.unpack_function_names \
836 and (isinstance(arg.type, stdapi.Blob) \
837 or (isinstance(arg.type, stdapi.Const) \
838 and isinstance(arg.type.type, stdapi.Blob))):
840 print ' gltrace::Context *ctx = gltrace::getContext();'
841 print ' GLint _unpack_buffer = 0;'
842 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
843 print ' _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
844 print ' if (_unpack_buffer) {'
845 print ' trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
847 Tracer.serializeArgValue(self, function, arg)
852 # Several GL state functions take GLenum symbolic names as
853 # integer/floats; so dump the symbolic name whenever possible
854 if function.name.startswith('gl') \
855 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
856 and arg.name == 'param':
858 assert function.args[arg.index - 1].name == 'pname'
859 assert function.args[arg.index - 1].type == glapi.GLenum
860 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
861 self.serializeValue(glapi.GLenum, arg.name)
863 Tracer.serializeArgValue(self, function, arg)
867 Tracer.serializeArgValue(self, function, arg)
869 def footer(self, api):
870 Tracer.footer(self, api)
872 # A simple state tracker to track the pointer values
874 print 'static void _trace_user_arrays(GLuint count)'
876 print ' gltrace::Context *ctx = gltrace::getContext();'
878 for camelcase_name, uppercase_name in self.arrays:
879 # in which profile is the array available?
880 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
881 if camelcase_name in self.arrays_es1:
882 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
884 function_name = 'gl%sPointer' % camelcase_name
885 enable_name = 'GL_%s_ARRAY' % uppercase_name
886 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
887 function = api.getFunctionByName(function_name)
889 print ' // %s' % function.prototype()
890 print ' if (%s) {' % profile_check
891 self.array_trace_prolog(api, uppercase_name)
892 self.array_prolog(api, uppercase_name)
893 print ' if (_glIsEnabled(%s)) {' % enable_name
894 print ' GLint _binding = 0;'
895 print ' _glGetIntegerv(%s, &_binding);' % binding_name
896 print ' if (!_binding) {'
898 # Get the arguments via glGet*
899 for arg in function.args:
900 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
901 arg_get_function, arg_type = TypeGetter().visit(arg.type)
902 print ' %s %s = 0;' % (arg_type, arg.name)
903 print ' _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
905 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
906 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
908 # Emit a fake function
909 self.array_trace_intermezzo(api, uppercase_name)
910 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
911 for arg in function.args:
912 assert not arg.output
913 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
914 if arg.name != 'pointer':
915 self.serializeValue(arg.type, arg.name)
917 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
918 print ' trace::localWriter.endArg();'
920 print ' trace::localWriter.endEnter();'
921 print ' trace::localWriter.beginLeave(_call);'
922 print ' trace::localWriter.endLeave();'
925 self.array_epilog(api, uppercase_name)
926 self.array_trace_epilog(api, uppercase_name)
930 # Samething, but for glVertexAttribPointer*
932 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
933 # - glVertexAttribPointer: no
934 # - glVertexAttribPointerARB: implementation dependent
935 # - glVertexAttribPointerNV: yes
937 # This means that the implementations of these functions do not always
938 # alias, and they need to be considered independently.
940 print ' // ES1 does not support generic vertex attributes'
941 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
944 print ' vertex_attrib _vertex_attrib = _get_vertex_attrib();'
946 for suffix in ['', 'ARB', 'NV']:
948 SUFFIX = '_' + suffix
951 function_name = 'glVertexAttribPointer' + suffix
952 function = api.getFunctionByName(function_name)
954 print ' // %s' % function.prototype()
955 print ' if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
957 print ' GLint _max_vertex_attribs = 16;'
959 print ' GLint _max_vertex_attribs = 0;'
960 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
961 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
962 print ' GLint _enabled = 0;'
964 print ' _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
966 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
967 print ' if (_enabled) {'
968 print ' GLint _binding = 0;'
970 # It doesn't seem possible to use VBOs with NV_vertex_program.
971 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
972 print ' if (!_binding) {'
974 # Get the arguments via glGet*
975 for arg in function.args[1:]:
977 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
979 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
980 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
981 print ' %s %s = 0;' % (arg_type, arg.name)
982 print ' _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
984 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
985 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
987 # Emit a fake function
988 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
989 for arg in function.args:
990 assert not arg.output
991 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
992 if arg.name != 'pointer':
993 self.serializeValue(arg.type, arg.name)
995 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
996 print ' trace::localWriter.endArg();'
998 print ' trace::localWriter.endEnter();'
999 print ' trace::localWriter.beginLeave(_call);'
1000 print ' trace::localWriter.endLeave();'
1011 # Hooks for glTexCoordPointer, which is identical to the other array
1012 # pointers except the fact that it is indexed by glClientActiveTexture.
1015 def array_prolog(self, api, uppercase_name):
1016 if uppercase_name == 'TEXTURE_COORD':
1017 print ' GLint client_active_texture = 0;'
1018 print ' _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1019 print ' GLint max_texture_coords = 0;'
1020 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
1021 print ' _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1023 print ' _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1024 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1025 print ' GLint texture = GL_TEXTURE0 + unit;'
1026 print ' _glClientActiveTexture(texture);'
1028 def array_trace_prolog(self, api, uppercase_name):
1029 if uppercase_name == 'TEXTURE_COORD':
1030 print ' bool client_active_texture_dirty = false;'
1032 def array_epilog(self, api, uppercase_name):
1033 if uppercase_name == 'TEXTURE_COORD':
1035 self.array_cleanup(api, uppercase_name)
1037 def array_cleanup(self, api, uppercase_name):
1038 if uppercase_name == 'TEXTURE_COORD':
1039 print ' _glClientActiveTexture(client_active_texture);'
1041 def array_trace_intermezzo(self, api, uppercase_name):
1042 if uppercase_name == 'TEXTURE_COORD':
1043 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
1044 print ' client_active_texture_dirty = true;'
1045 self.fake_glClientActiveTexture_call(api, "texture");
1048 def array_trace_epilog(self, api, uppercase_name):
1049 if uppercase_name == 'TEXTURE_COORD':
1050 print ' if (client_active_texture_dirty) {'
1051 self.fake_glClientActiveTexture_call(api, "client_active_texture");
1054 def fake_glClientActiveTexture_call(self, api, texture):
1055 function = api.getFunctionByName('glClientActiveTexture')
1056 self.fake_call(function, [texture])