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