]> git.cworth.org Git - apitrace/blob - retrace/glretrace.py
Try active shader program before current program.
[apitrace] / retrace / glretrace.py
1 ##########################################################################
2 #
3 # Copyright 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 retracer generator."""
28
29
30 from retrace import Retracer
31 import specs.stdapi as stdapi
32 import specs.glapi as glapi
33 import specs.glesapi as glesapi
34
35
36 class GlRetracer(Retracer):
37
38     table_name = 'glretrace::gl_callbacks'
39
40     def retraceFunction(self, function):
41         Retracer.retraceFunction(self, function)
42
43     array_pointer_function_names = set((
44         "glVertexPointer",
45         "glNormalPointer",
46         "glColorPointer",
47         "glIndexPointer",
48         "glTexCoordPointer",
49         "glEdgeFlagPointer",
50         "glFogCoordPointer",
51         "glSecondaryColorPointer",
52
53         "glInterleavedArrays",
54
55         "glVertexPointerEXT",
56         "glNormalPointerEXT",
57         "glColorPointerEXT",
58         "glIndexPointerEXT",
59         "glTexCoordPointerEXT",
60         "glEdgeFlagPointerEXT",
61         "glFogCoordPointerEXT",
62         "glSecondaryColorPointerEXT",
63
64         "glVertexAttribPointer",
65         "glVertexAttribPointerARB",
66         "glVertexAttribPointerNV",
67         "glVertexAttribIPointer",
68         "glVertexAttribIPointerEXT",
69         "glVertexAttribLPointer",
70         "glVertexAttribLPointerEXT",
71         
72         #"glMatrixIndexPointerARB",
73     ))
74
75     draw_array_function_names = set([
76         "glDrawArrays",
77         "glDrawArraysEXT",
78         "glDrawArraysIndirect",
79         "glDrawArraysInstanced",
80         "glDrawArraysInstancedARB",
81         "glDrawArraysInstancedEXT",
82         "glDrawArraysInstancedBaseInstance",
83         "glDrawMeshArraysSUN",
84         "glMultiDrawArrays",
85         "glMultiDrawArraysEXT",
86         "glMultiModeDrawArraysIBM",
87     ])
88
89     draw_elements_function_names = set([
90         "glDrawElements",
91         "glDrawElementsBaseVertex",
92         "glDrawElementsIndirect",
93         "glDrawElementsInstanced",
94         "glDrawElementsInstancedARB",
95         "glDrawElementsInstancedEXT",
96         "glDrawElementsInstancedBaseVertex",
97         "glDrawElementsInstancedBaseInstance",
98         "glDrawElementsInstancedBaseVertexBaseInstance",
99         "glDrawRangeElements",
100         "glDrawRangeElementsEXT",
101         "glDrawRangeElementsBaseVertex",
102         "glMultiDrawElements",
103         "glMultiDrawElementsBaseVertex",
104         "glMultiDrawElementsEXT",
105         "glMultiModeDrawElementsIBM",
106     ])
107
108     draw_indirect_function_names = set([
109         "glDrawArraysIndirect",
110         "glDrawElementsIndirect",
111     ])
112
113     misc_draw_function_names = set([
114         "glCallList",
115         "glCallLists",
116         "glClear",
117         "glEnd",
118         "glDrawPixels",
119         "glBlitFramebuffer",
120         "glBlitFramebufferEXT",
121     ])
122
123     bind_framebuffer_function_names = set([
124         "glBindFramebuffer",
125         "glBindFramebufferEXT",
126         "glBindFramebufferOES",
127     ])
128
129     # Names of the functions that can pack into the current pixel buffer
130     # object.  See also the ARB_pixel_buffer_object specification.
131     pack_function_names = set([
132         'glGetCompressedTexImage',
133         'glGetConvolutionFilter',
134         'glGetHistogram',
135         'glGetMinmax',
136         'glGetPixelMapfv',
137         'glGetPixelMapuiv',
138         'glGetPixelMapusv',
139         'glGetPolygonStipple',
140         'glGetSeparableFilter',
141         'glGetTexImage',
142         'glReadPixels',
143         'glGetnCompressedTexImageARB',
144         'glGetnConvolutionFilterARB',
145         'glGetnHistogramARB',
146         'glGetnMinmaxARB',
147         'glGetnPixelMapfvARB',
148         'glGetnPixelMapuivARB',
149         'glGetnPixelMapusvARB',
150         'glGetnPolygonStippleARB',
151         'glGetnSeparableFilterARB',
152         'glGetnTexImageARB',
153         'glReadnPixelsARB',
154     ])
155
156     map_function_names = set([
157         'glMapBuffer',
158         'glMapBufferARB',
159         'glMapBufferOES',
160         'glMapBufferRange',
161         'glMapNamedBufferEXT',
162         'glMapNamedBufferRangeEXT',
163         'glMapObjectBufferATI',
164     ])
165
166     unmap_function_names = set([
167         'glUnmapBuffer',
168         'glUnmapBufferARB',
169         'glUnmapBufferOES',
170         'glUnmapNamedBufferEXT',
171         'glUnmapObjectBufferATI',
172     ])
173
174     def retraceFunctionBody(self, function):
175         is_array_pointer = function.name in self.array_pointer_function_names
176         is_draw_array = function.name in self.draw_array_function_names
177         is_draw_elements = function.name in self.draw_elements_function_names
178         is_misc_draw = function.name in self.misc_draw_function_names
179
180         if is_array_pointer or is_draw_array or is_draw_elements:
181             print '    if (retrace::parser.version < 1) {'
182
183             if is_array_pointer or is_draw_array:
184                 print '        GLint _array_buffer = 0;'
185                 print '        glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &_array_buffer);'
186                 print '        if (!_array_buffer) {'
187                 self.failFunction(function)
188                 print '        }'
189
190             if is_draw_elements:
191                 print '        GLint _element_array_buffer = 0;'
192                 print '        glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &_element_array_buffer);'
193                 print '        if (!_element_array_buffer) {'
194                 self.failFunction(function)
195                 print '        }'
196             
197             print '    }'
198
199         # When no pack buffer object is bound, the pack functions are no-ops.
200         if function.name in self.pack_function_names:
201             print '    GLint _pack_buffer = 0;'
202             print '    glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &_pack_buffer);'
203             print '    if (!_pack_buffer) {'
204             print '        return;'
205             print '    }'
206
207         # Pre-snapshots
208         if function.name in self.bind_framebuffer_function_names:
209             print '    assert(call.flags & trace::CALL_FLAG_SWAP_RENDERTARGET);'
210         if function.name == 'glFrameTerminatorGREMEDY':
211             print '    glretrace::frame_complete(call);'
212             return
213
214         Retracer.retraceFunctionBody(self, function)
215
216         # Post-snapshots
217         if function.name in ('glFlush', 'glFinish'):
218             print '    if (!retrace::doubleBuffer) {'
219             print '        glretrace::frame_complete(call);'
220             print '    }'
221         if is_draw_array or is_draw_elements or is_misc_draw:
222             print '    assert(call.flags & trace::CALL_FLAG_RENDER);'
223
224
225     def invokeFunction(self, function):
226         # Infer the drawable size from GL calls
227         if function.name == "glViewport":
228             print '    glretrace::updateDrawable(x + width, y + height);'
229         if function.name == "glViewportArray":
230             # We are concerned about drawables so only care for the first viewport
231             print '    if (first == 0 && count > 0) {'
232             print '        GLfloat x = v[0], y = v[1], w = v[2], h = v[3];'
233             print '        glretrace::updateDrawable(x + w, y + h);'
234             print '    }'
235         if function.name == "glViewportIndexedf":
236             print '    if (index == 0) {'
237             print '        glretrace::updateDrawable(x + w, y + h);'
238             print '    }'
239         if function.name == "glViewportIndexedfv":
240             print '    if (index == 0) {'
241             print '        GLfloat x = v[0], y = v[1], w = v[2], h = v[3];'
242             print '        glretrace::updateDrawable(x + w, y + h);'
243             print '    }'
244         if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'):
245             # Some applications do all their rendering in a framebuffer, and
246             # then just blit to the drawable without ever calling glViewport.
247             print '    glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));'
248
249         if function.name == "glEnd":
250             print '    glretrace::insideGlBeginEnd = false;'
251
252         if function.name.startswith('gl') and not function.name.startswith('glX'):
253             print r'    if (retrace::debug && !glretrace::currentContext) {'
254             print r'        retrace::warning(call) << "no current context\n";'
255             print r'    }'
256
257         if function.name == 'memcpy':
258             print '    if (!dest || !src || !n) return;'
259
260         # Destroy the buffer mapping
261         if function.name in self.unmap_function_names:
262             print r'        GLvoid *ptr = NULL;'
263             if function.name == 'glUnmapBuffer':
264                 print r'            glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &ptr);'
265             elif function.name == 'glUnmapBufferARB':
266                 print r'            glGetBufferPointervARB(target, GL_BUFFER_MAP_POINTER_ARB, &ptr);'
267             elif function.name == 'glUnmapBufferOES':
268                 print r'            glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &ptr);'
269             elif function.name == 'glUnmapNamedBufferEXT':
270                 print r'            glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &ptr);'
271             elif function.name == 'glUnmapObjectBufferATI':
272                 # TODO
273                 pass
274             else:
275                 assert False
276             print r'        if (ptr) {'
277             print r'            retrace::delRegionByPointer(ptr);'
278             print r'        } else {'
279             print r'            retrace::warning(call) << "no current context\n";'
280             print r'        }'
281
282         if function.name in ('glBindProgramPipeline', 'glBindProgramPipelineEXT'):
283             # Note if glBindProgramPipeline has ever been called
284             print r'    if (pipeline) {'
285             print r'        _pipelineHasBeenBound = true;'
286             print r'    }'
287         
288         Retracer.invokeFunction(self, function)
289
290         # Error checking
291         if function.name == "glBegin":
292             print '    glretrace::insideGlBeginEnd = true;'
293         elif function.name.startswith('gl'):
294             # glGetError is not allowed inside glBegin/glEnd
295             print '    if (retrace::debug && !glretrace::insideGlBeginEnd) {'
296             print '        glretrace::checkGlError(call);'
297             if function.name in ('glProgramStringARB', 'glProgramStringNV'):
298                 print r'        GLint error_position = -1;'
299                 print r'        glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_position);'
300                 print r'        if (error_position != -1) {'
301                 print r'            const char *error_string = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);'
302                 print r'            retrace::warning(call) << error_string << "\n";'
303                 print r'        }'
304             if function.name == 'glCompileShader':
305                 print r'        GLint compile_status = 0;'
306                 print r'        glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);'
307                 print r'        if (!compile_status) {'
308                 print r'             GLint info_log_length = 0;'
309                 print r'             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);'
310                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
311                 print r'             glGetShaderInfoLog(shader, info_log_length, NULL, infoLog);'
312                 print r'             retrace::warning(call) << infoLog << "\n";'
313                 print r'             delete [] infoLog;'
314                 print r'        }'
315             if function.name in ('glLinkProgram', 'glCreateShaderProgramv', 'glCreateShaderProgramEXT'):
316                 if function.name != 'glLinkProgram':
317                     print r'        GLuint program = _result;'
318                 print r'        GLint link_status = 0;'
319                 print r'        glGetProgramiv(program, GL_LINK_STATUS, &link_status);'
320                 print r'        if (!link_status) {'
321                 print r'             GLint info_log_length = 0;'
322                 print r'             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);'
323                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
324                 print r'             glGetProgramInfoLog(program, info_log_length, NULL, infoLog);'
325                 print r'             retrace::warning(call) << infoLog << "\n";'
326                 print r'             delete [] infoLog;'
327                 print r'        }'
328             if function.name == 'glCompileShaderARB':
329                 print r'        GLint compile_status = 0;'
330                 print r'        glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);'
331                 print r'        if (!compile_status) {'
332                 print r'             GLint info_log_length = 0;'
333                 print r'             glGetObjectParameterivARB(shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);'
334                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
335                 print r'             glGetInfoLogARB(shaderObj, info_log_length, NULL, infoLog);'
336                 print r'             retrace::warning(call) << infoLog << "\n";'
337                 print r'             delete [] infoLog;'
338                 print r'        }'
339             if function.name == 'glLinkProgramARB':
340                 print r'        GLint link_status = 0;'
341                 print r'        glGetObjectParameterivARB(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);'
342                 print r'        if (!link_status) {'
343                 print r'             GLint info_log_length = 0;'
344                 print r'             glGetObjectParameterivARB(programObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);'
345                 print r'             GLchar *infoLog = new GLchar[info_log_length];'
346                 print r'             glGetInfoLogARB(programObj, info_log_length, NULL, infoLog);'
347                 print r'             retrace::warning(call) << infoLog << "\n";'
348                 print r'             delete [] infoLog;'
349                 print r'        }'
350             if function.name in self.map_function_names:
351                 print r'        if (!_result) {'
352                 print r'             retrace::warning(call) << "failed to map buffer\n";'
353                 print r'        }'
354             if function.name in self.unmap_function_names and function.type is not stdapi.Void:
355                 print r'        if (!_result) {'
356                 print r'             retrace::warning(call) << "failed to unmap buffer\n";'
357                 print r'        }'
358             if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'):
359                 print r'    GLint _origResult = call.ret->toSInt();'
360                 print r'    if (_result != _origResult) {'
361                 print r'        retrace::warning(call) << "vertex attrib location mismatch " << _origResult << " -> " << _result << "\n";'
362                 print r'    }'
363             if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatusEXT'):
364                 print r'    GLint _origResult = call.ret->toSInt();'
365                 print r'    if (_origResult == GL_FRAMEBUFFER_COMPLETE &&'
366                 print r'        _result != GL_FRAMEBUFFER_COMPLETE) {'
367                 print r'        retrace::warning(call) << "incomplete framebuffer (" << glstate::enumToString(_result) << ")\n";'
368                 print r'    }'
369             print '    }'
370
371         # Query the buffer length for whole buffer mappings
372         if function.name in self.map_function_names:
373             if 'length' in function.argNames():
374                 assert 'BufferRange' in function.name
375             else:
376                 assert 'BufferRange' not in function.name
377                 print r'    GLint length = 0;'
378                 if function.name in ('glMapBuffer', 'glMapBufferOES'):
379                     print r'    glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);'
380                 elif function.name == 'glMapBufferARB':
381                     print r'    glGetBufferParameterivARB(target, GL_BUFFER_SIZE_ARB, &length);'
382                 elif function.name == 'glMapNamedBufferEXT':
383                     print r'    glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_SIZE, &length);'
384                 elif function.name == 'glMapObjectBufferATI':
385                     print r'    glGetObjectBufferivATI(buffer, GL_OBJECT_BUFFER_SIZE_ATI, &length);'
386                 else:
387                     assert False
388
389     def extractArg(self, function, arg, arg_type, lvalue, rvalue):
390         if function.name in self.array_pointer_function_names and arg.name == 'pointer':
391             print '    %s = static_cast<%s>(retrace::toPointer(%s, true));' % (lvalue, arg_type, rvalue)
392             return
393
394         if function.name in self.draw_elements_function_names and arg.name == 'indices' or\
395            function.name in self.draw_indirect_function_names and arg.name == 'indirect':
396             self.extractOpaqueArg(function, arg, arg_type, lvalue, rvalue)
397             return
398
399         # Handle pointer with offsets into the current pack pixel buffer
400         # object.
401         if function.name in self.pack_function_names and arg.output:
402             assert isinstance(arg_type, (stdapi.Pointer, stdapi.Array, stdapi.Blob, stdapi.Opaque))
403             print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, arg_type, rvalue)
404             return
405
406         if arg.type is glapi.GLlocation \
407            and 'program' not in function.argNames():
408             # Determine the active program for uniforms swizzling
409             print '    GLint program = -1;'
410             print '    GLint pipeline = 0;'
411             print '    if (_pipelineHasBeenBound) {'
412             print '        glGetIntegerv(GL_PROGRAM_PIPELINE_BINDING, &pipeline);'
413             print '    }'
414             print '    if (pipeline) {'
415             print '        glGetProgramPipelineiv(pipeline, GL_ACTIVE_PROGRAM, &program);'
416             print '    } else {'
417             print '        glGetIntegerv(GL_CURRENT_PROGRAM, &program);'
418             print '    }'
419             print
420
421         if arg.type is glapi.GLlocationARB \
422            and 'programObj' not in function.argNames():
423             print '    GLhandleARB programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);'
424
425         Retracer.extractArg(self, function, arg, arg_type, lvalue, rvalue)
426
427         # Don't try to use more samples than the implementation supports
428         if arg.name == 'samples':
429             assert arg.type is glapi.GLsizei
430             print '    GLint max_samples = 0;'
431             print '    glGetIntegerv(GL_MAX_SAMPLES, &max_samples);'
432             print '    if (samples > max_samples) {'
433             print '        samples = max_samples;'
434             print '    }'
435
436         # These parameters are referred beyond the call life-time
437         # TODO: Replace ad-hoc solution for bindable parameters with general one
438         if function.name in ('glFeedbackBuffer', 'glSelectBuffer') and arg.output:
439             print '    _allocator.bind(%s);' % arg.name
440
441
442
443 if __name__ == '__main__':
444     print r'''
445 #include <string.h>
446
447 #include "glproc.hpp"
448 #include "glretrace.hpp"
449 #include "glstate.hpp"
450
451
452 static bool _pipelineHasBeenBound = false;
453 '''
454     api = glapi.glapi
455     api.addApi(glesapi.glesapi)
456     retracer = GlRetracer()
457     retracer.retraceApi(api)