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 %u;' % (name, count)
302 print ' case GL_COMPRESSED_TEXTURE_FORMATS: {'
303 print ' GLint num_compressed_texture_formats = 0;'
304 print ' _glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
305 print ' return num_compressed_texture_formats;'
308 print r' os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
314 # states such as GL_UNPACK_ROW_LENGTH are not available in GLES
315 print 'static inline bool'
316 print 'can_unpack_subimage(void) {'
317 print ' gltrace::Context *ctx = gltrace::getContext();'
318 print ' return (ctx->profile == gltrace::PROFILE_COMPAT);'
322 getProcAddressFunctionNames = []
324 def traceApi(self, api):
325 if self.getProcAddressFunctionNames:
326 # Generate a function to wrap proc addresses
327 getProcAddressFunction = api.getFunctionByName(self.getProcAddressFunctionNames[0])
328 argType = getProcAddressFunction.args[0].type
329 retType = getProcAddressFunction.type
331 print 'static %s _wrapProcAddress(%s procName, %s procPtr);' % (retType, argType, retType)
334 Tracer.traceApi(self, api)
336 print 'static %s _wrapProcAddress(%s procName, %s procPtr) {' % (retType, argType, retType)
337 print ' if (!procPtr) {'
338 print ' return procPtr;'
340 for function in api.getAllFunctions():
341 ptype = function_pointer_type(function)
342 pvalue = function_pointer_value(function)
343 print ' if (strcmp("%s", (const char *)procName) == 0) {' % function.name
344 print ' %s = (%s)procPtr;' % (pvalue, ptype)
345 print ' return (%s)&%s;' % (retType, function.name,)
347 print ' os::log("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);'
348 print ' return procPtr;'
352 Tracer.traceApi(self, api)
354 def defineShadowBufferHelper(self):
355 print 'void _shadow_glGetBufferSubData(GLenum target, GLintptr offset,'
356 print ' GLsizeiptr size, GLvoid *data)'
358 print ' gltrace::Context *ctx = gltrace::getContext();'
359 print ' if (!ctx->needsShadowBuffers() || target != GL_ELEMENT_ARRAY_BUFFER) {'
360 print ' _glGetBufferSubData(target, offset, size, data);'
364 print ' GLint buffer_binding = 0;'
365 print ' _glGetIntegerv(target, &buffer_binding);'
366 print ' if (buffer_binding > 0) {'
367 print ' gltrace::Buffer & buf = ctx->buffers[buffer_binding];'
368 print ' buf.getSubData(offset, size, data);'
372 def shadowBufferMethod(self, method):
373 # Emit code to fetch the shadow buffer, and invoke a method
374 print ' gltrace::Context *ctx = gltrace::getContext();'
375 print ' if (ctx->needsShadowBuffers() && target == GL_ELEMENT_ARRAY_BUFFER) {'
376 print ' GLint buffer_binding = 0;'
377 print ' _glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buffer_binding);'
378 print ' if (buffer_binding > 0) {'
379 print ' gltrace::Buffer & buf = ctx->buffers[buffer_binding];'
380 print ' buf.' + method + ';'
385 def shadowBufferProlog(self, function):
386 if function.name == 'glBufferData':
387 self.shadowBufferMethod('bufferData(size, data)')
389 if function.name == 'glBufferSubData':
390 self.shadowBufferMethod('bufferSubData(offset, size, data)')
392 if function.name == 'glDeleteBuffers':
393 print ' gltrace::Context *ctx = gltrace::getContext();'
394 print ' if (ctx->needsShadowBuffers()) {'
395 print ' for (GLsizei i = 0; i < n; i++) {'
396 print ' ctx->buffers.erase(buffer[i]);'
400 array_pointer_function_names = set((
408 "glSecondaryColorPointer",
410 "glInterleavedArrays",
412 "glVertexPointerEXT",
413 "glNormalPointerEXT",
416 "glTexCoordPointerEXT",
417 "glEdgeFlagPointerEXT",
418 "glFogCoordPointerEXT",
419 "glSecondaryColorPointerEXT",
421 "glVertexAttribPointer",
422 "glVertexAttribPointerARB",
423 "glVertexAttribPointerNV",
424 "glVertexAttribIPointer",
425 "glVertexAttribIPointerEXT",
426 "glVertexAttribLPointer",
427 "glVertexAttribLPointerEXT",
429 #"glMatrixIndexPointerARB",
432 draw_function_names = set((
435 'glDrawRangeElements',
437 'glMultiDrawElements',
438 'glDrawArraysInstanced',
439 "glDrawArraysInstancedBaseInstance",
440 'glDrawElementsInstanced',
441 'glDrawArraysInstancedARB',
442 'glDrawElementsInstancedARB',
443 'glDrawElementsBaseVertex',
444 'glDrawRangeElementsBaseVertex',
445 'glDrawElementsInstancedBaseVertex',
446 "glDrawElementsInstancedBaseInstance",
447 "glDrawElementsInstancedBaseVertexBaseInstance",
448 'glMultiDrawElementsBaseVertex',
449 'glDrawArraysIndirect',
450 'glDrawElementsIndirect',
452 'glDrawRangeElementsEXT',
453 'glDrawRangeElementsEXT_size',
454 'glMultiDrawArraysEXT',
455 'glMultiDrawElementsEXT',
456 'glMultiModeDrawArraysIBM',
457 'glMultiModeDrawElementsIBM',
458 'glDrawArraysInstancedEXT',
459 'glDrawElementsInstancedEXT',
462 interleaved_formats = [
475 'GL_T2F_C4F_N3F_V3F',
476 'GL_T4F_C4F_N3F_V4F',
479 def traceFunctionImplBody(self, function):
480 # Defer tracing of user array pointers...
481 if function.name in self.array_pointer_function_names:
482 print ' GLint _array_buffer = 0;'
483 print ' _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
484 print ' if (!_array_buffer) {'
485 print ' gltrace::Context *ctx = gltrace::getContext();'
486 print ' ctx->user_arrays = true;'
487 if function.name == "glVertexAttribPointerARB":
488 print ' ctx->user_arrays_arb = true;'
489 if function.name == "glVertexAttribPointerNV":
490 print ' ctx->user_arrays_nv = true;'
491 self.invokeFunction(function)
493 # And also break down glInterleavedArrays into the individual calls
494 if function.name == 'glInterleavedArrays':
497 # Initialize the enable flags
498 for camelcase_name, uppercase_name in self.arrays:
499 flag_name = '_' + uppercase_name.lower()
500 print ' GLboolean %s = GL_FALSE;' % flag_name
503 # Switch for the interleaved formats
504 print ' switch (format) {'
505 for format in self.interleaved_formats:
506 print ' case %s:' % format
507 for camelcase_name, uppercase_name in self.arrays:
508 flag_name = '_' + uppercase_name.lower()
509 if format.find('_' + uppercase_name[0]) >= 0:
510 print ' %s = GL_TRUE;' % flag_name
517 # Emit fake glEnableClientState/glDisableClientState flags
518 for camelcase_name, uppercase_name in self.arrays:
519 flag_name = '_' + uppercase_name.lower()
520 enable_name = 'GL_%s_ARRAY' % uppercase_name
522 # Emit a fake function
524 print ' static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
525 print ' unsigned _call = trace::localWriter.beginEnter(&_sig);'
526 print ' trace::localWriter.beginArg(0);'
527 self.serializeValue(glapi.GLenum, enable_name)
528 print ' trace::localWriter.endArg();'
529 print ' trace::localWriter.endEnter();'
530 print ' trace::localWriter.beginLeave(_call);'
531 print ' trace::localWriter.endLeave();'
537 # ... to the draw calls
538 if function.name in self.draw_function_names:
539 print ' if (_need_user_arrays()) {'
540 arg_names = ', '.join([arg.name for arg in function.args[1:]])
541 print ' GLuint _count = _%s_count(%s);' % (function.name, arg_names)
542 print ' _trace_user_arrays(_count);'
545 # Emit a fake memcpy on buffer uploads
546 if function.name == 'glBufferParameteriAPPLE':
547 print ' if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
548 print ' _checkBufferFlushingUnmapAPPLE = true;'
550 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
551 if function.name.endswith('ARB'):
555 print ' GLint access = 0;'
556 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
557 print ' if (access != GL_READ_ONLY) {'
558 print ' GLvoid *map = NULL;'
559 print ' _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);' % suffix
561 print ' GLint length = -1;'
562 print ' bool flush = true;'
563 print ' if (_checkBufferMapRange) {'
564 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
565 print ' GLint access_flags = 0;'
566 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
567 print ' flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
568 print ' if (length == -1) {'
569 print ' // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
570 print ' static bool warned = false;'
571 print ' if (!warned) {'
572 print ' os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
573 print ' warned = true;'
575 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
576 print ' if (mapping) {'
577 print ' length = mapping->length;'
578 print ' flush = flush && !mapping->explicit_flush;'
581 print ' flush = false;'
586 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
588 print ' if (_checkBufferFlushingUnmapAPPLE) {'
589 print ' GLint flushing_unmap = GL_TRUE;'
590 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
591 print ' flush = flush && flushing_unmap;'
593 print ' if (flush && length > 0) {'
594 self.emit_memcpy('map', 'map', 'length')
598 if function.name == 'glUnmapBufferOES':
599 print ' GLint access = 0;'
600 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
601 print ' if (access == GL_WRITE_ONLY_OES) {'
602 print ' GLvoid *map = NULL;'
603 print ' _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
604 print ' GLint size = 0;'
605 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
606 print ' if (map && size > 0) {'
607 self.emit_memcpy('map', 'map', 'size')
608 self.shadowBufferMethod('bufferSubData(0, size, map)')
611 if function.name == 'glUnmapNamedBufferEXT':
612 print ' GLint access_flags = 0;'
613 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
614 print ' if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
615 print ' GLvoid *map = NULL;'
616 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
617 print ' GLint length = 0;'
618 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
619 print ' if (map && length > 0) {'
620 self.emit_memcpy('map', 'map', 'length')
623 if function.name == 'glFlushMappedBufferRange':
624 print ' GLvoid *map = NULL;'
625 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
626 print ' if (map && length > 0) {'
627 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
629 if function.name == 'glFlushMappedBufferRangeAPPLE':
630 print ' GLvoid *map = NULL;'
631 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
632 print ' if (map && size > 0) {'
633 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
635 if function.name == 'glFlushMappedNamedBufferRangeEXT':
636 print ' GLvoid *map = NULL;'
637 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
638 print ' if (map && length > 0) {'
639 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
642 # Don't leave vertex attrib locations to chance. Instead emit fake
643 # glBindAttribLocation calls to ensure that the same locations will be
644 # used when retracing. Trying to remap locations after the fact would
645 # be an herculian task given that vertex attrib locations appear in
646 # many entry-points, including non-shader related ones.
647 if function.name == 'glLinkProgram':
648 Tracer.invokeFunction(self, function)
649 print ' GLint active_attributes = 0;'
650 print ' _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
651 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
652 print ' GLint size = 0;'
653 print ' GLenum type = 0;'
654 print ' GLchar name[256];'
655 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
656 print ' _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
657 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
658 print ' GLint location = _glGetAttribLocation(program, name);'
659 print ' if (location >= 0) {'
660 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
661 self.fake_call(bind_function, ['program', 'location', 'name'])
665 if function.name == 'glLinkProgramARB':
666 Tracer.invokeFunction(self, function)
667 print ' GLint active_attributes = 0;'
668 print ' _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
669 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
670 print ' GLint size = 0;'
671 print ' GLenum type = 0;'
672 print ' GLcharARB name[256];'
673 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
674 print ' _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
675 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
676 print ' GLint location = _glGetAttribLocationARB(programObj, name);'
677 print ' if (location >= 0) {'
678 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
679 self.fake_call(bind_function, ['programObj', 'location', 'name'])
684 self.shadowBufferProlog(function)
686 Tracer.traceFunctionImplBody(self, function)
689 # GL_GREMEDY_string_marker
690 'glStringMarkerGREMEDY',
691 # GL_GREMEDY_frame_terminator
692 'glFrameTerminatorGREMEDY',
693 # GL_EXT_debug_marker
694 'glInsertEventMarkerEXT',
695 'glPushGroupMarkerEXT',
696 'glPopGroupMarkerEXT',
699 def invokeFunction(self, function):
700 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
701 # These functions have been dispatched already
704 # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
706 if function.name in self.marker_functions:
709 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
711 for marker_function in self.marker_functions:
712 if self.api.getFunctionByName(marker_function):
713 print ' %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
714 print ' _result = (%s)&%s;' % (function.type, marker_function)
718 Tracer.invokeFunction(self, function)
722 # Override GL extensions
723 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
724 Tracer.invokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
727 Tracer.invokeFunction(self, function)
731 'ELEMENT_ARRAY_BUFFER',
733 'PIXEL_UNPACK_BUFFER',
736 'TRANSFORM_FEEDBACK_BUFFER',
739 'DRAW_INDIRECT_BUFFER',
740 'ATOMIC_COUNTER_BUFFER',
743 def wrapRet(self, function, instance):
744 Tracer.wrapRet(self, function, instance)
746 # Replace function addresses with ours
747 if function.name in self.getProcAddressFunctionNames:
748 print ' %s = _wrapProcAddress(%s, %s);' % (instance, function.args[0].name, instance)
750 # Keep track of buffer mappings
751 if function.name in ('glMapBuffer', 'glMapBufferARB'):
752 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
753 print ' if (mapping) {'
754 print ' mapping->map = %s;' % (instance)
755 print ' mapping->length = 0;'
756 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
757 print ' mapping->write = (access != GL_READ_ONLY);'
758 print ' mapping->explicit_flush = false;'
760 if function.name == 'glMapBufferRange':
761 print ' if (access & GL_MAP_WRITE_BIT) {'
762 print ' _checkBufferMapRange = true;'
764 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
765 print ' if (mapping) {'
766 print ' mapping->map = %s;' % (instance)
767 print ' mapping->length = length;'
768 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
769 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
777 def gl_boolean(self, value):
778 return self.boolean_names[int(bool(value))]
780 # Names of the functions that unpack from a pixel buffer object. See the
781 # ARB_pixel_buffer_object specification.
782 unpack_function_names = set([
786 'glCompressedTexImage1D',
787 'glCompressedTexImage2D',
788 'glCompressedTexImage3D',
789 'glCompressedTexSubImage1D',
790 'glCompressedTexSubImage2D',
791 'glCompressedTexSubImage3D',
792 'glConvolutionFilter1D',
793 'glConvolutionFilter2D',
795 'glMultiTexImage1DEXT',
796 'glMultiTexImage2DEXT',
797 'glMultiTexImage3DEXT',
798 'glMultiTexSubImage1DEXT',
799 'glMultiTexSubImage2DEXT',
800 'glMultiTexSubImage3DEXT',
805 'glSeparableFilter2D',
813 'glTexSubImage1DEXT',
815 'glTexSubImage2DEXT',
817 'glTexSubImage3DEXT',
818 'glTextureImage1DEXT',
819 'glTextureImage2DEXT',
820 'glTextureImage3DEXT',
821 'glTextureSubImage1DEXT',
822 'glTextureSubImage2DEXT',
823 'glTextureSubImage3DEXT',
826 def serializeArgValue(self, function, arg):
827 # Recognize offsets instead of blobs when a PBO is bound
828 if function.name in self.unpack_function_names \
829 and (isinstance(arg.type, stdapi.Blob) \
830 or (isinstance(arg.type, stdapi.Const) \
831 and isinstance(arg.type.type, stdapi.Blob))):
833 print ' gltrace::Context *ctx = gltrace::getContext();'
834 print ' GLint _unpack_buffer = 0;'
835 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
836 print ' _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
837 print ' if (_unpack_buffer) {'
838 print ' trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
840 Tracer.serializeArgValue(self, function, arg)
845 # Several GL state functions take GLenum symbolic names as
846 # integer/floats; so dump the symbolic name whenever possible
847 if function.name.startswith('gl') \
848 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
849 and arg.name == 'param':
851 assert function.args[arg.index - 1].name == 'pname'
852 assert function.args[arg.index - 1].type == glapi.GLenum
853 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
854 self.serializeValue(glapi.GLenum, arg.name)
856 Tracer.serializeArgValue(self, function, arg)
860 Tracer.serializeArgValue(self, function, arg)
862 def footer(self, api):
863 Tracer.footer(self, api)
865 # A simple state tracker to track the pointer values
867 print 'static void _trace_user_arrays(GLuint count)'
869 print ' gltrace::Context *ctx = gltrace::getContext();'
871 for camelcase_name, uppercase_name in self.arrays:
872 # in which profile is the array available?
873 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
874 if camelcase_name in self.arrays_es1:
875 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
877 function_name = 'gl%sPointer' % camelcase_name
878 enable_name = 'GL_%s_ARRAY' % uppercase_name
879 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
880 function = api.getFunctionByName(function_name)
882 print ' // %s' % function.prototype()
883 print ' if (%s) {' % profile_check
884 self.array_trace_prolog(api, uppercase_name)
885 self.array_prolog(api, uppercase_name)
886 print ' if (_glIsEnabled(%s)) {' % enable_name
887 print ' GLint _binding = 0;'
888 print ' _glGetIntegerv(%s, &_binding);' % binding_name
889 print ' if (!_binding) {'
891 # Get the arguments via glGet*
892 for arg in function.args:
893 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
894 arg_get_function, arg_type = TypeGetter().visit(arg.type)
895 print ' %s %s = 0;' % (arg_type, arg.name)
896 print ' _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
898 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
899 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
901 # Emit a fake function
902 self.array_trace_intermezzo(api, uppercase_name)
903 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
904 for arg in function.args:
905 assert not arg.output
906 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
907 if arg.name != 'pointer':
908 self.serializeValue(arg.type, arg.name)
910 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
911 print ' trace::localWriter.endArg();'
913 print ' trace::localWriter.endEnter();'
914 print ' trace::localWriter.beginLeave(_call);'
915 print ' trace::localWriter.endLeave();'
918 self.array_epilog(api, uppercase_name)
919 self.array_trace_epilog(api, uppercase_name)
923 # Samething, but for glVertexAttribPointer*
925 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
926 # - glVertexAttribPointer: no
927 # - glVertexAttribPointerARB: implementation dependent
928 # - glVertexAttribPointerNV: yes
930 # This means that the implementations of these functions do not always
931 # alias, and they need to be considered independently.
933 print ' // ES1 does not support generic vertex attributes'
934 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
937 print ' vertex_attrib _vertex_attrib = _get_vertex_attrib();'
939 for suffix in ['', 'ARB', 'NV']:
941 SUFFIX = '_' + suffix
944 function_name = 'glVertexAttribPointer' + suffix
945 function = api.getFunctionByName(function_name)
947 print ' // %s' % function.prototype()
948 print ' if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
950 print ' GLint _max_vertex_attribs = 16;'
952 print ' GLint _max_vertex_attribs = 0;'
953 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
954 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
955 print ' GLint _enabled = 0;'
957 print ' _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
959 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
960 print ' if (_enabled) {'
961 print ' GLint _binding = 0;'
963 # It doesn't seem possible to use VBOs with NV_vertex_program.
964 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
965 print ' if (!_binding) {'
967 # Get the arguments via glGet*
968 for arg in function.args[1:]:
970 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
972 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
973 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
974 print ' %s %s = 0;' % (arg_type, arg.name)
975 print ' _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
977 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
978 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
980 # Emit a fake function
981 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
982 for arg in function.args:
983 assert not arg.output
984 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
985 if arg.name != 'pointer':
986 self.serializeValue(arg.type, arg.name)
988 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
989 print ' trace::localWriter.endArg();'
991 print ' trace::localWriter.endEnter();'
992 print ' trace::localWriter.beginLeave(_call);'
993 print ' trace::localWriter.endLeave();'
1004 # Hooks for glTexCoordPointer, which is identical to the other array
1005 # pointers except the fact that it is indexed by glClientActiveTexture.
1008 def array_prolog(self, api, uppercase_name):
1009 if uppercase_name == 'TEXTURE_COORD':
1010 print ' GLint client_active_texture = 0;'
1011 print ' _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1012 print ' GLint max_texture_coords = 0;'
1013 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
1014 print ' _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1016 print ' _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1017 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1018 print ' GLint texture = GL_TEXTURE0 + unit;'
1019 print ' _glClientActiveTexture(texture);'
1021 def array_trace_prolog(self, api, uppercase_name):
1022 if uppercase_name == 'TEXTURE_COORD':
1023 print ' bool client_active_texture_dirty = false;'
1025 def array_epilog(self, api, uppercase_name):
1026 if uppercase_name == 'TEXTURE_COORD':
1028 self.array_cleanup(api, uppercase_name)
1030 def array_cleanup(self, api, uppercase_name):
1031 if uppercase_name == 'TEXTURE_COORD':
1032 print ' _glClientActiveTexture(client_active_texture);'
1034 def array_trace_intermezzo(self, api, uppercase_name):
1035 if uppercase_name == 'TEXTURE_COORD':
1036 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
1037 print ' client_active_texture_dirty = true;'
1038 self.fake_glClientActiveTexture_call(api, "texture");
1041 def array_trace_epilog(self, api, uppercase_name):
1042 if uppercase_name == 'TEXTURE_COORD':
1043 print ' if (client_active_texture_dirty) {'
1044 self.fake_glClientActiveTexture_call(api, "client_active_texture");
1047 def fake_glClientActiveTexture_call(self, api, texture):
1048 function = api.getFunctionByName('glClientActiveTexture')
1049 self.fake_call(function, [texture])