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.functions:
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 ' struct gltrace::Context *ctx = gltrace::getContext();'
359 print ' if (!ctx->needsShadowBuffers() || target != GL_ELEMENT_ARRAY_BUFFER) {'
360 print ' glGetBufferSubData(target, offset, size, data);'
364 print ' struct gltrace::Buffer *buf;'
365 print ' GLint buf_id;'
367 print ' glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buf_id);'
368 print ' buf = ctx->buffers[buf_id];'
369 print ' assert(size + offset <= buf->size);'
370 print ' memcpy(data, (uint8_t *)buf->data + offset, size);'
373 def shadowBufferProlog(self, function):
374 if function.name == 'glBufferData':
375 print ' gltrace::Context *ctx = gltrace::getContext();'
376 print ' if (ctx->needsShadowBuffers() && target == GL_ELEMENT_ARRAY_BUFFER) {'
377 print ' struct gltrace::Buffer *buf;'
378 print ' GLint buf_id;'
380 print ' glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buf_id);'
381 print ' buf = ctx->buffers[buf_id];'
382 print ' buf->resetData(data, size);'
386 if function.name == 'glBufferSubData':
387 print ' gltrace::Context *ctx = gltrace::getContext();'
388 print ' if (ctx->needsShadowBuffers() && target == GL_ELEMENT_ARRAY_BUFFER) {'
389 print ' struct gltrace::Buffer *buf;'
390 print ' GLint buf_id;'
392 print ' glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buf_id);'
393 print ' buf = ctx->buffers[buf_id];'
394 print ' memcpy((uint8_t *)buf->data + offset, data, size);'
398 if function.name == 'glDeleteBuffers':
399 print ' gltrace::Context *ctx = gltrace::getContext();'
400 print ' if (ctx->needsShadowBuffers()) {'
403 print ' for (i = 0; i < n; i++) {'
404 print ' unsigned long buf_id;'
405 print ' struct gltrace::Buffer *buf;'
407 print ' buf_id = buffer[i];'
408 print ' buf = ctx->buffers[buf_id];'
410 print ' ctx->buffers.erase(buf_id);'
416 def shadowBufferEpilog(self, function):
417 if function.name == 'glGenBuffers':
418 print ' gltrace::Context *ctx = gltrace::getContext();'
419 print ' if (ctx->needsShadowBuffers()) {'
421 print ' for (i = 0; i < n; i++) {'
422 print ' GLuint buf_id = buffer[i];'
423 print ' ctx->buffers[buf_id] = new gltrace::Buffer;'
429 array_pointer_function_names = set((
437 "glSecondaryColorPointer",
439 "glInterleavedArrays",
441 "glVertexPointerEXT",
442 "glNormalPointerEXT",
445 "glTexCoordPointerEXT",
446 "glEdgeFlagPointerEXT",
447 "glFogCoordPointerEXT",
448 "glSecondaryColorPointerEXT",
450 "glVertexAttribPointer",
451 "glVertexAttribPointerARB",
452 "glVertexAttribPointerNV",
453 "glVertexAttribIPointer",
454 "glVertexAttribIPointerEXT",
455 "glVertexAttribLPointer",
456 "glVertexAttribLPointerEXT",
458 #"glMatrixIndexPointerARB",
461 draw_function_names = set((
464 'glDrawRangeElements',
466 'glMultiDrawElements',
467 'glDrawArraysInstanced',
468 "glDrawArraysInstancedBaseInstance",
469 'glDrawElementsInstanced',
470 'glDrawArraysInstancedARB',
471 'glDrawElementsInstancedARB',
472 'glDrawElementsBaseVertex',
473 'glDrawRangeElementsBaseVertex',
474 'glDrawElementsInstancedBaseVertex',
475 "glDrawElementsInstancedBaseInstance",
476 "glDrawElementsInstancedBaseVertexBaseInstance",
477 'glMultiDrawElementsBaseVertex',
478 'glDrawArraysIndirect',
479 'glDrawElementsIndirect',
481 'glDrawRangeElementsEXT',
482 'glDrawRangeElementsEXT_size',
483 'glMultiDrawArraysEXT',
484 'glMultiDrawElementsEXT',
485 'glMultiModeDrawArraysIBM',
486 'glMultiModeDrawElementsIBM',
487 'glDrawArraysInstancedEXT',
488 'glDrawElementsInstancedEXT',
491 interleaved_formats = [
504 'GL_T2F_C4F_N3F_V3F',
505 'GL_T4F_C4F_N3F_V4F',
508 def traceFunctionImplBody(self, function):
509 # Defer tracing of user array pointers...
510 if function.name in self.array_pointer_function_names:
511 print ' GLint _array_buffer = 0;'
512 print ' _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
513 print ' if (!_array_buffer) {'
514 print ' gltrace::Context *ctx = gltrace::getContext();'
515 print ' ctx->user_arrays = true;'
516 if function.name == "glVertexAttribPointerARB":
517 print ' ctx->user_arrays_arb = true;'
518 if function.name == "glVertexAttribPointerNV":
519 print ' ctx->user_arrays_nv = true;'
520 self.invokeFunction(function)
522 # And also break down glInterleavedArrays into the individual calls
523 if function.name == 'glInterleavedArrays':
526 # Initialize the enable flags
527 for camelcase_name, uppercase_name in self.arrays:
528 flag_name = '_' + uppercase_name.lower()
529 print ' GLboolean %s = GL_FALSE;' % flag_name
532 # Switch for the interleaved formats
533 print ' switch (format) {'
534 for format in self.interleaved_formats:
535 print ' case %s:' % format
536 for camelcase_name, uppercase_name in self.arrays:
537 flag_name = '_' + uppercase_name.lower()
538 if format.find('_' + uppercase_name[0]) >= 0:
539 print ' %s = GL_TRUE;' % flag_name
546 # Emit fake glEnableClientState/glDisableClientState flags
547 for camelcase_name, uppercase_name in self.arrays:
548 flag_name = '_' + uppercase_name.lower()
549 enable_name = 'GL_%s_ARRAY' % uppercase_name
551 # Emit a fake function
553 print ' static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
554 print ' unsigned _call = trace::localWriter.beginEnter(&_sig);'
555 print ' trace::localWriter.beginArg(0);'
556 self.serializeValue(glapi.GLenum, enable_name)
557 print ' trace::localWriter.endArg();'
558 print ' trace::localWriter.endEnter();'
559 print ' trace::localWriter.beginLeave(_call);'
560 print ' trace::localWriter.endLeave();'
566 # ... to the draw calls
567 if function.name in self.draw_function_names:
568 print ' if (_need_user_arrays()) {'
569 arg_names = ', '.join([arg.name for arg in function.args[1:]])
570 print ' GLuint _count = _%s_count(%s);' % (function.name, arg_names)
571 print ' _trace_user_arrays(_count);'
574 # Emit a fake memcpy on buffer uploads
575 if function.name == 'glBufferParameteriAPPLE':
576 print ' if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
577 print ' _checkBufferFlushingUnmapAPPLE = true;'
579 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
580 if function.name.endswith('ARB'):
584 print ' GLint access = 0;'
585 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
586 print ' if (access != GL_READ_ONLY) {'
587 print ' GLvoid *map = NULL;'
588 print ' _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);' % suffix
590 print ' GLint length = -1;'
591 print ' bool flush = true;'
592 print ' if (_checkBufferMapRange) {'
593 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
594 print ' GLint access_flags = 0;'
595 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
596 print ' flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
597 print ' if (length == -1) {'
598 print ' // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
599 print ' static bool warned = false;'
600 print ' if (!warned) {'
601 print ' os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
602 print ' warned = true;'
604 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
605 print ' if (mapping) {'
606 print ' length = mapping->length;'
607 print ' flush = flush && !mapping->explicit_flush;'
610 print ' flush = false;'
615 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
617 print ' if (_checkBufferFlushingUnmapAPPLE) {'
618 print ' GLint flushing_unmap = GL_TRUE;'
619 print ' _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
620 print ' flush = flush && flushing_unmap;'
622 print ' if (flush && length > 0) {'
623 self.emit_memcpy('map', 'map', 'length')
627 if function.name == 'glUnmapBufferOES':
628 print ' GLint access = 0;'
629 print ' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
630 print ' if (access == GL_WRITE_ONLY_OES) {'
631 print ' GLvoid *map = NULL;'
632 print ' _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
633 print ' GLint size = 0;'
634 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
635 print ' if (map && size > 0) {'
636 self.emit_memcpy('map', 'map', 'size')
639 if function.name == 'glUnmapNamedBufferEXT':
640 print ' GLint access_flags = 0;'
641 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
642 print ' if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
643 print ' GLvoid *map = NULL;'
644 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
645 print ' GLint length = 0;'
646 print ' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
647 print ' if (map && length > 0) {'
648 self.emit_memcpy('map', 'map', 'length')
651 if function.name == 'glFlushMappedBufferRange':
652 print ' GLvoid *map = NULL;'
653 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
654 print ' if (map && length > 0) {'
655 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
657 if function.name == 'glFlushMappedBufferRangeAPPLE':
658 print ' GLvoid *map = NULL;'
659 print ' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
660 print ' if (map && size > 0) {'
661 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
663 if function.name == 'glFlushMappedNamedBufferRangeEXT':
664 print ' GLvoid *map = NULL;'
665 print ' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
666 print ' if (map && length > 0) {'
667 self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
670 # Don't leave vertex attrib locations to chance. Instead emit fake
671 # glBindAttribLocation calls to ensure that the same locations will be
672 # used when retracing. Trying to remap locations after the fact would
673 # be an herculian task given that vertex attrib locations appear in
674 # many entry-points, including non-shader related ones.
675 if function.name == 'glLinkProgram':
676 Tracer.invokeFunction(self, function)
677 print ' GLint active_attributes = 0;'
678 print ' _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
679 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
680 print ' GLint size = 0;'
681 print ' GLenum type = 0;'
682 print ' GLchar name[256];'
683 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
684 print ' _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
685 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
686 print ' GLint location = _glGetAttribLocation(program, name);'
687 print ' if (location >= 0) {'
688 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
689 self.fake_call(bind_function, ['program', 'location', 'name'])
693 if function.name == 'glLinkProgramARB':
694 Tracer.invokeFunction(self, function)
695 print ' GLint active_attributes = 0;'
696 print ' _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
697 print ' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
698 print ' GLint size = 0;'
699 print ' GLenum type = 0;'
700 print ' GLcharARB name[256];'
701 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
702 print ' _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
703 print " if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
704 print ' GLint location = _glGetAttribLocationARB(programObj, name);'
705 print ' if (location >= 0) {'
706 bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
707 self.fake_call(bind_function, ['programObj', 'location', 'name'])
712 self.shadowBufferProlog(function)
714 Tracer.traceFunctionImplBody(self, function)
716 self.shadowBufferEpilog(function)
719 # GL_GREMEDY_string_marker
720 'glStringMarkerGREMEDY',
721 # GL_GREMEDY_frame_terminator
722 'glFrameTerminatorGREMEDY',
723 # GL_EXT_debug_marker
724 'glInsertEventMarkerEXT',
725 'glPushGroupMarkerEXT',
726 'glPopGroupMarkerEXT',
729 def invokeFunction(self, function):
730 if function.name in ('glLinkProgram', 'glLinkProgramARB'):
731 # These functions have been dispatched already
734 # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
736 if function.name in self.marker_functions:
739 if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
741 for marker_function in self.marker_functions:
742 if self.api.getFunctionByName(marker_function):
743 print ' %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
744 print ' _result = (%s)&%s;' % (function.type, marker_function)
748 Tracer.invokeFunction(self, function)
752 # Override GL extensions
753 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
754 Tracer.invokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
757 Tracer.invokeFunction(self, function)
761 'ELEMENT_ARRAY_BUFFER',
763 'PIXEL_UNPACK_BUFFER',
766 'TRANSFORM_FEEDBACK_BUFFER',
769 'DRAW_INDIRECT_BUFFER',
770 'ATOMIC_COUNTER_BUFFER',
773 def wrapRet(self, function, instance):
774 Tracer.wrapRet(self, function, instance)
776 # Replace function addresses with ours
777 if function.name in self.getProcAddressFunctionNames:
778 print ' %s = _wrapProcAddress(%s, %s);' % (instance, function.args[0].name, instance)
780 # Keep track of buffer mappings
781 if function.name in ('glMapBuffer', 'glMapBufferARB'):
782 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
783 print ' if (mapping) {'
784 print ' mapping->map = %s;' % (instance)
785 print ' mapping->length = 0;'
786 print ' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
787 print ' mapping->write = (access != GL_READ_ONLY);'
788 print ' mapping->explicit_flush = false;'
790 if function.name == 'glMapBufferRange':
791 print ' if (access & GL_MAP_WRITE_BIT) {'
792 print ' _checkBufferMapRange = true;'
794 print ' struct buffer_mapping *mapping = get_buffer_mapping(target);'
795 print ' if (mapping) {'
796 print ' mapping->map = %s;' % (instance)
797 print ' mapping->length = length;'
798 print ' mapping->write = access & GL_MAP_WRITE_BIT;'
799 print ' mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
807 def gl_boolean(self, value):
808 return self.boolean_names[int(bool(value))]
810 # Names of the functions that unpack from a pixel buffer object. See the
811 # ARB_pixel_buffer_object specification.
812 unpack_function_names = set([
816 'glCompressedTexImage1D',
817 'glCompressedTexImage2D',
818 'glCompressedTexImage3D',
819 'glCompressedTexSubImage1D',
820 'glCompressedTexSubImage2D',
821 'glCompressedTexSubImage3D',
822 'glConvolutionFilter1D',
823 'glConvolutionFilter2D',
825 'glMultiTexImage1DEXT',
826 'glMultiTexImage2DEXT',
827 'glMultiTexImage3DEXT',
828 'glMultiTexSubImage1DEXT',
829 'glMultiTexSubImage2DEXT',
830 'glMultiTexSubImage3DEXT',
835 'glSeparableFilter2D',
843 'glTexSubImage1DEXT',
845 'glTexSubImage2DEXT',
847 'glTexSubImage3DEXT',
848 'glTextureImage1DEXT',
849 'glTextureImage2DEXT',
850 'glTextureImage3DEXT',
851 'glTextureSubImage1DEXT',
852 'glTextureSubImage2DEXT',
853 'glTextureSubImage3DEXT',
856 def serializeArgValue(self, function, arg):
857 if function.name in self.draw_function_names and arg.name == 'indices':
858 print ' GLint _element_array_buffer = 0;'
859 print ' _glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &_element_array_buffer);'
860 print ' if (!_element_array_buffer) {'
861 if isinstance(arg.type, stdapi.Array):
862 print ' trace::localWriter.beginArray(%s);' % arg.type.length
863 print ' for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
864 print ' trace::localWriter.beginElement();'
865 print ' trace::localWriter.writeBlob(%s[i], count[i]*_gl_type_size(type));' % (arg.name)
866 print ' trace::localWriter.endElement();'
868 print ' trace::localWriter.endArray();'
870 print ' trace::localWriter.writeBlob(%s, count*_gl_type_size(type));' % (arg.name)
872 Tracer.serializeArgValue(self, function, arg)
876 # Recognize offsets instead of blobs when a PBO is bound
877 if function.name in self.unpack_function_names \
878 and (isinstance(arg.type, stdapi.Blob) \
879 or (isinstance(arg.type, stdapi.Const) \
880 and isinstance(arg.type.type, stdapi.Blob))):
882 print ' gltrace::Context *ctx = gltrace::getContext();'
883 print ' GLint _unpack_buffer = 0;'
884 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
885 print ' _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
886 print ' if (_unpack_buffer) {'
887 print ' trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
889 Tracer.serializeArgValue(self, function, arg)
894 # Several GL state functions take GLenum symbolic names as
895 # integer/floats; so dump the symbolic name whenever possible
896 if function.name.startswith('gl') \
897 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
898 and arg.name == 'param':
900 assert function.args[arg.index - 1].name == 'pname'
901 assert function.args[arg.index - 1].type == glapi.GLenum
902 print ' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
903 self.serializeValue(glapi.GLenum, arg.name)
905 Tracer.serializeArgValue(self, function, arg)
909 Tracer.serializeArgValue(self, function, arg)
911 def footer(self, api):
912 Tracer.footer(self, api)
914 # A simple state tracker to track the pointer values
916 print 'static void _trace_user_arrays(GLuint count)'
918 print ' gltrace::Context *ctx = gltrace::getContext();'
920 for camelcase_name, uppercase_name in self.arrays:
921 # in which profile is the array available?
922 profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
923 if camelcase_name in self.arrays_es1:
924 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
926 function_name = 'gl%sPointer' % camelcase_name
927 enable_name = 'GL_%s_ARRAY' % uppercase_name
928 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
929 function = api.getFunctionByName(function_name)
931 print ' // %s' % function.prototype()
932 print ' if (%s) {' % profile_check
933 self.array_trace_prolog(api, uppercase_name)
934 self.array_prolog(api, uppercase_name)
935 print ' if (_glIsEnabled(%s)) {' % enable_name
936 print ' GLint _binding = 0;'
937 print ' _glGetIntegerv(%s, &_binding);' % binding_name
938 print ' if (!_binding) {'
940 # Get the arguments via glGet*
941 for arg in function.args:
942 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
943 arg_get_function, arg_type = TypeGetter().visit(arg.type)
944 print ' %s %s = 0;' % (arg_type, arg.name)
945 print ' _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
947 arg_names = ', '.join([arg.name for arg in function.args[:-1]])
948 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
950 # Emit a fake function
951 self.array_trace_intermezzo(api, uppercase_name)
952 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
953 for arg in function.args:
954 assert not arg.output
955 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
956 if arg.name != 'pointer':
957 self.serializeValue(arg.type, arg.name)
959 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
960 print ' trace::localWriter.endArg();'
962 print ' trace::localWriter.endEnter();'
963 print ' trace::localWriter.beginLeave(_call);'
964 print ' trace::localWriter.endLeave();'
967 self.array_epilog(api, uppercase_name)
968 self.array_trace_epilog(api, uppercase_name)
972 # Samething, but for glVertexAttribPointer*
974 # Some variants of glVertexAttribPointer alias conventional and generic attributes:
975 # - glVertexAttribPointer: no
976 # - glVertexAttribPointerARB: implementation dependent
977 # - glVertexAttribPointerNV: yes
979 # This means that the implementations of these functions do not always
980 # alias, and they need to be considered independently.
982 print ' // ES1 does not support generic vertex attributes'
983 print ' if (ctx->profile == gltrace::PROFILE_ES1)'
986 print ' vertex_attrib _vertex_attrib = _get_vertex_attrib();'
988 for suffix in ['', 'ARB', 'NV']:
990 SUFFIX = '_' + suffix
993 function_name = 'glVertexAttribPointer' + suffix
994 function = api.getFunctionByName(function_name)
996 print ' // %s' % function.prototype()
997 print ' if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
999 print ' GLint _max_vertex_attribs = 16;'
1001 print ' GLint _max_vertex_attribs = 0;'
1002 print ' _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
1003 print ' for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
1004 print ' GLint _enabled = 0;'
1006 print ' _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
1008 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
1009 print ' if (_enabled) {'
1010 print ' GLint _binding = 0;'
1012 # It doesn't seem possible to use VBOs with NV_vertex_program.
1013 print ' _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
1014 print ' if (!_binding) {'
1016 # Get the arguments via glGet*
1017 for arg in function.args[1:]:
1019 arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
1021 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
1022 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
1023 print ' %s %s = 0;' % (arg_type, arg.name)
1024 print ' _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
1026 arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
1027 print ' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
1029 # Emit a fake function
1030 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1031 for arg in function.args:
1032 assert not arg.output
1033 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
1034 if arg.name != 'pointer':
1035 self.serializeValue(arg.type, arg.name)
1037 print ' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
1038 print ' trace::localWriter.endArg();'
1040 print ' trace::localWriter.endEnter();'
1041 print ' trace::localWriter.beginLeave(_call);'
1042 print ' trace::localWriter.endLeave();'
1053 # Hooks for glTexCoordPointer, which is identical to the other array
1054 # pointers except the fact that it is indexed by glClientActiveTexture.
1057 def array_prolog(self, api, uppercase_name):
1058 if uppercase_name == 'TEXTURE_COORD':
1059 print ' GLint client_active_texture = 0;'
1060 print ' _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1061 print ' GLint max_texture_coords = 0;'
1062 print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
1063 print ' _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1065 print ' _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1066 print ' for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1067 print ' GLint texture = GL_TEXTURE0 + unit;'
1068 print ' _glClientActiveTexture(texture);'
1070 def array_trace_prolog(self, api, uppercase_name):
1071 if uppercase_name == 'TEXTURE_COORD':
1072 print ' bool client_active_texture_dirty = false;'
1074 def array_epilog(self, api, uppercase_name):
1075 if uppercase_name == 'TEXTURE_COORD':
1077 self.array_cleanup(api, uppercase_name)
1079 def array_cleanup(self, api, uppercase_name):
1080 if uppercase_name == 'TEXTURE_COORD':
1081 print ' _glClientActiveTexture(client_active_texture);'
1083 def array_trace_intermezzo(self, api, uppercase_name):
1084 if uppercase_name == 'TEXTURE_COORD':
1085 print ' if (texture != client_active_texture || client_active_texture_dirty) {'
1086 print ' client_active_texture_dirty = true;'
1087 self.fake_glClientActiveTexture_call(api, "texture");
1090 def array_trace_epilog(self, api, uppercase_name):
1091 if uppercase_name == 'TEXTURE_COORD':
1092 print ' if (client_active_texture_dirty) {'
1093 self.fake_glClientActiveTexture_call(api, "client_active_texture");
1096 def fake_glClientActiveTexture_call(self, api, texture):
1097 function = api.getFunctionByName('glClientActiveTexture')
1098 self.fake_call(function, [texture])