]> git.cworth.org Git - apitrace/blob - wrappers/gltrace.py
gltrace,glretrace: Properly handle PBOs with GL_EXT_direct_state_access.
[apitrace] / wrappers / 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 from trace import Tracer
31 from dispatch import function_pointer_type, function_pointer_value
32 import specs.stdapi as stdapi
33 import specs.glapi as glapi
34 import specs.glparams as glparams
35 from specs.glxapi import glxapi
36
37
38 class TypeGetter(stdapi.Visitor):
39     '''Determine which glGet*v function that matches the specified type.'''
40
41     def __init__(self, prefix = 'glGet', long_suffix = True, ext_suffix = ''):
42         self.prefix = prefix
43         self.long_suffix = long_suffix
44         self.ext_suffix = ext_suffix
45
46     def visitConst(self, const):
47         return self.visit(const.type)
48
49     def visitAlias(self, alias):
50         if alias.expr == 'GLboolean':
51             if self.long_suffix:
52                 suffix = 'Booleanv'
53                 arg_type = alias.expr
54             else:
55                 suffix = 'iv'
56                 arg_type = 'GLint'
57         elif alias.expr == 'GLdouble':
58             if self.long_suffix:
59                 suffix = 'Doublev'
60                 arg_type = alias.expr
61             else:
62                 suffix = 'dv'
63                 arg_type = alias.expr
64         elif alias.expr == 'GLfloat':
65             if self.long_suffix:
66                 suffix = 'Floatv'
67                 arg_type = alias.expr
68             else:
69                 suffix = 'fv'
70                 arg_type = alias.expr
71         elif alias.expr in ('GLint', 'GLuint', 'GLsizei'):
72             if self.long_suffix:
73                 suffix = 'Integerv'
74                 arg_type = 'GLint'
75             else:
76                 suffix = 'iv'
77                 arg_type = 'GLint'
78         else:
79             print alias.expr
80             assert False
81         function_name = self.prefix + suffix + self.ext_suffix
82         return function_name, arg_type
83     
84     def visitEnum(self, enum):
85         return self.visit(glapi.GLint)
86
87     def visitBitmask(self, bitmask):
88         return self.visit(glapi.GLint)
89
90     def visitOpaque(self, pointer):
91         return self.prefix + 'Pointerv' + self.ext_suffix, 'GLvoid *'
92
93
94 class GlTracer(Tracer):
95
96     arrays = [
97         ("Vertex", "VERTEX"),
98         ("Normal", "NORMAL"),
99         ("Color", "COLOR"),
100         ("Index", "INDEX"),
101         ("TexCoord", "TEXTURE_COORD"),
102         ("EdgeFlag", "EDGE_FLAG"),
103         ("FogCoord", "FOG_COORD"),
104         ("SecondaryColor", "SECONDARY_COLOR"),
105     ]
106     arrays.reverse()
107
108     # arrays available in PROFILE_ES1
109     arrays_es1 = ("Vertex", "Normal", "Color", "TexCoord")
110
111     def header(self, api):
112         Tracer.header(self, api)
113
114         print '#include "gltrace.hpp"'
115         print
116         
117         # Which glVertexAttrib* variant to use
118         print 'enum vertex_attrib {'
119         print '    VERTEX_ATTRIB,'
120         print '    VERTEX_ATTRIB_ARB,'
121         print '    VERTEX_ATTRIB_NV,'
122         print '};'
123         print
124         print 'static vertex_attrib _get_vertex_attrib(void) {'
125         print '    gltrace::Context *ctx = gltrace::getContext();'
126         print '    if (ctx->user_arrays_arb || ctx->user_arrays_nv) {'
127         print '        GLboolean _vertex_program = GL_FALSE;'
128         print '        _glGetBooleanv(GL_VERTEX_PROGRAM_ARB, &_vertex_program);'
129         print '        if (_vertex_program) {'
130         print '            if (ctx->user_arrays_nv) {'
131         print '                GLint _vertex_program_binding_nv = 0;'
132         print '                _glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &_vertex_program_binding_nv);'
133         print '                if (_vertex_program_binding_nv) {'
134         print '                    return VERTEX_ATTRIB_NV;'
135         print '                }'
136         print '            }'
137         print '            return VERTEX_ATTRIB_ARB;'
138         print '        }'
139         print '    }'
140         print '    return VERTEX_ATTRIB;'
141         print '}'
142         print
143
144         self.defineShadowBufferHelper()
145
146         # Whether we need user arrays
147         print 'static inline bool _need_user_arrays(void)'
148         print '{'
149         print '    gltrace::Context *ctx = gltrace::getContext();'
150         print '    if (!ctx->user_arrays) {'
151         print '        return false;'
152         print '    }'
153         print
154
155         for camelcase_name, uppercase_name in self.arrays:
156             # in which profile is the array available?
157             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
158             if camelcase_name in self.arrays_es1:
159                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
160
161             function_name = 'gl%sPointer' % camelcase_name
162             enable_name = 'GL_%s_ARRAY' % uppercase_name
163             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
164             print '    // %s' % function_name
165             print '  if (%s) {' % profile_check
166             self.array_prolog(api, uppercase_name)
167             print '    if (_glIsEnabled(%s)) {' % enable_name
168             print '        GLint _binding = 0;'
169             print '        _glGetIntegerv(%s, &_binding);' % binding_name
170             print '        if (!_binding) {'
171             self.array_cleanup(api, uppercase_name)
172             print '            return true;'
173             print '        }'
174             print '    }'
175             self.array_epilog(api, uppercase_name)
176             print '  }'
177             print
178
179         print '    // ES1 does not support generic vertex attributes'
180         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
181         print '        return false;'
182         print
183         print '    vertex_attrib _vertex_attrib = _get_vertex_attrib();'
184         print
185         print '    // glVertexAttribPointer'
186         print '    if (_vertex_attrib == VERTEX_ATTRIB) {'
187         print '        GLint _max_vertex_attribs = 0;'
188         print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
189         print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
190         print '            GLint _enabled = 0;'
191         print '            _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &_enabled);'
192         print '            if (_enabled) {'
193         print '                GLint _binding = 0;'
194         print '                _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &_binding);'
195         print '                if (!_binding) {'
196         print '                    return true;'
197         print '                }'
198         print '            }'
199         print '        }'
200         print '    }'
201         print
202         print '    // glVertexAttribPointerARB'
203         print '    if (_vertex_attrib == VERTEX_ATTRIB_ARB) {'
204         print '        GLint _max_vertex_attribs = 0;'
205         print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &_max_vertex_attribs);'
206         print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
207         print '            GLint _enabled = 0;'
208         print '            _glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &_enabled);'
209         print '            if (_enabled) {'
210         print '                GLint _binding = 0;'
211         print '                _glGetVertexAttribivARB(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB, &_binding);'
212         print '                if (!_binding) {'
213         print '                    return true;'
214         print '                }'
215         print '            }'
216         print '        }'
217         print '    }'
218         print
219         print '    // glVertexAttribPointerNV'
220         print '    if (_vertex_attrib == VERTEX_ATTRIB_NV) {'
221         print '        for (GLint index = 0; index < 16; ++index) {'
222         print '            GLint _enabled = 0;'
223         print '            _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
224         print '            if (_enabled) {'
225         print '                return true;'
226         print '            }'
227         print '        }'
228         print '    }'
229         print
230
231         print '    return false;'
232         print '}'
233         print
234
235         print 'static void _trace_user_arrays(GLuint count);'
236         print
237
238         # Buffer mappings
239         print '// whether glMapBufferRange(GL_MAP_WRITE_BIT) has ever been called'
240         print 'static bool _checkBufferMapRange = false;'
241         print
242         print '// whether glBufferParameteriAPPLE(GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE) has ever been called'
243         print 'static bool _checkBufferFlushingUnmapAPPLE = false;'
244         print
245         # Buffer mapping information, necessary for old Mesa 2.1 drivers which
246         # do not support glGetBufferParameteriv(GL_BUFFER_ACCESS_FLAGS/GL_BUFFER_MAP_LENGTH)
247         print 'struct buffer_mapping {'
248         print '    void *map;'
249         print '    GLint length;'
250         print '    bool write;'
251         print '    bool explicit_flush;'
252         print '};'
253         print
254         for target in self.buffer_targets:
255             print 'struct buffer_mapping _%s_mapping;' % target.lower();
256         print
257         print 'static inline struct buffer_mapping *'
258         print 'get_buffer_mapping(GLenum target) {'
259         print '    switch (target) {'
260         for target in self.buffer_targets:
261             print '    case GL_%s:' % target
262             print '        return & _%s_mapping;' % target.lower()
263         print '    default:'
264         print '        os::log("apitrace: warning: unknown buffer target 0x%04X\\n", target);'
265         print '        return NULL;'
266         print '    }'
267         print '}'
268         print
269
270         # Generate a helper function to determine whether a parameter name
271         # refers to a symbolic value or not
272         print 'static bool'
273         print 'is_symbolic_pname(GLenum pname) {'
274         print '    switch (pname) {'
275         for function, type, count, name in glparams.parameters:
276             if type is glapi.GLenum:
277                 print '    case %s:' % name
278         print '        return true;'
279         print '    default:'
280         print '        return false;'
281         print '    }'
282         print '}'
283         print
284         
285         # Generate a helper function to determine whether a parameter value is
286         # potentially symbolic or not; i.e., if the value can be represented in
287         # an enum or not
288         print 'template<class T>'
289         print 'static inline bool'
290         print 'is_symbolic_param(T param) {'
291         print '    return static_cast<T>(static_cast<GLenum>(param)) == param;'
292         print '}'
293         print
294
295         # Generate a helper function to know how many elements a parameter has
296         print 'static size_t'
297         print '_gl_param_size(GLenum pname) {'
298         print '    switch (pname) {'
299         for function, type, count, name in glparams.parameters:
300             if type is not None:
301                 print '    case %s: return %s;' % (name, count)
302         print '    default:'
303         print r'        os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
304         print '        return 1;'
305         print '    }'
306         print '}'
307         print
308
309         # states such as GL_UNPACK_ROW_LENGTH are not available in GLES
310         print 'static inline bool'
311         print 'can_unpack_subimage(void) {'
312         print '    gltrace::Context *ctx = gltrace::getContext();'
313         print '    return (ctx->profile == gltrace::PROFILE_COMPAT);'
314         print '}'
315         print
316
317     getProcAddressFunctionNames = []
318
319     def traceApi(self, api):
320         if self.getProcAddressFunctionNames:
321             # Generate a function to wrap proc addresses
322             getProcAddressFunction = api.getFunctionByName(self.getProcAddressFunctionNames[0])
323             argType = getProcAddressFunction.args[0].type
324             retType = getProcAddressFunction.type
325             
326             print 'static %s _wrapProcAddress(%s procName, %s procPtr);' % (retType, argType, retType)
327             print
328             
329             Tracer.traceApi(self, api)
330             
331             print 'static %s _wrapProcAddress(%s procName, %s procPtr) {' % (retType, argType, retType)
332             print '    if (!procPtr) {'
333             print '        return procPtr;'
334             print '    }'
335             for function in api.getAllFunctions():
336                 ptype = function_pointer_type(function)
337                 pvalue = function_pointer_value(function)
338                 print '    if (strcmp("%s", (const char *)procName) == 0) {' % function.name
339                 print '        %s = (%s)procPtr;' % (pvalue, ptype)
340                 print '        return (%s)&%s;' % (retType, function.name,)
341                 print '    }'
342             print '    os::log("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);'
343             print '    return procPtr;'
344             print '}'
345             print
346         else:
347             Tracer.traceApi(self, api)
348
349     def defineShadowBufferHelper(self):
350         print 'void _shadow_glGetBufferSubData(GLenum target, GLintptr offset,'
351         print '                                GLsizeiptr size, GLvoid *data)'
352         print '{'
353         print '    gltrace::Context *ctx = gltrace::getContext();'
354         print '    if (!ctx->needsShadowBuffers() || target != GL_ELEMENT_ARRAY_BUFFER) {'
355         print '        _glGetBufferSubData(target, offset, size, data);'
356         print '        return;'
357         print '    }'
358         print
359         print '    GLint buffer_binding = 0;'
360         print '    _glGetIntegerv(target, &buffer_binding);'
361         print '    if (buffer_binding > 0) {'
362         print '        gltrace::Buffer & buf = ctx->buffers[buffer_binding];'
363         print '        buf.getSubData(offset, size, data);'
364         print '    }'
365         print '}'
366
367     def shadowBufferMethod(self, method):
368         # Emit code to fetch the shadow buffer, and invoke a method
369         print '    gltrace::Context *ctx = gltrace::getContext();'
370         print '    if (ctx->needsShadowBuffers() && target == GL_ELEMENT_ARRAY_BUFFER) {'
371         print '        GLint buffer_binding = 0;'
372         print '        _glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buffer_binding);'
373         print '        if (buffer_binding > 0) {'
374         print '            gltrace::Buffer & buf = ctx->buffers[buffer_binding];'
375         print '            buf.' + method + ';'
376         print '        }'
377         print '    }'
378         print
379
380     def shadowBufferProlog(self, function):
381         if function.name == 'glBufferData':
382             self.shadowBufferMethod('bufferData(size, data)')
383
384         if function.name == 'glBufferSubData':
385             self.shadowBufferMethod('bufferSubData(offset, size, data)')
386
387         if function.name == 'glDeleteBuffers':
388             print '    gltrace::Context *ctx = gltrace::getContext();'
389             print '    if (ctx->needsShadowBuffers()) {'
390             print '        for (GLsizei i = 0; i < n; i++) {'
391             print '            ctx->buffers.erase(buffer[i]);'
392             print '        }'
393             print '    }'
394
395     array_pointer_function_names = set((
396         "glVertexPointer",
397         "glNormalPointer",
398         "glColorPointer",
399         "glIndexPointer",
400         "glTexCoordPointer",
401         "glEdgeFlagPointer",
402         "glFogCoordPointer",
403         "glSecondaryColorPointer",
404         
405         "glInterleavedArrays",
406
407         "glVertexPointerEXT",
408         "glNormalPointerEXT",
409         "glColorPointerEXT",
410         "glIndexPointerEXT",
411         "glTexCoordPointerEXT",
412         "glEdgeFlagPointerEXT",
413         "glFogCoordPointerEXT",
414         "glSecondaryColorPointerEXT",
415
416         "glVertexAttribPointer",
417         "glVertexAttribPointerARB",
418         "glVertexAttribPointerNV",
419         "glVertexAttribIPointer",
420         "glVertexAttribIPointerEXT",
421         "glVertexAttribLPointer",
422         "glVertexAttribLPointerEXT",
423         
424         #"glMatrixIndexPointerARB",
425     ))
426
427     draw_function_names = set((
428         'glDrawArrays',
429         'glDrawElements',
430         'glDrawRangeElements',
431         'glMultiDrawArrays',
432         'glMultiDrawElements',
433         'glDrawArraysInstanced',
434         "glDrawArraysInstancedBaseInstance",
435         'glDrawElementsInstanced',
436         'glDrawArraysInstancedARB',
437         'glDrawElementsInstancedARB',
438         'glDrawElementsBaseVertex',
439         'glDrawRangeElementsBaseVertex',
440         'glDrawElementsInstancedBaseVertex',
441         "glDrawElementsInstancedBaseInstance",
442         "glDrawElementsInstancedBaseVertexBaseInstance",
443         'glMultiDrawElementsBaseVertex',
444         'glDrawArraysIndirect',
445         'glDrawElementsIndirect',
446         'glDrawArraysEXT',
447         'glDrawRangeElementsEXT',
448         'glDrawRangeElementsEXT_size',
449         'glMultiDrawArraysEXT',
450         'glMultiDrawElementsEXT',
451         'glMultiModeDrawArraysIBM',
452         'glMultiModeDrawElementsIBM',
453         'glDrawArraysInstancedEXT',
454         'glDrawElementsInstancedEXT',
455     ))
456
457     interleaved_formats = [
458          'GL_V2F',
459          'GL_V3F',
460          'GL_C4UB_V2F',
461          'GL_C4UB_V3F',
462          'GL_C3F_V3F',
463          'GL_N3F_V3F',
464          'GL_C4F_N3F_V3F',
465          'GL_T2F_V3F',
466          'GL_T4F_V4F',
467          'GL_T2F_C4UB_V3F',
468          'GL_T2F_C3F_V3F',
469          'GL_T2F_N3F_V3F',
470          'GL_T2F_C4F_N3F_V3F',
471          'GL_T4F_C4F_N3F_V4F',
472     ]
473
474     def traceFunctionImplBody(self, function):
475         # Defer tracing of user array pointers...
476         if function.name in self.array_pointer_function_names:
477             print '    GLint _array_buffer = 0;'
478             print '    _glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
479             print '    if (!_array_buffer) {'
480             print '        gltrace::Context *ctx = gltrace::getContext();'
481             print '        ctx->user_arrays = true;'
482             if function.name == "glVertexAttribPointerARB":
483                 print '        ctx->user_arrays_arb = true;'
484             if function.name == "glVertexAttribPointerNV":
485                 print '        ctx->user_arrays_nv = true;'
486             self.invokeFunction(function)
487
488             # And also break down glInterleavedArrays into the individual calls
489             if function.name == 'glInterleavedArrays':
490                 print
491
492                 # Initialize the enable flags
493                 for camelcase_name, uppercase_name in self.arrays:
494                     flag_name = '_' + uppercase_name.lower()
495                     print '        GLboolean %s = GL_FALSE;' % flag_name
496                 print
497
498                 # Switch for the interleaved formats
499                 print '        switch (format) {'
500                 for format in self.interleaved_formats:
501                     print '            case %s:' % format
502                     for camelcase_name, uppercase_name in self.arrays:
503                         flag_name = '_' + uppercase_name.lower()
504                         if format.find('_' + uppercase_name[0]) >= 0:
505                             print '                %s = GL_TRUE;' % flag_name
506                     print '                break;'
507                 print '            default:'
508                 print '               return;'
509                 print '        }'
510                 print
511
512                 # Emit fake glEnableClientState/glDisableClientState flags
513                 for camelcase_name, uppercase_name in self.arrays:
514                     flag_name = '_' + uppercase_name.lower()
515                     enable_name = 'GL_%s_ARRAY' % uppercase_name
516
517                     # Emit a fake function
518                     print '        {'
519                     print '            static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name
520                     print '            unsigned _call = trace::localWriter.beginEnter(&_sig);'
521                     print '            trace::localWriter.beginArg(0);'
522                     self.serializeValue(glapi.GLenum, enable_name)
523                     print '            trace::localWriter.endArg();'
524                     print '            trace::localWriter.endEnter();'
525                     print '            trace::localWriter.beginLeave(_call);'
526                     print '            trace::localWriter.endLeave();'
527                     print '        }'
528
529             print '        return;'
530             print '    }'
531
532         # ... to the draw calls
533         if function.name in self.draw_function_names:
534             print '    if (_need_user_arrays()) {'
535             arg_names = ', '.join([arg.name for arg in function.args[1:]])
536             print '        GLuint _count = _%s_count(%s);' % (function.name, arg_names)
537             print '        _trace_user_arrays(_count);'
538             print '    }'
539         
540         # Emit a fake memcpy on buffer uploads
541         if function.name == 'glBufferParameteriAPPLE':
542             print '    if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {'
543             print '        _checkBufferFlushingUnmapAPPLE = true;'
544             print '    }'
545         if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
546             if function.name.endswith('ARB'):
547                 suffix = 'ARB'
548             else:
549                 suffix = ''
550             print '    GLint access = 0;'
551             print '    _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix
552             print '    if (access != GL_READ_ONLY) {'
553             print '        GLvoid *map = NULL;'
554             print '        _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);'  % suffix
555             print '        if (map) {'
556             print '            GLint length = -1;'
557             print '            bool flush = true;'
558             print '            if (_checkBufferMapRange) {'
559             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix
560             print '                GLint access_flags = 0;'
561             print '                _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
562             print '                flush = flush && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT);'
563             print '                if (length == -1) {'
564             print '                    // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0'
565             print '                    static bool warned = false;'
566             print '                    if (!warned) {'
567             print '                        os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix
568             print '                        warned = true;'
569             print '                    }'
570             print '                    struct buffer_mapping *mapping = get_buffer_mapping(target);'
571             print '                    if (mapping) {'
572             print '                        length = mapping->length;'
573             print '                        flush = flush && !mapping->explicit_flush;'
574             print '                    } else {'
575             print '                        length = 0;'
576             print '                        flush = false;'
577             print '                    }'
578             print '                }'
579             print '            } else {'
580             print '                length = 0;'
581             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix
582             print '            }'
583             print '            if (_checkBufferFlushingUnmapAPPLE) {'
584             print '                GLint flushing_unmap = GL_TRUE;'
585             print '                _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix
586             print '                flush = flush && flushing_unmap;'
587             print '            }'
588             print '            if (flush && length > 0) {'
589             self.emit_memcpy('map', 'map', 'length')
590             print '            }'
591             print '        }'
592             print '    }'
593         if function.name == 'glUnmapBufferOES':
594             print '    GLint access = 0;'
595             print '    _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_OES, &access);'
596             print '    if (access == GL_WRITE_ONLY_OES) {'
597             print '        GLvoid *map = NULL;'
598             print '        _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);'
599             print '        GLint size = 0;'
600             print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);'
601             print '        if (map && size > 0) {'
602             self.emit_memcpy('map', 'map', 'size')
603             self.shadowBufferMethod('bufferSubData(0, size, map)')
604             print '        }'
605             print '    }'
606         if function.name == 'glUnmapNamedBufferEXT':
607             print '    GLint access_flags = 0;'
608             print '    _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);'
609             print '    if ((access_flags & GL_MAP_WRITE_BIT) && !(access_flags & GL_MAP_FLUSH_EXPLICIT_BIT)) {'
610             print '        GLvoid *map = NULL;'
611             print '        _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
612             print '        GLint length = 0;'
613             print '        _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);'
614             print '        if (map && length > 0) {'
615             self.emit_memcpy('map', 'map', 'length')
616             print '        }'
617             print '    }'
618         if function.name == 'glFlushMappedBufferRange':
619             print '    GLvoid *map = NULL;'
620             print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
621             print '    if (map && length > 0) {'
622             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
623             print '    }'
624         if function.name == 'glFlushMappedBufferRangeAPPLE':
625             print '    GLvoid *map = NULL;'
626             print '    _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);'
627             print '    if (map && size > 0) {'
628             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'size')
629             print '    }'
630         if function.name == 'glFlushMappedNamedBufferRangeEXT':
631             print '    GLvoid *map = NULL;'
632             print '    _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);'
633             print '    if (map && length > 0) {'
634             self.emit_memcpy('(char *)map + offset', '(const char *)map + offset', 'length')
635             print '    }'
636
637         # Don't leave vertex attrib locations to chance.  Instead emit fake
638         # glBindAttribLocation calls to ensure that the same locations will be
639         # used when retracing.  Trying to remap locations after the fact would
640         # be an herculian task given that vertex attrib locations appear in
641         # many entry-points, including non-shader related ones.
642         if function.name == 'glLinkProgram':
643             Tracer.invokeFunction(self, function)
644             print '    GLint active_attributes = 0;'
645             print '    _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);'
646             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
647             print '        GLint size = 0;'
648             print '        GLenum type = 0;'
649             print '        GLchar name[256];'
650             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
651             print '        _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);'
652             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
653             print '            GLint location = _glGetAttribLocation(program, name);'
654             print '            if (location >= 0) {'
655             bind_function = glapi.glapi.getFunctionByName('glBindAttribLocation')
656             self.fake_call(bind_function, ['program', 'location', 'name'])
657             print '            }'
658             print '        }'
659             print '    }'
660         if function.name == 'glLinkProgramARB':
661             Tracer.invokeFunction(self, function)
662             print '    GLint active_attributes = 0;'
663             print '    _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);'
664             print '    for (GLint attrib = 0; attrib < active_attributes; ++attrib) {'
665             print '        GLint size = 0;'
666             print '        GLenum type = 0;'
667             print '        GLcharARB name[256];'
668             # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256
669             print '        _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);'
670             print "        if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {"
671             print '            GLint location = _glGetAttribLocationARB(programObj, name);'
672             print '            if (location >= 0) {'
673             bind_function = glapi.glapi.getFunctionByName('glBindAttribLocationARB')
674             self.fake_call(bind_function, ['programObj', 'location', 'name'])
675             print '            }'
676             print '        }'
677             print '    }'
678
679         self.shadowBufferProlog(function)
680
681         Tracer.traceFunctionImplBody(self, function)
682
683     marker_functions = [
684         # GL_GREMEDY_string_marker
685         'glStringMarkerGREMEDY',
686         # GL_GREMEDY_frame_terminator
687         'glFrameTerminatorGREMEDY',
688         # GL_EXT_debug_marker
689         'glInsertEventMarkerEXT',
690         'glPushGroupMarkerEXT',
691         'glPopGroupMarkerEXT',
692     ]
693
694     def invokeFunction(self, function):
695         if function.name in ('glLinkProgram', 'glLinkProgramARB'):
696             # These functions have been dispatched already
697             return
698
699         # We implement GL_EXT_debug_marker, GL_GREMEDY_*, etc., and not the
700         # driver
701         if function.name in self.marker_functions:
702             return
703
704         if function.name in ('glXGetProcAddress', 'glXGetProcAddressARB', 'wglGetProcAddress'):
705             else_ = ''
706             for marker_function in self.marker_functions:
707                 if self.api.getFunctionByName(marker_function):
708                     print '    %sif (strcmp("%s", (const char *)%s) == 0) {' % (else_, marker_function, function.args[0].name)
709                     print '        _result = (%s)&%s;' % (function.type, marker_function)
710                     print '    }'
711                 else_ = 'else '
712             print '    %s{' % else_
713             Tracer.invokeFunction(self, function)
714             print '    }'
715             return
716
717         # Override GL extensions
718         if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'):
719             Tracer.invokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override')
720             return
721
722         Tracer.invokeFunction(self, function)
723
724     buffer_targets = [
725         'ARRAY_BUFFER',
726         'ELEMENT_ARRAY_BUFFER',
727         'PIXEL_PACK_BUFFER',
728         'PIXEL_UNPACK_BUFFER',
729         'UNIFORM_BUFFER',
730         'TEXTURE_BUFFER',
731         'TRANSFORM_FEEDBACK_BUFFER',
732         'COPY_READ_BUFFER',
733         'COPY_WRITE_BUFFER',
734         'DRAW_INDIRECT_BUFFER',
735         'ATOMIC_COUNTER_BUFFER',
736     ]
737
738     def wrapRet(self, function, instance):
739         Tracer.wrapRet(self, function, instance)
740
741         # Replace function addresses with ours
742         if function.name in self.getProcAddressFunctionNames:
743             print '    %s = _wrapProcAddress(%s, %s);' % (instance, function.args[0].name, instance)
744
745         # Keep track of buffer mappings
746         if function.name in ('glMapBuffer', 'glMapBufferARB'):
747             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
748             print '    if (mapping) {'
749             print '        mapping->map = %s;' % (instance)
750             print '        mapping->length = 0;'
751             print '        _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
752             print '        mapping->write = (access != GL_READ_ONLY);'
753             print '        mapping->explicit_flush = false;'
754             print '    }'
755         if function.name == 'glMapBufferRange':
756             print '    if (access & GL_MAP_WRITE_BIT) {'
757             print '        _checkBufferMapRange = true;'
758             print '    }'
759             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
760             print '    if (mapping) {'
761             print '        mapping->map = %s;' % (instance)
762             print '        mapping->length = length;'
763             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
764             print '        mapping->explicit_flush = access & GL_MAP_FLUSH_EXPLICIT_BIT;'
765             print '    }'
766
767     boolean_names = [
768         'GL_FALSE',
769         'GL_TRUE',
770     ]
771
772     def gl_boolean(self, value):
773         return self.boolean_names[int(bool(value))]
774
775     # Names of the functions that unpack from a pixel buffer object.  See the
776     # ARB_pixel_buffer_object specification.
777     unpack_function_names = set([
778         'glBitmap',
779         'glColorSubTable',
780         'glColorTable',
781         'glCompressedMultiTexImage1DEXT',
782         'glCompressedMultiTexImage2DEXT',
783         'glCompressedMultiTexImage3DEXT',
784         'glCompressedMultiTexSubImage1DEXT',
785         'glCompressedMultiTexSubImage2DEXT',
786         'glCompressedMultiTexSubImage3DEXT',
787         'glCompressedTexImage1D',
788         'glCompressedTexImage2D',
789         'glCompressedTexImage3D',
790         'glCompressedTexSubImage1D',
791         'glCompressedTexSubImage2D',
792         'glCompressedTexSubImage3D',
793         'glCompressedTextureImage1DEXT',
794         'glCompressedTextureImage2DEXT',
795         'glCompressedTextureImage3DEXT',
796         'glCompressedTextureSubImage1DEXT',
797         'glCompressedTextureSubImage2DEXT',
798         'glCompressedTextureSubImage3DEXT',
799         'glConvolutionFilter1D',
800         'glConvolutionFilter2D',
801         'glDrawPixels',
802         'glMultiTexImage1DEXT',
803         'glMultiTexImage2DEXT',
804         'glMultiTexImage3DEXT',
805         'glMultiTexSubImage1DEXT',
806         'glMultiTexSubImage2DEXT',
807         'glMultiTexSubImage3DEXT',
808         'glPixelMapfv',
809         'glPixelMapuiv',
810         'glPixelMapusv',
811         'glPolygonStipple',
812         'glSeparableFilter2D',
813         'glTexImage1D',
814         'glTexImage1DEXT',
815         'glTexImage2D',
816         'glTexImage2DEXT',
817         'glTexImage3D',
818         'glTexImage3DEXT',
819         'glTexSubImage1D',
820         'glTexSubImage1DEXT',
821         'glTexSubImage2D',
822         'glTexSubImage2DEXT',
823         'glTexSubImage3D',
824         'glTexSubImage3DEXT',
825         'glTextureImage1DEXT',
826         'glTextureImage2DEXT',
827         'glTextureImage3DEXT',
828         'glTextureSubImage1DEXT',
829         'glTextureSubImage2DEXT',
830         'glTextureSubImage3DEXT',
831     ])
832
833     def serializeArgValue(self, function, arg):
834         # Recognize offsets instead of blobs when a PBO is bound
835         if function.name in self.unpack_function_names \
836            and (isinstance(arg.type, stdapi.Blob) \
837                 or (isinstance(arg.type, stdapi.Const) \
838                     and isinstance(arg.type.type, stdapi.Blob))):
839             print '    {'
840             print '        gltrace::Context *ctx = gltrace::getContext();'
841             print '        GLint _unpack_buffer = 0;'
842             print '        if (ctx->profile == gltrace::PROFILE_COMPAT)'
843             print '            _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);'
844             print '        if (_unpack_buffer) {'
845             print '            trace::localWriter.writePointer((uintptr_t)%s);' % arg.name
846             print '        } else {'
847             Tracer.serializeArgValue(self, function, arg)
848             print '        }'
849             print '    }'
850             return
851
852         # Several GL state functions take GLenum symbolic names as
853         # integer/floats; so dump the symbolic name whenever possible
854         if function.name.startswith('gl') \
855            and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \
856            and arg.name == 'param':
857             assert arg.index > 0
858             assert function.args[arg.index - 1].name == 'pname'
859             assert function.args[arg.index - 1].type == glapi.GLenum
860             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
861             self.serializeValue(glapi.GLenum, arg.name)
862             print '    } else {'
863             Tracer.serializeArgValue(self, function, arg)
864             print '    }'
865             return
866
867         Tracer.serializeArgValue(self, function, arg)
868
869     def footer(self, api):
870         Tracer.footer(self, api)
871
872         # A simple state tracker to track the pointer values
873         # update the state
874         print 'static void _trace_user_arrays(GLuint count)'
875         print '{'
876         print '    gltrace::Context *ctx = gltrace::getContext();'
877
878         for camelcase_name, uppercase_name in self.arrays:
879             # in which profile is the array available?
880             profile_check = 'ctx->profile == gltrace::PROFILE_COMPAT'
881             if camelcase_name in self.arrays_es1:
882                 profile_check = '(' + profile_check + ' || ctx->profile == gltrace::PROFILE_ES1)';
883
884             function_name = 'gl%sPointer' % camelcase_name
885             enable_name = 'GL_%s_ARRAY' % uppercase_name
886             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
887             function = api.getFunctionByName(function_name)
888
889             print '    // %s' % function.prototype()
890             print '  if (%s) {' % profile_check
891             self.array_trace_prolog(api, uppercase_name)
892             self.array_prolog(api, uppercase_name)
893             print '    if (_glIsEnabled(%s)) {' % enable_name
894             print '        GLint _binding = 0;'
895             print '        _glGetIntegerv(%s, &_binding);' % binding_name
896             print '        if (!_binding) {'
897
898             # Get the arguments via glGet*
899             for arg in function.args:
900                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
901                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
902                 print '            %s %s = 0;' % (arg_type, arg.name)
903                 print '            _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
904             
905             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
906             print '            size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
907
908             # Emit a fake function
909             self.array_trace_intermezzo(api, uppercase_name)
910             print '            unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
911             for arg in function.args:
912                 assert not arg.output
913                 print '            trace::localWriter.beginArg(%u);' % (arg.index,)
914                 if arg.name != 'pointer':
915                     self.serializeValue(arg.type, arg.name)
916                 else:
917                     print '            trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
918                 print '            trace::localWriter.endArg();'
919             
920             print '            trace::localWriter.endEnter();'
921             print '            trace::localWriter.beginLeave(_call);'
922             print '            trace::localWriter.endLeave();'
923             print '        }'
924             print '    }'
925             self.array_epilog(api, uppercase_name)
926             self.array_trace_epilog(api, uppercase_name)
927             print '  }'
928             print
929
930         # Samething, but for glVertexAttribPointer*
931         #
932         # Some variants of glVertexAttribPointer alias conventional and generic attributes:
933         # - glVertexAttribPointer: no
934         # - glVertexAttribPointerARB: implementation dependent
935         # - glVertexAttribPointerNV: yes
936         #
937         # This means that the implementations of these functions do not always
938         # alias, and they need to be considered independently.
939         #
940         print '    // ES1 does not support generic vertex attributes'
941         print '    if (ctx->profile == gltrace::PROFILE_ES1)'
942         print '        return;'
943         print
944         print '    vertex_attrib _vertex_attrib = _get_vertex_attrib();'
945         print
946         for suffix in ['', 'ARB', 'NV']:
947             if suffix:
948                 SUFFIX = '_' + suffix
949             else:
950                 SUFFIX = suffix
951             function_name = 'glVertexAttribPointer' + suffix
952             function = api.getFunctionByName(function_name)
953
954             print '    // %s' % function.prototype()
955             print '    if (_vertex_attrib == VERTEX_ATTRIB%s) {' % SUFFIX
956             if suffix == 'NV':
957                 print '        GLint _max_vertex_attribs = 16;'
958             else:
959                 print '        GLint _max_vertex_attribs = 0;'
960                 print '        _glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_max_vertex_attribs);'
961             print '        for (GLint index = 0; index < _max_vertex_attribs; ++index) {'
962             print '            GLint _enabled = 0;'
963             if suffix == 'NV':
964                 print '            _glGetIntegerv(GL_VERTEX_ATTRIB_ARRAY0_NV + index, &_enabled);'
965             else:
966                 print '            _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED%s, &_enabled);' % (suffix, SUFFIX)
967             print '            if (_enabled) {'
968             print '                GLint _binding = 0;'
969             if suffix != 'NV':
970                 # It doesn't seem possible to use VBOs with NV_vertex_program.
971                 print '                _glGetVertexAttribiv%s(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING%s, &_binding);' % (suffix, SUFFIX)
972             print '                if (!_binding) {'
973
974             # Get the arguments via glGet*
975             for arg in function.args[1:]:
976                 if suffix == 'NV':
977                     arg_get_enum = 'GL_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
978                 else:
979                     arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s%s' % (arg.name.upper(), SUFFIX)
980                 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False, suffix).visit(arg.type)
981                 print '                    %s %s = 0;' % (arg_type, arg.name)
982                 print '                    _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
983             
984             arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
985             print '                    size_t _size = _%s_size(%s, count);' % (function.name, arg_names)
986
987             # Emit a fake function
988             print '                    unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
989             for arg in function.args:
990                 assert not arg.output
991                 print '                    trace::localWriter.beginArg(%u);' % (arg.index,)
992                 if arg.name != 'pointer':
993                     self.serializeValue(arg.type, arg.name)
994                 else:
995                     print '                    trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)
996                 print '                    trace::localWriter.endArg();'
997             
998             print '                    trace::localWriter.endEnter();'
999             print '                    trace::localWriter.beginLeave(_call);'
1000             print '                    trace::localWriter.endLeave();'
1001             print '                }'
1002             print '            }'
1003             print '        }'
1004             print '    }'
1005             print
1006
1007         print '}'
1008         print
1009
1010     #
1011     # Hooks for glTexCoordPointer, which is identical to the other array
1012     # pointers except the fact that it is indexed by glClientActiveTexture.
1013     #
1014
1015     def array_prolog(self, api, uppercase_name):
1016         if uppercase_name == 'TEXTURE_COORD':
1017             print '    GLint client_active_texture = 0;'
1018             print '    _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
1019             print '    GLint max_texture_coords = 0;'
1020             print '    if (ctx->profile == gltrace::PROFILE_COMPAT)'
1021             print '        _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
1022             print '    else'
1023             print '        _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_coords);'
1024             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
1025             print '        GLint texture = GL_TEXTURE0 + unit;'
1026             print '        _glClientActiveTexture(texture);'
1027
1028     def array_trace_prolog(self, api, uppercase_name):
1029         if uppercase_name == 'TEXTURE_COORD':
1030             print '    bool client_active_texture_dirty = false;'
1031
1032     def array_epilog(self, api, uppercase_name):
1033         if uppercase_name == 'TEXTURE_COORD':
1034             print '    }'
1035         self.array_cleanup(api, uppercase_name)
1036
1037     def array_cleanup(self, api, uppercase_name):
1038         if uppercase_name == 'TEXTURE_COORD':
1039             print '    _glClientActiveTexture(client_active_texture);'
1040         
1041     def array_trace_intermezzo(self, api, uppercase_name):
1042         if uppercase_name == 'TEXTURE_COORD':
1043             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
1044             print '        client_active_texture_dirty = true;'
1045             self.fake_glClientActiveTexture_call(api, "texture");
1046             print '    }'
1047
1048     def array_trace_epilog(self, api, uppercase_name):
1049         if uppercase_name == 'TEXTURE_COORD':
1050             print '    if (client_active_texture_dirty) {'
1051             self.fake_glClientActiveTexture_call(api, "client_active_texture");
1052             print '    }'
1053
1054     def fake_glClientActiveTexture_call(self, api, texture):
1055         function = api.getFunctionByName('glClientActiveTexture')
1056         self.fake_call(function, [texture])
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068