Added few more stubs so that control reaches to DestroyDevice().
[mesa.git] / src / gallium / tools / trace / dump_state.py
1 #!/usr/bin/env python2
2 ##########################################################################
3 #
4 # Copyright 2008-2013, VMware, Inc.
5 # All Rights Reserved.
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a
8 # copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish,
11 # distribute, sub license, and/or sell copies of the Software, and to
12 # permit persons to whom the Software is furnished to do so, subject to
13 # the following conditions:
14 #
15 # The above copyright notice and this permission notice (including the
16 # next paragraph) shall be included in all copies or substantial portions
17 # of the Software.
18 #
19 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 # IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23 # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 #
27 ##########################################################################
28
29
30 import sys
31 import struct
32 import json
33 import binascii
34 import re
35 import copy
36
37 import model
38 import parse as parser
39
40
41 try:
42 from struct import unpack_from
43 except ImportError:
44 def unpack_from(fmt, buf, offset=0):
45 size = struct.calcsize(fmt)
46 return struct.unpack(fmt, buf[offset:offset + size])
47
48 #
49 # Some constants
50 #
51 PIPE_BUFFER = 0
52 PIPE_SHADER_VERTEX = 0
53 PIPE_SHADER_FRAGMENT = 1
54 PIPE_SHADER_GEOMETRY = 2
55 PIPE_SHADER_COMPUTE = 3
56 PIPE_SHADER_TYPES = 4
57
58
59 def serialize(obj):
60 '''JSON serializer function for non-standard Python objects.'''
61
62 if isinstance(obj, bytearray):
63 # TODO: Decide on a single way of dumping blobs
64 if False:
65 # Don't dump full blobs, but merely a description of their size and
66 # CRC32 hash.
67 crc32 = binascii.crc32(obj)
68 if crc32 < 0:
69 crc32 += 0x100000000
70 return 'blob(size=%u,crc32=0x%08x)' % (len(obj), crc32)
71 if True:
72 # Dump blobs as an array of 16byte hexadecimals
73 res = []
74 for i in range(0, len(obj), 16):
75 res.append(binascii.b2a_hex(obj[i: i+16]))
76 return res
77 # Dump blobs as a single hexadecimal string
78 return binascii.b2a_hex(obj)
79
80 # If the object has a __json__ method, use it.
81 try:
82 method = obj.__json__
83 except AttributeError:
84 raise TypeError(obj)
85 else:
86 return method()
87
88
89 class Struct:
90 """C-like struct.
91
92 Python doesn't have C structs, but do its dynamic nature, any object is
93 pretty close.
94 """
95
96 def __json__(self):
97 '''Convert the structure to a standard Python dict, so it can be
98 serialized.'''
99
100 obj = {}
101 for name, value in self.__dict__.items():
102 if not name.startswith('_'):
103 obj[name] = value
104 return obj
105
106 def __repr__(self):
107 return repr(self.__json__())
108
109
110 class Translator(model.Visitor):
111 """Translate model arguments into regular Python objects"""
112
113 def __init__(self, interpreter):
114 self.interpreter = interpreter
115 self.result = None
116
117 def visit(self, node):
118 self.result = None
119 node.visit(self)
120 return self.result
121
122 def visit_literal(self, node):
123 self.result = node.value
124
125 def visit_blob(self, node):
126 self.result = node
127
128 def visit_named_constant(self, node):
129 self.result = node.name
130
131 def visit_array(self, node):
132 array = []
133 for element in node.elements:
134 array.append(self.visit(element))
135 self.result = array
136
137 def visit_struct(self, node):
138 struct = Struct()
139 for member_name, member_node in node.members:
140 member_name = member_name.replace('.', '_')
141 member_value = self.visit(member_node)
142 setattr(struct, member_name, member_value)
143 self.result = struct
144
145 def visit_pointer(self, node):
146 self.result = self.interpreter.lookup_object(node.address)
147
148
149 class Dispatcher:
150 '''Base class for classes whose methods can dispatch Gallium calls.'''
151
152 def __init__(self, interpreter):
153 self.interpreter = interpreter
154
155
156 class Global(Dispatcher):
157 '''Global name space.
158
159 For calls that are not associated with objects, i.e, functions and not
160 methods.
161 '''
162
163 def pipe_screen_create(self):
164 return Screen(self.interpreter)
165
166 def pipe_context_create(self, screen):
167 return screen.context_create()
168
169
170 class Transfer:
171 '''pipe_transfer'''
172
173 def __init__(self, resource, usage, subresource, box):
174 self.resource = resource
175 self.usage = usage
176 self.subresource = subresource
177 self.box = box
178
179
180 class Screen(Dispatcher):
181 '''pipe_screen'''
182
183 def __init__(self, interpreter):
184 Dispatcher.__init__(self, interpreter)
185
186 def destroy(self):
187 pass
188
189 def context_create(self, priv=None, flags=0):
190 return Context(self.interpreter)
191
192 def is_format_supported(self, format, target, sample_count, bind, geom_flags):
193 pass
194
195 def resource_create(self, templat):
196 resource = templat
197 # Normalize state to avoid spurious differences
198 if resource.nr_samples == 0:
199 resource.nr_samples = 1
200 if resource.target == PIPE_BUFFER:
201 # We will keep track of buffer contents
202 resource.data = bytearray(resource.width)
203 # Ignore format
204 del resource.format
205 return resource
206
207 def resource_destroy(self, resource):
208 self.interpreter.unregister_object(resource)
209
210 def fence_finish(self, fence, timeout=None):
211 pass
212
213 def fence_signalled(self, fence):
214 pass
215
216 def fence_reference(self, dst, src):
217 pass
218
219 def flush_frontbuffer(self, resource):
220 pass
221
222
223 class Context(Dispatcher):
224 '''pipe_context'''
225
226 # Internal methods variable should be prefixed with '_'
227
228 def __init__(self, interpreter):
229 Dispatcher.__init__(self, interpreter)
230
231 # Setup initial state
232 self._state = Struct()
233 self._state.scissors = []
234 self._state.viewports = []
235 self._state.vertex_buffers = []
236 self._state.vertex_elements = []
237 self._state.vs = Struct()
238 self._state.gs = Struct()
239 self._state.fs = Struct()
240 self._state.vs.shader = None
241 self._state.gs.shader = None
242 self._state.fs.shader = None
243 self._state.vs.sampler = []
244 self._state.gs.sampler = []
245 self._state.fs.sampler = []
246 self._state.vs.sampler_views = []
247 self._state.gs.sampler_views = []
248 self._state.fs.sampler_views = []
249 self._state.vs.constant_buffer = []
250 self._state.gs.constant_buffer = []
251 self._state.fs.constant_buffer = []
252 self._state.render_condition_condition = 0
253 self._state.render_condition_mode = 0
254
255 self._draw_no = 0
256
257 def destroy(self):
258 pass
259
260 def create_blend_state(self, state):
261 # Normalize state to avoid spurious differences
262 if not state.logicop_enable:
263 del state.logicop_func
264 if not state.rt[0].blend_enable:
265 del state.rt[0].rgb_src_factor
266 del state.rt[0].rgb_dst_factor
267 del state.rt[0].rgb_func
268 del state.rt[0].alpha_src_factor
269 del state.rt[0].alpha_dst_factor
270 del state.rt[0].alpha_func
271 return state
272
273 def bind_blend_state(self, state):
274 # Normalize state
275 self._state.blend = state
276
277 def delete_blend_state(self, state):
278 pass
279
280 def create_sampler_state(self, state):
281 return state
282
283 def delete_sampler_state(self, state):
284 pass
285
286 def bind_sampler_states(self, shader, start, num_states, states):
287 # FIXME: Handle non-zero start
288 assert start == 0
289 self._get_stage_state(shader).sampler = states
290
291 def bind_vertex_sampler_states(self, num_states, states):
292 # XXX: deprecated method
293 self._state.vs.sampler = states
294
295 def bind_geometry_sampler_states(self, num_states, states):
296 # XXX: deprecated method
297 self._state.gs.sampler = states
298
299 def bind_fragment_sampler_states(self, num_states, states):
300 # XXX: deprecated method
301 self._state.fs.sampler = states
302
303 def create_rasterizer_state(self, state):
304 return state
305
306 def bind_rasterizer_state(self, state):
307 self._state.rasterizer = state
308
309 def delete_rasterizer_state(self, state):
310 pass
311
312 def create_depth_stencil_alpha_state(self, state):
313 # Normalize state to avoid spurious differences
314 if not state.alpha.enabled:
315 del state.alpha.func
316 del state.alpha.ref_value
317 for i in range(2):
318 if not state.stencil[i].enabled:
319 del state.stencil[i].func
320 return state
321
322 def bind_depth_stencil_alpha_state(self, state):
323 self._state.depth_stencil_alpha = state
324
325 def delete_depth_stencil_alpha_state(self, state):
326 pass
327
328 _tokenLabelRE = re.compile('^\s*\d+: ', re.MULTILINE)
329
330 def _create_shader_state(self, state):
331 # Strip the labels from the tokens
332 if state.tokens is not None:
333 state.tokens = self._tokenLabelRE.sub('', state.tokens)
334 return state
335
336 create_vs_state = _create_shader_state
337 create_gs_state = _create_shader_state
338 create_fs_state = _create_shader_state
339
340 def bind_vs_state(self, state):
341 self._state.vs.shader = state
342
343 def bind_gs_state(self, state):
344 self._state.gs.shader = state
345
346 def bind_fs_state(self, state):
347 self._state.fs.shader = state
348
349 def _delete_shader_state(self, state):
350 return state
351
352 delete_vs_state = _delete_shader_state
353 delete_gs_state = _delete_shader_state
354 delete_fs_state = _delete_shader_state
355
356 def set_blend_color(self, state):
357 self._state.blend_color = state
358
359 def set_stencil_ref(self, state):
360 self._state.stencil_ref = state
361
362 def set_clip_state(self, state):
363 self._state.clip = state
364
365 def _dump_constant_buffer(self, buffer):
366 if not self.interpreter.verbosity(2):
367 return
368
369 data = self.real.buffer_read(buffer)
370 format = '4f'
371 index = 0
372 for offset in range(0, len(data), struct.calcsize(format)):
373 x, y, z, w = unpack_from(format, data, offset)
374 sys.stdout.write('\tCONST[%2u] = {%10.4f, %10.4f, %10.4f, %10.4f}\n' % (index, x, y, z, w))
375 index += 1
376 sys.stdout.flush()
377
378 def _get_stage_state(self, shader):
379 if shader == PIPE_SHADER_VERTEX:
380 return self._state.vs
381 if shader == PIPE_SHADER_GEOMETRY:
382 return self._state.gs
383 if shader == PIPE_SHADER_FRAGMENT:
384 return self._state.fs
385 assert False
386
387 def set_constant_buffer(self, shader, index, constant_buffer):
388 self._update(self._get_stage_state(shader).constant_buffer, index, 1, [constant_buffer])
389
390 def set_framebuffer_state(self, state):
391 self._state.fb = state
392
393 def set_polygon_stipple(self, state):
394 self._state.polygon_stipple = state
395
396 def _update(self, array, start_slot, num_slots, states):
397 if not isinstance(states, list):
398 # XXX: trace is not serializing multiple scissors/viewports properly yet
399 num_slots = 1
400 states = [states]
401 while len(array) < start_slot + num_slots:
402 array.append(None)
403 for i in range(num_slots):
404 array[start_slot + i] = states[i]
405
406 def set_scissor_states(self, start_slot, num_scissors, states):
407 self._update(self._state.scissors, start_slot, num_scissors, states)
408
409 def set_viewport_states(self, start_slot, num_viewports, states):
410 self._update(self._state.viewports, start_slot, num_viewports, states)
411
412 def create_sampler_view(self, resource, templ):
413 templ.resource = resource
414 return templ
415
416 def sampler_view_destroy(self, view):
417 pass
418
419 def set_sampler_views(self, shader, start, num, views):
420 # FIXME: Handle non-zero start
421 assert start == 0
422 self._get_stage_state(shader).sampler_views = views
423
424 def set_fragment_sampler_views(self, num, views):
425 # XXX: deprecated
426 self._state.fs.sampler_views = views
427
428 def set_geometry_sampler_views(self, num, views):
429 # XXX: deprecated
430 self._state.gs.sampler_views = views
431
432 def set_vertex_sampler_views(self, num, views):
433 # XXX: deprecated
434 self._state.vs.sampler_views = views
435
436 def set_vertex_buffers(self, start_slot, num_buffers, buffers):
437 self._update(self._state.vertex_buffers, start_slot, num_buffers, buffers)
438
439 def create_vertex_elements_state(self, num_elements, elements):
440 return elements[0:num_elements]
441
442 def bind_vertex_elements_state(self, state):
443 self._state.vertex_elements = state
444
445 def delete_vertex_elements_state(self, state):
446 pass
447
448 def set_index_buffer(self, ib):
449 self._state.index_buffer = ib
450
451 # Don't dump more than this number of indices/vertices
452 MAX_ELEMENTS = 16
453
454 def _merge_indices(self, info):
455 '''Merge the vertices into our state.'''
456
457 index_size = self._state.index_buffer.index_size
458
459 format = {
460 1: 'B',
461 2: 'H',
462 4: 'I',
463 }[index_size]
464
465 assert struct.calcsize(format) == index_size
466
467 if self._state.index_buffer.buffer is None:
468 # Could happen with index in user memory
469 return 0, 0
470
471 data = self._state.index_buffer.buffer.data
472 max_index, min_index = 0, 0xffffffff
473
474 count = min(info.count, self.MAX_ELEMENTS)
475 indices = []
476 for i in xrange(info.start, info.start + count):
477 offset = self._state.index_buffer.offset + i*index_size
478 if offset + index_size > len(data):
479 index = 0
480 else:
481 index, = unpack_from(format, data, offset)
482 indices.append(index)
483 min_index = min(min_index, index)
484 max_index = max(max_index, index)
485
486 self._state.indices = indices
487
488 return min_index + info.index_bias, max_index + info.index_bias
489
490 def _merge_vertices(self, start, count):
491 '''Merge the vertices into our state.'''
492
493 count = min(count, self.MAX_ELEMENTS)
494 vertices = []
495 for index in xrange(start, start + count):
496 if index >= start + 16:
497 sys.stdout.write('\t...\n')
498 break
499 vertex = []
500 for velem in self._state.vertex_elements:
501 vbuf = self._state.vertex_buffers[velem.vertex_buffer_index]
502 resource = vbuf.buffer_resource
503 if resource is None:
504 continue
505
506 data = resource.data
507
508 offset = vbuf.buffer_offset + velem.src_offset + vbuf.stride*index
509 format = {
510 'PIPE_FORMAT_R32_FLOAT': 'f',
511 'PIPE_FORMAT_R32G32_FLOAT': '2f',
512 'PIPE_FORMAT_R32G32B32_FLOAT': '3f',
513 'PIPE_FORMAT_R32G32B32A32_FLOAT': '4f',
514 'PIPE_FORMAT_R32_UINT': 'I',
515 'PIPE_FORMAT_R32G32_UINT': '2I',
516 'PIPE_FORMAT_R32G32B32_UINT': '3I',
517 'PIPE_FORMAT_R32G32B32A32_UINT': '4I',
518 'PIPE_FORMAT_R8_UINT': 'B',
519 'PIPE_FORMAT_R8G8_UINT': '2B',
520 'PIPE_FORMAT_R8G8B8_UINT': '3B',
521 'PIPE_FORMAT_R8G8B8A8_UINT': '4B',
522 'PIPE_FORMAT_A8R8G8B8_UNORM': '4B',
523 'PIPE_FORMAT_R8G8B8A8_UNORM': '4B',
524 'PIPE_FORMAT_B8G8R8A8_UNORM': '4B',
525 'PIPE_FORMAT_R16G16B16_SNORM': '3h',
526 }[velem.src_format]
527
528 data = resource.data
529 attribute = unpack_from(format, data, offset)
530 vertex.append(attribute)
531
532 vertices.append(vertex)
533
534 self._state.vertices = vertices
535
536 def render_condition(self, query, condition = 0, mode = 0):
537 self._state.render_condition_query = query
538 self._state.render_condition_condition = condition
539 self._state.render_condition_mode = mode
540
541 def set_stream_output_targets(self, num_targets, tgs, offsets):
542 self._state.so_targets = tgs
543 self._state.offsets = offsets
544
545 def draw_vbo(self, info):
546 self._draw_no += 1
547
548 if self.interpreter.call_no < self.interpreter.options.call and \
549 self._draw_no < self.interpreter.options.draw:
550 return
551
552 # Merge the all draw state
553
554 self._state.draw = info
555
556 if info.index_size != 0:
557 min_index, max_index = self._merge_indices(info)
558 else:
559 min_index = info.start
560 max_index = info.start + info.count - 1
561 self._merge_vertices(min_index, max_index - min_index + 1)
562
563 self._dump_state()
564
565 _dclRE = re.compile('^DCL\s+(IN|OUT|SAMP|SVIEW)\[([0-9]+)\].*$', re.MULTILINE)
566
567 def _normalize_stage_state(self, stage):
568
569 registers = {}
570
571 if stage.shader is not None and stage.shader.tokens is not None:
572 for mo in self._dclRE.finditer(stage.shader.tokens):
573 file_ = mo.group(1)
574 index = mo.group(2)
575 register = registers.setdefault(file_, set())
576 register.add(int(index))
577
578 if 'SAMP' in registers and 'SVIEW' not in registers:
579 registers['SVIEW'] = registers['SAMP']
580
581 mapping = [
582 #("CONST", "constant_buffer"),
583 ("SAMP", "sampler"),
584 ("SVIEW", "sampler_views"),
585 ]
586
587 for fileName, attrName in mapping:
588 register = registers.setdefault(fileName, set())
589 attr = getattr(stage, attrName)
590 for index in range(len(attr)):
591 if index not in register:
592 attr[index] = None
593 while attr and attr[-1] is None:
594 attr.pop()
595
596 def _dump_state(self):
597 '''Dump our state to JSON and terminate.'''
598
599 state = copy.deepcopy(self._state)
600
601 self._normalize_stage_state(state.vs)
602 self._normalize_stage_state(state.gs)
603 self._normalize_stage_state(state.fs)
604
605 json.dump(
606 obj = state,
607 fp = sys.stdout,
608 default = serialize,
609 sort_keys = True,
610 indent = 4,
611 separators = (',', ': ')
612 )
613
614 sys.exit(0)
615
616 def resource_copy_region(self, dst, dst_level, dstx, dsty, dstz, src, src_level, src_box):
617 if dst.target == PIPE_BUFFER or src.target == PIPE_BUFFER:
618 assert dst.target == PIPE_BUFFER and src.target == PIPE_BUFFER
619 assert dst_level == 0
620 assert dsty == 0
621 assert dstz == 0
622 assert src_level == 0
623 assert src_box.y == 0
624 assert src_box.z == 0
625 assert src_box.height == 1
626 assert src_box.depth == 1
627 dst.data[dstx : dstx + src_box.width] = src.data[src_box.x : src_box.x + src_box.width]
628 pass
629
630 def is_resource_referenced(self, texture, face, level):
631 pass
632
633 def get_transfer(self, texture, sr, usage, box):
634 if texture is None:
635 return None
636 transfer = Transfer(texture, sr, usage, box)
637 return transfer
638
639 def tex_transfer_destroy(self, transfer):
640 self.interpreter.unregister_object(transfer)
641
642 def buffer_subdata(self, resource, usage, data, box=None, offset=None, size=None, level=None, stride=None, layer_stride=None):
643 if box is not None:
644 # XXX trace_context_transfer_unmap generates brokens buffer_subdata
645 assert offset is None
646 assert size is None
647 assert level == 0
648 offset = box.x
649 size = box.width
650 box = None
651
652 if resource is not None and resource.target == PIPE_BUFFER:
653 data = data.getValue()
654 assert len(data) >= size
655 assert offset + size <= len(resource.data)
656 resource.data[offset : offset + size] = data[:size]
657
658 def texture_subdata(self, resource, level, usage, box, data, stride, layer_stride):
659 pass
660
661 def transfer_inline_write(self, resource, level, usage, box, stride, layer_stride, data):
662 if resource is not None and resource.target == PIPE_BUFFER:
663 data = data.getValue()
664 assert len(data) >= box.width
665 assert box.x + box.width <= len(resource.data)
666 resource.data[box.x : box.x + box.width] = data[:box.width]
667
668 def flush(self, flags):
669 # Return a fake fence
670 return self.interpreter.call_no
671
672 def clear(self, buffers, color, depth, stencil):
673 pass
674
675 def clear_render_target(self, dst, rgba, dstx, dsty, width, height):
676 pass
677
678 def clear_depth_stencil(self, dst, clear_flags, depth, stencil, dstx, dsty, width, height):
679 pass
680
681 def create_surface(self, resource, surf_tmpl):
682 assert resource is not None
683 surf_tmpl.resource = resource
684 return surf_tmpl
685
686 def surface_destroy(self, surface):
687 self.interpreter.unregister_object(surface)
688
689 def create_query(self, query_type, index):
690 return query_type
691
692 def destroy_query(self, query):
693 pass
694
695 def begin_query(self, query):
696 pass
697
698 def end_query(self, query):
699 pass
700
701 def create_stream_output_target(self, res, buffer_offset, buffer_size):
702 so_target = Struct()
703 so_target.resource = res
704 so_target.offset = buffer_offset
705 so_target.size = buffer_size
706 return so_target
707
708
709 class Interpreter(parser.TraceDumper):
710 '''Specialization of a trace parser that interprets the calls as it goes
711 along.'''
712
713 ignoredCalls = set((
714 ('pipe_screen', 'is_format_supported'),
715 ('pipe_screen', 'get_name'),
716 ('pipe_screen', 'get_vendor'),
717 ('pipe_screen', 'get_param'),
718 ('pipe_screen', 'get_paramf'),
719 ('pipe_screen', 'get_shader_param'),
720 ('pipe_context', 'clear_render_target'), # XXX workaround trace bugs
721 ))
722
723 def __init__(self, stream, options):
724 parser.TraceDumper.__init__(self, stream, sys.stderr)
725 self.options = options
726 self.objects = {}
727 self.result = None
728 self.globl = Global(self)
729 self.call_no = None
730
731 def register_object(self, address, object):
732 self.objects[address] = object
733
734 def unregister_object(self, object):
735 # TODO
736 pass
737
738 def lookup_object(self, address):
739 try:
740 return self.objects[address]
741 except KeyError:
742 # Could happen, e.g., with user memory pointers
743 return address
744
745 def interpret(self, trace):
746 for call in trace.calls:
747 self.interpret_call(call)
748
749 def handle_call(self, call):
750 if (call.klass, call.method) in self.ignoredCalls:
751 return
752
753 self.call_no = call.no
754
755 if self.verbosity(1):
756 # Write the call to stderr (as stdout would corrupt the JSON output)
757 sys.stderr.flush()
758 sys.stdout.flush()
759 parser.TraceDumper.handle_call(self, call)
760 sys.stderr.flush()
761 sys.stdout.flush()
762
763 args = [(str(name), self.interpret_arg(arg)) for name, arg in call.args]
764
765 if call.klass:
766 name, obj = args[0]
767 args = args[1:]
768 else:
769 obj = self.globl
770
771 method = getattr(obj, call.method)
772 ret = method(**dict(args))
773
774 # Keep track of created pointer objects.
775 if call.ret and isinstance(call.ret, model.Pointer):
776 if ret is None:
777 sys.stderr.write('warning: NULL returned\n')
778 self.register_object(call.ret.address, ret)
779
780 self.call_no = None
781
782 def interpret_arg(self, node):
783 translator = Translator(self)
784 return translator.visit(node)
785
786 def verbosity(self, level):
787 return self.options.verbosity >= level
788
789
790 class Main(parser.Main):
791
792 def get_optparser(self):
793 '''Custom options.'''
794
795 optparser = parser.Main.get_optparser(self)
796 optparser.add_option("-q", "--quiet", action="store_const", const=0, dest="verbosity", help="no messages")
797 optparser.add_option("-v", "--verbose", action="count", dest="verbosity", default=0, help="increase verbosity level")
798 optparser.add_option("-c", "--call", action="store", type="int", dest="call", default=0xffffffff, help="dump on this call")
799 optparser.add_option("-d", "--draw", action="store", type="int", dest="draw", default=0xffffffff, help="dump on this draw")
800 return optparser
801
802 def process_arg(self, stream, options):
803 parser = Interpreter(stream, options)
804 parser.parse()
805
806
807 if __name__ == '__main__':
808 Main().main()