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