]> git.cworth.org Git - apitrace/blob - wrappers/gltrace.py
glxtrace: Basic EXT_texture_from_pixmap support.
[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         '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         # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
704         # driver
705         if function.name in self.marker_functions:
706             return
707
708         if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
709             else_ = ''
710             for marker_function in self.marker_functions:
711                 if self.api.getFunctionByName(marker_function):
712                     print '    %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
713                     print '        _result = (%s)&%s;' % (function.type, marker_function)
714                     print '    }'
715                 else_ = 'else '
716             print '    %s{' % else_
717             Tracer.invokeFunction(self, function)
718             print '    }'
719             return
720
721         # Override GL extensions
722         if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
723             Tracer.invokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
724             return
725
726         Tracer.invokeFunction(self, function)
727
728     buffer_targets = [
729         'ARRAY_BUFFER',
730         'ELEMENT_ARRAY_BUFFER',
731         'PIXEL_PACK_BUFFER',
732         'PIXEL_UNPACK_BUFFER',
733         'UNIFORM_BUFFER',
734         'TEXTURE_BUFFER',
735         'TRANSFORM_FEEDBACK_BUFFER',
736         'COPY_READ_BUFFER',
737         'COPY_WRITE_BUFFER',
738         'DRAW_INDIRECT_BUFFER',
739         'ATOMIC_COUNTER_BUFFER',
740     ]
741
742     def wrapRet(self, function, instance):
743         Tracer.wrapRet(self, function, instance)
744
745         # Replace function addresses with ours
746         if function.name in self.getProcAddressFunctionNames:
747             print '    %s = _wrapProcAddress(%s, %s);' % (instance, function.args[0].name, instance)
748
749         # Keep track of buffer mappings
750         if function.name in ('glMapBuffer', 'glMapBufferARB'):
751             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
752             print '    if (mapping) {'
753             print '        mapping->map = %s;' % (instance)
754             print '        mapping->length = 0;'
755             print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
756             print '        mapping->write = (access != GL_READ_ONLY);'
757             print '        mapping->explicit_flush = false;'
758             print '    }'
759         if function.name == 'glMapBufferRange':
760             print '    if (access & GL_MAP_WRITE_BIT) {'
761             print '        _checkBufferMapRange = true;'
762             print '    }'
763             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
764             print '    if (mapping) {'
765             print '        mapping->map = %s;' % (instance)
766             print '        mapping->length = length;'
767             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
768             print '        mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
769             print '    }'
770
771     boolean_names = [
772         'GL_FALSE',
773         'GL_TRUE',
774     ]
775
776     def gl_boolean(self, value):
777         return self.boolean_names[int(bool(value))]
778
779     # Names of the functions that unpack from a pixel buffer object.  See the
780     # ARB_pixel_buffer_object specification.
781     unpack_function_names = set([
782         'glBitmap',
783         'glColorSubTable',
784         'glColorTable',
785         'glCompressedMultiTexImage1DEXT',
786         'glCompressedMultiTexImage2DEXT',
787         'glCompressedMultiTexImage3DEXT',
788         'glCompressedMultiTexSubImage1DEXT',
789         'glCompressedMultiTexSubImage2DEXT',
790         'glCompressedMultiTexSubImage3DEXT',
791         'glCompressedTexImage1D',
792         'glCompressedTexImage2D',
793         'glCompressedTexImage3D',
794         'glCompressedTexSubImage1D',
795         'glCompressedTexSubImage2D',
796         'glCompressedTexSubImage3D',
797         'glCompressedTextureImage1DEXT',
798         'glCompressedTextureImage2DEXT',
799         'glCompressedTextureImage3DEXT',
800         'glCompressedTextureSubImage1DEXT',
801         'glCompressedTextureSubImage2DEXT',
802         'glCompressedTextureSubImage3DEXT',
803         'glConvolutionFilter1D',
804         'glConvolutionFilter2D',
805         'glDrawPixels',
806         'glMultiTexImage1DEXT',
807         'glMultiTexImage2DEXT',
808         'glMultiTexImage3DEXT',
809         'glMultiTexSubImage1DEXT',
810         'glMultiTexSubImage2DEXT',
811         'glMultiTexSubImage3DEXT',
812         'glPixelMapfv',
813         'glPixelMapuiv',
814         'glPixelMapusv',
815         'glPolygonStipple',
816         'glSeparableFilter2D',
817         'glTexImage1D',
818         'glTexImage1DEXT',
819         'glTexImage2D',
820         'glTexImage2DEXT',
821         'glTexImage3D',
822         'glTexImage3DEXT',
823         'glTexSubImage1D',
824         'glTexSubImage1DEXT',
825         'glTexSubImage2D',
826         'glTexSubImage2DEXT',
827         'glTexSubImage3D',
828         'glTexSubImage3DEXT',
829         'glTextureImage1DEXT',
830         'glTextureImage2DEXT',
831         'glTextureImage3DEXT',
832         'glTextureSubImage1DEXT',
833         'glTextureSubImage2DEXT',
834         'glTextureSubImage3DEXT',
835     ])
836
837     def serializeArgValue(self, function, arg):
838         # Recognize offsets instead of blobs when a PBO is bound
839         if function.name in self.unpack_function_names \
840            and (isinstance(arg.type, stdapi.Blob) \
841                 or (isinstance(arg.type, stdapi.Const) \
842                     and isinstance(arg.type.type, stdapi.Blob))):
843             print '    {'
844             print '        gltrace::Context *ctx = gltrace::getContext();'
845             print '        GLint _unpack_buffer = 0;'
846             print '        if (ctx->profile == gltrace::PROFILE_COMPAT)'
847             print '            _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
848             print '        if (_unpack_buffer) {'
849             print '            trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
850             print '        } else {'
851             Tracer.serializeArgValue(self, function, arg)
852             print '        }'
853             print '    }'
854             return
855
856         # Several GL state functions take GLenum symbolic names as
857         # integer/floats; so dump the symbolic name whenever possible
858         if function.name.startswith('gl') \
859            and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
860            and arg.name == 'param':
861             assert arg.index > 0
862             assert function.args[arg.index - 1].name == 'pname'
863             assert function.args[arg.index - 1].type == glapi.GLenum
864             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
865             self.serializeValue(glapi.GLenum, arg.name)
866             print '    } else {'
867             Tracer.serializeArgValue(self, function, arg)
868             print '    }'
869             return
870
871         Tracer.serializeArgValue(self, function, arg)
872
873     def footer(self, api):
874         Tracer.footer(self, api)
875
876         # A simple state tracker to track the pointer values
877         # update the state
878         print 'static void _trace_user_arrays(GLuint count)'
879         print '{'
880         print '    gltrace::Context *ctx = gltrace::getContext();'
881
882         for camelcase_name, uppercase_name in self.arrays:
883             # in which profile is the array available?
884             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
885             if camelcase_name in self.arrays_es1:
886                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
887
888             function_name = 'gl%sPointer' % camelcase_name
889             enable_name = 'GL_%s_ARRAY' % uppercase_name
890             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
891             function = api.getFunctionByName(function_name)
892
893             print '    // %s' % function.prototype()
894             print '  if (%s) {' % profile_check
895             self.array_trace_prolog(api, uppercase_name)
896             self.array_prolog(api, uppercase_name)
897             print '    if (_glIsEnabled(%s)) {' % enable_name
898             print '        GLint _binding = 0;'
899             print '        _glGetIntegerv(%s, &_binding);' % binding_name
900             print '        if (!_binding) {'
901
902             # Get the arguments via glGet*
903             for arg in function.args:
904                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
905                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
906                 print '            %s %s = 0;' % (arg_type, arg.name)
907                 print '            _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
908             
909             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
910             print '            size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
911
912             # Emit a fake function
913             self.array_trace_intermezzo(api, uppercase_name)
914             print '            unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
915             for arg in function.args:
916                 assert not arg.output
917                 print '            trace::localWriter.beginArg(%u);' % (arg.index,)
918                 if arg.name != 'pointer':
919                     self.serializeValue(arg.type, arg.name)
920                 else:
921                     print '            trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
922                 print '            trace::localWriter.endArg();'
923             
924             print '            trace::localWriter.endEnter();'
925             print '            trace::localWriter.beginLeave(_call);'
926             print '            trace::localWriter.endLeave();'
927             print '        }'
928             print '    }'
929             self.array_epilog(api, uppercase_name)
930             self.array_trace_epilog(api, uppercase_name)
931             print '  }'
932             print
933
934         # Samething, but for glVertexAttribPointer*
935         #
936         # Some variants of glVertexAttribPointer alias conventional and generic attributes:
937         # - glVertexAttribPointer: no
938         # - glVertexAttribPointerARB: implementation dependent
939         # - glVertexAttribPointerNV: yes
940         #
941         # This means that the implementations of these functions do not always
942         # alias, and they need to be considered independently.
943         #
944         print '    // ES1 does not support generic vertex attributes'
945         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
946         print '        return;'
947         print
948         print '    vertex_attrib _vertex_attrib = _get_vertex_attrib();'
949         print
950         for suffix in ['', 'ARB', 'NV']:
951             if suffix:
952                 SUFFIX = '_' + suffix
953             else:
954                 SUFFIX = suffix
955             function_name = 'glVertexAttribPointer' + suffix
956             function = api.getFunctionByName(function_name)
957
958             print '    // %s' % function.prototype()
959             print '    if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
960             if suffix == 'NV':
961                 print '        GLint _max_vertex_attribs = 16;'
962             else:
963                 print '        GLint _max_vertex_attribs = 0;'
964                 print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
965             print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
966             print '            GLint _enabled = 0;'
967             if suffix == 'NV':
968                 print '            _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
969             else:
970                 print '            _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
971             print '            if (_enabled) {'
972             print '                GLint _binding = 0;'
973             if suffix != 'NV':
974                 # It doesn't seem possible to use VBOs with NV_vertex_program.
975                 print '                _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
976             print '                if (!_binding) {'
977
978             # Get the arguments via glGet*
979             for arg in function.args[1:]:
980                 if suffix == 'NV':
981                     arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
982                 else:
983                     arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
984                 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
985                 print '                    %s %s = 0;' % (arg_type, arg.name)
986                 print '                    _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
987             
988             arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
989             print '                    size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
990
991             # Emit a fake function
992             print '                    unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
993             for arg in function.args:
994                 assert not arg.output
995                 print '                    trace::localWriter.beginArg(%u);' % (arg.index,)
996                 if arg.name != 'pointer':
997                     self.serializeValue(arg.type, arg.name)
998                 else:
999                     print '                    trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
1000                 print '                    trace::localWriter.endArg();'
1001             
1002             print '                    trace::localWriter.endEnter();'
1003             print '                    trace::localWriter.beginLeave(_call);'
1004             print '                    trace::localWriter.endLeave();'
1005             print '                }'
1006             print '            }'
1007             print '        }'
1008             print '    }'
1009             print
1010
1011         print '}'
1012         print
1013
1014     #
1015     # Hooks for glTexCoordPointer, which is identical to the other array
1016     # pointers except the fact that it is indexed by glClientActiveTexture.
1017     #
1018
1019     def array_prolog(self, api, uppercase_name):
1020         if uppercase_name == 'TEXTURE_COORD':
1021             print '    GLint client_active_texture = 0;'
1022             print '    _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1023             print '    GLint max_texture_coords = 0;'
1024             print '    if (ctx->profile == gltrace::PROFILE_COMPAT)'
1025             print '        _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1026             print '    else'
1027             print '        _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1028             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1029             print '        GLint texture = GL_TEXTURE0 + unit;'
1030             print '        _glClientActiveTexture(texture);'
1031
1032     def array_trace_prolog(self, api, uppercase_name):
1033         if uppercase_name == 'TEXTURE_COORD':
1034             print '    bool client_active_texture_dirty = false;'
1035
1036     def array_epilog(self, api, uppercase_name):
1037         if uppercase_name == 'TEXTURE_COORD':
1038             print '    }'
1039         self.array_cleanup(api, uppercase_name)
1040
1041     def array_cleanup(self, api, uppercase_name):
1042         if uppercase_name == 'TEXTURE_COORD':
1043             print '    _glClientActiveTexture(client_active_texture);'
1044         
1045     def array_trace_intermezzo(self, api, uppercase_name):
1046         if uppercase_name == 'TEXTURE_COORD':
1047             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
1048             print '        client_active_texture_dirty = true;'
1049             self.fake_glClientActiveTexture_call(api, "texture");
1050             print '    }'
1051
1052     def array_trace_epilog(self, api, uppercase_name):
1053         if uppercase_name == 'TEXTURE_COORD':
1054             print '    if (client_active_texture_dirty) {'
1055             self.fake_glClientActiveTexture_call(api, "client_active_texture");
1056             print '    }'
1057
1058     def fake_glClientActiveTexture_call(self, api, texture):
1059         function = api.getFunctionByName('glClientActiveTexture')
1060         self.fake_call(function, [texture])
1061
1062     def emitFakeTexture2D(self):
1063         function = glapi.glapi.getFunctionByName('glTexImage2D')
1064         instances = function.argNames()
1065         print '        unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1066         for arg in function.args:
1067             assert not arg.output
1068             self.serializeArg(function, arg)
1069         print '        trace::localWriter.endEnter();'
1070         print '        trace::localWriter.beginLeave(_fake_call);'
1071         print '        trace::localWriter.endLeave();'
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082