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