Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. #!/usr/bin/env python
  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_value = self.visit(member_node)
  141.             setattr(struct, member_name, member_value)
  142.         self.result = struct
  143.    
  144.     def visit_pointer(self, node):
  145.         self.result = self.interpreter.lookup_object(node.address)
  146.  
  147.  
  148. class Dispatcher:
  149.     '''Base class for classes whose methods can dispatch Gallium calls.'''
  150.    
  151.     def __init__(self, interpreter):
  152.         self.interpreter = interpreter
  153.        
  154.  
  155. class Global(Dispatcher):
  156.     '''Global name space.
  157.  
  158.    For calls that are not associated with objects, i.e, functions and not
  159.    methods.
  160.    '''
  161.  
  162.     def pipe_screen_create(self):
  163.         return Screen(self.interpreter)
  164.    
  165.     def pipe_context_create(self, screen):
  166.         return screen.context_create()
  167.  
  168.    
  169. class Transfer:
  170.     '''pipe_transfer'''
  171.  
  172.     def __init__(self, resource, usage, subresource, box):
  173.         self.resource = resource
  174.         self.usage = usage
  175.         self.subresource = subresource
  176.         self.box = box
  177.  
  178.  
  179. class Screen(Dispatcher):
  180.     '''pipe_screen'''
  181.    
  182.     def __init__(self, interpreter):
  183.         Dispatcher.__init__(self, interpreter)
  184.  
  185.     def destroy(self):
  186.         pass
  187.  
  188.     def context_create(self):
  189.         return Context(self.interpreter)
  190.    
  191.     def is_format_supported(self, format, target, sample_count, bind, geom_flags):
  192.         pass
  193.    
  194.     def resource_create(self, templat):
  195.         resource = templat
  196.         # Normalize state to avoid spurious differences
  197.         if resource.nr_samples == 0:
  198.             resource.nr_samples = 1
  199.         if resource.target == PIPE_BUFFER:
  200.             # We will keep track of buffer contents
  201.             resource.data = bytearray(resource.width)
  202.             # Ignore format
  203.             del resource.format
  204.         return resource
  205.  
  206.     def resource_destroy(self, resource):
  207.         self.interpreter.unregister_object(resource)
  208.  
  209.     def fence_finish(self, fence, timeout=None):
  210.         pass
  211.    
  212.     def fence_signalled(self, fence):
  213.         pass
  214.    
  215.     def fence_reference(self, dst, src):
  216.         pass
  217.    
  218.     def flush_frontbuffer(self, resource):
  219.         pass
  220.  
  221.  
  222. class Context(Dispatcher):
  223.     '''pipe_context'''
  224.  
  225.     # Internal methods variable should be prefixed with '_'
  226.    
  227.     def __init__(self, interpreter):
  228.         Dispatcher.__init__(self, interpreter)
  229.  
  230.         # Setup initial state
  231.         self._state = Struct()
  232.         self._state.scissors = []
  233.         self._state.viewports = []
  234.         self._state.vertex_buffers = []
  235.         self._state.vertex_elements = []
  236.         self._state.vs = Struct()
  237.         self._state.gs = Struct()
  238.         self._state.fs = Struct()
  239.         self._state.vs.shader = None
  240.         self._state.gs.shader = None
  241.         self._state.fs.shader = None
  242.         self._state.vs.sampler = []
  243.         self._state.gs.sampler = []
  244.         self._state.fs.sampler = []
  245.         self._state.vs.sampler_views = []
  246.         self._state.gs.sampler_views = []
  247.         self._state.fs.sampler_views = []
  248.         self._state.vs.constant_buffer = []
  249.         self._state.gs.constant_buffer = []
  250.         self._state.fs.constant_buffer = []
  251.         self._state.render_condition_condition = 0
  252.         self._state.render_condition_mode = 0
  253.  
  254.         self._draw_no = 0
  255.  
  256.     def destroy(self):
  257.         pass
  258.    
  259.     def create_blend_state(self, state):
  260.         # Normalize state to avoid spurious differences
  261.         if not state.logicop_enable:
  262.             del state.logicop_func
  263.         if not state.rt[0].blend_enable:
  264.             del state.rt[0].rgb_src_factor
  265.             del state.rt[0].rgb_dst_factor
  266.             del state.rt[0].rgb_func
  267.             del state.rt[0].alpha_src_factor
  268.             del state.rt[0].alpha_dst_factor
  269.             del state.rt[0].alpha_func
  270.         return state
  271.  
  272.     def bind_blend_state(self, state):
  273.         # Normalize state
  274.         self._state.blend = state
  275.  
  276.     def delete_blend_state(self, state):
  277.         pass
  278.    
  279.     def create_sampler_state(self, state):
  280.         return state
  281.  
  282.     def delete_sampler_state(self, state):
  283.         pass
  284.  
  285.     def bind_sampler_states(self, shader, start, num_states, states):
  286.         # FIXME: Handle non-zero start
  287.         assert start == 0
  288.         self._get_stage_state(shader).sampler = states
  289.  
  290.     def bind_vertex_sampler_states(self, num_states, states):
  291.         # XXX: deprecated method
  292.         self._state.vs.sampler = states
  293.  
  294.     def bind_geometry_sampler_states(self, num_states, states):
  295.         # XXX: deprecated method
  296.         self._state.gs.sampler = states
  297.  
  298.     def bind_fragment_sampler_states(self, num_states, states):
  299.         # XXX: deprecated method
  300.         self._state.fs.sampler = states
  301.        
  302.     def create_rasterizer_state(self, state):
  303.         return state
  304.  
  305.     def bind_rasterizer_state(self, state):
  306.         self._state.rasterizer = state
  307.        
  308.     def delete_rasterizer_state(self, state):
  309.         pass
  310.    
  311.     def create_depth_stencil_alpha_state(self, state):
  312.         # Normalize state to avoid spurious differences
  313.         if not state.alpha.enabled:
  314.             del state.alpha.func
  315.             del state.alpha.ref_value
  316.         for i in range(2):
  317.             if not state.stencil[i].enabled:
  318.                 del state.stencil[i].func
  319.         return state
  320.  
  321.     def bind_depth_stencil_alpha_state(self, state):
  322.         self._state.depth_stencil_alpha = state
  323.            
  324.     def delete_depth_stencil_alpha_state(self, state):
  325.         pass
  326.  
  327.     _tokenLabelRE = re.compile('^\s*\d+: ', re.MULTILINE)
  328.  
  329.     def _create_shader_state(self, state):
  330.         # Strip the labels from the tokens
  331.         if state.tokens is not None:
  332.             state.tokens = self._tokenLabelRE.sub('', state.tokens)
  333.         return state
  334.  
  335.     create_vs_state = _create_shader_state
  336.     create_gs_state = _create_shader_state
  337.     create_fs_state = _create_shader_state
  338.    
  339.     def bind_vs_state(self, state):
  340.         self._state.vs.shader = state
  341.  
  342.     def bind_gs_state(self, state):
  343.         self._state.gs.shader = state
  344.        
  345.     def bind_fs_state(self, state):
  346.         self._state.fs.shader = state
  347.        
  348.     def _delete_shader_state(self, state):
  349.         return state
  350.  
  351.     delete_vs_state = _delete_shader_state
  352.     delete_gs_state = _delete_shader_state
  353.     delete_fs_state = _delete_shader_state
  354.  
  355.     def set_blend_color(self, state):
  356.         self._state.blend_color = state
  357.  
  358.     def set_stencil_ref(self, state):
  359.         self._state.stencil_ref = state
  360.  
  361.     def set_clip_state(self, state):
  362.         self._state.clip = state
  363.  
  364.     def _dump_constant_buffer(self, buffer):
  365.         if not self.interpreter.verbosity(2):
  366.             return
  367.  
  368.         data = self.real.buffer_read(buffer)
  369.         format = '4f'
  370.         index = 0
  371.         for offset in range(0, len(data), struct.calcsize(format)):
  372.             x, y, z, w = unpack_from(format, data, offset)
  373.             sys.stdout.write('\tCONST[%2u] = {%10.4f, %10.4f, %10.4f, %10.4f}\n' % (index, x, y, z, w))
  374.             index += 1
  375.         sys.stdout.flush()
  376.  
  377.     def _get_stage_state(self, shader):
  378.         if shader == PIPE_SHADER_VERTEX:
  379.             return self._state.vs
  380.         if shader == PIPE_SHADER_GEOMETRY:
  381.             return self._state.gs
  382.         if shader == PIPE_SHADER_FRAGMENT:
  383.             return self._state.fs
  384.         assert False
  385.  
  386.     def set_constant_buffer(self, shader, index, constant_buffer):
  387.         self._update(self._get_stage_state(shader).constant_buffer, index, 1, [constant_buffer])
  388.  
  389.     def set_framebuffer_state(self, state):
  390.         self._state.fb = state
  391.  
  392.     def set_polygon_stipple(self, state):
  393.         self._state.polygon_stipple = state
  394.  
  395.     def _update(self, array, start_slot, num_slots, states):
  396.         if not isinstance(states, list):
  397.             # XXX: trace is not serializing multiple scissors/viewports properly yet
  398.             num_slots = 1
  399.             states = [states]
  400.         while len(array) < start_slot + num_slots:
  401.             array.append(None)
  402.         for i in range(num_slots):
  403.             array[start_slot + i] = states[i]
  404.  
  405.     def set_scissor_states(self, start_slot, num_scissors, states):
  406.         self._update(self._state.scissors, start_slot, num_scissors, states)
  407.  
  408.     def set_viewport_states(self, start_slot, num_viewports, states):
  409.         self._update(self._state.viewports, start_slot, num_viewports, states)
  410.  
  411.     def create_sampler_view(self, resource, templ):
  412.         templ.resource = resource
  413.         return templ
  414.  
  415.     def sampler_view_destroy(self, view):
  416.         pass
  417.  
  418.     def set_sampler_views(self, shader, start, num, views):
  419.         # FIXME: Handle non-zero start
  420.         assert start == 0
  421.         self._get_stage_state(shader).sampler_views = views
  422.  
  423.     def set_fragment_sampler_views(self, num, views):
  424.         # XXX: deprecated
  425.         self._state.fs.sampler_views = views
  426.  
  427.     def set_geometry_sampler_views(self, num, views):
  428.         # XXX: deprecated
  429.         self._state.gs.sampler_views = views
  430.  
  431.     def set_vertex_sampler_views(self, num, views):
  432.         # XXX: deprecated
  433.         self._state.vs.sampler_views = views
  434.  
  435.     def set_vertex_buffers(self, start_slot, num_buffers, buffers):
  436.         self._update(self._state.vertex_buffers, start_slot, num_buffers, buffers)
  437.            
  438.     def create_vertex_elements_state(self, num_elements, elements):
  439.         return elements[0:num_elements]
  440.  
  441.     def bind_vertex_elements_state(self, state):
  442.         self._state.vertex_elements = state
  443.  
  444.     def delete_vertex_elements_state(self, state):
  445.         pass
  446.  
  447.     def set_index_buffer(self, ib):
  448.         self._state.index_buffer = ib
  449.  
  450.     # Don't dump more than this number of indices/vertices
  451.     MAX_ELEMENTS = 16
  452.  
  453.     def _merge_indices(self, info):
  454.         '''Merge the vertices into our state.'''
  455.  
  456.         index_size = self._state.index_buffer.index_size
  457.        
  458.         format = {
  459.             1: 'B',
  460.             2: 'H',
  461.             4: 'I',
  462.         }[index_size]
  463.  
  464.         assert struct.calcsize(format) == index_size
  465.  
  466.         if self._state.index_buffer.buffer is None:
  467.             # Could happen with index in user memory
  468.             return 0, 0
  469.  
  470.         data = self._state.index_buffer.buffer.data
  471.         max_index, min_index = 0, 0xffffffff
  472.  
  473.         count = min(info.count, self.MAX_ELEMENTS)
  474.         indices = []
  475.         for i in xrange(info.start, info.start + count):
  476.             offset = self._state.index_buffer.offset + i*index_size
  477.             if offset + index_size > len(data):
  478.                 index = 0
  479.             else:
  480.                 index, = unpack_from(format, data, offset)
  481.             indices.append(index)
  482.             min_index = min(min_index, index)
  483.             max_index = max(max_index, index)
  484.  
  485.         self._state.indices = indices
  486.  
  487.         return min_index + info.index_bias, max_index + info.index_bias
  488.  
  489.     def _merge_vertices(self, start, count):
  490.         '''Merge the vertices into our state.'''
  491.  
  492.         count = min(count, self.MAX_ELEMENTS)
  493.         vertices = []
  494.         for index in xrange(start, start + count):
  495.             if index >= start + 16:
  496.                 sys.stdout.write('\t...\n')
  497.                 break
  498.             vertex = []
  499.             for velem in self._state.vertex_elements:
  500.                 vbuf = self._state.vertex_buffers[velem.vertex_buffer_index]
  501.                 if vbuf.buffer is None:
  502.                     continue
  503.  
  504.                 data = vbuf.buffer.data
  505.  
  506.                 offset = vbuf.buffer_offset + velem.src_offset + vbuf.stride*index
  507.                 format = {
  508.                     'PIPE_FORMAT_R32_FLOAT': 'f',
  509.                     'PIPE_FORMAT_R32G32_FLOAT': '2f',
  510.                     'PIPE_FORMAT_R32G32B32_FLOAT': '3f',
  511.                     'PIPE_FORMAT_R32G32B32A32_FLOAT': '4f',
  512.                     'PIPE_FORMAT_R32_UINT': 'I',
  513.                     'PIPE_FORMAT_R32G32_UINT': '2I',
  514.                     'PIPE_FORMAT_R32G32B32_UINT': '3I',
  515.                     'PIPE_FORMAT_R32G32B32A32_UINT': '4I',
  516.                     'PIPE_FORMAT_R8_UINT': 'B',
  517.                     'PIPE_FORMAT_R8G8_UINT': '2B',
  518.                     'PIPE_FORMAT_R8G8B8_UINT': '3B',
  519.                     'PIPE_FORMAT_R8G8B8A8_UINT': '4B',
  520.                     'PIPE_FORMAT_A8R8G8B8_UNORM': '4B',
  521.                     'PIPE_FORMAT_R8G8B8A8_UNORM': '4B',
  522.                     'PIPE_FORMAT_B8G8R8A8_UNORM': '4B',
  523.                     'PIPE_FORMAT_R16G16B16_SNORM': '3h',
  524.                 }[velem.src_format]
  525.  
  526.                 data = vbuf.buffer.data
  527.                 attribute = unpack_from(format, data, offset)
  528.                 vertex.append(attribute)
  529.  
  530.             vertices.append(vertex)
  531.  
  532.         self._state.vertices = vertices
  533.  
  534.     def render_condition(self, query, condition = 0, mode = 0):
  535.         self._state.render_condition_query = query
  536.         self._state.render_condition_condition = condition
  537.         self._state.render_condition_mode = mode
  538.  
  539.     def set_stream_output_targets(self, num_targets, tgs, offsets):
  540.         self._state.so_targets = tgs
  541.         self._state.offsets = offsets
  542.  
  543.     def draw_vbo(self, info):
  544.         self._draw_no += 1
  545.  
  546.         if self.interpreter.call_no < self.interpreter.options.call and \
  547.             self._draw_no < self.interpreter.options.draw:
  548.                 return
  549.  
  550.         # Merge the all draw state
  551.  
  552.         self._state.draw = info
  553.  
  554.         if info.indexed:
  555.             min_index, max_index = self._merge_indices(info)
  556.         else:
  557.             min_index = info.start
  558.             max_index = info.start + info.count - 1
  559.         self._merge_vertices(min_index, max_index - min_index + 1)
  560.  
  561.         self._dump_state()
  562.  
  563.     _dclRE = re.compile('^DCL\s+(IN|OUT|SAMP|SVIEW)\[([0-9]+)\].*$', re.MULTILINE)
  564.  
  565.     def _normalize_stage_state(self, stage):
  566.  
  567.         registers = {}
  568.  
  569.         if stage.shader is not None and stage.shader.tokens is not None:
  570.             for mo in self._dclRE.finditer(stage.shader.tokens):
  571.                 file_ = mo.group(1)
  572.                 index = mo.group(2)
  573.                 register = registers.setdefault(file_, set())
  574.                 register.add(int(index))
  575.  
  576.         if 'SAMP' in registers and 'SVIEW' not in registers:
  577.             registers['SVIEW'] = registers['SAMP']
  578.  
  579.         mapping = [
  580.             #("CONST", "constant_buffer"),
  581.             ("SAMP", "sampler"),
  582.             ("SVIEW", "sampler_views"),
  583.         ]
  584.  
  585.         for fileName, attrName in mapping:
  586.             register = registers.setdefault(fileName, set())
  587.             attr = getattr(stage, attrName)
  588.             for index in range(len(attr)):
  589.                 if index not in register:
  590.                     attr[index] = None
  591.             while attr and attr[-1] is None:
  592.                 attr.pop()
  593.  
  594.     def _dump_state(self):
  595.         '''Dump our state to JSON and terminate.'''
  596.  
  597.         state = copy.deepcopy(self._state)
  598.  
  599.         self._normalize_stage_state(state.vs)
  600.         self._normalize_stage_state(state.gs)
  601.         self._normalize_stage_state(state.fs)
  602.  
  603.         json.dump(
  604.             obj = state,
  605.             fp = sys.stdout,
  606.             default = serialize,
  607.             sort_keys = True,
  608.             indent = 4,
  609.             separators = (',', ': ')
  610.         )
  611.  
  612.         sys.exit(0)
  613.  
  614.     def resource_copy_region(self, dst, dst_level, dstx, dsty, dstz, src, src_level, src_box):
  615.         if dst.target == PIPE_BUFFER or src.target == PIPE_BUFFER:
  616.             assert dst.target == PIPE_BUFFER and src.target == PIPE_BUFFER
  617.             assert dst_level == 0
  618.             assert dsty == 0
  619.             assert dstz == 0
  620.             assert src_level == 0
  621.             assert src_box.y == 0
  622.             assert src_box.z == 0
  623.             assert src_box.height == 1
  624.             assert src_box.depth == 1
  625.             dst.data[dstx : dstx + src_box.width] = src.data[src_box.x : src_box.x + src_box.width]
  626.         pass
  627.  
  628.     def is_resource_referenced(self, texture, face, level):
  629.         pass
  630.    
  631.     def get_transfer(self, texture, sr, usage, box):
  632.         if texture is None:
  633.             return None
  634.         transfer = Transfer(texture, sr, usage, box)
  635.         return transfer
  636.    
  637.     def tex_transfer_destroy(self, transfer):
  638.         self.interpreter.unregister_object(transfer)
  639.  
  640.     def transfer_inline_write(self, resource, level, usage, box, stride, layer_stride, data):
  641.         if resource is not None and resource.target == PIPE_BUFFER:
  642.             data = data.getValue()
  643.             assert len(data) >= box.width
  644.             assert box.x + box.width <= len(resource.data)
  645.             resource.data[box.x : box.x + box.width] = data[:box.width]
  646.  
  647.     def flush(self, flags):
  648.         # Return a fake fence
  649.         return self.interpreter.call_no
  650.  
  651.     def clear(self, buffers, color, depth, stencil):
  652.         pass
  653.        
  654.     def clear_render_target(self, dst, rgba, dstx, dsty, width, height):
  655.         pass
  656.  
  657.     def clear_depth_stencil(self, dst, clear_flags, depth, stencil, dstx, dsty, width, height):
  658.         pass
  659.  
  660.     def create_surface(self, resource, surf_tmpl):
  661.         assert resource is not None
  662.         surf_tmpl.resource = resource
  663.         return surf_tmpl
  664.  
  665.     def surface_destroy(self, surface):
  666.         self.interpreter.unregister_object(surface)
  667.  
  668.     def create_query(self, query_type, index):
  669.         return query_type
  670.    
  671.     def destroy_query(self, query):
  672.         pass
  673.  
  674.     def begin_query(self, query):
  675.         pass
  676.  
  677.     def end_query(self, query):
  678.         pass
  679.  
  680.     def create_stream_output_target(self, res, buffer_offset, buffer_size):
  681.         so_target = Struct()
  682.         so_target.resource = res
  683.         so_target.offset = buffer_offset
  684.         so_target.size = buffer_size
  685.         return so_target
  686.  
  687.  
  688. class Interpreter(parser.TraceDumper):
  689.     '''Specialization of a trace parser that interprets the calls as it goes
  690.    along.'''
  691.    
  692.     ignoredCalls = set((
  693.             ('pipe_screen', 'is_format_supported'),
  694.             ('pipe_screen', 'get_name'),
  695.             ('pipe_screen', 'get_vendor'),
  696.             ('pipe_screen', 'get_param'),
  697.             ('pipe_screen', 'get_paramf'),
  698.             ('pipe_screen', 'get_shader_param'),
  699.             ('pipe_context', 'clear_render_target'), # XXX workaround trace bugs
  700.     ))
  701.  
  702.     def __init__(self, stream, options):
  703.         parser.TraceDumper.__init__(self, stream, sys.stderr)
  704.         self.options = options
  705.         self.objects = {}
  706.         self.result = None
  707.         self.globl = Global(self)
  708.         self.call_no = None
  709.  
  710.     def register_object(self, address, object):
  711.         self.objects[address] = object
  712.        
  713.     def unregister_object(self, object):
  714.         # TODO
  715.         pass
  716.  
  717.     def lookup_object(self, address):
  718.         try:
  719.             return self.objects[address]
  720.         except KeyError:
  721.             # Could happen, e.g., with user memory pointers
  722.             return address
  723.    
  724.     def interpret(self, trace):
  725.         for call in trace.calls:
  726.             self.interpret_call(call)
  727.  
  728.     def handle_call(self, call):
  729.         if (call.klass, call.method) in self.ignoredCalls:
  730.             return
  731.  
  732.         self.call_no = call.no
  733.  
  734.         if self.verbosity(1):
  735.             # Write the call to stderr (as stdout would corrupt the JSON output)
  736.             sys.stderr.flush()
  737.             sys.stdout.flush()
  738.             parser.TraceDumper.handle_call(self, call)
  739.             sys.stderr.flush()
  740.             sys.stdout.flush()
  741.        
  742.         args = [(str(name), self.interpret_arg(arg)) for name, arg in call.args]
  743.        
  744.         if call.klass:
  745.             name, obj = args[0]
  746.             args = args[1:]
  747.         else:
  748.             obj = self.globl
  749.            
  750.         method = getattr(obj, call.method)
  751.         ret = method(**dict(args))
  752.        
  753.         # Keep track of created pointer objects.
  754.         if call.ret and isinstance(call.ret, model.Pointer):
  755.             if ret is None:
  756.                 sys.stderr.write('warning: NULL returned\n')
  757.             self.register_object(call.ret.address, ret)
  758.  
  759.         self.call_no = None
  760.  
  761.     def interpret_arg(self, node):
  762.         translator = Translator(self)
  763.         return translator.visit(node)
  764.  
  765.     def verbosity(self, level):
  766.         return self.options.verbosity >= level
  767.    
  768.  
  769. class Main(parser.Main):
  770.  
  771.     def get_optparser(self):
  772.         '''Custom options.'''
  773.  
  774.         optparser = parser.Main.get_optparser(self)
  775.         optparser.add_option("-q", "--quiet", action="store_const", const=0, dest="verbosity", help="no messages")
  776.         optparser.add_option("-v", "--verbose", action="count", dest="verbosity", default=0, help="increase verbosity level")
  777.         optparser.add_option("-c", "--call", action="store", type="int", dest="call", default=0xffffffff, help="dump on this call")
  778.         optparser.add_option("-d", "--draw", action="store", type="int", dest="draw", default=0xffffffff, help="dump on this draw")
  779.         return optparser
  780.  
  781.     def process_arg(self, stream, options):
  782.         parser = Interpreter(stream, options)
  783.         parser.parse()
  784.  
  785.  
  786. if __name__ == '__main__':
  787.     Main().main()
  788.