]> git.cworth.org Git - apitrace/blob - wrappers/gltrace.py
4ee9373439f9baa3fba04844a8599fd48b61dd81
[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         # Recognize offsets instead of blobs when a PBO is bound
828         if function.name in self.unpack_function_names \
829            and (isinstance(arg.type, stdapi.Blob) \
830                 or (isinstance(arg.type, stdapi.Const) \
831                     and isinstance(arg.type.type, stdapi.Blob))):
832             print '    {'
833             print '        gltrace::Context *ctx = gltrace::getContext();'
834             print '        GLint _unpack_buffer = 0;'
835             print '        if (ctx->profile == gltrace::PROFILE_COMPAT)'
836             print '            _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
837             print '        if (_unpack_buffer) {'
838             print '            trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
839             print '        } else {'
840             Tracer.serializeArgValue(self, function, arg)
841             print '        }'
842             print '    }'
843             return
844
845         # Several GL state functions take GLenum symbolic names as
846         # integer/floats; so dump the symbolic name whenever possible
847         if function.name.startswith('gl') \
848            and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
849            and arg.name == 'param':
850             assert arg.index > 0
851             assert function.args[arg.index - 1].name == 'pname'
852             assert function.args[arg.index - 1].type == glapi.GLenum
853             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
854             self.serializeValue(glapi.GLenum, arg.name)
855             print '    } else {'
856             Tracer.serializeArgValue(self, function, arg)
857             print '    }'
858             return
859
860         Tracer.serializeArgValue(self, function, arg)
861
862     def footer(self, api):
863         Tracer.footer(self, api)
864
865         # A simple state tracker to track the pointer values
866         # update the state
867         print 'static void _trace_user_arrays(GLuint count)'
868         print '{'
869         print '    gltrace::Context *ctx = gltrace::getContext();'
870
871         for camelcase_name, uppercase_name in self.arrays:
872             # in which profile is the array available?
873             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
874             if camelcase_name in self.arrays_es1:
875                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
876
877             function_name = 'gl%sPointer' % camelcase_name
878             enable_name = 'GL_%s_ARRAY' % uppercase_name
879             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
880             function = api.getFunctionByName(function_name)
881
882             print '    // %s' % function.prototype()
883             print '  if (%s) {' % profile_check
884             self.array_trace_prolog(api, uppercase_name)
885             self.array_prolog(api, uppercase_name)
886             print '    if (_glIsEnabled(%s)) {' % enable_name
887             print '        GLint _binding = 0;'
888             print '        _glGetIntegerv(%s, &_binding);' % binding_name
889             print '        if (!_binding) {'
890
891             # Get the arguments via glGet*
892             for arg in function.args:
893                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
894                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
895                 print '            %s %s = 0;' % (arg_type, arg.name)
896                 print '            _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
897             
898             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
899             print '            size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
900
901             # Emit a fake function
902             self.array_trace_intermezzo(api, uppercase_name)
903             print '            unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
904             for arg in function.args:
905                 assert not arg.output
906                 print '            trace::localWriter.beginArg(%u);' % (arg.index,)
907                 if arg.name != 'pointer':
908                     self.serializeValue(arg.type, arg.name)
909                 else:
910                     print '            trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
911                 print '            trace::localWriter.endArg();'
912             
913             print '            trace::localWriter.endEnter();'
914             print '            trace::localWriter.beginLeave(_call);'
915             print '            trace::localWriter.endLeave();'
916             print '        }'
917             print '    }'
918             self.array_epilog(api, uppercase_name)
919             self.array_trace_epilog(api, uppercase_name)
920             print '  }'
921             print
922
923         # Samething, but for glVertexAttribPointer*
924         #
925         # Some variants of glVertexAttribPointer alias conventional and generic attributes:
926         # - glVertexAttribPointer: no
927         # - glVertexAttribPointerARB: implementation dependent
928         # - glVertexAttribPointerNV: yes
929         #
930         # This means that the implementations of these functions do not always
931         # alias, and they need to be considered independently.
932         #
933         print '    // ES1 does not support generic vertex attributes'
934         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
935         print '        return;'
936         print
937         print '    vertex_attrib _vertex_attrib = _get_vertex_attrib();'
938         print
939         for suffix in ['', 'ARB', 'NV']:
940             if suffix:
941                 SUFFIX = '_' + suffix
942             else:
943                 SUFFIX = suffix
944             function_name = 'glVertexAttribPointer' + suffix
945             function = api.getFunctionByName(function_name)
946
947             print '    // %s' % function.prototype()
948             print '    if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
949             if suffix == 'NV':
950                 print '        GLint _max_vertex_attribs = 16;'
951             else:
952                 print '        GLint _max_vertex_attribs = 0;'
953                 print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
954             print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
955             print '            GLint _enabled = 0;'
956             if suffix == 'NV':
957                 print '            _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
958             else:
959                 print '            _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
960             print '            if (_enabled) {'
961             print '                GLint _binding = 0;'
962             if suffix != 'NV':
963                 # It doesn't seem possible to use VBOs with NV_vertex_program.
964                 print '                _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
965             print '                if (!_binding) {'
966
967             # Get the arguments via glGet*
968             for arg in function.args[1:]:
969                 if suffix == 'NV':
970                     arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
971                 else:
972                     arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
973                 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
974                 print '                    %s %s = 0;' % (arg_type, arg.name)
975                 print '                    _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
976             
977             arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
978             print '                    size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
979
980             # Emit a fake function
981             print '                    unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
982             for arg in function.args:
983                 assert not arg.output
984                 print '                    trace::localWriter.beginArg(%u);' % (arg.index,)
985                 if arg.name != 'pointer':
986                     self.serializeValue(arg.type, arg.name)
987                 else:
988                     print '                    trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
989                 print '                    trace::localWriter.endArg();'
990             
991             print '                    trace::localWriter.endEnter();'
992             print '                    trace::localWriter.beginLeave(_call);'
993             print '                    trace::localWriter.endLeave();'
994             print '                }'
995             print '            }'
996             print '        }'
997             print '    }'
998             print
999
1000         print '}'
1001         print
1002
1003     #
1004     # Hooks for glTexCoordPointer, which is identical to the other array
1005     # pointers except the fact that it is indexed by glClientActiveTexture.
1006     #
1007
1008     def array_prolog(self, api, uppercase_name):
1009         if uppercase_name == 'TEXTURE_COORD':
1010             print '    GLint client_active_texture = 0;'
1011             print '    _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1012             print '    GLint max_texture_coords = 0;'
1013             print '    if (ctx->profile == gltrace::PROFILE_COMPAT)'
1014             print '        _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1015             print '    else'
1016             print '        _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1017             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1018             print '        GLint texture = GL_TEXTURE0 + unit;'
1019             print '        _glClientActiveTexture(texture);'
1020
1021     def array_trace_prolog(self, api, uppercase_name):
1022         if uppercase_name == 'TEXTURE_COORD':
1023             print '    bool client_active_texture_dirty = false;'
1024
1025     def array_epilog(self, api, uppercase_name):
1026         if uppercase_name == 'TEXTURE_COORD':
1027             print '    }'
1028         self.array_cleanup(api, uppercase_name)
1029
1030     def array_cleanup(self, api, uppercase_name):
1031         if uppercase_name == 'TEXTURE_COORD':
1032             print '    _glClientActiveTexture(client_active_texture);'
1033         
1034     def array_trace_intermezzo(self, api, uppercase_name):
1035         if uppercase_name == 'TEXTURE_COORD':
1036             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
1037             print '        client_active_texture_dirty = true;'
1038             self.fake_glClientActiveTexture_call(api, "texture");
1039             print '    }'
1040
1041     def array_trace_epilog(self, api, uppercase_name):
1042         if uppercase_name == 'TEXTURE_COORD':
1043             print '    if (client_active_texture_dirty) {'
1044             self.fake_glClientActiveTexture_call(api, "client_active_texture");
1045             print '    }'
1046
1047     def fake_glClientActiveTexture_call(self, api, texture):
1048         function = api.getFunctionByName('glClientActiveTexture')
1049         self.fake_call(function, [texture])
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061