]> git.cworth.org Git - apitrace/blob - wrappers/gltrace.py
e73c5918140dcc63e6030cf7fb3b762ebff304eb
[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(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buffer_binding);'
361         print '    if (buffer_binding > 0) {'
362         print '        gltrace::Buffer & buf = ctx->buffers[buffer_binding];'
363         print '        buf.getSubData(offset, size, data);'
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         'glMultiDrawArraysIndirect',
447         'glMultiDrawArraysIndirectAMD',
448         'glMultiDrawElementsIndirect',
449         'glMultiDrawElementsIndirectAMD',
450         'glDrawArraysEXT',
451         'glDrawRangeElementsEXT',
452         'glDrawRangeElementsEXT_size',
453         'glMultiDrawArraysEXT',
454         'glMultiDrawElementsEXT',
455         'glMultiModeDrawArraysIBM',
456         'glMultiModeDrawElementsIBM',
457         'glDrawArraysInstancedEXT',
458         'glDrawElementsInstancedEXT',
459     ))
460
461     interleaved_formats = [
462          'GL_V2F',
463          'GL_V3F',
464          'GL_C4UB_V2F',
465          'GL_C4UB_V3F',
466          'GL_C3F_V3F',
467          'GL_N3F_V3F',
468          'GL_C4F_N3F_V3F',
469          'GL_T2F_V3F',
470          'GL_T4F_V4F',
471          'GL_T2F_C4UB_V3F',
472          'GL_T2F_C3F_V3F',
473          'GL_T2F_N3F_V3F',
474          'GL_T2F_C4F_N3F_V3F',
475          'GL_T4F_C4F_N3F_V4F',
476     ]
477
478     def traceFunctionImplBody(self, function):
479         # Defer tracing of user array pointers...
480         if function.name in self.array_pointer_function_names:
481             print '    GLint _array_buffer = 0;'
482             print '    _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
483             print '    if (!_array_buffer) {'
484             print '        gltrace::Context *ctx = gltrace::getContext();'
485             print '        ctx->user_arrays = true;'
486             if function.name == "glVertexAttribPointerARB":
487                 print '        ctx->user_arrays_arb = true;'
488             if function.name == "glVertexAttribPointerNV":
489                 print '        ctx->user_arrays_nv = true;'
490             self.invokeFunction(function)
491
492             # And also break down glInterleavedArrays into the individual calls
493             if function.name == 'glInterleavedArrays':
494                 print
495
496                 # Initialize the enable flags
497                 for camelcase_name, uppercase_name in self.arrays:
498                     flag_name = '_' + uppercase_name.lower()
499                     print '        GLboolean %s = GL_FALSE;' % flag_name
500                 print
501
502                 # Switch for the interleaved formats
503                 print '        switch (format) {'
504                 for format in self.interleaved_formats:
505                     print '            case %s:' % format
506                     for camelcase_name, uppercase_name in self.arrays:
507                         flag_name = '_' + uppercase_name.lower()
508                         if format.find('_' + uppercase_name[0]) >= 0:
509                             print '                %s = GL_TRUE;' % flag_name
510                     print '                break;'
511                 print '            default:'
512                 print '               return;'
513                 print '        }'
514                 print
515
516                 # Emit fake glEnableClientState/glDisableClientState flags
517                 for camelcase_name, uppercase_name in self.arrays:
518                     flag_name = '_' + uppercase_name.lower()
519                     enable_name = 'GL_%s_ARRAY' % uppercase_name
520
521                     # Emit a fake function
522                     print '        {'
523                     print '            static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
524                     print '            unsigned _call = trace::localWriter.beginEnter(&_sig);'
525                     print '            trace::localWriter.beginArg(0);'
526                     self.serializeValue(glapi.GLenum, enable_name)
527                     print '            trace::localWriter.endArg();'
528                     print '            trace::localWriter.endEnter();'
529                     print '            trace::localWriter.beginLeave(_call);'
530                     print '            trace::localWriter.endLeave();'
531                     print '        }'
532
533             print '        return;'
534             print '    }'
535
536         # ... to the draw calls
537         if function.name in self.draw_function_names:
538             print '    if (_need_user_arrays()) {'
539             arg_names = ', '.join([arg.name for arg in function.args[1:]])
540             print '        GLuint _count = _%s_count(%s);' % (function.name, arg_names)
541             print '        _trace_user_arrays(_count);'
542             print '    }'
543         
544         # Emit a fake memcpy on buffer uploads
545         if function.name == 'glBufferParameteriAPPLE':
546             print '    if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
547             print '        _checkBufferFlushingUnmapAPPLE = true;'
548             print '    }'
549         if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
550             if function.name.endswith('ARB'):
551                 suffix = 'ARB'
552             else:
553                 suffix = ''
554             print '    GLint access = 0;'
555             print '    _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
556             print '    if (access != GL_READ_ONLY) {'
557             print '        GLvoid *map = NULL;'
558             print '        _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);'  % suffix
559             print '        if (map) {'
560             print '            GLint length = -1;'
561             print '            bool flush = true;'
562             print '            if (_checkBufferMapRange) {'
563             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
564             print '                GLint access_flags = 0;'
565             print '                _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
566             print '                flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
567             print '                if (length == -1) {'
568             print '                    // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
569             print '                    static bool warned = false;'
570             print '                    if (!warned) {'
571             print '                        os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
572             print '                        warned = true;'
573             print '                    }'
574             print '                    struct buffer_mapping *mapping = get_buffer_mapping(target);'
575             print '                    if (mapping) {'
576             print '                        length = mapping->length;'
577             print '                        flush = flush && !mapping->explicit_flush;'
578             print '                    } else {'
579             print '                        length = 0;'
580             print '                        flush = false;'
581             print '                    }'
582             print '                }'
583             print '            } else {'
584             print '                length = 0;'
585             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
586             print '            }'
587             print '            if (_checkBufferFlushingUnmapAPPLE) {'
588             print '                GLint flushing_unmap = GL_TRUE;'
589             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
590             print '                flush = flush && flushing_unmap;'
591             print '            }'
592             print '            if (flush && length > 0) {'
593             self.emit_memcpy('map', 'map', 'length')
594             print '            }'
595             print '        }'
596             print '    }'
597         if function.name == 'glUnmapBufferOES':
598             print '    GLint access = 0;'
599             print '    _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
600             print '    if (access == GL_WRITE_ONLY_OES) {'
601             print '        GLvoid *map = NULL;'
602             print '        _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
603             print '        GLint size = 0;'
604             print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
605             print '        if (map && size > 0) {'
606             self.emit_memcpy('map', 'map', 'size')
607             self.shadowBufferMethod('bufferSubData(0, size, map)')
608             print '        }'
609             print '    }'
610         if function.name == 'glUnmapNamedBufferEXT':
611             print '    GLint access_flags = 0;'
612             print '    _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
613             print '    if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
614             print '        GLvoid *map = NULL;'
615             print '        _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
616             print '        GLint length = 0;'
617             print '        _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
618             print '        if (map && length > 0) {'
619             self.emit_memcpy('map', 'map', 'length')
620             print '        }'
621             print '    }'
622         if function.name == 'glFlushMappedBufferRange':
623             print '    GLvoid *map = NULL;'
624             print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
625             print '    if (map && length > 0) {'
626             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
627             print '    }'
628         if function.name == 'glFlushMappedBufferRangeAPPLE':
629             print '    GLvoid *map = NULL;'
630             print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
631             print '    if (map && size > 0) {'
632             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
633             print '    }'
634         if function.name == 'glFlushMappedNamedBufferRangeEXT':
635             print '    GLvoid *map = NULL;'
636             print '    _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
637             print '    if (map && length > 0) {'
638             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
639             print '    }'
640
641         # Don't leave vertex attrib locations to chance.  Instead emit fake
642         # glBindAttribLocation calls to ensure that the same locations will be
643         # used when retracing.  Trying to remap locations after the fact would
644         # be an herculian task given that vertex attrib locations appear in
645         # many entry-points, including non-shader related ones.
646         if function.name == 'glLinkProgram':
647             Tracer.invokeFunction(self, function)
648             print '    GLint active_attributes = 0;'
649             print '    _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
650             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
651             print '        GLint size = 0;'
652             print '        GLenum type = 0;'
653             print '        GLchar name[256];'
654             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
655             print '        _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
656             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
657             print '            GLint location = _glGetAttribLocation(program, name);'
658             print '            if (location >= 0) {'
659             bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
660             self.fake_call(bind_function, ['program', 'location', 'name'])
661             print '            }'
662             print '        }'
663             print '    }'
664         if function.name == 'glLinkProgramARB':
665             Tracer.invokeFunction(self, function)
666             print '    GLint active_attributes = 0;'
667             print '    _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
668             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
669             print '        GLint size = 0;'
670             print '        GLenum type = 0;'
671             print '        GLcharARB name[256];'
672             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
673             print '        _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
674             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
675             print '            GLint location = _glGetAttribLocationARB(programObj, name);'
676             print '            if (location >= 0) {'
677             bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
678             self.fake_call(bind_function, ['programObj', 'location', 'name'])
679             print '            }'
680             print '        }'
681             print '    }'
682
683         self.shadowBufferProlog(function)
684
685         Tracer.traceFunctionImplBody(self, function)
686
687     marker_functions = [
688         # GL_GREMEDY_string_marker
689         'glStringMarkerGREMEDY',
690         # GL_GREMEDY_frame_terminator
691         'glFrameTerminatorGREMEDY',
692         # GL_EXT_debug_marker
693         'glInsertEventMarkerEXT',
694         'glPushGroupMarkerEXT',
695         'glPopGroupMarkerEXT',
696     ]
697
698     def invokeFunction(self, function):
699         if function.name in ('glLinkProgram', 'glLinkProgramARB'):
700             # These functions have been dispatched already
701             return
702
703         Tracer.invokeFunction(self, function)
704
705     def doInvokeFunction(self, function):
706         # Same as invokeFunction() but called both when trace is enabled or disabled.
707         #
708         # Used to modify the behavior of GL entry-points.
709
710         # Override GL extensions
711         if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
712             Tracer.doInvokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
713             return
714
715         # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
716         # driver
717         if function.name in self.marker_functions:
718             return
719
720         if function.name in self.getProcAddressFunctionNames:
721             else_ = ''
722             for marker_function in self.marker_functions:
723                 if self.api.getFunctionByName(marker_function):
724                     print '    %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
725                     print '        _result = (%s)&%s;' % (function.type, marker_function)
726                     print '    }'
727                 else_ = 'else '
728             print '    %s{' % else_
729             Tracer.doInvokeFunction(self, function)
730
731             # Replace function addresses with ours
732             # XXX: Doing this here instead of wrapRet means that the trace will
733             # contain the addresses of the wrapper functions, and not the real
734             # functions, but in practice this should make no difference.
735             if function.name in self.getProcAddressFunctionNames:
736                 print '    _result = _wrapProcAddress(%s, _result);' % (function.args[0].name,)
737
738             print '    }'
739             return
740
741         Tracer.doInvokeFunction(self, function)
742
743     buffer_targets = [
744         'ARRAY_BUFFER',
745         'ELEMENT_ARRAY_BUFFER',
746         'PIXEL_PACK_BUFFER',
747         'PIXEL_UNPACK_BUFFER',
748         'UNIFORM_BUFFER',
749         'TEXTURE_BUFFER',
750         'TRANSFORM_FEEDBACK_BUFFER',
751         'COPY_READ_BUFFER',
752         'COPY_WRITE_BUFFER',
753         'DRAW_INDIRECT_BUFFER',
754         'ATOMIC_COUNTER_BUFFER',
755     ]
756
757     def wrapRet(self, function, instance):
758         Tracer.wrapRet(self, function, instance)
759
760         # Keep track of buffer mappings
761         if function.name in ('glMapBuffer', 'glMapBufferARB'):
762             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
763             print '    if (mapping) {'
764             print '        mapping->map = %s;' % (instance)
765             print '        mapping->length = 0;'
766             print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
767             print '        mapping->write = (access != GL_READ_ONLY);'
768             print '        mapping->explicit_flush = false;'
769             print '    }'
770         if function.name == 'glMapBufferRange':
771             print '    if (access & GL_MAP_WRITE_BIT) {'
772             print '        _checkBufferMapRange = true;'
773             print '    }'
774             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
775             print '    if (mapping) {'
776             print '        mapping->map = %s;' % (instance)
777             print '        mapping->length = length;'
778             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
779             print '        mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
780             print '    }'
781
782     boolean_names = [
783         'GL_FALSE',
784         'GL_TRUE',
785     ]
786
787     def gl_boolean(self, value):
788         return self.boolean_names[int(bool(value))]
789
790     # Names of the functions that unpack from a pixel buffer object.  See the
791     # ARB_pixel_buffer_object specification.
792     unpack_function_names = set([
793         'glBitmap',
794         'glColorSubTable',
795         'glColorTable',
796         'glCompressedMultiTexImage1DEXT',
797         'glCompressedMultiTexImage2DEXT',
798         'glCompressedMultiTexImage3DEXT',
799         'glCompressedMultiTexSubImage1DEXT',
800         'glCompressedMultiTexSubImage2DEXT',
801         'glCompressedMultiTexSubImage3DEXT',
802         'glCompressedTexImage1D',
803         'glCompressedTexImage2D',
804         'glCompressedTexImage3D',
805         'glCompressedTexSubImage1D',
806         'glCompressedTexSubImage2D',
807         'glCompressedTexSubImage3D',
808         'glCompressedTextureImage1DEXT',
809         'glCompressedTextureImage2DEXT',
810         'glCompressedTextureImage3DEXT',
811         'glCompressedTextureSubImage1DEXT',
812         'glCompressedTextureSubImage2DEXT',
813         'glCompressedTextureSubImage3DEXT',
814         'glConvolutionFilter1D',
815         'glConvolutionFilter2D',
816         'glDrawPixels',
817         'glMultiTexImage1DEXT',
818         'glMultiTexImage2DEXT',
819         'glMultiTexImage3DEXT',
820         'glMultiTexSubImage1DEXT',
821         'glMultiTexSubImage2DEXT',
822         'glMultiTexSubImage3DEXT',
823         'glPixelMapfv',
824         'glPixelMapuiv',
825         'glPixelMapusv',
826         'glPolygonStipple',
827         'glSeparableFilter2D',
828         'glTexImage1D',
829         'glTexImage1DEXT',
830         'glTexImage2D',
831         'glTexImage2DEXT',
832         'glTexImage3D',
833         'glTexImage3DEXT',
834         'glTexSubImage1D',
835         'glTexSubImage1DEXT',
836         'glTexSubImage2D',
837         'glTexSubImage2DEXT',
838         'glTexSubImage3D',
839         'glTexSubImage3DEXT',
840         'glTextureImage1DEXT',
841         'glTextureImage2DEXT',
842         'glTextureImage3DEXT',
843         'glTextureSubImage1DEXT',
844         'glTextureSubImage2DEXT',
845         'glTextureSubImage3DEXT',
846     ])
847
848     def serializeArgValue(self, function, arg):
849         # Recognize offsets instead of blobs when a PBO is bound
850         if function.name in self.unpack_function_names \
851            and (isinstance(arg.type, stdapi.Blob) \
852                 or (isinstance(arg.type, stdapi.Const) \
853                     and isinstance(arg.type.type, stdapi.Blob))):
854             print '    {'
855             print '        gltrace::Context *ctx = gltrace::getContext();'
856             print '        GLint _unpack_buffer = 0;'
857             print '        if (ctx->profile == gltrace::PROFILE_COMPAT)'
858             print '            _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
859             print '        if (_unpack_buffer) {'
860             print '            trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
861             print '        } else {'
862             Tracer.serializeArgValue(self, function, arg)
863             print '        }'
864             print '    }'
865             return
866
867         # Several GL state functions take GLenum symbolic names as
868         # integer/floats; so dump the symbolic name whenever possible
869         if function.name.startswith('gl') \
870            and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
871            and arg.name == 'param':
872             assert arg.index > 0
873             assert function.args[arg.index - 1].name == 'pname'
874             assert function.args[arg.index - 1].type == glapi.GLenum
875             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
876             self.serializeValue(glapi.GLenum, arg.name)
877             print '    } else {'
878             Tracer.serializeArgValue(self, function, arg)
879             print '    }'
880             return
881
882         Tracer.serializeArgValue(self, function, arg)
883
884     def footer(self, api):
885         Tracer.footer(self, api)
886
887         # A simple state tracker to track the pointer values
888         # update the state
889         print 'static void _trace_user_arrays(GLuint count)'
890         print '{'
891         print '    gltrace::Context *ctx = gltrace::getContext();'
892
893         for camelcase_name, uppercase_name in self.arrays:
894             # in which profile is the array available?
895             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
896             if camelcase_name in self.arrays_es1:
897                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
898
899             function_name = 'gl%sPointer' % camelcase_name
900             enable_name = 'GL_%s_ARRAY' % uppercase_name
901             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
902             function = api.getFunctionByName(function_name)
903
904             print '    // %s' % function.prototype()
905             print '  if (%s) {' % profile_check
906             self.array_trace_prolog(api, uppercase_name)
907             self.array_prolog(api, uppercase_name)
908             print '    if (_glIsEnabled(%s)) {' % enable_name
909             print '        GLint _binding = 0;'
910             print '        _glGetIntegerv(%s, &_binding);' % binding_name
911             print '        if (!_binding) {'
912
913             # Get the arguments via glGet*
914             for arg in function.args:
915                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
916                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
917                 print '            %s %s = 0;' % (arg_type, arg.name)
918                 print '            _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
919             
920             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
921             print '            size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
922
923             # Emit a fake function
924             self.array_trace_intermezzo(api, uppercase_name)
925             print '            unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
926             for arg in function.args:
927                 assert not arg.output
928                 print '            trace::localWriter.beginArg(%u);' % (arg.index,)
929                 if arg.name != 'pointer':
930                     self.serializeValue(arg.type, arg.name)
931                 else:
932                     print '            trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
933                 print '            trace::localWriter.endArg();'
934             
935             print '            trace::localWriter.endEnter();'
936             print '            trace::localWriter.beginLeave(_call);'
937             print '            trace::localWriter.endLeave();'
938             print '        }'
939             print '    }'
940             self.array_epilog(api, uppercase_name)
941             self.array_trace_epilog(api, uppercase_name)
942             print '  }'
943             print
944
945         # Samething, but for glVertexAttribPointer*
946         #
947         # Some variants of glVertexAttribPointer alias conventional and generic attributes:
948         # - glVertexAttribPointer: no
949         # - glVertexAttribPointerARB: implementation dependent
950         # - glVertexAttribPointerNV: yes
951         #
952         # This means that the implementations of these functions do not always
953         # alias, and they need to be considered independently.
954         #
955         print '    // ES1 does not support generic vertex attributes'
956         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
957         print '        return;'
958         print
959         print '    vertex_attrib _vertex_attrib = _get_vertex_attrib();'
960         print
961         for suffix in ['', 'ARB', 'NV']:
962             if suffix:
963                 SUFFIX = '_' + suffix
964             else:
965                 SUFFIX = suffix
966             function_name = 'glVertexAttribPointer' + suffix
967             function = api.getFunctionByName(function_name)
968
969             print '    // %s' % function.prototype()
970             print '    if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
971             if suffix == 'NV':
972                 print '        GLint _max_vertex_attribs = 16;'
973             else:
974                 print '        GLint _max_vertex_attribs = 0;'
975                 print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
976             print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
977             print '            GLint _enabled = 0;'
978             if suffix == 'NV':
979                 print '            _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
980             else:
981                 print '            _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
982             print '            if (_enabled) {'
983             print '                GLint _binding = 0;'
984             if suffix != 'NV':
985                 # It doesn't seem possible to use VBOs with NV_vertex_program.
986                 print '                _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
987             print '                if (!_binding) {'
988
989             # Get the arguments via glGet*
990             for arg in function.args[1:]:
991                 if suffix == 'NV':
992                     arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
993                 else:
994                     arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
995                 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
996                 print '                    %s %s = 0;' % (arg_type, arg.name)
997                 print '                    _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
998             
999             arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
1000             print '                    size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
1001
1002             # Emit a fake function
1003             print '                    unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1004             for arg in function.args:
1005                 assert not arg.output
1006                 print '                    trace::localWriter.beginArg(%u);' % (arg.index,)
1007                 if arg.name != 'pointer':
1008                     self.serializeValue(arg.type, arg.name)
1009                 else:
1010                     print '                    trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
1011                 print '                    trace::localWriter.endArg();'
1012             
1013             print '                    trace::localWriter.endEnter();'
1014             print '                    trace::localWriter.beginLeave(_call);'
1015             print '                    trace::localWriter.endLeave();'
1016             print '                }'
1017             print '            }'
1018             print '        }'
1019             print '    }'
1020             print
1021
1022         print '}'
1023         print
1024
1025     #
1026     # Hooks for glTexCoordPointer, which is identical to the other array
1027     # pointers except the fact that it is indexed by glClientActiveTexture.
1028     #
1029
1030     def array_prolog(self, api, uppercase_name):
1031         if uppercase_name == 'TEXTURE_COORD':
1032             print '    GLint client_active_texture = 0;'
1033             print '    _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1034             print '    GLint max_texture_coords = 0;'
1035             print '    if (ctx->profile == gltrace::PROFILE_COMPAT)'
1036             print '        _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1037             print '    else'
1038             print '        _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1039             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1040             print '        GLint texture = GL_TEXTURE0 + unit;'
1041             print '        _glClientActiveTexture(texture);'
1042
1043     def array_trace_prolog(self, api, uppercase_name):
1044         if uppercase_name == 'TEXTURE_COORD':
1045             print '    bool client_active_texture_dirty = false;'
1046
1047     def array_epilog(self, api, uppercase_name):
1048         if uppercase_name == 'TEXTURE_COORD':
1049             print '    }'
1050         self.array_cleanup(api, uppercase_name)
1051
1052     def array_cleanup(self, api, uppercase_name):
1053         if uppercase_name == 'TEXTURE_COORD':
1054             print '    _glClientActiveTexture(client_active_texture);'
1055         
1056     def array_trace_intermezzo(self, api, uppercase_name):
1057         if uppercase_name == 'TEXTURE_COORD':
1058             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
1059             print '        client_active_texture_dirty = true;'
1060             self.fake_glClientActiveTexture_call(api, "texture");
1061             print '    }'
1062
1063     def array_trace_epilog(self, api, uppercase_name):
1064         if uppercase_name == 'TEXTURE_COORD':
1065             print '    if (client_active_texture_dirty) {'
1066             self.fake_glClientActiveTexture_call(api, "client_active_texture");
1067             print '    }'
1068
1069     def fake_glClientActiveTexture_call(self, api, texture):
1070         function = api.getFunctionByName('glClientActiveTexture')
1071         self.fake_call(function, [texture])
1072
1073     def emitFakeTexture2D(self):
1074         function = glapi.glapi.getFunctionByName('glTexImage2D')
1075         instances = function.argNames()
1076         print '        unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1077         for arg in function.args:
1078             assert not arg.output
1079             self.serializeArg(function, arg)
1080         print '        trace::localWriter.endEnter();'
1081         print '        trace::localWriter.beginLeave(_fake_call);'
1082         print '        trace::localWriter.endLeave();'
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093