]> git.cworth.org Git - apitrace/blob - wrappers/gltrace.py
gltrace/retrace: Full support for variable length parameters.
[apitrace] / wrappers / gltrace.py
1 ##########################################################################
2 #
3 # Copyright 2008-2010 VMware, Inc.
4 # All Rights Reserved.
5 #
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:
12 #
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
15 #
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
22 # THE SOFTWARE.
23 #
24 ##########################################################################/
25
26
27 """GL tracing generator."""
28
29
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
36
37
38 class TypeGetter(stdapi.Visitor):
39     '''Determine which glGet*v function that matches the specified type.'''
40
41     def __init__(self, prefix = 'glGet', long_suffix = True, ext_suffix = ''):
42         self.prefix = prefix
43         self.long_suffix = long_suffix
44         self.ext_suffix = ext_suffix
45
46     def visitConst(self, const):
47         return self.visit(const.type)
48
49     def visitAlias(self, alias):
50         if alias.expr == 'GLboolean':
51             if self.long_suffix:
52                 suffix = 'Booleanv'
53                 arg_type = alias.expr
54             else:
55                 suffix = 'iv'
56                 arg_type = 'GLint'
57         elif alias.expr == 'GLdouble':
58             if self.long_suffix:
59                 suffix = 'Doublev'
60                 arg_type = alias.expr
61             else:
62                 suffix = 'dv'
63                 arg_type = alias.expr
64         elif alias.expr == 'GLfloat':
65             if self.long_suffix:
66                 suffix = 'Floatv'
67                 arg_type = alias.expr
68             else:
69                 suffix = 'fv'
70                 arg_type = alias.expr
71         elif alias.expr in ('GLint', 'GLuint', 'GLsizei'):
72             if self.long_suffix:
73                 suffix = 'Integerv'
74                 arg_type = 'GLint'
75             else:
76                 suffix = 'iv'
77                 arg_type = 'GLint'
78         else:
79             print alias.expr
80             assert False
81         function_name = self.prefix + suffix + self.ext_suffix
82         return function_name, arg_type
83     
84     def visitEnum(self, enum):
85         return self.visit(glapi.GLint)
86
87     def visitBitmask(self, bitmask):
88         return self.visit(glapi.GLint)
89
90     def visitOpaque(self, pointer):
91         return self.prefix + 'Pointerv' + self.ext_suffix, 'GLvoid *'
92
93
94 class GlTracer(Tracer):
95
96     arrays = [
97         ("Vertex", "VERTEX"),
98         ("Normal", "NORMAL"),
99         ("Color", "COLOR"),
100         ("Index", "INDEX"),
101         ("TexCoord", "TEXTURE_COORD"),
102         ("EdgeFlag", "EDGE_FLAG"),
103         ("FogCoord", "FOG_COORD"),
104         ("SecondaryColor", "SECONDARY_COLOR"),
105     ]
106     arrays.reverse()
107
108     # arrays available in PROFILE_ES1
109     arrays_es1 = ("Vertex", "Normal", "Color", "TexCoord")
110
111     def header(self, api):
112         Tracer.header(self, api)
113
114         print '#include "gltrace.hpp"'
115         print
116         
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,'
122         print '};'
123         print
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;'
135         print '                }'
136         print '            }'
137         print '            return VERTEX_ATTRIB_ARB;'
138         print '        }'
139         print '    }'
140         print '    return VERTEX_ATTRIB;'
141         print '}'
142         print
143
144         self.defineShadowBufferHelper()
145
146         # Whether we need user arrays
147         print 'static inline bool _need_user_arrays(void)'
148         print '{'
149         print '    gltrace::Context *ctx = gltrace::getContext();'
150         print '    if (!ctx->user_arrays) {'
151         print '        return false;'
152         print '    }'
153         print
154
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)';
160
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;'
173             print '        }'
174             print '    }'
175             self.array_epilog(api, uppercase_name)
176             print '  }'
177             print
178
179         print '    // ES1 does not support generic vertex attributes'
180         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
181         print '        return false;'
182         print
183         print '    vertex_attrib _vertex_attrib = _get_vertex_attrib();'
184         print
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;'
197         print '                }'
198         print '            }'
199         print '        }'
200         print '    }'
201         print
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;'
214         print '                }'
215         print '            }'
216         print '        }'
217         print '    }'
218         print
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;'
226         print '            }'
227         print '        }'
228         print '    }'
229         print
230
231         print '    return false;'
232         print '}'
233         print
234
235         print 'static void _trace_user_arrays(GLuint count);'
236         print
237
238         # Buffer mappings
239         print '// whether glMapBufferRange(GL_MAP_WRITE_BIT) has ever been called'
240         print 'static bool _checkBufferMapRange = false;'
241         print
242         print '// whether glBufferParameteriAPPLE(GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE) has ever been called'
243         print 'static bool _checkBufferFlushingUnmapAPPLE = false;'
244         print
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 {'
248         print '    void *map;'
249         print '    GLint length;'
250         print '    bool write;'
251         print '    bool explicit_flush;'
252         print '};'
253         print
254         for target in self.buffer_targets:
255             print 'struct buffer_mapping _%s_mapping;' % target.lower();
256         print
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()
263         print '    default:'
264         print '        os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
265         print '        return NULL;'
266         print '    }'
267         print '}'
268         print
269
270         # Generate a helper function to determine whether a parameter name
271         # refers to a symbolic value or not
272         print 'static bool'
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;'
279         print '    default:'
280         print '        return false;'
281         print '    }'
282         print '}'
283         print
284         
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
287         # an enum or not
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;'
292         print '}'
293         print
294
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:
300             if type is not None:
301                 print '    case %s: return %s;' % (name, count)
302         print '    default:'
303         print r'        os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
304         print '        return 1;'
305         print '    }'
306         print '}'
307         print
308
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);'
314         print '}'
315         print
316
317     getProcAddressFunctionNames = []
318
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
325             
326             print 'static %s _wrapProcAddress(%s procName, %s procPtr);' % (retType, argType, retType)
327             print
328             
329             Tracer.traceApi(self, api)
330             
331             print 'static %s _wrapProcAddress(%s procName, %s procPtr) {' % (retType, argType, retType)
332             print '    if (!procPtr) {'
333             print '        return procPtr;'
334             print '    }'
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,)
341                 print '    }'
342             print '    os::log("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);'
343             print '    return procPtr;'
344             print '}'
345             print
346         else:
347             Tracer.traceApi(self, api)
348
349     def defineShadowBufferHelper(self):
350         print 'void _shadow_glGetBufferSubData(GLenum target, GLintptr offset,'
351         print '                                GLsizeiptr size, GLvoid *data)'
352         print '{'
353         print '    gltrace::Context *ctx = gltrace::getContext();'
354         print '    if (!ctx->needsShadowBuffers() || target != GL_ELEMENT_ARRAY_BUFFER) {'
355         print '        _glGetBufferSubData(target, offset, size, data);'
356         print '        return;'
357         print '    }'
358         print
359         print '    GLint buffer_binding = 0;'
360         print '    _glGetIntegerv(target, &buffer_binding);'
361         print '    if (buffer_binding > 0) {'
362         print '        gltrace::Buffer & buf = ctx->buffers[buffer_binding];'
363         print '        buf.getSubData(offset, size, data);'
364         print '    }'
365         print '}'
366
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 + ';'
376         print '        }'
377         print '    }'
378         print
379
380     def shadowBufferProlog(self, function):
381         if function.name == 'glBufferData':
382             self.shadowBufferMethod('bufferData(size, data)')
383
384         if function.name == 'glBufferSubData':
385             self.shadowBufferMethod('bufferSubData(offset, size, data)')
386
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]);'
392             print '        }'
393             print '    }'
394
395     array_pointer_function_names = set((
396         "glVertexPointer",
397         "glNormalPointer",
398         "glColorPointer",
399         "glIndexPointer",
400         "glTexCoordPointer",
401         "glEdgeFlagPointer",
402         "glFogCoordPointer",
403         "glSecondaryColorPointer",
404         
405         "glInterleavedArrays",
406
407         "glVertexPointerEXT",
408         "glNormalPointerEXT",
409         "glColorPointerEXT",
410         "glIndexPointerEXT",
411         "glTexCoordPointerEXT",
412         "glEdgeFlagPointerEXT",
413         "glFogCoordPointerEXT",
414         "glSecondaryColorPointerEXT",
415
416         "glVertexAttribPointer",
417         "glVertexAttribPointerARB",
418         "glVertexAttribPointerNV",
419         "glVertexAttribIPointer",
420         "glVertexAttribIPointerEXT",
421         "glVertexAttribLPointer",
422         "glVertexAttribLPointerEXT",
423         
424         #"glMatrixIndexPointerARB",
425     ))
426
427     draw_function_names = set((
428         'glDrawArrays',
429         'glDrawElements',
430         'glDrawRangeElements',
431         'glMultiDrawArrays',
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         'glDrawArraysEXT',
447         'glDrawRangeElementsEXT',
448         'glDrawRangeElementsEXT_size',
449         'glMultiDrawArraysEXT',
450         'glMultiDrawElementsEXT',
451         'glMultiModeDrawArraysIBM',
452         'glMultiModeDrawElementsIBM',
453         'glDrawArraysInstancedEXT',
454         'glDrawElementsInstancedEXT',
455     ))
456
457     interleaved_formats = [
458          'GL_V2F',
459          'GL_V3F',
460          'GL_C4UB_V2F',
461          'GL_C4UB_V3F',
462          'GL_C3F_V3F',
463          'GL_N3F_V3F',
464          'GL_C4F_N3F_V3F',
465          'GL_T2F_V3F',
466          'GL_T4F_V4F',
467          'GL_T2F_C4UB_V3F',
468          'GL_T2F_C3F_V3F',
469          'GL_T2F_N3F_V3F',
470          'GL_T2F_C4F_N3F_V3F',
471          'GL_T4F_C4F_N3F_V4F',
472     ]
473
474     def traceFunctionImplBody(self, function):
475         # Defer tracing of user array pointers...
476         if function.name in self.array_pointer_function_names:
477             print '    GLint _array_buffer = 0;'
478             print '    _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
479             print '    if (!_array_buffer) {'
480             print '        gltrace::Context *ctx = gltrace::getContext();'
481             print '        ctx->user_arrays = true;'
482             if function.name == "glVertexAttribPointerARB":
483                 print '        ctx->user_arrays_arb = true;'
484             if function.name == "glVertexAttribPointerNV":
485                 print '        ctx->user_arrays_nv = true;'
486             self.invokeFunction(function)
487
488             # And also break down glInterleavedArrays into the individual calls
489             if function.name == 'glInterleavedArrays':
490                 print
491
492                 # Initialize the enable flags
493                 for camelcase_name, uppercase_name in self.arrays:
494                     flag_name = '_' + uppercase_name.lower()
495                     print '        GLboolean %s = GL_FALSE;' % flag_name
496                 print
497
498                 # Switch for the interleaved formats
499                 print '        switch (format) {'
500                 for format in self.interleaved_formats:
501                     print '            case %s:' % format
502                     for camelcase_name, uppercase_name in self.arrays:
503                         flag_name = '_' + uppercase_name.lower()
504                         if format.find('_' + uppercase_name[0]) >= 0:
505                             print '                %s = GL_TRUE;' % flag_name
506                     print '                break;'
507                 print '            default:'
508                 print '               return;'
509                 print '        }'
510                 print
511
512                 # Emit fake glEnableClientState/glDisableClientState flags
513                 for camelcase_name, uppercase_name in self.arrays:
514                     flag_name = '_' + uppercase_name.lower()
515                     enable_name = 'GL_%s_ARRAY' % uppercase_name
516
517                     # Emit a fake function
518                     print '        {'
519                     print '            static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
520                     print '            unsigned _call = trace::localWriter.beginEnter(&_sig);'
521                     print '            trace::localWriter.beginArg(0);'
522                     self.serializeValue(glapi.GLenum, enable_name)
523                     print '            trace::localWriter.endArg();'
524                     print '            trace::localWriter.endEnter();'
525                     print '            trace::localWriter.beginLeave(_call);'
526                     print '            trace::localWriter.endLeave();'
527                     print '        }'
528
529             print '        return;'
530             print '    }'
531
532         # ... to the draw calls
533         if function.name in self.draw_function_names:
534             print '    if (_need_user_arrays()) {'
535             arg_names = ', '.join([arg.name for arg in function.args[1:]])
536             print '        GLuint _count = _%s_count(%s);' % (function.name, arg_names)
537             print '        _trace_user_arrays(_count);'
538             print '    }'
539         
540         # Emit a fake memcpy on buffer uploads
541         if function.name == 'glBufferParameteriAPPLE':
542             print '    if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
543             print '        _checkBufferFlushingUnmapAPPLE = true;'
544             print '    }'
545         if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
546             if function.name.endswith('ARB'):
547                 suffix = 'ARB'
548             else:
549                 suffix = ''
550             print '    GLint access = 0;'
551             print '    _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
552             print '    if (access != GL_READ_ONLY) {'
553             print '        GLvoid *map = NULL;'
554             print '        _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);'  % suffix
555             print '        if (map) {'
556             print '            GLint length = -1;'
557             print '            bool flush = true;'
558             print '            if (_checkBufferMapRange) {'
559             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
560             print '                GLint access_flags = 0;'
561             print '                _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
562             print '                flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
563             print '                if (length == -1) {'
564             print '                    // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
565             print '                    static bool warned = false;'
566             print '                    if (!warned) {'
567             print '                        os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
568             print '                        warned = true;'
569             print '                    }'
570             print '                    struct buffer_mapping *mapping = get_buffer_mapping(target);'
571             print '                    if (mapping) {'
572             print '                        length = mapping->length;'
573             print '                        flush = flush && !mapping->explicit_flush;'
574             print '                    } else {'
575             print '                        length = 0;'
576             print '                        flush = false;'
577             print '                    }'
578             print '                }'
579             print '            } else {'
580             print '                length = 0;'
581             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
582             print '            }'
583             print '            if (_checkBufferFlushingUnmapAPPLE) {'
584             print '                GLint flushing_unmap = GL_TRUE;'
585             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
586             print '                flush = flush && flushing_unmap;'
587             print '            }'
588             print '            if (flush && length > 0) {'
589             self.emit_memcpy('map', 'map', 'length')
590             print '            }'
591             print '        }'
592             print '    }'
593         if function.name == 'glUnmapBufferOES':
594             print '    GLint access = 0;'
595             print '    _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
596             print '    if (access == GL_WRITE_ONLY_OES) {'
597             print '        GLvoid *map = NULL;'
598             print '        _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
599             print '        GLint size = 0;'
600             print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
601             print '        if (map && size > 0) {'
602             self.emit_memcpy('map', 'map', 'size')
603             self.shadowBufferMethod('bufferSubData(0, size, map)')
604             print '        }'
605             print '    }'
606         if function.name == 'glUnmapNamedBufferEXT':
607             print '    GLint access_flags = 0;'
608             print '    _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
609             print '    if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
610             print '        GLvoid *map = NULL;'
611             print '        _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
612             print '        GLint length = 0;'
613             print '        _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
614             print '        if (map && length > 0) {'
615             self.emit_memcpy('map', 'map', 'length')
616             print '        }'
617             print '    }'
618         if function.name == 'glFlushMappedBufferRange':
619             print '    GLvoid *map = NULL;'
620             print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
621             print '    if (map && length > 0) {'
622             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
623             print '    }'
624         if function.name == 'glFlushMappedBufferRangeAPPLE':
625             print '    GLvoid *map = NULL;'
626             print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
627             print '    if (map && size > 0) {'
628             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
629             print '    }'
630         if function.name == 'glFlushMappedNamedBufferRangeEXT':
631             print '    GLvoid *map = NULL;'
632             print '    _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
633             print '    if (map && length > 0) {'
634             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
635             print '    }'
636
637         # Don't leave vertex attrib locations to chance.  Instead emit fake
638         # glBindAttribLocation calls to ensure that the same locations will be
639         # used when retracing.  Trying to remap locations after the fact would
640         # be an herculian task given that vertex attrib locations appear in
641         # many entry-points, including non-shader related ones.
642         if function.name == 'glLinkProgram':
643             Tracer.invokeFunction(self, function)
644             print '    GLint active_attributes = 0;'
645             print '    _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
646             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
647             print '        GLint size = 0;'
648             print '        GLenum type = 0;'
649             print '        GLchar name[256];'
650             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
651             print '        _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
652             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
653             print '            GLint location = _glGetAttribLocation(program, name);'
654             print '            if (location >= 0) {'
655             bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
656             self.fake_call(bind_function, ['program', 'location', 'name'])
657             print '            }'
658             print '        }'
659             print '    }'
660         if function.name == 'glLinkProgramARB':
661             Tracer.invokeFunction(self, function)
662             print '    GLint active_attributes = 0;'
663             print '    _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
664             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
665             print '        GLint size = 0;'
666             print '        GLenum type = 0;'
667             print '        GLcharARB name[256];'
668             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
669             print '        _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
670             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
671             print '            GLint location = _glGetAttribLocationARB(programObj, name);'
672             print '            if (location >= 0) {'
673             bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
674             self.fake_call(bind_function, ['programObj', 'location', 'name'])
675             print '            }'
676             print '        }'
677             print '    }'
678
679         self.shadowBufferProlog(function)
680
681         Tracer.traceFunctionImplBody(self, function)
682
683     marker_functions = [
684         # GL_GREMEDY_string_marker
685         'glStringMarkerGREMEDY',
686         # GL_GREMEDY_frame_terminator
687         'glFrameTerminatorGREMEDY',
688         # GL_EXT_debug_marker
689         'glInsertEventMarkerEXT',
690         'glPushGroupMarkerEXT',
691         'glPopGroupMarkerEXT',
692     ]
693
694     def invokeFunction(self, function):
695         if function.name in ('glLinkProgram', 'glLinkProgramARB'):
696             # These functions have been dispatched already
697             return
698
699         # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
700         # driver
701         if function.name in self.marker_functions:
702             return
703
704         if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
705             else_ = ''
706             for marker_function in self.marker_functions:
707                 if self.api.getFunctionByName(marker_function):
708                     print '    %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
709                     print '        _result = (%s)&%s;' % (function.type, marker_function)
710                     print '    }'
711                 else_ = 'else '
712             print '    %s{' % else_
713             Tracer.invokeFunction(self, function)
714             print '    }'
715             return
716
717         # Override GL extensions
718         if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
719             Tracer.invokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
720             return
721
722         Tracer.invokeFunction(self, function)
723
724     buffer_targets = [
725         'ARRAY_BUFFER',
726         'ELEMENT_ARRAY_BUFFER',
727         'PIXEL_PACK_BUFFER',
728         'PIXEL_UNPACK_BUFFER',
729         'UNIFORM_BUFFER',
730         'TEXTURE_BUFFER',
731         'TRANSFORM_FEEDBACK_BUFFER',
732         'COPY_READ_BUFFER',
733         'COPY_WRITE_BUFFER',
734         'DRAW_INDIRECT_BUFFER',
735         'ATOMIC_COUNTER_BUFFER',
736     ]
737
738     def wrapRet(self, function, instance):
739         Tracer.wrapRet(self, function, instance)
740
741         # Replace function addresses with ours
742         if function.name in self.getProcAddressFunctionNames:
743             print '    %s = _wrapProcAddress(%s, %s);' % (instance, function.args[0].name, instance)
744
745         # Keep track of buffer mappings
746         if function.name in ('glMapBuffer', 'glMapBufferARB'):
747             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
748             print '    if (mapping) {'
749             print '        mapping->map = %s;' % (instance)
750             print '        mapping->length = 0;'
751             print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
752             print '        mapping->write = (access != GL_READ_ONLY);'
753             print '        mapping->explicit_flush = false;'
754             print '    }'
755         if function.name == 'glMapBufferRange':
756             print '    if (access & GL_MAP_WRITE_BIT) {'
757             print '        _checkBufferMapRange = true;'
758             print '    }'
759             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
760             print '    if (mapping) {'
761             print '        mapping->map = %s;' % (instance)
762             print '        mapping->length = length;'
763             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
764             print '        mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
765             print '    }'
766
767     boolean_names = [
768         'GL_FALSE',
769         'GL_TRUE',
770     ]
771
772     def gl_boolean(self, value):
773         return self.boolean_names[int(bool(value))]
774
775     # Names of the functions that unpack from a pixel buffer object.  See the
776     # ARB_pixel_buffer_object specification.
777     unpack_function_names = set([
778         'glBitmap',
779         'glColorSubTable',
780         'glColorTable',
781         'glCompressedTexImage1D',
782         'glCompressedTexImage2D',
783         'glCompressedTexImage3D',
784         'glCompressedTexSubImage1D',
785         'glCompressedTexSubImage2D',
786         'glCompressedTexSubImage3D',
787         'glConvolutionFilter1D',
788         'glConvolutionFilter2D',
789         'glDrawPixels',
790         'glMultiTexImage1DEXT',
791         'glMultiTexImage2DEXT',
792         'glMultiTexImage3DEXT',
793         'glMultiTexSubImage1DEXT',
794         'glMultiTexSubImage2DEXT',
795         'glMultiTexSubImage3DEXT',
796         'glPixelMapfv',
797         'glPixelMapuiv',
798         'glPixelMapusv',
799         'glPolygonStipple',
800         'glSeparableFilter2D',
801         'glTexImage1D',
802         'glTexImage1DEXT',
803         'glTexImage2D',
804         'glTexImage2DEXT',
805         'glTexImage3D',
806         'glTexImage3DEXT',
807         'glTexSubImage1D',
808         'glTexSubImage1DEXT',
809         'glTexSubImage2D',
810         'glTexSubImage2DEXT',
811         'glTexSubImage3D',
812         'glTexSubImage3DEXT',
813         'glTextureImage1DEXT',
814         'glTextureImage2DEXT',
815         'glTextureImage3DEXT',
816         'glTextureSubImage1DEXT',
817         'glTextureSubImage2DEXT',
818         'glTextureSubImage3DEXT',
819     ])
820
821     def serializeArgValue(self, function, arg):
822         # Recognize offsets instead of blobs when a PBO is bound
823         if function.name in self.unpack_function_names \
824            and (isinstance(arg.type, stdapi.Blob) \
825                 or (isinstance(arg.type, stdapi.Const) \
826                     and isinstance(arg.type.type, stdapi.Blob))):
827             print '    {'
828             print '        gltrace::Context *ctx = gltrace::getContext();'
829             print '        GLint _unpack_buffer = 0;'
830             print '        if (ctx->profile == gltrace::PROFILE_COMPAT)'
831             print '            _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
832             print '        if (_unpack_buffer) {'
833             print '            trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
834             print '        } else {'
835             Tracer.serializeArgValue(self, function, arg)
836             print '        }'
837             print '    }'
838             return
839
840         # Several GL state functions take GLenum symbolic names as
841         # integer/floats; so dump the symbolic name whenever possible
842         if function.name.startswith('gl') \
843            and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
844            and arg.name == 'param':
845             assert arg.index > 0
846             assert function.args[arg.index - 1].name == 'pname'
847             assert function.args[arg.index - 1].type == glapi.GLenum
848             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
849             self.serializeValue(glapi.GLenum, arg.name)
850             print '    } else {'
851             Tracer.serializeArgValue(self, function, arg)
852             print '    }'
853             return
854
855         Tracer.serializeArgValue(self, function, arg)
856
857     def footer(self, api):
858         Tracer.footer(self, api)
859
860         # A simple state tracker to track the pointer values
861         # update the state
862         print 'static void _trace_user_arrays(GLuint count)'
863         print '{'
864         print '    gltrace::Context *ctx = gltrace::getContext();'
865
866         for camelcase_name, uppercase_name in self.arrays:
867             # in which profile is the array available?
868             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
869             if camelcase_name in self.arrays_es1:
870                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
871
872             function_name = 'gl%sPointer' % camelcase_name
873             enable_name = 'GL_%s_ARRAY' % uppercase_name
874             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
875             function = api.getFunctionByName(function_name)
876
877             print '    // %s' % function.prototype()
878             print '  if (%s) {' % profile_check
879             self.array_trace_prolog(api, uppercase_name)
880             self.array_prolog(api, uppercase_name)
881             print '    if (_glIsEnabled(%s)) {' % enable_name
882             print '        GLint _binding = 0;'
883             print '        _glGetIntegerv(%s, &_binding);' % binding_name
884             print '        if (!_binding) {'
885
886             # Get the arguments via glGet*
887             for arg in function.args:
888                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
889                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
890                 print '            %s %s = 0;' % (arg_type, arg.name)
891                 print '            _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
892             
893             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
894             print '            size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
895
896             # Emit a fake function
897             self.array_trace_intermezzo(api, uppercase_name)
898             print '            unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
899             for arg in function.args:
900                 assert not arg.output
901                 print '            trace::localWriter.beginArg(%u);' % (arg.index,)
902                 if arg.name != 'pointer':
903                     self.serializeValue(arg.type, arg.name)
904                 else:
905                     print '            trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
906                 print '            trace::localWriter.endArg();'
907             
908             print '            trace::localWriter.endEnter();'
909             print '            trace::localWriter.beginLeave(_call);'
910             print '            trace::localWriter.endLeave();'
911             print '        }'
912             print '    }'
913             self.array_epilog(api, uppercase_name)
914             self.array_trace_epilog(api, uppercase_name)
915             print '  }'
916             print
917
918         # Samething, but for glVertexAttribPointer*
919         #
920         # Some variants of glVertexAttribPointer alias conventional and generic attributes:
921         # - glVertexAttribPointer: no
922         # - glVertexAttribPointerARB: implementation dependent
923         # - glVertexAttribPointerNV: yes
924         #
925         # This means that the implementations of these functions do not always
926         # alias, and they need to be considered independently.
927         #
928         print '    // ES1 does not support generic vertex attributes'
929         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
930         print '        return;'
931         print
932         print '    vertex_attrib _vertex_attrib = _get_vertex_attrib();'
933         print
934         for suffix in ['', 'ARB', 'NV']:
935             if suffix:
936                 SUFFIX = '_' + suffix
937             else:
938                 SUFFIX = suffix
939             function_name = 'glVertexAttribPointer' + suffix
940             function = api.getFunctionByName(function_name)
941
942             print '    // %s' % function.prototype()
943             print '    if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
944             if suffix == 'NV':
945                 print '        GLint _max_vertex_attribs = 16;'
946             else:
947                 print '        GLint _max_vertex_attribs = 0;'
948                 print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
949             print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
950             print '            GLint _enabled = 0;'
951             if suffix == 'NV':
952                 print '            _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
953             else:
954                 print '            _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
955             print '            if (_enabled) {'
956             print '                GLint _binding = 0;'
957             if suffix != 'NV':
958                 # It doesn't seem possible to use VBOs with NV_vertex_program.
959                 print '                _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
960             print '                if (!_binding) {'
961
962             # Get the arguments via glGet*
963             for arg in function.args[1:]:
964                 if suffix == 'NV':
965                     arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
966                 else:
967                     arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
968                 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
969                 print '                    %s %s = 0;' % (arg_type, arg.name)
970                 print '                    _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
971             
972             arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
973             print '                    size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
974
975             # Emit a fake function
976             print '                    unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
977             for arg in function.args:
978                 assert not arg.output
979                 print '                    trace::localWriter.beginArg(%u);' % (arg.index,)
980                 if arg.name != 'pointer':
981                     self.serializeValue(arg.type, arg.name)
982                 else:
983                     print '                    trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
984                 print '                    trace::localWriter.endArg();'
985             
986             print '                    trace::localWriter.endEnter();'
987             print '                    trace::localWriter.beginLeave(_call);'
988             print '                    trace::localWriter.endLeave();'
989             print '                }'
990             print '            }'
991             print '        }'
992             print '    }'
993             print
994
995         print '}'
996         print
997
998     #
999     # Hooks for glTexCoordPointer, which is identical to the other array
1000     # pointers except the fact that it is indexed by glClientActiveTexture.
1001     #
1002
1003     def array_prolog(self, api, uppercase_name):
1004         if uppercase_name == 'TEXTURE_COORD':
1005             print '    GLint client_active_texture = 0;'
1006             print '    _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1007             print '    GLint max_texture_coords = 0;'
1008             print '    if (ctx->profile == gltrace::PROFILE_COMPAT)'
1009             print '        _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1010             print '    else'
1011             print '        _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1012             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1013             print '        GLint texture = GL_TEXTURE0 + unit;'
1014             print '        _glClientActiveTexture(texture);'
1015
1016     def array_trace_prolog(self, api, uppercase_name):
1017         if uppercase_name == 'TEXTURE_COORD':
1018             print '    bool client_active_texture_dirty = false;'
1019
1020     def array_epilog(self, api, uppercase_name):
1021         if uppercase_name == 'TEXTURE_COORD':
1022             print '    }'
1023         self.array_cleanup(api, uppercase_name)
1024
1025     def array_cleanup(self, api, uppercase_name):
1026         if uppercase_name == 'TEXTURE_COORD':
1027             print '    _glClientActiveTexture(client_active_texture);'
1028         
1029     def array_trace_intermezzo(self, api, uppercase_name):
1030         if uppercase_name == 'TEXTURE_COORD':
1031             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
1032             print '        client_active_texture_dirty = true;'
1033             self.fake_glClientActiveTexture_call(api, "texture");
1034             print '    }'
1035
1036     def array_trace_epilog(self, api, uppercase_name):
1037         if uppercase_name == 'TEXTURE_COORD':
1038             print '    if (client_active_texture_dirty) {'
1039             self.fake_glClientActiveTexture_call(api, "client_active_texture");
1040             print '    }'
1041
1042     def fake_glClientActiveTexture_call(self, api, texture):
1043         function = api.getFunctionByName('glClientActiveTexture')
1044         self.fake_call(function, [texture])
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056