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)
333 # Provide fallback functions to missing debug functions
334 print ' if (!procPtr) {'
336 for function_name in self.debug_functions:
337 if self.api.getFunctionByName(function_name):
338 print ' %sif (strcmp("%s", (const char *)procName) == 0) {' % (else_, function_name)
339 print ' return (%s)&%s;' % (retType, function_name)
343 print ' return NULL;'
347 for function in api.getAllFunctions():
348 ptype = function_pointer_type(function)
349 pvalue = function_pointer_value(function)
350 print ' if (strcmp("%s", (const char *)procName) == 0) {' % function.name
351 print ' %s = (%s)procPtr;' % (pvalue, ptype)
352 print ' return (%s)&%s;' % (retType, function.name,)
354 print ' os::log("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);'
355 print ' return procPtr;'
359 Tracer.traceApi(self, api)
361 def defineShadowBufferHelper(self):
362 print 'void _shadow_glGetBufferSubData(GLenum target, GLintptr offset,'
363 print ' GLsizeiptr size, GLvoid *data)'
365 print ' gltrace::Context *ctx = gltrace::getContext();'
366 print ' if (!ctx->needsShadowBuffers() || target != GL_ELEMENT_ARRAY_BUFFER) {'
367 print ' _glGetBufferSubData(target, offset, size, data);'
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.getSubData(offset, size, data);'
379 def shadowBufferMethod(self, method):
380 # Emit code to fetch the shadow buffer, and invoke a method
381 print ' gltrace::Context *ctx = gltrace::getContext();'
382 print ' if (ctx->needsShadowBuffers() && target == GL_ELEMENT_ARRAY_BUFFER) {'
383 print ' GLint buffer_binding = 0;'
384 print ' _glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buffer_binding);'
385 print ' if (buffer_binding > 0) {'
386 print ' gltrace::Buffer & buf = ctx->buffers[buffer_binding];'
387 print ' buf.' + method + ';'
392 def shadowBufferProlog(self, function):
393 if function.name == 'glBufferData':
394 self.shadowBufferMethod('bufferData(size, data)')
396 if function.name == 'glBufferSubData':
397 self.shadowBufferMethod('bufferSubData(offset, size, data)')
399 if function.name == 'glDeleteBuffers':
400 print ' gltrace::Context *ctx = gltrace::getContext();'
401 print ' if (ctx->needsShadowBuffers()) {'
402 print ' for (GLsizei i = 0; i < n; i++) {'
403 print ' ctx->buffers.erase(buffer[i]);'
407 array_pointer_function_names = set((
415 "glSecondaryColorPointer",
417 "glInterleavedArrays",
419 "glVertexPointerEXT",
420 "glNormalPointerEXT",
423 "glTexCoordPointerEXT",
424 "glEdgeFlagPointerEXT",
425 "glFogCoordPointerEXT",
426 "glSecondaryColorPointerEXT",
428 "glVertexAttribPointer",
429 "glVertexAttribPointerARB",
430 "glVertexAttribPointerNV",
431 "glVertexAttribIPointer",
432 "glVertexAttribIPointerEXT",
433 "glVertexAttribLPointer",
434 "glVertexAttribLPointerEXT",
436 #"glMatrixIndexPointerARB",
439 draw_function_names = set((
442 'glDrawRangeElements',
444 'glMultiDrawElements',
445 'glDrawArraysInstanced',
446 "glDrawArraysInstancedBaseInstance",
447 'glDrawElementsInstanced',
448 'glDrawArraysInstancedARB',
449 'glDrawElementsInstancedARB',
450 'glDrawElementsBaseVertex',
451 'glDrawRangeElementsBaseVertex',
452 'glDrawElementsInstancedBaseVertex',
453 "glDrawElementsInstancedBaseInstance",
454 "glDrawElementsInstancedBaseVertexBaseInstance",
455 'glMultiDrawElementsBaseVertex',
456 'glDrawArraysIndirect',
457 'glDrawElementsIndirect',
458 'glMultiDrawArraysIndirect',
459 'glMultiDrawArraysIndirectAMD',
460 'glMultiDrawElementsIndirect',
461 'glMultiDrawElementsIndirectAMD',
463 'glDrawRangeElementsEXT',
464 'glDrawRangeElementsEXT_size',
465 'glMultiDrawArraysEXT',
466 'glMultiDrawElementsEXT',
467 'glMultiModeDrawArraysIBM',
468 'glMultiModeDrawElementsIBM',
469 'glDrawArraysInstancedEXT',
470 'glDrawElementsInstancedEXT',
473 interleaved_formats = [
486 'GL_T2F_C4F_N3F_V3F',
487 'GL_T4F_C4F_N3F_V4F',
490 def traceFunctionImplBody(self, function):
491 # Defer tracing of user array pointers...
492 if function.name in self.array_pointer_function_names:
493 print ' GLint _array_buffer = 0;'
494 print ' _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
495 print ' if (!_array_buffer) {'
496 print ' gltrace::Context *ctx = gltrace::getContext();'
497 print ' ctx->user_arrays = true;'
498 if function.name == "glVertexAttribPointerARB":
499 print ' ctx->user_arrays_arb = true;'
500 if function.name == "glVertexAttribPointerNV":
501 print ' ctx->user_arrays_nv = true;'
502 self.invokeFunction(function)
504 # And also break down glInterleavedArrays into the individual calls
505 if function.name == 'glInterleavedArrays':
508 # Initialize the enable flags
509 for camelcase_name, uppercase_name in self.arrays:
510 flag_name = '_' + uppercase_name.lower()
511 print ' GLboolean %s = GL_FALSE;' % flag_name
514 # Switch for the interleaved formats
515 print ' switch (format) {'
516 for format in self.interleaved_formats:
517 print ' case %s:' % format
518 for camelcase_name, uppercase_name in self.arrays:
519 flag_name = '_' + uppercase_name.lower()
520 if format.find('_' + uppercase_name[0]) >= 0:
521 print ' %s = GL_TRUE;' % flag_name
528 # Emit fake glEnableClientState/glDisableClientState flags
529 for camelcase_name, uppercase_name in self.arrays:
530 flag_name = '_' + uppercase_name.lower()
531 enable_name = 'GL_%s_ARRAY' % uppercase_name
533 # Emit a fake function
535 print ' static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
536 print ' unsigned _call = trace::localWriter.beginEnter(&_sig);'
537 print ' trace::localWriter.beginArg(0);'
538 self.serializeValue(glapi.GLenum, enable_name)
539 print ' trace::localWriter.endArg();'
540 print ' trace::localWriter.endEnter();'
541 print ' trace::localWriter.beginLeave(_call);'
542 print ' trace::localWriter.endLeave();'
548 # ... to the draw calls
549 if function.name in self.draw_function_names:
550 print ' if (_need_user_arrays()) {'
551 arg_names = ', '.join([arg.name for arg in function.args[1:]])
552 print ' GLuint _count = _%s_count(%s);' % (function.name, arg_names)
553 print ' _trace_user_arrays(_count);'
556 # Emit a fake memcpy on buffer uploads
557 if function.name == 'glBufferParameteriAPPLE':
558 print ' if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
559 print ' _checkBufferFlushingUnmapAPPLE = true;'
561 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
562 if function.name.endswith('ARB'):
566 print ' GLint access = 0;'
567 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
568 print ' if (access != GL_READ_ONLY) {'
569 print ' GLvoid *map = NULL;'
570 print ' _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);' % suffix
572 print ' GLint length = -1;'
573 print ' bool flush = true;'
574 print ' if (_checkBufferMapRange) {'
575 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
576 print ' GLint access_flags = 0;'
577 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
578 print ' flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
579 print ' if (length == -1) {'
580 print ' // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
581 print ' static bool warned = false;'
582 print ' if (!warned) {'
583 print ' os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
584 print ' warned = true;'
586 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
587 print ' if (mapping) {'
588 print ' length = mapping->length;'
589 print ' flush = flush && !mapping->explicit_flush;'
592 print ' flush = false;'
597 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
599 print ' if (_checkBufferFlushingUnmapAPPLE) {'
600 print ' GLint flushing_unmap = GL_TRUE;'
601 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
602 print ' flush = flush && flushing_unmap;'
604 print ' if (flush && length > 0) {'
605 self.emit_memcpy('map', 'map', 'length')
609 if function.name == 'glUnmapBufferOES':
610 print ' GLint access = 0;'
611 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
612 print ' if (access == GL_WRITE_ONLY_OES) {'
613 print ' GLvoid *map = NULL;'
614 print ' _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
615 print ' GLint size = 0;'
616 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
617 print ' if (map && size > 0) {'
618 self.emit_memcpy('map', 'map', 'size')
619 self.shadowBufferMethod('bufferSubData(0, size, map)')
622 if function.name == 'glUnmapNamedBufferEXT':
623 print ' GLint access_flags = 0;'
624 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
625 print ' if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
626 print ' GLvoid *map = NULL;'
627 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
628 print ' GLint length = 0;'
629 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
630 print ' if (map && length > 0) {'
631 self.emit_memcpy('map', 'map', 'length')
634 if function.name == 'glFlushMappedBufferRange':
635 print ' GLvoid *map = NULL;'
636 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
637 print ' if (map && length > 0) {'
638 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
640 if function.name == 'glFlushMappedBufferRangeAPPLE':
641 print ' GLvoid *map = NULL;'
642 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
643 print ' if (map && size > 0) {'
644 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
646 if function.name == 'glFlushMappedNamedBufferRangeEXT':
647 print ' GLvoid *map = NULL;'
648 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
649 print ' if (map && length > 0) {'
650 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
653 # Don't leave vertex attrib locations to chance. Instead emit fake
654 # glBindAttribLocation calls to ensure that the same locations will be
655 # used when retracing. Trying to remap locations after the fact would
656 # be an herculian task given that vertex attrib locations appear in
657 # many entry-points, including non-shader related ones.
658 if function.name == 'glLinkProgram':
659 Tracer.invokeFunction(self, function)
660 print ' GLint active_attributes = 0;'
661 print ' _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
662 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
663 print ' GLint size = 0;'
664 print ' GLenum type = 0;'
665 print ' GLchar name[256];'
666 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
667 print ' _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
668 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
669 print ' GLint location = _glGetAttribLocation(program, name);'
670 print ' if (location >= 0) {'
671 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
672 self.fake_call(bind_function, ['program', 'location', 'name'])
676 if function.name == 'glLinkProgramARB':
677 Tracer.invokeFunction(self, function)
678 print ' GLint active_attributes = 0;'
679 print ' _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
680 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
681 print ' GLint size = 0;'
682 print ' GLenum type = 0;'
683 print ' GLcharARB name[256];'
684 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
685 print ' _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
686 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
687 print ' GLint location = _glGetAttribLocationARB(programObj, name);'
688 print ' if (location >= 0) {'
689 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
690 self.fake_call(bind_function, ['programObj', 'location', 'name'])
695 self.shadowBufferProlog(function)
697 Tracer.traceFunctionImplBody(self, function)
699 # These entrypoints are only expected to be implemented by tools;
700 # drivers will probably not implement them.
702 # GL_GREMEDY_string_marker
703 'glStringMarkerGREMEDY',
704 # GL_GREMEDY_frame_terminator
705 'glFrameTerminatorGREMEDY',
706 # GL_EXT_debug_marker
707 'glInsertEventMarkerEXT',
708 'glPushGroupMarkerEXT',
709 'glPopGroupMarkerEXT',
712 # These entrypoints may be implemented by drivers, but are also very useful
713 # for debugging / analysis tools.
716 'glDebugMessageControl',
717 'glDebugMessageInsert',
718 'glDebugMessageCallback',
719 'glGetDebugMessageLog',
725 'glGetObjectPtrLabel',
726 # GL_ARB_debug_output
727 'glDebugMessageControlARB',
728 'glDebugMessageInsertARB',
729 'glDebugMessageCallbackARB',
730 'glGetDebugMessageLogARB',
731 # GL_AMD_debug_output
732 'glDebugMessageEnableAMD',
733 'glDebugMessageInsertAMD',
734 'glDebugMessageCallbackAMD',
735 'glGetDebugMessageLogAMD',
738 def invokeFunction(self, function):
739 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
740 # These functions have been dispatched already
743 Tracer.invokeFunction(self, function)
745 def doInvokeFunction(self, function):
746 # Same as invokeFunction() but called both when trace is enabled or disabled.
748 # Used to modify the behavior of GL entry-points.
750 # Override GL extensions
751 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
752 Tracer.doInvokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
755 # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
757 if function.name in self.marker_functions:
760 # We may be faking KHR_debug, so ensure the pointer queries result is
761 # always zeroed to prevent dereference of unitialized pointers
762 if function.name == 'glGetPointerv':
763 print ' if (params &&'
764 print ' (pname == GL_DEBUG_CALLBACK_FUNCTION ||'
765 print ' pname == GL_DEBUG_CALLBACK_USER_PARAM)) {'
766 print ' *params = NULL;'
769 if function.name in self.getProcAddressFunctionNames:
771 for marker_function in self.marker_functions:
772 if self.api.getFunctionByName(marker_function):
773 print ' %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
774 print ' _result = (%s)&%s;' % (function.type, marker_function)
778 Tracer.doInvokeFunction(self, function)
780 # Replace function addresses with ours
781 # XXX: Doing this here instead of wrapRet means that the trace will
782 # contain the addresses of the wrapper functions, and not the real
783 # functions, but in practice this should make no difference.
784 if function.name in self.getProcAddressFunctionNames:
785 print ' _result = _wrapProcAddress(%s, _result);' % (function.args[0].name,)
790 Tracer.doInvokeFunction(self, function)
794 'ELEMENT_ARRAY_BUFFER',
796 'PIXEL_UNPACK_BUFFER',
799 'TRANSFORM_FEEDBACK_BUFFER',
802 'DRAW_INDIRECT_BUFFER',
803 'ATOMIC_COUNTER_BUFFER',
806 def wrapRet(self, function, instance):
807 Tracer.wrapRet(self, function, instance)
809 # Keep track of buffer mappings
810 if function.name in ('glMapBuffer', 'glMapBufferARB'):
811 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
812 print ' if (mapping) {'
813 print ' mapping->map = %s;' % (instance)
814 print ' mapping->length = 0;'
815 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
816 print ' mapping->write = (access != GL_READ_ONLY);'
817 print ' mapping->explicit_flush = false;'
819 if function.name == 'glMapBufferRange':
820 print ' if (access & GL_MAP_WRITE_BIT) {'
821 print ' _checkBufferMapRange = true;'
823 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
824 print ' if (mapping) {'
825 print ' mapping->map = %s;' % (instance)
826 print ' mapping->length = length;'
827 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
828 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
836 def gl_boolean(self, value):
837 return self.boolean_names[int(bool(value))]
839 # Names of the functions that unpack from a pixel buffer object. See the
840 # ARB_pixel_buffer_object specification.
841 unpack_function_names = set([
845 'glCompressedMultiTexImage1DEXT',
846 'glCompressedMultiTexImage2DEXT',
847 'glCompressedMultiTexImage3DEXT',
848 'glCompressedMultiTexSubImage1DEXT',
849 'glCompressedMultiTexSubImage2DEXT',
850 'glCompressedMultiTexSubImage3DEXT',
851 'glCompressedTexImage1D',
852 'glCompressedTexImage2D',
853 'glCompressedTexImage3D',
854 'glCompressedTexSubImage1D',
855 'glCompressedTexSubImage2D',
856 'glCompressedTexSubImage3D',
857 'glCompressedTextureImage1DEXT',
858 'glCompressedTextureImage2DEXT',
859 'glCompressedTextureImage3DEXT',
860 'glCompressedTextureSubImage1DEXT',
861 'glCompressedTextureSubImage2DEXT',
862 'glCompressedTextureSubImage3DEXT',
863 'glConvolutionFilter1D',
864 'glConvolutionFilter2D',
866 'glMultiTexImage1DEXT',
867 'glMultiTexImage2DEXT',
868 'glMultiTexImage3DEXT',
869 'glMultiTexSubImage1DEXT',
870 'glMultiTexSubImage2DEXT',
871 'glMultiTexSubImage3DEXT',
876 'glSeparableFilter2D',
884 'glTexSubImage1DEXT',
886 'glTexSubImage2DEXT',
888 'glTexSubImage3DEXT',
889 'glTextureImage1DEXT',
890 'glTextureImage2DEXT',
891 'glTextureImage3DEXT',
892 'glTextureSubImage1DEXT',
893 'glTextureSubImage2DEXT',
894 'glTextureSubImage3DEXT',
897 def serializeArgValue(self, function, arg):
898 # Recognize offsets instead of blobs when a PBO is bound
899 if function.name in self.unpack_function_names \
900 and (isinstance(arg.type, stdapi.Blob) \
901 or (isinstance(arg.type, stdapi.Const) \
902 and isinstance(arg.type.type, stdapi.Blob))):
904 print ' gltrace::Context *ctx = gltrace::getContext();'
905 print ' GLint _unpack_buffer = 0;'
906 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
907 print ' _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
908 print ' if (_unpack_buffer) {'
909 print ' trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
911 Tracer.serializeArgValue(self, function, arg)
916 # Several GL state functions take GLenum symbolic names as
917 # integer/floats; so dump the symbolic name whenever possible
918 if function.name.startswith('gl') \
919 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
920 and arg.name == 'param':
922 assert function.args[arg.index - 1].name == 'pname'
923 assert function.args[arg.index - 1].type == glapi.GLenum
924 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
925 self.serializeValue(glapi.GLenum, arg.name)
927 Tracer.serializeArgValue(self, function, arg)
931 Tracer.serializeArgValue(self, function, arg)
933 def footer(self, api):
934 Tracer.footer(self, api)
936 # A simple state tracker to track the pointer values
938 print 'static void _trace_user_arrays(GLuint count)'
940 print ' gltrace::Context *ctx = gltrace::getContext();'
942 for camelcase_name, uppercase_name in self.arrays:
943 # in which profile is the array available?
944 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
945 if camelcase_name in self.arrays_es1:
946 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
948 function_name = 'gl%sPointer' % camelcase_name
949 enable_name = 'GL_%s_ARRAY' % uppercase_name
950 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
951 function = api.getFunctionByName(function_name)
953 print ' // %s' % function.prototype()
954 print ' if (%s) {' % profile_check
955 self.array_trace_prolog(api, uppercase_name)
956 self.array_prolog(api, uppercase_name)
957 print ' if (_glIsEnabled(%s)) {' % enable_name
958 print ' GLint _binding = 0;'
959 print ' _glGetIntegerv(%s, &_binding);' % binding_name
960 print ' if (!_binding) {'
962 # Get the arguments via glGet*
963 for arg in function.args:
964 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
965 arg_get_function, arg_type = TypeGetter().visit(arg.type)
966 print ' %s %s = 0;' % (arg_type, arg.name)
967 print ' _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
969 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
970 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
972 # Emit a fake function
973 self.array_trace_intermezzo(api, uppercase_name)
974 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
975 for arg in function.args:
976 assert not arg.output
977 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
978 if arg.name != 'pointer':
979 self.serializeValue(arg.type, arg.name)
981 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
982 print ' trace::localWriter.endArg();'
984 print ' trace::localWriter.endEnter();'
985 print ' trace::localWriter.beginLeave(_call);'
986 print ' trace::localWriter.endLeave();'
989 self.array_epilog(api, uppercase_name)
990 self.array_trace_epilog(api, uppercase_name)
994 # Samething, but for glVertexAttribPointer*
996 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
997 # - glVertexAttribPointer: no
998 # - glVertexAttribPointerARB: implementation dependent
999 # - glVertexAttribPointerNV: yes
1001 # This means that the implementations of these functions do not always
1002 # alias, and they need to be considered independently.
1004 print ' // ES1 does not support generic vertex attributes'
1005 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
1008 print ' vertex_attrib _vertex_attrib = _get_vertex_attrib();'
1010 for suffix in ['', 'ARB', 'NV']:
1012 SUFFIX = '_' + suffix
1015 function_name = 'glVertexAttribPointer' + suffix
1016 function = api.getFunctionByName(function_name)
1018 print ' // %s' % function.prototype()
1019 print ' if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
1021 print ' GLint _max_vertex_attribs = 16;'
1023 print ' GLint _max_vertex_attribs = 0;'
1024 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
1025 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
1026 print ' GLint _enabled = 0;'
1028 print ' _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
1030 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
1031 print ' if (_enabled) {'
1032 print ' GLint _binding = 0;'
1034 # It doesn't seem possible to use VBOs with NV_vertex_program.
1035 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
1036 print ' if (!_binding) {'
1038 # Get the arguments via glGet*
1039 for arg in function.args[1:]:
1041 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
1043 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
1044 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
1045 print ' %s %s = 0;' % (arg_type, arg.name)
1046 print ' _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
1048 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
1049 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
1051 # Emit a fake function
1052 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1053 for arg in function.args:
1054 assert not arg.output
1055 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
1056 if arg.name != 'pointer':
1057 self.serializeValue(arg.type, arg.name)
1059 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
1060 print ' trace::localWriter.endArg();'
1062 print ' trace::localWriter.endEnter();'
1063 print ' trace::localWriter.beginLeave(_call);'
1064 print ' trace::localWriter.endLeave();'
1075 # Hooks for glTexCoordPointer, which is identical to the other array
1076 # pointers except the fact that it is indexed by glClientActiveTexture.
1079 def array_prolog(self, api, uppercase_name):
1080 if uppercase_name == 'TEXTURE_COORD':
1081 print ' GLint client_active_texture = 0;'
1082 print ' _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1083 print ' GLint max_texture_coords = 0;'
1084 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
1085 print ' _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1087 print ' _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1088 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1089 print ' GLint texture = GL_TEXTURE0 + unit;'
1090 print ' _glClientActiveTexture(texture);'
1092 def array_trace_prolog(self, api, uppercase_name):
1093 if uppercase_name == 'TEXTURE_COORD':
1094 print ' bool client_active_texture_dirty = false;'
1096 def array_epilog(self, api, uppercase_name):
1097 if uppercase_name == 'TEXTURE_COORD':
1099 self.array_cleanup(api, uppercase_name)
1101 def array_cleanup(self, api, uppercase_name):
1102 if uppercase_name == 'TEXTURE_COORD':
1103 print ' _glClientActiveTexture(client_active_texture);'
1105 def array_trace_intermezzo(self, api, uppercase_name):
1106 if uppercase_name == 'TEXTURE_COORD':
1107 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
1108 print ' client_active_texture_dirty = true;'
1109 self.fake_glClientActiveTexture_call(api, "texture");
1112 def array_trace_epilog(self, api, uppercase_name):
1113 if uppercase_name == 'TEXTURE_COORD':
1114 print ' if (client_active_texture_dirty) {'
1115 self.fake_glClientActiveTexture_call(api, "client_active_texture");
1118 def fake_glClientActiveTexture_call(self, api, texture):
1119 function = api.getFunctionByName('glClientActiveTexture')
1120 self.fake_call(function, [texture])
1122 def emitFakeTexture2D(self):
1123 function = glapi.glapi.getFunctionByName('glTexImage2D')
1124 instances = function.argNames()
1125 print ' unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1126 for arg in function.args:
1127 assert not arg.output
1128 self.serializeArg(function, arg)
1129 print ' trace::localWriter.endEnter();'
1130 print ' trace::localWriter.beginLeave(_fake_call);'
1131 print ' trace::localWriter.endLeave();'