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