]> git.cworth.org Git - apitrace/blob - wrappers/gltrace.py
Move tracers to wrappers subdirectory.
[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 import specs.stdapi as stdapi
32 import specs.glapi as glapi
33 import specs.glparams as glparams
34 from specs.glxapi import glxapi
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 '                    static bool warned = false;'
498             print '                    if (!warned) {'
499             print '                        os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
500             print '                        warned = true;'
501             print '                    }'
502             print '                    struct buffer_mapping *mapping = get_buffer_mapping(target);'
503             print '                    if (mapping) {'
504             print '                        length = mapping->length;'
505             print '                        flush = flush && !mapping->explicit_flush;'
506             print '                    } else {'
507             print '                        length = 0;'
508             print '                        flush = false;'
509             print '                    }'
510             print '                }'
511             print '            } else {'
512             print '                length = 0;'
513             print '                __glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
514             print '            }'
515             print '            if (__checkBufferFlushingUnmapAPPLE) {'
516             print '                GLint flushing_unmap = GL_TRUE;'
517             print '                __glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
518             print '                flush = flush && flushing_unmap;'
519             print '            }'
520             print '            if (flush && length > 0) {'
521             self.emit_memcpy('map', 'map', 'length')
522             print '            }'
523             print '        }'
524             print '    }'
525         if function.name == 'glUnmapBufferOES':
526             print '    GLint access = 0;'
527             print '    __glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
528             print '    if (access == GL_WRITE_ONLY_OES) {'
529             print '        GLvoid *map = NULL;'
530             print '        __glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
531             print '        GLint size = 0;'
532             print '        __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
533             print '        if (map && size > 0) {'
534             self.emit_memcpy('map', 'map', 'size')
535             print '        }'
536             print '    }'
537         if function.name == 'glUnmapNamedBufferEXT':
538             print '    GLint access_flags = 0;'
539             print '    __glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
540             print '    if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
541             print '        GLvoid *map = NULL;'
542             print '        __glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
543             print '        GLint length = 0;'
544             print '        __glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
545             print '        if (map && length > 0) {'
546             self.emit_memcpy('map', 'map', 'length')
547             print '        }'
548             print '    }'
549         if function.name == 'glFlushMappedBufferRange':
550             print '    GLvoid *map = NULL;'
551             print '    __glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
552             print '    if (map && length > 0) {'
553             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
554             print '    }'
555         if function.name == 'glFlushMappedBufferRangeAPPLE':
556             print '    GLvoid *map = NULL;'
557             print '    __glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
558             print '    if (map && size > 0) {'
559             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
560             print '    }'
561         if function.name == 'glFlushMappedNamedBufferRangeEXT':
562             print '    GLvoid *map = NULL;'
563             print '    __glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
564             print '    if (map && length > 0) {'
565             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
566             print '    }'
567
568         # Don't leave vertex attrib locations to chance.  Instead emit fake
569         # glBindAttribLocation calls to ensure that the same locations will be
570         # used when retracing.  Trying to remap locations after the fact would
571         # be an herculian task given that vertex attrib locations appear in
572         # many entry-points, including non-shader related ones.
573         if function.name == 'glLinkProgram':
574             Tracer.invokeFunction(self, function)
575             print '    GLint active_attributes = 0;'
576             print '    __glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
577             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
578             print '        GLint size = 0;'
579             print '        GLenum type = 0;'
580             print '        GLchar name[256];'
581             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
582             print '        __glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
583             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
584             print '            GLint location = __glGetAttribLocation(program, name);'
585             print '            if (location >= 0) {'
586             bind_function = glapi.glapi.get_function_by_name('glBindAttribLocation')
587             self.fake_call(bind_function, ['program', 'location', 'name'])
588             print '            }'
589             print '        }'
590             print '    }'
591         if function.name == 'glLinkProgramARB':
592             Tracer.invokeFunction(self, function)
593             print '    GLint active_attributes = 0;'
594             print '    __glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
595             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
596             print '        GLint size = 0;'
597             print '        GLenum type = 0;'
598             print '        GLcharARB name[256];'
599             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
600             print '        __glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
601             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
602             print '            GLint location = __glGetAttribLocationARB(programObj, name);'
603             print '            if (location >= 0) {'
604             bind_function = glapi.glapi.get_function_by_name('glBindAttribLocationARB')
605             self.fake_call(bind_function, ['programObj', 'location', 'name'])
606             print '            }'
607             print '        }'
608             print '    }'
609
610         Tracer.traceFunctionImplBody(self, function)
611
612     marker_functions = [
613         # GL_GREMEDY_string_marker
614         'glStringMarkerGREMEDY',
615         # GL_GREMEDY_frame_terminator
616         'glFrameTerminatorGREMEDY',
617         # GL_EXT_debug_marker
618         'glInsertEventMarkerEXT',
619         'glPushGroupMarkerEXT',
620         'glPopGroupMarkerEXT',
621     ]
622
623     def invokeFunction(self, function):
624         if function.name in ('glLinkProgram', 'glLinkProgramARB'):
625             # These functions have been dispatched already
626             return
627
628         # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
629         # driver
630         if function.name in self.marker_functions:
631             return
632
633         if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
634             else_ = ''
635             for marker_function in self.marker_functions:
636                 if self.api.get_function_by_name(marker_function):
637                     print '    %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
638                     print '        __result = (%s)&%s;' % (function.type, marker_function)
639                     print '    }'
640                 else_ = 'else '
641             print '    %s{' % else_
642             Tracer.invokeFunction(self, function)
643             print '    }'
644             return
645
646         # Override GL extensions
647         if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
648             Tracer.invokeFunction(self, function, prefix = 'gltrace::__', suffix = '_override')
649             return
650
651         Tracer.invokeFunction(self, function)
652
653     buffer_targets = [
654         'ARRAY_BUFFER',
655         'ELEMENT_ARRAY_BUFFER',
656         'PIXEL_PACK_BUFFER',
657         'PIXEL_UNPACK_BUFFER',
658         'UNIFORM_BUFFER',
659         'TEXTURE_BUFFER',
660         'TRANSFORM_FEEDBACK_BUFFER',
661         'COPY_READ_BUFFER',
662         'COPY_WRITE_BUFFER',
663         'DRAW_INDIRECT_BUFFER',
664         'ATOMIC_COUNTER_BUFFER',
665     ]
666
667     def wrapRet(self, function, instance):
668         Tracer.wrapRet(self, function, instance)
669
670         # Keep track of buffer mappings
671         if function.name in ('glMapBuffer', 'glMapBufferARB'):
672             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
673             print '    if (mapping) {'
674             print '        mapping->map = %s;' % (instance)
675             print '        mapping->length = 0;'
676             print '        __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
677             print '        mapping->write = (access != GL_READ_ONLY);'
678             print '        mapping->explicit_flush = false;'
679             print '    }'
680         if function.name == 'glMapBufferRange':
681             print '    if (access & GL_MAP_WRITE_BIT) {'
682             print '        __checkBufferMapRange = true;'
683             print '    }'
684             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
685             print '    if (mapping) {'
686             print '        mapping->map = %s;' % (instance)
687             print '        mapping->length = length;'
688             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
689             print '        mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
690             print '    }'
691
692     boolean_names = [
693         'GL_FALSE',
694         'GL_TRUE',
695     ]
696
697     def gl_boolean(self, value):
698         return self.boolean_names[int(bool(value))]
699
700     # Names of the functions that unpack from a pixel buffer object.  See the
701     # ARB_pixel_buffer_object specification.
702     unpack_function_names = set([
703         'glBitmap',
704         'glColorSubTable',
705         'glColorTable',
706         'glCompressedTexImage1D',
707         'glCompressedTexImage2D',
708         'glCompressedTexImage3D',
709         'glCompressedTexSubImage1D',
710         'glCompressedTexSubImage2D',
711         'glCompressedTexSubImage3D',
712         'glConvolutionFilter1D',
713         'glConvolutionFilter2D',
714         'glDrawPixels',
715         'glMultiTexImage1DEXT',
716         'glMultiTexImage2DEXT',
717         'glMultiTexImage3DEXT',
718         'glMultiTexSubImage1DEXT',
719         'glMultiTexSubImage2DEXT',
720         'glMultiTexSubImage3DEXT',
721         'glPixelMapfv',
722         'glPixelMapuiv',
723         'glPixelMapusv',
724         'glPolygonStipple',
725         'glSeparableFilter2D',
726         'glTexImage1D',
727         'glTexImage1DEXT',
728         'glTexImage2D',
729         'glTexImage2DEXT',
730         'glTexImage3D',
731         'glTexImage3DEXT',
732         'glTexSubImage1D',
733         'glTexSubImage1DEXT',
734         'glTexSubImage2D',
735         'glTexSubImage2DEXT',
736         'glTexSubImage3D',
737         'glTexSubImage3DEXT',
738         'glTextureImage1DEXT',
739         'glTextureImage2DEXT',
740         'glTextureImage3DEXT',
741         'glTextureSubImage1DEXT',
742         'glTextureSubImage2DEXT',
743         'glTextureSubImage3DEXT',
744     ])
745
746     def serializeArgValue(self, function, arg):
747         if function.name in self.draw_function_names and arg.name == 'indices':
748             print '    GLint __element_array_buffer = 0;'
749             print '    __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
750             print '    if (!__element_array_buffer) {'
751             if isinstance(arg.type, stdapi.Array):
752                 print '        trace::localWriter.beginArray(%s);' % arg.type.length
753                 print '        for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
754                 print '            trace::localWriter.beginElement();'
755                 print '            trace::localWriter.writeBlob(%s[i], count[i]*__gl_type_size(type));' % (arg.name)
756                 print '            trace::localWriter.endElement();'
757                 print '        }'
758                 print '        trace::localWriter.endArray();'
759             else:
760                 print '        trace::localWriter.writeBlob(%s, count*__gl_type_size(type));' % (arg.name)
761             print '    } else {'
762             Tracer.serializeArgValue(self, function, arg)
763             print '    }'
764             return
765
766         # Recognize offsets instead of blobs when a PBO is bound
767         if function.name in self.unpack_function_names \
768            and (isinstance(arg.type, stdapi.Blob) \
769                 or (isinstance(arg.type, stdapi.Const) \
770                     and isinstance(arg.type.type, stdapi.Blob))):
771             print '    {'
772             print '        gltrace::Context *ctx = gltrace::getContext();'
773             print '        GLint __unpack_buffer = 0;'
774             print '        if (ctx->profile == gltrace::PROFILE_COMPAT)'
775             print '            __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
776             print '        if (__unpack_buffer) {'
777             print '            trace::localWriter.writeOpaque(%s);' % arg.name
778             print '        } else {'
779             Tracer.serializeArgValue(self, function, arg)
780             print '        }'
781             print '    }'
782             return
783
784         # Several GL state functions take GLenum symbolic names as
785         # integer/floats; so dump the symbolic name whenever possible
786         if function.name.startswith('gl') \
787            and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
788            and arg.name == 'param':
789             assert arg.index > 0
790             assert function.args[arg.index - 1].name == 'pname'
791             assert function.args[arg.index - 1].type == glapi.GLenum
792             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
793             self.serializeValue(glapi.GLenum, arg.name)
794             print '    } else {'
795             Tracer.serializeArgValue(self, function, arg)
796             print '    }'
797             return
798
799         Tracer.serializeArgValue(self, function, arg)
800
801     def footer(self, api):
802         Tracer.footer(self, api)
803
804         # A simple state tracker to track the pointer values
805         # update the state
806         print 'static void __trace_user_arrays(GLuint maxindex)'
807         print '{'
808         print '    gltrace::Context *ctx = gltrace::getContext();'
809
810         for camelcase_name, uppercase_name in self.arrays:
811             # in which profile is the array available?
812             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
813             if camelcase_name in self.arrays_es1:
814                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
815
816             function_name = 'gl%sPointer' % camelcase_name
817             enable_name = 'GL_%s_ARRAY' % uppercase_name
818             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
819             function = api.get_function_by_name(function_name)
820
821             print '    // %s' % function.prototype()
822             print '  if (%s) {' % profile_check
823             self.array_trace_prolog(api, uppercase_name)
824             self.array_prolog(api, uppercase_name)
825             print '    if (__glIsEnabled(%s)) {' % enable_name
826             print '        GLint __binding = 0;'
827             print '        __glGetIntegerv(%s, &__binding);' % binding_name
828             print '        if (!__binding) {'
829
830             # Get the arguments via glGet*
831             for arg in function.args:
832                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
833                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
834                 print '            %s %s = 0;' % (arg_type, arg.name)
835                 print '            __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
836             
837             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
838             print '            size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
839
840             # Emit a fake function
841             self.array_trace_intermezzo(api, uppercase_name)
842             print '            unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
843             for arg in function.args:
844                 assert not arg.output
845                 print '            trace::localWriter.beginArg(%u);' % (arg.index,)
846                 if arg.name != 'pointer':
847                     self.serializeValue(arg.type, arg.name)
848                 else:
849                     print '            trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
850                 print '            trace::localWriter.endArg();'
851             
852             print '            trace::localWriter.endEnter();'
853             print '            trace::localWriter.beginLeave(__call);'
854             print '            trace::localWriter.endLeave();'
855             print '        }'
856             print '    }'
857             self.array_epilog(api, uppercase_name)
858             self.array_trace_epilog(api, uppercase_name)
859             print '  }'
860             print
861
862         # Samething, but for glVertexAttribPointer*
863         #
864         # Some variants of glVertexAttribPointer alias conventional and generic attributes:
865         # - glVertexAttribPointer: no
866         # - glVertexAttribPointerARB: implementation dependent
867         # - glVertexAttribPointerNV: yes
868         #
869         # This means that the implementations of these functions do not always
870         # alias, and they need to be considered independently.
871         #
872         print '    // ES1 does not support generic vertex attributes'
873         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
874         print '        return;'
875         print
876         print '    vertex_attrib __vertex_attrib = __get_vertex_attrib();'
877         print
878         for suffix in ['', 'ARB', 'NV']:
879             if suffix:
880                 SUFFIX = '_' + suffix
881             else:
882                 SUFFIX = suffix
883             function_name = 'glVertexAttribPointer' + suffix
884             function = api.get_function_by_name(function_name)
885
886             print '    // %s' % function.prototype()
887             print '    if (__vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
888             if suffix == 'NV':
889                 print '        GLint __max_vertex_attribs = 16;'
890             else:
891                 print '        GLint __max_vertex_attribs = 0;'
892                 print '        __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
893             print '        for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
894             print '            GLint __enabled = 0;'
895             if suffix == 'NV':
896                 print '            __glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &__enabled);'
897             else:
898                 print '            __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &__enabled);' % (suffix, SUFFIX)
899             print '            if (__enabled) {'
900             print '                GLint __binding = 0;'
901             if suffix != 'NV':
902                 # It doesn't seem possible to use VBOs with NV_vertex_program.
903                 print '                __glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &__binding);' % (suffix, SUFFIX)
904             print '                if (!__binding) {'
905
906             # Get the arguments via glGet*
907             for arg in function.args[1:]:
908                 if suffix == 'NV':
909                     arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
910                 else:
911                     arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
912                 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
913                 print '                    %s %s = 0;' % (arg_type, arg.name)
914                 print '                    __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
915             
916             arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
917             print '                    size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
918
919             # Emit a fake function
920             print '                    unsigned __call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
921             for arg in function.args:
922                 assert not arg.output
923                 print '                    trace::localWriter.beginArg(%u);' % (arg.index,)
924                 if arg.name != 'pointer':
925                     self.serializeValue(arg.type, arg.name)
926                 else:
927                     print '                    trace::localWriter.writeBlob((const void *)%s, __size);' % (arg.name)
928                 print '                    trace::localWriter.endArg();'
929             
930             print '                    trace::localWriter.endEnter();'
931             print '                    trace::localWriter.beginLeave(__call);'
932             print '                    trace::localWriter.endLeave();'
933             print '                }'
934             print '            }'
935             print '        }'
936             print '    }'
937             print
938
939         print '}'
940         print
941
942     #
943     # Hooks for glTexCoordPointer, which is identical to the other array
944     # pointers except the fact that it is indexed by glClientActiveTexture.
945     #
946
947     def array_prolog(self, api, uppercase_name):
948         if uppercase_name == 'TEXTURE_COORD':
949             print '    GLint client_active_texture = 0;'
950             print '    __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
951             print '    GLint max_texture_coords = 0;'
952             print '    if (ctx->profile == gltrace::PROFILE_COMPAT)'
953             print '        __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
954             print '    else'
955             print '        __glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
956             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
957             print '        GLint texture = GL_TEXTURE0 + unit;'
958             print '        __glClientActiveTexture(texture);'
959
960     def array_trace_prolog(self, api, uppercase_name):
961         if uppercase_name == 'TEXTURE_COORD':
962             print '    bool client_active_texture_dirty = false;'
963
964     def array_epilog(self, api, uppercase_name):
965         if uppercase_name == 'TEXTURE_COORD':
966             print '    }'
967         self.array_cleanup(api, uppercase_name)
968
969     def array_cleanup(self, api, uppercase_name):
970         if uppercase_name == 'TEXTURE_COORD':
971             print '    __glClientActiveTexture(client_active_texture);'
972         
973     def array_trace_intermezzo(self, api, uppercase_name):
974         if uppercase_name == 'TEXTURE_COORD':
975             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
976             print '        client_active_texture_dirty = true;'
977             self.fake_glClientActiveTexture_call(api, "texture");
978             print '    }'
979
980     def array_trace_epilog(self, api, uppercase_name):
981         if uppercase_name == 'TEXTURE_COORD':
982             print '    if (client_active_texture_dirty) {'
983             self.fake_glClientActiveTexture_call(api, "client_active_texture");
984             print '    }'
985
986     def fake_glClientActiveTexture_call(self, api, texture):
987         function = api.get_function_by_name('glClientActiveTexture')
988         self.fake_call(function, [texture])
989
990     def fake_call(self, function, args):
991         print '            unsigned __fake_call = trace::localWriter.beginEnter(&__%s_sig);' % (function.name,)
992         for arg, instance in zip(function.args, args):
993             assert not arg.output
994             print '            trace::localWriter.beginArg(%u);' % (arg.index,)
995             self.serializeValue(arg.type, instance)
996             print '            trace::localWriter.endArg();'
997         print '            trace::localWriter.endEnter();'
998         print '            trace::localWriter.beginLeave(__fake_call);'
999         print '            trace::localWriter.endLeave();'
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010