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(GL_ELEMENT_ARRAY_BUFFER_BINDING, &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',
446 'glMultiDrawArraysIndirect',
447 'glMultiDrawArraysIndirectAMD',
448 'glMultiDrawElementsIndirect',
449 'glMultiDrawElementsIndirectAMD',
451 'glDrawRangeElementsEXT',
452 'glDrawRangeElementsEXT_size',
453 'glMultiDrawArraysEXT',
454 'glMultiDrawElementsEXT',
455 'glMultiModeDrawArraysIBM',
456 'glMultiModeDrawElementsIBM',
457 'glDrawArraysInstancedEXT',
458 'glDrawElementsInstancedEXT',
461 interleaved_formats = [
474 'GL_T2F_C4F_N3F_V3F',
475 'GL_T4F_C4F_N3F_V4F',
478 def traceFunctionImplBody(self, function):
479 # Defer tracing of user array pointers...
480 if function.name in self.array_pointer_function_names:
481 print ' GLint _array_buffer = 0;'
482 print ' _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
483 print ' if (!_array_buffer) {'
484 print ' gltrace::Context *ctx = gltrace::getContext();'
485 print ' ctx->user_arrays = true;'
486 if function.name == "glVertexAttribPointerARB":
487 print ' ctx->user_arrays_arb = true;'
488 if function.name == "glVertexAttribPointerNV":
489 print ' ctx->user_arrays_nv = true;'
490 self.invokeFunction(function)
492 # And also break down glInterleavedArrays into the individual calls
493 if function.name == 'glInterleavedArrays':
496 # Initialize the enable flags
497 for camelcase_name, uppercase_name in self.arrays:
498 flag_name = '_' + uppercase_name.lower()
499 print ' GLboolean %s = GL_FALSE;' % flag_name
502 # Switch for the interleaved formats
503 print ' switch (format) {'
504 for format in self.interleaved_formats:
505 print ' case %s:' % format
506 for camelcase_name, uppercase_name in self.arrays:
507 flag_name = '_' + uppercase_name.lower()
508 if format.find('_' + uppercase_name[0]) >= 0:
509 print ' %s = GL_TRUE;' % flag_name
516 # Emit fake glEnableClientState/glDisableClientState flags
517 for camelcase_name, uppercase_name in self.arrays:
518 flag_name = '_' + uppercase_name.lower()
519 enable_name = 'GL_%s_ARRAY' % uppercase_name
521 # Emit a fake function
523 print ' static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
524 print ' unsigned _call = trace::localWriter.beginEnter(&_sig);'
525 print ' trace::localWriter.beginArg(0);'
526 self.serializeValue(glapi.GLenum, enable_name)
527 print ' trace::localWriter.endArg();'
528 print ' trace::localWriter.endEnter();'
529 print ' trace::localWriter.beginLeave(_call);'
530 print ' trace::localWriter.endLeave();'
536 # ... to the draw calls
537 if function.name in self.draw_function_names:
538 print ' if (_need_user_arrays()) {'
539 arg_names = ', '.join([arg.name for arg in function.args[1:]])
540 print ' GLuint _count = _%s_count(%s);' % (function.name, arg_names)
541 print ' _trace_user_arrays(_count);'
544 # Emit a fake memcpy on buffer uploads
545 if function.name == 'glBufferParameteriAPPLE':
546 print ' if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
547 print ' _checkBufferFlushingUnmapAPPLE = true;'
549 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
550 if function.name.endswith('ARB'):
554 print ' GLint access = 0;'
555 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
556 print ' if (access != GL_READ_ONLY) {'
557 print ' GLvoid *map = NULL;'
558 print ' _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);' % suffix
560 print ' GLint length = -1;'
561 print ' bool flush = true;'
562 print ' if (_checkBufferMapRange) {'
563 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
564 print ' GLint access_flags = 0;'
565 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
566 print ' flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
567 print ' if (length == -1) {'
568 print ' // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
569 print ' static bool warned = false;'
570 print ' if (!warned) {'
571 print ' os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
572 print ' warned = true;'
574 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
575 print ' if (mapping) {'
576 print ' length = mapping->length;'
577 print ' flush = flush && !mapping->explicit_flush;'
580 print ' flush = false;'
585 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
587 print ' if (_checkBufferFlushingUnmapAPPLE) {'
588 print ' GLint flushing_unmap = GL_TRUE;'
589 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
590 print ' flush = flush && flushing_unmap;'
592 print ' if (flush && length > 0) {'
593 self.emit_memcpy('map', 'map', 'length')
597 if function.name == 'glUnmapBufferOES':
598 print ' GLint access = 0;'
599 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
600 print ' if (access == GL_WRITE_ONLY_OES) {'
601 print ' GLvoid *map = NULL;'
602 print ' _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
603 print ' GLint size = 0;'
604 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
605 print ' if (map && size > 0) {'
606 self.emit_memcpy('map', 'map', 'size')
607 self.shadowBufferMethod('bufferSubData(0, size, map)')
610 if function.name == 'glUnmapNamedBufferEXT':
611 print ' GLint access_flags = 0;'
612 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
613 print ' if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
614 print ' GLvoid *map = NULL;'
615 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
616 print ' GLint length = 0;'
617 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
618 print ' if (map && length > 0) {'
619 self.emit_memcpy('map', 'map', 'length')
622 if function.name == 'glFlushMappedBufferRange':
623 print ' GLvoid *map = NULL;'
624 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
625 print ' if (map && length > 0) {'
626 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
628 if function.name == 'glFlushMappedBufferRangeAPPLE':
629 print ' GLvoid *map = NULL;'
630 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
631 print ' if (map && size > 0) {'
632 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
634 if function.name == 'glFlushMappedNamedBufferRangeEXT':
635 print ' GLvoid *map = NULL;'
636 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
637 print ' if (map && length > 0) {'
638 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
641 # Don't leave vertex attrib locations to chance. Instead emit fake
642 # glBindAttribLocation calls to ensure that the same locations will be
643 # used when retracing. Trying to remap locations after the fact would
644 # be an herculian task given that vertex attrib locations appear in
645 # many entry-points, including non-shader related ones.
646 if function.name == 'glLinkProgram':
647 Tracer.invokeFunction(self, function)
648 print ' GLint active_attributes = 0;'
649 print ' _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
650 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
651 print ' GLint size = 0;'
652 print ' GLenum type = 0;'
653 print ' GLchar name[256];'
654 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
655 print ' _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
656 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
657 print ' GLint location = _glGetAttribLocation(program, name);'
658 print ' if (location >= 0) {'
659 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
660 self.fake_call(bind_function, ['program', 'location', 'name'])
664 if function.name == 'glLinkProgramARB':
665 Tracer.invokeFunction(self, function)
666 print ' GLint active_attributes = 0;'
667 print ' _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
668 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
669 print ' GLint size = 0;'
670 print ' GLenum type = 0;'
671 print ' GLcharARB name[256];'
672 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
673 print ' _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
674 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
675 print ' GLint location = _glGetAttribLocationARB(programObj, name);'
676 print ' if (location >= 0) {'
677 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
678 self.fake_call(bind_function, ['programObj', 'location', 'name'])
683 self.shadowBufferProlog(function)
685 Tracer.traceFunctionImplBody(self, function)
688 # GL_GREMEDY_string_marker
689 'glStringMarkerGREMEDY',
690 # GL_GREMEDY_frame_terminator
691 'glFrameTerminatorGREMEDY',
692 # GL_EXT_debug_marker
693 'glInsertEventMarkerEXT',
694 'glPushGroupMarkerEXT',
695 'glPopGroupMarkerEXT',
698 def invokeFunction(self, function):
699 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
700 # These functions have been dispatched already
703 Tracer.invokeFunction(self, function)
705 def doInvokeFunction(self, function):
706 # Same as invokeFunction() but called both when trace is enabled or disabled.
708 # Used to modify the behavior of GL entry-points.
710 # Override GL extensions
711 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
712 Tracer.doInvokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
715 # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
717 if function.name in self.marker_functions:
720 if function.name in self.getProcAddressFunctionNames:
722 for marker_function in self.marker_functions:
723 if self.api.getFunctionByName(marker_function):
724 print ' %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
725 print ' _result = (%s)&%s;' % (function.type, marker_function)
729 Tracer.doInvokeFunction(self, function)
731 # Replace function addresses with ours
732 # XXX: Doing this here instead of wrapRet means that the trace will
733 # contain the addresses of the wrapper functions, and not the real
734 # functions, but in practice this should make no difference.
735 if function.name in self.getProcAddressFunctionNames:
736 print ' _result = _wrapProcAddress(%s, _result);' % (function.args[0].name,)
741 Tracer.doInvokeFunction(self, function)
745 'ELEMENT_ARRAY_BUFFER',
747 'PIXEL_UNPACK_BUFFER',
750 'TRANSFORM_FEEDBACK_BUFFER',
753 'DRAW_INDIRECT_BUFFER',
754 'ATOMIC_COUNTER_BUFFER',
757 def wrapRet(self, function, instance):
758 Tracer.wrapRet(self, function, instance)
760 # Keep track of buffer mappings
761 if function.name in ('glMapBuffer', 'glMapBufferARB'):
762 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
763 print ' if (mapping) {'
764 print ' mapping->map = %s;' % (instance)
765 print ' mapping->length = 0;'
766 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
767 print ' mapping->write = (access != GL_READ_ONLY);'
768 print ' mapping->explicit_flush = false;'
770 if function.name == 'glMapBufferRange':
771 print ' if (access & GL_MAP_WRITE_BIT) {'
772 print ' _checkBufferMapRange = true;'
774 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
775 print ' if (mapping) {'
776 print ' mapping->map = %s;' % (instance)
777 print ' mapping->length = length;'
778 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
779 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
787 def gl_boolean(self, value):
788 return self.boolean_names[int(bool(value))]
790 # Names of the functions that unpack from a pixel buffer object. See the
791 # ARB_pixel_buffer_object specification.
792 unpack_function_names = set([
796 'glCompressedMultiTexImage1DEXT',
797 'glCompressedMultiTexImage2DEXT',
798 'glCompressedMultiTexImage3DEXT',
799 'glCompressedMultiTexSubImage1DEXT',
800 'glCompressedMultiTexSubImage2DEXT',
801 'glCompressedMultiTexSubImage3DEXT',
802 'glCompressedTexImage1D',
803 'glCompressedTexImage2D',
804 'glCompressedTexImage3D',
805 'glCompressedTexSubImage1D',
806 'glCompressedTexSubImage2D',
807 'glCompressedTexSubImage3D',
808 'glCompressedTextureImage1DEXT',
809 'glCompressedTextureImage2DEXT',
810 'glCompressedTextureImage3DEXT',
811 'glCompressedTextureSubImage1DEXT',
812 'glCompressedTextureSubImage2DEXT',
813 'glCompressedTextureSubImage3DEXT',
814 'glConvolutionFilter1D',
815 'glConvolutionFilter2D',
817 'glMultiTexImage1DEXT',
818 'glMultiTexImage2DEXT',
819 'glMultiTexImage3DEXT',
820 'glMultiTexSubImage1DEXT',
821 'glMultiTexSubImage2DEXT',
822 'glMultiTexSubImage3DEXT',
827 'glSeparableFilter2D',
835 'glTexSubImage1DEXT',
837 'glTexSubImage2DEXT',
839 'glTexSubImage3DEXT',
840 'glTextureImage1DEXT',
841 'glTextureImage2DEXT',
842 'glTextureImage3DEXT',
843 'glTextureSubImage1DEXT',
844 'glTextureSubImage2DEXT',
845 'glTextureSubImage3DEXT',
848 def serializeArgValue(self, function, arg):
849 # Recognize offsets instead of blobs when a PBO is bound
850 if function.name in self.unpack_function_names \
851 and (isinstance(arg.type, stdapi.Blob) \
852 or (isinstance(arg.type, stdapi.Const) \
853 and isinstance(arg.type.type, stdapi.Blob))):
855 print ' gltrace::Context *ctx = gltrace::getContext();'
856 print ' GLint _unpack_buffer = 0;'
857 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
858 print ' _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
859 print ' if (_unpack_buffer) {'
860 print ' trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
862 Tracer.serializeArgValue(self, function, arg)
867 # Several GL state functions take GLenum symbolic names as
868 # integer/floats; so dump the symbolic name whenever possible
869 if function.name.startswith('gl') \
870 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
871 and arg.name == 'param':
873 assert function.args[arg.index - 1].name == 'pname'
874 assert function.args[arg.index - 1].type == glapi.GLenum
875 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
876 self.serializeValue(glapi.GLenum, arg.name)
878 Tracer.serializeArgValue(self, function, arg)
882 Tracer.serializeArgValue(self, function, arg)
884 def footer(self, api):
885 Tracer.footer(self, api)
887 # A simple state tracker to track the pointer values
889 print 'static void _trace_user_arrays(GLuint count)'
891 print ' gltrace::Context *ctx = gltrace::getContext();'
893 for camelcase_name, uppercase_name in self.arrays:
894 # in which profile is the array available?
895 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
896 if camelcase_name in self.arrays_es1:
897 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
899 function_name = 'gl%sPointer' % camelcase_name
900 enable_name = 'GL_%s_ARRAY' % uppercase_name
901 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
902 function = api.getFunctionByName(function_name)
904 print ' // %s' % function.prototype()
905 print ' if (%s) {' % profile_check
906 self.array_trace_prolog(api, uppercase_name)
907 self.array_prolog(api, uppercase_name)
908 print ' if (_glIsEnabled(%s)) {' % enable_name
909 print ' GLint _binding = 0;'
910 print ' _glGetIntegerv(%s, &_binding);' % binding_name
911 print ' if (!_binding) {'
913 # Get the arguments via glGet*
914 for arg in function.args:
915 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
916 arg_get_function, arg_type = TypeGetter().visit(arg.type)
917 print ' %s %s = 0;' % (arg_type, arg.name)
918 print ' _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
920 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
921 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
923 # Emit a fake function
924 self.array_trace_intermezzo(api, uppercase_name)
925 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
926 for arg in function.args:
927 assert not arg.output
928 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
929 if arg.name != 'pointer':
930 self.serializeValue(arg.type, arg.name)
932 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
933 print ' trace::localWriter.endArg();'
935 print ' trace::localWriter.endEnter();'
936 print ' trace::localWriter.beginLeave(_call);'
937 print ' trace::localWriter.endLeave();'
940 self.array_epilog(api, uppercase_name)
941 self.array_trace_epilog(api, uppercase_name)
945 # Samething, but for glVertexAttribPointer*
947 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
948 # - glVertexAttribPointer: no
949 # - glVertexAttribPointerARB: implementation dependent
950 # - glVertexAttribPointerNV: yes
952 # This means that the implementations of these functions do not always
953 # alias, and they need to be considered independently.
955 print ' // ES1 does not support generic vertex attributes'
956 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
959 print ' vertex_attrib _vertex_attrib = _get_vertex_attrib();'
961 for suffix in ['', 'ARB', 'NV']:
963 SUFFIX = '_' + suffix
966 function_name = 'glVertexAttribPointer' + suffix
967 function = api.getFunctionByName(function_name)
969 print ' // %s' % function.prototype()
970 print ' if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
972 print ' GLint _max_vertex_attribs = 16;'
974 print ' GLint _max_vertex_attribs = 0;'
975 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
976 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
977 print ' GLint _enabled = 0;'
979 print ' _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
981 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
982 print ' if (_enabled) {'
983 print ' GLint _binding = 0;'
985 # It doesn't seem possible to use VBOs with NV_vertex_program.
986 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
987 print ' if (!_binding) {'
989 # Get the arguments via glGet*
990 for arg in function.args[1:]:
992 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
994 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
995 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
996 print ' %s %s = 0;' % (arg_type, arg.name)
997 print ' _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
999 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
1000 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
1002 # Emit a fake function
1003 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1004 for arg in function.args:
1005 assert not arg.output
1006 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
1007 if arg.name != 'pointer':
1008 self.serializeValue(arg.type, arg.name)
1010 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
1011 print ' trace::localWriter.endArg();'
1013 print ' trace::localWriter.endEnter();'
1014 print ' trace::localWriter.beginLeave(_call);'
1015 print ' trace::localWriter.endLeave();'
1026 # Hooks for glTexCoordPointer, which is identical to the other array
1027 # pointers except the fact that it is indexed by glClientActiveTexture.
1030 def array_prolog(self, api, uppercase_name):
1031 if uppercase_name == 'TEXTURE_COORD':
1032 print ' GLint client_active_texture = 0;'
1033 print ' _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1034 print ' GLint max_texture_coords = 0;'
1035 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
1036 print ' _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1038 print ' _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1039 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1040 print ' GLint texture = GL_TEXTURE0 + unit;'
1041 print ' _glClientActiveTexture(texture);'
1043 def array_trace_prolog(self, api, uppercase_name):
1044 if uppercase_name == 'TEXTURE_COORD':
1045 print ' bool client_active_texture_dirty = false;'
1047 def array_epilog(self, api, uppercase_name):
1048 if uppercase_name == 'TEXTURE_COORD':
1050 self.array_cleanup(api, uppercase_name)
1052 def array_cleanup(self, api, uppercase_name):
1053 if uppercase_name == 'TEXTURE_COORD':
1054 print ' _glClientActiveTexture(client_active_texture);'
1056 def array_trace_intermezzo(self, api, uppercase_name):
1057 if uppercase_name == 'TEXTURE_COORD':
1058 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
1059 print ' client_active_texture_dirty = true;'
1060 self.fake_glClientActiveTexture_call(api, "texture");
1063 def array_trace_epilog(self, api, uppercase_name):
1064 if uppercase_name == 'TEXTURE_COORD':
1065 print ' if (client_active_texture_dirty) {'
1066 self.fake_glClientActiveTexture_call(api, "client_active_texture");
1069 def fake_glClientActiveTexture_call(self, api, texture):
1070 function = api.getFunctionByName('glClientActiveTexture')
1071 self.fake_call(function, [texture])
1073 def emitFakeTexture2D(self):
1074 function = glapi.glapi.getFunctionByName('glTexImage2D')
1075 instances = function.argNames()
1076 print ' unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1077 for arg in function.args:
1078 assert not arg.output
1079 self.serializeArg(function, arg)
1080 print ' trace::localWriter.endEnter();'
1081 print ' trace::localWriter.beginLeave(_fake_call);'
1082 print ' trace::localWriter.endLeave();'