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