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