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