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