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