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 if function.name in self.getProcAddressFunctionNames:
762 for marker_function in self.marker_functions:
763 if self.api.getFunctionByName(marker_function):
764 print ' %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
765 print ' _result = (%s)&%s;' % (function.type, marker_function)
769 Tracer.doInvokeFunction(self, function)
771 # Replace function addresses with ours
772 # XXX: Doing this here instead of wrapRet means that the trace will
773 # contain the addresses of the wrapper functions, and not the real
774 # functions, but in practice this should make no difference.
775 if function.name in self.getProcAddressFunctionNames:
776 print ' _result = _wrapProcAddress(%s, _result);' % (function.args[0].name,)
781 Tracer.doInvokeFunction(self, function)
785 'ELEMENT_ARRAY_BUFFER',
787 'PIXEL_UNPACK_BUFFER',
790 'TRANSFORM_FEEDBACK_BUFFER',
793 'DRAW_INDIRECT_BUFFER',
794 'ATOMIC_COUNTER_BUFFER',
797 def wrapRet(self, function, instance):
798 Tracer.wrapRet(self, function, instance)
800 # Keep track of buffer mappings
801 if function.name in ('glMapBuffer', 'glMapBufferARB'):
802 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
803 print ' if (mapping) {'
804 print ' mapping->map = %s;' % (instance)
805 print ' mapping->length = 0;'
806 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
807 print ' mapping->write = (access != GL_READ_ONLY);'
808 print ' mapping->explicit_flush = false;'
810 if function.name == 'glMapBufferRange':
811 print ' if (access & GL_MAP_WRITE_BIT) {'
812 print ' _checkBufferMapRange = true;'
814 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
815 print ' if (mapping) {'
816 print ' mapping->map = %s;' % (instance)
817 print ' mapping->length = length;'
818 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
819 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
827 def gl_boolean(self, value):
828 return self.boolean_names[int(bool(value))]
830 # Names of the functions that unpack from a pixel buffer object. See the
831 # ARB_pixel_buffer_object specification.
832 unpack_function_names = set([
836 'glCompressedMultiTexImage1DEXT',
837 'glCompressedMultiTexImage2DEXT',
838 'glCompressedMultiTexImage3DEXT',
839 'glCompressedMultiTexSubImage1DEXT',
840 'glCompressedMultiTexSubImage2DEXT',
841 'glCompressedMultiTexSubImage3DEXT',
842 'glCompressedTexImage1D',
843 'glCompressedTexImage2D',
844 'glCompressedTexImage3D',
845 'glCompressedTexSubImage1D',
846 'glCompressedTexSubImage2D',
847 'glCompressedTexSubImage3D',
848 'glCompressedTextureImage1DEXT',
849 'glCompressedTextureImage2DEXT',
850 'glCompressedTextureImage3DEXT',
851 'glCompressedTextureSubImage1DEXT',
852 'glCompressedTextureSubImage2DEXT',
853 'glCompressedTextureSubImage3DEXT',
854 'glConvolutionFilter1D',
855 'glConvolutionFilter2D',
857 'glMultiTexImage1DEXT',
858 'glMultiTexImage2DEXT',
859 'glMultiTexImage3DEXT',
860 'glMultiTexSubImage1DEXT',
861 'glMultiTexSubImage2DEXT',
862 'glMultiTexSubImage3DEXT',
867 'glSeparableFilter2D',
875 'glTexSubImage1DEXT',
877 'glTexSubImage2DEXT',
879 'glTexSubImage3DEXT',
880 'glTextureImage1DEXT',
881 'glTextureImage2DEXT',
882 'glTextureImage3DEXT',
883 'glTextureSubImage1DEXT',
884 'glTextureSubImage2DEXT',
885 'glTextureSubImage3DEXT',
888 def serializeArgValue(self, function, arg):
889 # Recognize offsets instead of blobs when a PBO is bound
890 if function.name in self.unpack_function_names \
891 and (isinstance(arg.type, stdapi.Blob) \
892 or (isinstance(arg.type, stdapi.Const) \
893 and isinstance(arg.type.type, stdapi.Blob))):
895 print ' gltrace::Context *ctx = gltrace::getContext();'
896 print ' GLint _unpack_buffer = 0;'
897 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
898 print ' _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
899 print ' if (_unpack_buffer) {'
900 print ' trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
902 Tracer.serializeArgValue(self, function, arg)
907 # Several GL state functions take GLenum symbolic names as
908 # integer/floats; so dump the symbolic name whenever possible
909 if function.name.startswith('gl') \
910 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
911 and arg.name == 'param':
913 assert function.args[arg.index - 1].name == 'pname'
914 assert function.args[arg.index - 1].type == glapi.GLenum
915 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
916 self.serializeValue(glapi.GLenum, arg.name)
918 Tracer.serializeArgValue(self, function, arg)
922 Tracer.serializeArgValue(self, function, arg)
924 def footer(self, api):
925 Tracer.footer(self, api)
927 # A simple state tracker to track the pointer values
929 print 'static void _trace_user_arrays(GLuint count)'
931 print ' gltrace::Context *ctx = gltrace::getContext();'
933 for camelcase_name, uppercase_name in self.arrays:
934 # in which profile is the array available?
935 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
936 if camelcase_name in self.arrays_es1:
937 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
939 function_name = 'gl%sPointer' % camelcase_name
940 enable_name = 'GL_%s_ARRAY' % uppercase_name
941 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
942 function = api.getFunctionByName(function_name)
944 print ' // %s' % function.prototype()
945 print ' if (%s) {' % profile_check
946 self.array_trace_prolog(api, uppercase_name)
947 self.array_prolog(api, uppercase_name)
948 print ' if (_glIsEnabled(%s)) {' % enable_name
949 print ' GLint _binding = 0;'
950 print ' _glGetIntegerv(%s, &_binding);' % binding_name
951 print ' if (!_binding) {'
953 # Get the arguments via glGet*
954 for arg in function.args:
955 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
956 arg_get_function, arg_type = TypeGetter().visit(arg.type)
957 print ' %s %s = 0;' % (arg_type, arg.name)
958 print ' _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
960 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
961 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
963 # Emit a fake function
964 self.array_trace_intermezzo(api, uppercase_name)
965 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
966 for arg in function.args:
967 assert not arg.output
968 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
969 if arg.name != 'pointer':
970 self.serializeValue(arg.type, arg.name)
972 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
973 print ' trace::localWriter.endArg();'
975 print ' trace::localWriter.endEnter();'
976 print ' trace::localWriter.beginLeave(_call);'
977 print ' trace::localWriter.endLeave();'
980 self.array_epilog(api, uppercase_name)
981 self.array_trace_epilog(api, uppercase_name)
985 # Samething, but for glVertexAttribPointer*
987 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
988 # - glVertexAttribPointer: no
989 # - glVertexAttribPointerARB: implementation dependent
990 # - glVertexAttribPointerNV: yes
992 # This means that the implementations of these functions do not always
993 # alias, and they need to be considered independently.
995 print ' // ES1 does not support generic vertex attributes'
996 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
999 print ' vertex_attrib _vertex_attrib = _get_vertex_attrib();'
1001 for suffix in ['', 'ARB', 'NV']:
1003 SUFFIX = '_' + suffix
1006 function_name = 'glVertexAttribPointer' + suffix
1007 function = api.getFunctionByName(function_name)
1009 print ' // %s' % function.prototype()
1010 print ' if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
1012 print ' GLint _max_vertex_attribs = 16;'
1014 print ' GLint _max_vertex_attribs = 0;'
1015 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
1016 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
1017 print ' GLint _enabled = 0;'
1019 print ' _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
1021 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
1022 print ' if (_enabled) {'
1023 print ' GLint _binding = 0;'
1025 # It doesn't seem possible to use VBOs with NV_vertex_program.
1026 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
1027 print ' if (!_binding) {'
1029 # Get the arguments via glGet*
1030 for arg in function.args[1:]:
1032 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
1034 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
1035 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
1036 print ' %s %s = 0;' % (arg_type, arg.name)
1037 print ' _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
1039 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
1040 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
1042 # Emit a fake function
1043 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1044 for arg in function.args:
1045 assert not arg.output
1046 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
1047 if arg.name != 'pointer':
1048 self.serializeValue(arg.type, arg.name)
1050 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
1051 print ' trace::localWriter.endArg();'
1053 print ' trace::localWriter.endEnter();'
1054 print ' trace::localWriter.beginLeave(_call);'
1055 print ' trace::localWriter.endLeave();'
1066 # Hooks for glTexCoordPointer, which is identical to the other array
1067 # pointers except the fact that it is indexed by glClientActiveTexture.
1070 def array_prolog(self, api, uppercase_name):
1071 if uppercase_name == 'TEXTURE_COORD':
1072 print ' GLint client_active_texture = 0;'
1073 print ' _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1074 print ' GLint max_texture_coords = 0;'
1075 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
1076 print ' _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1078 print ' _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1079 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1080 print ' GLint texture = GL_TEXTURE0 + unit;'
1081 print ' _glClientActiveTexture(texture);'
1083 def array_trace_prolog(self, api, uppercase_name):
1084 if uppercase_name == 'TEXTURE_COORD':
1085 print ' bool client_active_texture_dirty = false;'
1087 def array_epilog(self, api, uppercase_name):
1088 if uppercase_name == 'TEXTURE_COORD':
1090 self.array_cleanup(api, uppercase_name)
1092 def array_cleanup(self, api, uppercase_name):
1093 if uppercase_name == 'TEXTURE_COORD':
1094 print ' _glClientActiveTexture(client_active_texture);'
1096 def array_trace_intermezzo(self, api, uppercase_name):
1097 if uppercase_name == 'TEXTURE_COORD':
1098 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
1099 print ' client_active_texture_dirty = true;'
1100 self.fake_glClientActiveTexture_call(api, "texture");
1103 def array_trace_epilog(self, api, uppercase_name):
1104 if uppercase_name == 'TEXTURE_COORD':
1105 print ' if (client_active_texture_dirty) {'
1106 self.fake_glClientActiveTexture_call(api, "client_active_texture");
1109 def fake_glClientActiveTexture_call(self, api, texture):
1110 function = api.getFunctionByName('glClientActiveTexture')
1111 self.fake_call(function, [texture])
1113 def emitFakeTexture2D(self):
1114 function = glapi.glapi.getFunctionByName('glTexImage2D')
1115 instances = function.argNames()
1116 print ' unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1117 for arg in function.args:
1118 assert not arg.output
1119 self.serializeArg(function, arg)
1120 print ' trace::localWriter.endEnter();'
1121 print ' trace::localWriter.beginLeave(_fake_call);'
1122 print ' trace::localWriter.endLeave();'