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