]> git.cworth.org Git - apitrace/blob - wrappers/gltrace.py
Compute the vertex buffer sizes in term of vertex count.
[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 'gltrace::Context *'
125         print 'gltrace::getContext(void)'
126         print '{'
127         print '    // TODO return the context set by other APIs (GLX, EGL, and etc.)'
128         print '    static gltrace::Context _ctx = { gltrace::PROFILE_COMPAT, false, false, false };'
129         print '    return &_ctx;'
130         print '}'
131         print
132         print 'static vertex_attrib _get_vertex_attrib(void) {'
133         print '    gltrace::Context *ctx = gltrace::getContext();'
134         print '    if (ctx->user_arrays_arb || ctx->user_arrays_nv) {'
135         print '        GLboolean _vertex_program = GL_FALSE;'
136         print '        _glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &_vertex_program);'
137         print '        if (_vertex_program) {'
138         print '            if (ctx->user_arrays_nv) {'
139         print '                GLint _vertex_program_binding_nv = 0;'
140         print '                _glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &_vertex_program_binding_nv);'
141         print '                if (_vertex_program_binding_nv) {'
142         print '                    return VERTEX_ATTRIB_NV;'
143         print '                }'
144         print '            }'
145         print '            return VERTEX_ATTRIB_ARB;'
146         print '        }'
147         print '    }'
148         print '    return VERTEX_ATTRIB;'
149         print '}'
150         print
151
152         # Whether we need user arrays
153         print 'static inline bool _need_user_arrays(void)'
154         print '{'
155         print '    gltrace::Context *ctx = gltrace::getContext();'
156         print '    if (!ctx->user_arrays) {'
157         print '        return false;'
158         print '    }'
159         print
160
161         for camelcase_name, uppercase_name in self.arrays:
162             # in which profile is the array available?
163             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
164             if camelcase_name in self.arrays_es1:
165                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
166
167             function_name = 'gl%sPointer' % camelcase_name
168             enable_name = 'GL_%s_ARRAY' % uppercase_name
169             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
170             print '    // %s' % function_name
171             print '  if (%s) {' % profile_check
172             self.array_prolog(api, uppercase_name)
173             print '    if (_glIsEnabled(%s)) {' % enable_name
174             print '        GLint _binding = 0;'
175             print '        _glGetIntegerv(%s, &_binding);' % binding_name
176             print '        if (!_binding) {'
177             self.array_cleanup(api, uppercase_name)
178             print '            return true;'
179             print '        }'
180             print '    }'
181             self.array_epilog(api, uppercase_name)
182             print '  }'
183             print
184
185         print '    // ES1 does not support generic vertex attributes'
186         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
187         print '        return false;'
188         print
189         print '    vertex_attrib _vertex_attrib = _get_vertex_attrib();'
190         print
191         print '    // glVertexAttribPointer'
192         print '    if (_vertex_attrib == VERTEX_ATTRIB) {'
193         print '        GLint _max_vertex_attribs = 0;'
194         print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
195         print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
196         print '            GLint _enabled = 0;'
197         print '            _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &_enabled);'
198         print '            if (_enabled) {'
199         print '                GLint _binding = 0;'
200         print '                _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &_binding);'
201         print '                if (!_binding) {'
202         print '                    return true;'
203         print '                }'
204         print '            }'
205         print '        }'
206         print '    }'
207         print
208         print '    // glVertexAttribPointerARB'
209         print '    if (_vertex_attrib == VERTEX_ATTRIB_ARB) {'
210         print '        GLint _max_vertex_attribs = 0;'
211         print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &_max_vertex_attribs);'
212         print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
213         print '            GLint _enabled = 0;'
214         print '            _glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &_enabled);'
215         print '            if (_enabled) {'
216         print '                GLint _binding = 0;'
217         print '                _glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &_binding);'
218         print '                if (!_binding) {'
219         print '                    return true;'
220         print '                }'
221         print '            }'
222         print '        }'
223         print '    }'
224         print
225         print '    // glVertexAttribPointerNV'
226         print '    if (_vertex_attrib == VERTEX_ATTRIB_NV) {'
227         print '        for (GLint index = 0; index < 16; ++index) {'
228         print '            GLint _enabled = 0;'
229         print '            _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
230         print '            if (_enabled) {'
231         print '                return true;'
232         print '            }'
233         print '        }'
234         print '    }'
235         print
236
237         print '    return false;'
238         print '}'
239         print
240
241         print 'static void _trace_user_arrays(GLuint count);'
242         print
243
244         # Buffer mappings
245         print '// whether glMapBufferRange(GL_MAP_WRITE_BIT) has ever been called'
246         print 'static bool _checkBufferMapRange = false;'
247         print
248         print '// whether glBufferParameteriAPPLE(GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE) has ever been called'
249         print 'static bool _checkBufferFlushingUnmapAPPLE = false;'
250         print
251         # Buffer mapping information, necessary for old Mesa 2.1 drivers which
252         # do not support glGetBufferParameteriv(GL_BUFFER_ACCESS_FLAGS/GL_BUFFER_MAP_LENGTH)
253         print 'struct buffer_mapping {'
254         print '    void *map;'
255         print '    GLint length;'
256         print '    bool write;'
257         print '    bool explicit_flush;'
258         print '};'
259         print
260         for target in self.buffer_targets:
261             print 'struct buffer_mapping _%s_mapping;' % target.lower();
262         print
263         print 'static inline struct buffer_mapping *'
264         print 'get_buffer_mapping(GLenum target) {'
265         print '    switch (target) {'
266         for target in self.buffer_targets:
267             print '    case GL_%s:' % target
268             print '        return & _%s_mapping;' % target.lower()
269         print '    default:'
270         print '        os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
271         print '        return NULL;'
272         print '    }'
273         print '}'
274         print
275
276         # Generate a helper function to determine whether a parameter name
277         # refers to a symbolic value or not
278         print 'static bool'
279         print 'is_symbolic_pname(GLenum pname) {'
280         print '    switch (pname) {'
281         for function, type, count, name in glparams.parameters:
282             if type is glapi.GLenum:
283                 print '    case %s:' % name
284         print '        return true;'
285         print '    default:'
286         print '        return false;'
287         print '    }'
288         print '}'
289         print
290         
291         # Generate a helper function to determine whether a parameter value is
292         # potentially symbolic or not; i.e., if the value can be represented in
293         # an enum or not
294         print 'template<class T>'
295         print 'static inline bool'
296         print 'is_symbolic_param(T param) {'
297         print '    return static_cast<T>(static_cast<GLenum>(param)) == param;'
298         print '}'
299         print
300
301         # Generate a helper function to know how many elements a parameter has
302         print 'static size_t'
303         print '_gl_param_size(GLenum pname) {'
304         print '    switch (pname) {'
305         for function, type, count, name in glparams.parameters:
306             if type is not None:
307                 print '    case %s: return %u;' % (name, count)
308         print '    case GL_COMPRESSED_TEXTURE_FORMATS: {'
309         print '            GLint num_compressed_texture_formats = 0;'
310         print '            _glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
311         print '            return num_compressed_texture_formats;'
312         print '        }'
313         print '    default:'
314         print r'        os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
315         print '        return 1;'
316         print '    }'
317         print '}'
318         print
319
320         # states such as GL_UNPACK_ROW_LENGTH are not available in GLES
321         print 'static inline bool'
322         print 'can_unpack_subimage(void) {'
323         print '    gltrace::Context *ctx = gltrace::getContext();'
324         print '    return (ctx->profile == gltrace::PROFILE_COMPAT);'
325         print '}'
326         print
327
328     getProcAddressFunctionNames = []
329
330     def traceApi(self, api):
331         if self.getProcAddressFunctionNames:
332             # Generate a function to wrap proc addresses
333             getProcAddressFunction = api.getFunctionByName(self.getProcAddressFunctionNames[0])
334             argType = getProcAddressFunction.args[0].type
335             retType = getProcAddressFunction.type
336             
337             print 'static %s _wrapProcAddress(%s procName, %s procPtr);' % (retType, argType, retType)
338             print
339             
340             Tracer.traceApi(self, api)
341             
342             print 'static %s _wrapProcAddress(%s procName, %s procPtr) {' % (retType, argType, retType)
343             print '    if (!procPtr) {'
344             print '        return procPtr;'
345             print '    }'
346             for function in api.functions:
347                 ptype = function_pointer_type(function)
348                 pvalue = function_pointer_value(function)
349                 print '    if (strcmp("%s", (const char *)procName) == 0) {' % function.name
350                 print '        %s = (%s)procPtr;' % (pvalue, ptype)
351                 print '        return (%s)&%s;' % (retType, function.name,)
352                 print '    }'
353             print '    os::log("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);'
354             print '    return procPtr;'
355             print '}'
356             print
357         else:
358             Tracer.traceApi(self, api)
359
360     array_pointer_function_names = set((
361         "glVertexPointer",
362         "glNormalPointer",
363         "glColorPointer",
364         "glIndexPointer",
365         "glTexCoordPointer",
366         "glEdgeFlagPointer",
367         "glFogCoordPointer",
368         "glSecondaryColorPointer",
369         
370         "glInterleavedArrays",
371
372         "glVertexPointerEXT",
373         "glNormalPointerEXT",
374         "glColorPointerEXT",
375         "glIndexPointerEXT",
376         "glTexCoordPointerEXT",
377         "glEdgeFlagPointerEXT",
378         "glFogCoordPointerEXT",
379         "glSecondaryColorPointerEXT",
380
381         "glVertexAttribPointer",
382         "glVertexAttribPointerARB",
383         "glVertexAttribPointerNV",
384         "glVertexAttribIPointer",
385         "glVertexAttribIPointerEXT",
386         "glVertexAttribLPointer",
387         "glVertexAttribLPointerEXT",
388         
389         #"glMatrixIndexPointerARB",
390     ))
391
392     draw_function_names = set((
393         'glDrawArrays',
394         'glDrawElements',
395         'glDrawRangeElements',
396         'glMultiDrawArrays',
397         'glMultiDrawElements',
398         'glDrawArraysInstanced',
399         "glDrawArraysInstancedBaseInstance",
400         'glDrawElementsInstanced',
401         'glDrawArraysInstancedARB',
402         'glDrawElementsInstancedARB',
403         'glDrawElementsBaseVertex',
404         'glDrawRangeElementsBaseVertex',
405         'glDrawElementsInstancedBaseVertex',
406         "glDrawElementsInstancedBaseInstance",
407         "glDrawElementsInstancedBaseVertexBaseInstance",
408         'glMultiDrawElementsBaseVertex',
409         'glDrawArraysIndirect',
410         'glDrawElementsIndirect',
411         'glDrawArraysEXT',
412         'glDrawRangeElementsEXT',
413         'glDrawRangeElementsEXT_size',
414         'glMultiDrawArraysEXT',
415         'glMultiDrawElementsEXT',
416         'glMultiModeDrawArraysIBM',
417         'glMultiModeDrawElementsIBM',
418         'glDrawArraysInstancedEXT',
419         'glDrawElementsInstancedEXT',
420     ))
421
422     interleaved_formats = [
423          'GL_V2F',
424          'GL_V3F',
425          'GL_C4UB_V2F',
426          'GL_C4UB_V3F',
427          'GL_C3F_V3F',
428          'GL_N3F_V3F',
429          'GL_C4F_N3F_V3F',
430          'GL_T2F_V3F',
431          'GL_T4F_V4F',
432          'GL_T2F_C4UB_V3F',
433          'GL_T2F_C3F_V3F',
434          'GL_T2F_N3F_V3F',
435          'GL_T2F_C4F_N3F_V3F',
436          'GL_T4F_C4F_N3F_V4F',
437     ]
438
439     def traceFunctionImplBody(self, function):
440         # Defer tracing of user array pointers...
441         if function.name in self.array_pointer_function_names:
442             print '    GLint _array_buffer = 0;'
443             print '    _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
444             print '    if (!_array_buffer) {'
445             print '        gltrace::Context *ctx = gltrace::getContext();'
446             print '        ctx->user_arrays = true;'
447             if function.name == "glVertexAttribPointerARB":
448                 print '        ctx->user_arrays_arb = true;'
449             if function.name == "glVertexAttribPointerNV":
450                 print '        ctx->user_arrays_nv = true;'
451             self.invokeFunction(function)
452
453             # And also break down glInterleavedArrays into the individual calls
454             if function.name == 'glInterleavedArrays':
455                 print
456
457                 # Initialize the enable flags
458                 for camelcase_name, uppercase_name in self.arrays:
459                     flag_name = '_' + uppercase_name.lower()
460                     print '        GLboolean %s = GL_FALSE;' % flag_name
461                 print
462
463                 # Switch for the interleaved formats
464                 print '        switch (format) {'
465                 for format in self.interleaved_formats:
466                     print '            case %s:' % format
467                     for camelcase_name, uppercase_name in self.arrays:
468                         flag_name = '_' + uppercase_name.lower()
469                         if format.find('_' + uppercase_name[0]) >= 0:
470                             print '                %s = GL_TRUE;' % flag_name
471                     print '                break;'
472                 print '            default:'
473                 print '               return;'
474                 print '        }'
475                 print
476
477                 # Emit fake glEnableClientState/glDisableClientState flags
478                 for camelcase_name, uppercase_name in self.arrays:
479                     flag_name = '_' + uppercase_name.lower()
480                     enable_name = 'GL_%s_ARRAY' % uppercase_name
481
482                     # Emit a fake function
483                     print '        {'
484                     print '            static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
485                     print '            unsigned _call = trace::localWriter.beginEnter(&_sig);'
486                     print '            trace::localWriter.beginArg(0);'
487                     self.serializeValue(glapi.GLenum, enable_name)
488                     print '            trace::localWriter.endArg();'
489                     print '            trace::localWriter.endEnter();'
490                     print '            trace::localWriter.beginLeave(_call);'
491                     print '            trace::localWriter.endLeave();'
492                     print '        }'
493
494             print '        return;'
495             print '    }'
496
497         # ... to the draw calls
498         if function.name in self.draw_function_names:
499             print '    if (_need_user_arrays()) {'
500             arg_names = ', '.join([arg.name for arg in function.args[1:]])
501             print '        GLuint _count = _%s_count(%s);' % (function.name, arg_names)
502             print '        _trace_user_arrays(_count);'
503             print '    }'
504         
505         # Emit a fake memcpy on buffer uploads
506         if function.name == 'glBufferParameteriAPPLE':
507             print '    if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
508             print '        _checkBufferFlushingUnmapAPPLE = true;'
509             print '    }'
510         if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
511             if function.name.endswith('ARB'):
512                 suffix = 'ARB'
513             else:
514                 suffix = ''
515             print '    GLint access = 0;'
516             print '    _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
517             print '    if (access != GL_READ_ONLY) {'
518             print '        GLvoid *map = NULL;'
519             print '        _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);'  % suffix
520             print '        if (map) {'
521             print '            GLint length = -1;'
522             print '            bool flush = true;'
523             print '            if (_checkBufferMapRange) {'
524             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
525             print '                GLint access_flags = 0;'
526             print '                _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
527             print '                flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
528             print '                if (length == -1) {'
529             print '                    // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
530             print '                    static bool warned = false;'
531             print '                    if (!warned) {'
532             print '                        os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
533             print '                        warned = true;'
534             print '                    }'
535             print '                    struct buffer_mapping *mapping = get_buffer_mapping(target);'
536             print '                    if (mapping) {'
537             print '                        length = mapping->length;'
538             print '                        flush = flush && !mapping->explicit_flush;'
539             print '                    } else {'
540             print '                        length = 0;'
541             print '                        flush = false;'
542             print '                    }'
543             print '                }'
544             print '            } else {'
545             print '                length = 0;'
546             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
547             print '            }'
548             print '            if (_checkBufferFlushingUnmapAPPLE) {'
549             print '                GLint flushing_unmap = GL_TRUE;'
550             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
551             print '                flush = flush && flushing_unmap;'
552             print '            }'
553             print '            if (flush && length > 0) {'
554             self.emit_memcpy('map', 'map', 'length')
555             print '            }'
556             print '        }'
557             print '    }'
558         if function.name == 'glUnmapBufferOES':
559             print '    GLint access = 0;'
560             print '    _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
561             print '    if (access == GL_WRITE_ONLY_OES) {'
562             print '        GLvoid *map = NULL;'
563             print '        _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
564             print '        GLint size = 0;'
565             print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
566             print '        if (map && size > 0) {'
567             self.emit_memcpy('map', 'map', 'size')
568             print '        }'
569             print '    }'
570         if function.name == 'glUnmapNamedBufferEXT':
571             print '    GLint access_flags = 0;'
572             print '    _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
573             print '    if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
574             print '        GLvoid *map = NULL;'
575             print '        _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
576             print '        GLint length = 0;'
577             print '        _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
578             print '        if (map && length > 0) {'
579             self.emit_memcpy('map', 'map', 'length')
580             print '        }'
581             print '    }'
582         if function.name == 'glFlushMappedBufferRange':
583             print '    GLvoid *map = NULL;'
584             print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
585             print '    if (map && length > 0) {'
586             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
587             print '    }'
588         if function.name == 'glFlushMappedBufferRangeAPPLE':
589             print '    GLvoid *map = NULL;'
590             print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
591             print '    if (map && size > 0) {'
592             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
593             print '    }'
594         if function.name == 'glFlushMappedNamedBufferRangeEXT':
595             print '    GLvoid *map = NULL;'
596             print '    _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
597             print '    if (map && length > 0) {'
598             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
599             print '    }'
600
601         # Don't leave vertex attrib locations to chance.  Instead emit fake
602         # glBindAttribLocation calls to ensure that the same locations will be
603         # used when retracing.  Trying to remap locations after the fact would
604         # be an herculian task given that vertex attrib locations appear in
605         # many entry-points, including non-shader related ones.
606         if function.name == 'glLinkProgram':
607             Tracer.invokeFunction(self, function)
608             print '    GLint active_attributes = 0;'
609             print '    _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
610             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
611             print '        GLint size = 0;'
612             print '        GLenum type = 0;'
613             print '        GLchar name[256];'
614             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
615             print '        _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
616             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
617             print '            GLint location = _glGetAttribLocation(program, name);'
618             print '            if (location >= 0) {'
619             bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
620             self.fake_call(bind_function, ['program', 'location', 'name'])
621             print '            }'
622             print '        }'
623             print '    }'
624         if function.name == 'glLinkProgramARB':
625             Tracer.invokeFunction(self, function)
626             print '    GLint active_attributes = 0;'
627             print '    _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
628             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
629             print '        GLint size = 0;'
630             print '        GLenum type = 0;'
631             print '        GLcharARB name[256];'
632             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
633             print '        _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
634             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
635             print '            GLint location = _glGetAttribLocationARB(programObj, name);'
636             print '            if (location >= 0) {'
637             bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
638             self.fake_call(bind_function, ['programObj', 'location', 'name'])
639             print '            }'
640             print '        }'
641             print '    }'
642
643         Tracer.traceFunctionImplBody(self, function)
644
645     marker_functions = [
646         # GL_GREMEDY_string_marker
647         'glStringMarkerGREMEDY',
648         # GL_GREMEDY_frame_terminator
649         'glFrameTerminatorGREMEDY',
650         # GL_EXT_debug_marker
651         'glInsertEventMarkerEXT',
652         'glPushGroupMarkerEXT',
653         'glPopGroupMarkerEXT',
654     ]
655
656     def invokeFunction(self, function):
657         if function.name in ('glLinkProgram', 'glLinkProgramARB'):
658             # These functions have been dispatched already
659             return
660
661         # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
662         # driver
663         if function.name in self.marker_functions:
664             return
665
666         if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
667             else_ = ''
668             for marker_function in self.marker_functions:
669                 if self.api.getFunctionByName(marker_function):
670                     print '    %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
671                     print '        _result = (%s)&%s;' % (function.type, marker_function)
672                     print '    }'
673                 else_ = 'else '
674             print '    %s{' % else_
675             Tracer.invokeFunction(self, function)
676             print '    }'
677             return
678
679         # Override GL extensions
680         if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
681             Tracer.invokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
682             return
683
684         Tracer.invokeFunction(self, function)
685
686     buffer_targets = [
687         'ARRAY_BUFFER',
688         'ELEMENT_ARRAY_BUFFER',
689         'PIXEL_PACK_BUFFER',
690         'PIXEL_UNPACK_BUFFER',
691         'UNIFORM_BUFFER',
692         'TEXTURE_BUFFER',
693         'TRANSFORM_FEEDBACK_BUFFER',
694         'COPY_READ_BUFFER',
695         'COPY_WRITE_BUFFER',
696         'DRAW_INDIRECT_BUFFER',
697         'ATOMIC_COUNTER_BUFFER',
698     ]
699
700     def wrapRet(self, function, instance):
701         Tracer.wrapRet(self, function, instance)
702
703         # Replace function addresses with ours
704         if function.name in self.getProcAddressFunctionNames:
705             print '    %s = _wrapProcAddress(%s, %s);' % (instance, function.args[0].name, instance)
706
707         # Keep track of buffer mappings
708         if function.name in ('glMapBuffer', 'glMapBufferARB'):
709             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
710             print '    if (mapping) {'
711             print '        mapping->map = %s;' % (instance)
712             print '        mapping->length = 0;'
713             print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
714             print '        mapping->write = (access != GL_READ_ONLY);'
715             print '        mapping->explicit_flush = false;'
716             print '    }'
717         if function.name == 'glMapBufferRange':
718             print '    if (access & GL_MAP_WRITE_BIT) {'
719             print '        _checkBufferMapRange = true;'
720             print '    }'
721             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
722             print '    if (mapping) {'
723             print '        mapping->map = %s;' % (instance)
724             print '        mapping->length = length;'
725             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
726             print '        mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
727             print '    }'
728
729     boolean_names = [
730         'GL_FALSE',
731         'GL_TRUE',
732     ]
733
734     def gl_boolean(self, value):
735         return self.boolean_names[int(bool(value))]
736
737     # Names of the functions that unpack from a pixel buffer object.  See the
738     # ARB_pixel_buffer_object specification.
739     unpack_function_names = set([
740         'glBitmap',
741         'glColorSubTable',
742         'glColorTable',
743         'glCompressedTexImage1D',
744         'glCompressedTexImage2D',
745         'glCompressedTexImage3D',
746         'glCompressedTexSubImage1D',
747         'glCompressedTexSubImage2D',
748         'glCompressedTexSubImage3D',
749         'glConvolutionFilter1D',
750         'glConvolutionFilter2D',
751         'glDrawPixels',
752         'glMultiTexImage1DEXT',
753         'glMultiTexImage2DEXT',
754         'glMultiTexImage3DEXT',
755         'glMultiTexSubImage1DEXT',
756         'glMultiTexSubImage2DEXT',
757         'glMultiTexSubImage3DEXT',
758         'glPixelMapfv',
759         'glPixelMapuiv',
760         'glPixelMapusv',
761         'glPolygonStipple',
762         'glSeparableFilter2D',
763         'glTexImage1D',
764         'glTexImage1DEXT',
765         'glTexImage2D',
766         'glTexImage2DEXT',
767         'glTexImage3D',
768         'glTexImage3DEXT',
769         'glTexSubImage1D',
770         'glTexSubImage1DEXT',
771         'glTexSubImage2D',
772         'glTexSubImage2DEXT',
773         'glTexSubImage3D',
774         'glTexSubImage3DEXT',
775         'glTextureImage1DEXT',
776         'glTextureImage2DEXT',
777         'glTextureImage3DEXT',
778         'glTextureSubImage1DEXT',
779         'glTextureSubImage2DEXT',
780         'glTextureSubImage3DEXT',
781     ])
782
783     def serializeArgValue(self, function, arg):
784         if function.name in self.draw_function_names and arg.name == 'indices':
785             print '    GLint _element_array_buffer = 0;'
786             print '    _glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &_element_array_buffer);'
787             print '    if (!_element_array_buffer) {'
788             if isinstance(arg.type, stdapi.Array):
789                 print '        trace::localWriter.beginArray(%s);' % arg.type.length
790                 print '        for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
791                 print '            trace::localWriter.beginElement();'
792                 print '            trace::localWriter.writeBlob(%s[i], count[i]*_gl_type_size(type));' % (arg.name)
793                 print '            trace::localWriter.endElement();'
794                 print '        }'
795                 print '        trace::localWriter.endArray();'
796             else:
797                 print '        trace::localWriter.writeBlob(%s, count*_gl_type_size(type));' % (arg.name)
798             print '    } else {'
799             Tracer.serializeArgValue(self, function, arg)
800             print '    }'
801             return
802
803         # Recognize offsets instead of blobs when a PBO is bound
804         if function.name in self.unpack_function_names \
805            and (isinstance(arg.type, stdapi.Blob) \
806                 or (isinstance(arg.type, stdapi.Const) \
807                     and isinstance(arg.type.type, stdapi.Blob))):
808             print '    {'
809             print '        gltrace::Context *ctx = gltrace::getContext();'
810             print '        GLint _unpack_buffer = 0;'
811             print '        if (ctx->profile == gltrace::PROFILE_COMPAT)'
812             print '            _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
813             print '        if (_unpack_buffer) {'
814             print '            trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
815             print '        } else {'
816             Tracer.serializeArgValue(self, function, arg)
817             print '        }'
818             print '    }'
819             return
820
821         # Several GL state functions take GLenum symbolic names as
822         # integer/floats; so dump the symbolic name whenever possible
823         if function.name.startswith('gl') \
824            and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
825            and arg.name == 'param':
826             assert arg.index > 0
827             assert function.args[arg.index - 1].name == 'pname'
828             assert function.args[arg.index - 1].type == glapi.GLenum
829             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
830             self.serializeValue(glapi.GLenum, arg.name)
831             print '    } else {'
832             Tracer.serializeArgValue(self, function, arg)
833             print '    }'
834             return
835
836         Tracer.serializeArgValue(self, function, arg)
837
838     def footer(self, api):
839         Tracer.footer(self, api)
840
841         # A simple state tracker to track the pointer values
842         # update the state
843         print 'static void _trace_user_arrays(GLuint count)'
844         print '{'
845         print '    gltrace::Context *ctx = gltrace::getContext();'
846
847         for camelcase_name, uppercase_name in self.arrays:
848             # in which profile is the array available?
849             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
850             if camelcase_name in self.arrays_es1:
851                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
852
853             function_name = 'gl%sPointer' % camelcase_name
854             enable_name = 'GL_%s_ARRAY' % uppercase_name
855             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
856             function = api.getFunctionByName(function_name)
857
858             print '    // %s' % function.prototype()
859             print '  if (%s) {' % profile_check
860             self.array_trace_prolog(api, uppercase_name)
861             self.array_prolog(api, uppercase_name)
862             print '    if (_glIsEnabled(%s)) {' % enable_name
863             print '        GLint _binding = 0;'
864             print '        _glGetIntegerv(%s, &_binding);' % binding_name
865             print '        if (!_binding) {'
866
867             # Get the arguments via glGet*
868             for arg in function.args:
869                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
870                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
871                 print '            %s %s = 0;' % (arg_type, arg.name)
872                 print '            _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
873             
874             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
875             print '            size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
876
877             # Emit a fake function
878             self.array_trace_intermezzo(api, uppercase_name)
879             print '            unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
880             for arg in function.args:
881                 assert not arg.output
882                 print '            trace::localWriter.beginArg(%u);' % (arg.index,)
883                 if arg.name != 'pointer':
884                     self.serializeValue(arg.type, arg.name)
885                 else:
886                     print '            trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
887                 print '            trace::localWriter.endArg();'
888             
889             print '            trace::localWriter.endEnter();'
890             print '            trace::localWriter.beginLeave(_call);'
891             print '            trace::localWriter.endLeave();'
892             print '        }'
893             print '    }'
894             self.array_epilog(api, uppercase_name)
895             self.array_trace_epilog(api, uppercase_name)
896             print '  }'
897             print
898
899         # Samething, but for glVertexAttribPointer*
900         #
901         # Some variants of glVertexAttribPointer alias conventional and generic attributes:
902         # - glVertexAttribPointer: no
903         # - glVertexAttribPointerARB: implementation dependent
904         # - glVertexAttribPointerNV: yes
905         #
906         # This means that the implementations of these functions do not always
907         # alias, and they need to be considered independently.
908         #
909         print '    // ES1 does not support generic vertex attributes'
910         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
911         print '        return;'
912         print
913         print '    vertex_attrib _vertex_attrib = _get_vertex_attrib();'
914         print
915         for suffix in ['', 'ARB', 'NV']:
916             if suffix:
917                 SUFFIX = '_' + suffix
918             else:
919                 SUFFIX = suffix
920             function_name = 'glVertexAttribPointer' + suffix
921             function = api.getFunctionByName(function_name)
922
923             print '    // %s' % function.prototype()
924             print '    if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
925             if suffix == 'NV':
926                 print '        GLint _max_vertex_attribs = 16;'
927             else:
928                 print '        GLint _max_vertex_attribs = 0;'
929                 print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
930             print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
931             print '            GLint _enabled = 0;'
932             if suffix == 'NV':
933                 print '            _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
934             else:
935                 print '            _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
936             print '            if (_enabled) {'
937             print '                GLint _binding = 0;'
938             if suffix != 'NV':
939                 # It doesn't seem possible to use VBOs with NV_vertex_program.
940                 print '                _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
941             print '                if (!_binding) {'
942
943             # Get the arguments via glGet*
944             for arg in function.args[1:]:
945                 if suffix == 'NV':
946                     arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
947                 else:
948                     arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
949                 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
950                 print '                    %s %s = 0;' % (arg_type, arg.name)
951                 print '                    _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
952             
953             arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
954             print '                    size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
955
956             # Emit a fake function
957             print '                    unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
958             for arg in function.args:
959                 assert not arg.output
960                 print '                    trace::localWriter.beginArg(%u);' % (arg.index,)
961                 if arg.name != 'pointer':
962                     self.serializeValue(arg.type, arg.name)
963                 else:
964                     print '                    trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
965                 print '                    trace::localWriter.endArg();'
966             
967             print '                    trace::localWriter.endEnter();'
968             print '                    trace::localWriter.beginLeave(_call);'
969             print '                    trace::localWriter.endLeave();'
970             print '                }'
971             print '            }'
972             print '        }'
973             print '    }'
974             print
975
976         print '}'
977         print
978
979     #
980     # Hooks for glTexCoordPointer, which is identical to the other array
981     # pointers except the fact that it is indexed by glClientActiveTexture.
982     #
983
984     def array_prolog(self, api, uppercase_name):
985         if uppercase_name == 'TEXTURE_COORD':
986             print '    GLint client_active_texture = 0;'
987             print '    _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
988             print '    GLint max_texture_coords = 0;'
989             print '    if (ctx->profile == gltrace::PROFILE_COMPAT)'
990             print '        _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
991             print '    else'
992             print '        _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
993             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
994             print '        GLint texture = GL_TEXTURE0 + unit;'
995             print '        _glClientActiveTexture(texture);'
996
997     def array_trace_prolog(self, api, uppercase_name):
998         if uppercase_name == 'TEXTURE_COORD':
999             print '    bool client_active_texture_dirty = false;'
1000
1001     def array_epilog(self, api, uppercase_name):
1002         if uppercase_name == 'TEXTURE_COORD':
1003             print '    }'
1004         self.array_cleanup(api, uppercase_name)
1005
1006     def array_cleanup(self, api, uppercase_name):
1007         if uppercase_name == 'TEXTURE_COORD':
1008             print '    _glClientActiveTexture(client_active_texture);'
1009         
1010     def array_trace_intermezzo(self, api, uppercase_name):
1011         if uppercase_name == 'TEXTURE_COORD':
1012             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
1013             print '        client_active_texture_dirty = true;'
1014             self.fake_glClientActiveTexture_call(api, "texture");
1015             print '    }'
1016
1017     def array_trace_epilog(self, api, uppercase_name):
1018         if uppercase_name == 'TEXTURE_COORD':
1019             print '    if (client_active_texture_dirty) {'
1020             self.fake_glClientActiveTexture_call(api, "client_active_texture");
1021             print '    }'
1022
1023     def fake_glClientActiveTexture_call(self, api, texture):
1024         function = api.getFunctionByName('glClientActiveTexture')
1025         self.fake_call(function, [texture])
1026
1027     def fake_call(self, function, args):
1028         print '            unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
1029         for arg, instance in zip(function.args, args):
1030             assert not arg.output
1031             print '            trace::localWriter.beginArg(%u);' % (arg.index,)
1032             self.serializeValue(arg.type, instance)
1033             print '            trace::localWriter.endArg();'
1034         print '            trace::localWriter.endEnter();'
1035         print '            trace::localWriter.beginLeave(_fake_call);'
1036         print '            trace::localWriter.endLeave();'
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047