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 'glCompressedTexImage1D',
782 'glCompressedTexImage2D',
783 'glCompressedTexImage3D',
784 'glCompressedTexSubImage1D',
785 'glCompressedTexSubImage2D',
786 'glCompressedTexSubImage3D',
787 'glConvolutionFilter1D',
788 'glConvolutionFilter2D',
790 'glMultiTexImage1DEXT',
791 'glMultiTexImage2DEXT',
792 'glMultiTexImage3DEXT',
793 'glMultiTexSubImage1DEXT',
794 'glMultiTexSubImage2DEXT',
795 'glMultiTexSubImage3DEXT',
800 'glSeparableFilter2D',
808 'glTexSubImage1DEXT',
810 'glTexSubImage2DEXT',
812 'glTexSubImage3DEXT',
813 'glTextureImage1DEXT',
814 'glTextureImage2DEXT',
815 'glTextureImage3DEXT',
816 'glTextureSubImage1DEXT',
817 'glTextureSubImage2DEXT',
818 'glTextureSubImage3DEXT',
821 def serializeArgValue(self, function, arg):
822 # Recognize offsets instead of blobs when a PBO is bound
823 if function.name in self.unpack_function_names \
824 and (isinstance(arg.type, stdapi.Blob) \
825 or (isinstance(arg.type, stdapi.Const) \
826 and isinstance(arg.type.type, stdapi.Blob))):
828 print ' gltrace::Context *ctx = gltrace::getContext();'
829 print ' GLint _unpack_buffer = 0;'
830 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
831 print ' _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
832 print ' if (_unpack_buffer) {'
833 print ' trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
835 Tracer.serializeArgValue(self, function, arg)
840 # Several GL state functions take GLenum symbolic names as
841 # integer/floats; so dump the symbolic name whenever possible
842 if function.name.startswith('gl') \
843 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
844 and arg.name == 'param':
846 assert function.args[arg.index - 1].name == 'pname'
847 assert function.args[arg.index - 1].type == glapi.GLenum
848 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
849 self.serializeValue(glapi.GLenum, arg.name)
851 Tracer.serializeArgValue(self, function, arg)
855 Tracer.serializeArgValue(self, function, arg)
857 def footer(self, api):
858 Tracer.footer(self, api)
860 # A simple state tracker to track the pointer values
862 print 'static void _trace_user_arrays(GLuint count)'
864 print ' gltrace::Context *ctx = gltrace::getContext();'
866 for camelcase_name, uppercase_name in self.arrays:
867 # in which profile is the array available?
868 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
869 if camelcase_name in self.arrays_es1:
870 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
872 function_name = 'gl%sPointer' % camelcase_name
873 enable_name = 'GL_%s_ARRAY' % uppercase_name
874 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
875 function = api.getFunctionByName(function_name)
877 print ' // %s' % function.prototype()
878 print ' if (%s) {' % profile_check
879 self.array_trace_prolog(api, uppercase_name)
880 self.array_prolog(api, uppercase_name)
881 print ' if (_glIsEnabled(%s)) {' % enable_name
882 print ' GLint _binding = 0;'
883 print ' _glGetIntegerv(%s, &_binding);' % binding_name
884 print ' if (!_binding) {'
886 # Get the arguments via glGet*
887 for arg in function.args:
888 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
889 arg_get_function, arg_type = TypeGetter().visit(arg.type)
890 print ' %s %s = 0;' % (arg_type, arg.name)
891 print ' _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
893 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
894 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
896 # Emit a fake function
897 self.array_trace_intermezzo(api, uppercase_name)
898 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
899 for arg in function.args:
900 assert not arg.output
901 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
902 if arg.name != 'pointer':
903 self.serializeValue(arg.type, arg.name)
905 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
906 print ' trace::localWriter.endArg();'
908 print ' trace::localWriter.endEnter();'
909 print ' trace::localWriter.beginLeave(_call);'
910 print ' trace::localWriter.endLeave();'
913 self.array_epilog(api, uppercase_name)
914 self.array_trace_epilog(api, uppercase_name)
918 # Samething, but for glVertexAttribPointer*
920 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
921 # - glVertexAttribPointer: no
922 # - glVertexAttribPointerARB: implementation dependent
923 # - glVertexAttribPointerNV: yes
925 # This means that the implementations of these functions do not always
926 # alias, and they need to be considered independently.
928 print ' // ES1 does not support generic vertex attributes'
929 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
932 print ' vertex_attrib _vertex_attrib = _get_vertex_attrib();'
934 for suffix in ['', 'ARB', 'NV']:
936 SUFFIX = '_' + suffix
939 function_name = 'glVertexAttribPointer' + suffix
940 function = api.getFunctionByName(function_name)
942 print ' // %s' % function.prototype()
943 print ' if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
945 print ' GLint _max_vertex_attribs = 16;'
947 print ' GLint _max_vertex_attribs = 0;'
948 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
949 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
950 print ' GLint _enabled = 0;'
952 print ' _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
954 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
955 print ' if (_enabled) {'
956 print ' GLint _binding = 0;'
958 # It doesn't seem possible to use VBOs with NV_vertex_program.
959 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
960 print ' if (!_binding) {'
962 # Get the arguments via glGet*
963 for arg in function.args[1:]:
965 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
967 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
968 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
969 print ' %s %s = 0;' % (arg_type, arg.name)
970 print ' _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
972 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
973 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
975 # Emit a fake function
976 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
977 for arg in function.args:
978 assert not arg.output
979 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
980 if arg.name != 'pointer':
981 self.serializeValue(arg.type, arg.name)
983 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
984 print ' trace::localWriter.endArg();'
986 print ' trace::localWriter.endEnter();'
987 print ' trace::localWriter.beginLeave(_call);'
988 print ' trace::localWriter.endLeave();'
999 # Hooks for glTexCoordPointer, which is identical to the other array
1000 # pointers except the fact that it is indexed by glClientActiveTexture.
1003 def array_prolog(self, api, uppercase_name):
1004 if uppercase_name == 'TEXTURE_COORD':
1005 print ' GLint client_active_texture = 0;'
1006 print ' _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1007 print ' GLint max_texture_coords = 0;'
1008 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
1009 print ' _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1011 print ' _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1012 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1013 print ' GLint texture = GL_TEXTURE0 + unit;'
1014 print ' _glClientActiveTexture(texture);'
1016 def array_trace_prolog(self, api, uppercase_name):
1017 if uppercase_name == 'TEXTURE_COORD':
1018 print ' bool client_active_texture_dirty = false;'
1020 def array_epilog(self, api, uppercase_name):
1021 if uppercase_name == 'TEXTURE_COORD':
1023 self.array_cleanup(api, uppercase_name)
1025 def array_cleanup(self, api, uppercase_name):
1026 if uppercase_name == 'TEXTURE_COORD':
1027 print ' _glClientActiveTexture(client_active_texture);'
1029 def array_trace_intermezzo(self, api, uppercase_name):
1030 if uppercase_name == 'TEXTURE_COORD':
1031 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
1032 print ' client_active_texture_dirty = true;'
1033 self.fake_glClientActiveTexture_call(api, "texture");
1036 def array_trace_epilog(self, api, uppercase_name):
1037 if uppercase_name == 'TEXTURE_COORD':
1038 print ' if (client_active_texture_dirty) {'
1039 self.fake_glClientActiveTexture_call(api, "client_active_texture");
1042 def fake_glClientActiveTexture_call(self, api, texture):
1043 function = api.getFunctionByName('glClientActiveTexture')
1044 self.fake_call(function, [texture])