trace: Bring state dump up to speed.

Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Roland Scheidegger <sroland@vmware.com>
Reviewed-By: Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17107>
This commit is contained in:
Jose Fonseca 2022-06-16 11:06:31 +01:00 committed by Marge Bot
parent 0296050c0e
commit c5ddb95953

View file

@ -1,9 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
########################################################################## ##########################################################################
# #
# Copyright 2008-2013, VMware, Inc. # Copyright 2008-2021, VMware, Inc.
# All Rights Reserved. # All Rights Reserved.
# #
# Permission is hereby granted, free of charge, to any person obtaining a # Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the # copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including # "Software"), to deal in the Software without restriction, including
@ -11,11 +11,11 @@
# distribute, sub license, and/or sell copies of the Software, and to # distribute, sub license, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to # permit persons to whom the Software is furnished to do so, subject to
# the following conditions: # the following conditions:
# #
# The above copyright notice and this permission notice (including the # The above copyright notice and this permission notice (including the
# next paragraph) shall be included in all copies or substantial portions # next paragraph) shall be included in all copies or substantial portions
# of the Software. # of the Software.
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
@ -23,7 +23,7 @@
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# #
########################################################################## ##########################################################################
@ -50,12 +50,7 @@ except ImportError:
# #
# Some constants # Some constants
# #
PIPE_BUFFER = 0 PIPE_BUFFER = 'PIPE_BUFFER'
PIPE_SHADER_VERTEX = 0
PIPE_SHADER_FRAGMENT = 1
PIPE_SHADER_GEOMETRY = 2
PIPE_SHADER_COMPUTE = 3
PIPE_SHADER_TYPES = 4
def serialize(obj): def serialize(obj):
@ -89,7 +84,7 @@ def serialize(obj):
class Struct: class Struct:
"""C-like struct. """C-like struct.
Python doesn't have C structs, but do its dynamic nature, any object is Python doesn't have C structs, but do its dynamic nature, any object is
pretty close. pretty close.
""" """
@ -119,22 +114,22 @@ class Translator(model.Visitor):
self.result = None self.result = None
node.visit(self) node.visit(self)
return self.result return self.result
def visit_literal(self, node): def visit_literal(self, node):
self.result = node.value self.result = node.value
def visit_blob(self, node): def visit_blob(self, node):
self.result = node self.result = node
def visit_named_constant(self, node): def visit_named_constant(self, node):
self.result = node.name self.result = node.name
def visit_array(self, node): def visit_array(self, node):
array = [] array = []
for element in node.elements: for element in node.elements:
array.append(self.visit(element)) array.append(self.visit(element))
self.result = array self.result = array
def visit_struct(self, node): def visit_struct(self, node):
struct = Struct() struct = Struct()
for member_name, member_node in node.members: for member_name, member_node in node.members:
@ -142,17 +137,17 @@ class Translator(model.Visitor):
member_value = self.visit(member_node) member_value = self.visit(member_node)
setattr(struct, member_name, member_value) setattr(struct, member_name, member_value)
self.result = struct self.result = struct
def visit_pointer(self, node): def visit_pointer(self, node):
self.result = self.interpreter.lookup_object(node.address) self.result = self.interpreter.lookup_object(node.address)
class Dispatcher: class Dispatcher:
'''Base class for classes whose methods can dispatch Gallium calls.''' '''Base class for classes whose methods can dispatch Gallium calls.'''
def __init__(self, interpreter): def __init__(self, interpreter):
self.interpreter = interpreter self.interpreter = interpreter
class Global(Dispatcher): class Global(Dispatcher):
'''Global name space. '''Global name space.
@ -163,11 +158,11 @@ class Global(Dispatcher):
def pipe_screen_create(self): def pipe_screen_create(self):
return Screen(self.interpreter) return Screen(self.interpreter)
def pipe_context_create(self, screen): def pipe_context_create(self, screen):
return screen.context_create() return screen.context_create()
class Transfer: class Transfer:
'''pipe_transfer''' '''pipe_transfer'''
@ -180,7 +175,7 @@ class Transfer:
class Screen(Dispatcher): class Screen(Dispatcher):
'''pipe_screen''' '''pipe_screen'''
def __init__(self, interpreter): def __init__(self, interpreter):
Dispatcher.__init__(self, interpreter) Dispatcher.__init__(self, interpreter)
@ -189,10 +184,7 @@ class Screen(Dispatcher):
def context_create(self, priv=None, flags=0): def context_create(self, priv=None, flags=0):
return Context(self.interpreter) return Context(self.interpreter)
def is_format_supported(self, format, target, sample_count, bind, geom_flags):
pass
def resource_create(self, templat): def resource_create(self, templat):
resource = templat resource = templat
# Normalize state to avoid spurious differences # Normalize state to avoid spurious differences
@ -205,18 +197,35 @@ class Screen(Dispatcher):
del resource.format del resource.format
return resource return resource
resource_create_unbacked = resource_create
def allocate_memory(screen, size):
pass
def free_memory(screen, pmem):
pass
def map_memory(screen, pmem):
pass
def unmap_memory(screen, pmem):
pass
def resource_bind_backing(screen, resource, pmem, offset):
pass
def resource_destroy(self, resource): def resource_destroy(self, resource):
self.interpreter.unregister_object(resource) self.interpreter.unregister_object(resource)
def fence_finish(self, fence, timeout=None, ctx=None): def fence_finish(self, fence, timeout=None, ctx=None):
pass pass
def fence_signalled(self, fence): def fence_signalled(self, fence):
pass pass
def fence_reference(self, dst, src): def fence_reference(self, dst, src):
pass pass
def flush_frontbuffer(self, resource): def flush_frontbuffer(self, resource):
pass pass
@ -225,7 +234,7 @@ class Context(Dispatcher):
'''pipe_context''' '''pipe_context'''
# Internal methods variable should be prefixed with '_' # Internal methods variable should be prefixed with '_'
def __init__(self, interpreter): def __init__(self, interpreter):
Dispatcher.__init__(self, interpreter) Dispatcher.__init__(self, interpreter)
@ -236,28 +245,39 @@ class Context(Dispatcher):
self._state.vertex_buffers = [] self._state.vertex_buffers = []
self._state.vertex_elements = [] self._state.vertex_elements = []
self._state.vs = Struct() self._state.vs = Struct()
self._state.tcs = Struct()
self._state.tes = Struct()
self._state.gs = Struct() self._state.gs = Struct()
self._state.fs = Struct() self._state.fs = Struct()
self._state.vs.shader = None self._state.vs.shader = None
self._state.tcs.shader = None
self._state.tes.shader = None
self._state.gs.shader = None self._state.gs.shader = None
self._state.fs.shader = None self._state.fs.shader = None
self._state.vs.sampler = [] self._state.vs.sampler = []
self._state.tcs.sampler = []
self._state.tes.sampler = []
self._state.gs.sampler = [] self._state.gs.sampler = []
self._state.fs.sampler = [] self._state.fs.sampler = []
self._state.vs.sampler_views = [] self._state.vs.sampler_views = []
self._state.tcs.sampler_views = []
self._state.tes.sampler_views = []
self._state.gs.sampler_views = [] self._state.gs.sampler_views = []
self._state.fs.sampler_views = [] self._state.fs.sampler_views = []
self._state.vs.constant_buffer = [] self._state.vs.constant_buffer = []
self._state.tcs.constant_buffer = []
self._state.tes.constant_buffer = []
self._state.gs.constant_buffer = [] self._state.gs.constant_buffer = []
self._state.fs.constant_buffer = [] self._state.fs.constant_buffer = []
self._state.render_condition_condition = 0 self._state.render_condition_condition = 0
self._state.render_condition_mode = 0 self._state.render_condition_mode = 0
self._state.sample_mask = 0xffffffff
self._draw_no = 0 self._draw_no = 0
def destroy(self): def destroy(self):
pass pass
def create_blend_state(self, state): def create_blend_state(self, state):
# Normalize state to avoid spurious differences # Normalize state to avoid spurious differences
if not state.logicop_enable: if not state.logicop_enable:
@ -277,7 +297,7 @@ class Context(Dispatcher):
def delete_blend_state(self, state): def delete_blend_state(self, state):
pass pass
def create_sampler_state(self, state): def create_sampler_state(self, state):
return state return state
@ -300,21 +320,21 @@ class Context(Dispatcher):
def bind_fragment_sampler_states(self, num_states, states): def bind_fragment_sampler_states(self, num_states, states):
# XXX: deprecated method # XXX: deprecated method
self._state.fs.sampler = states self._state.fs.sampler = states
def create_rasterizer_state(self, state): def create_rasterizer_state(self, state):
return state return state
def bind_rasterizer_state(self, state): def bind_rasterizer_state(self, state):
self._state.rasterizer = state self._state.rasterizer = state
def delete_rasterizer_state(self, state): def delete_rasterizer_state(self, state):
pass pass
def create_depth_stencil_alpha_state(self, state): def create_depth_stencil_alpha_state(self, state):
# Normalize state to avoid spurious differences # Normalize state to avoid spurious differences
if not state.alpha.enabled: if not state.alpha_enabled:
del state.alpha.func del state.alpha_func
del state.alpha.ref_value del state.alpha_ref_value
for i in range(2): for i in range(2):
if not state.stencil[i].enabled: if not state.stencil[i].enabled:
del state.stencil[i].func del state.stencil[i].func
@ -322,7 +342,7 @@ class Context(Dispatcher):
def bind_depth_stencil_alpha_state(self, state): def bind_depth_stencil_alpha_state(self, state):
self._state.depth_stencil_alpha = state self._state.depth_stencil_alpha = state
def delete_depth_stencil_alpha_state(self, state): def delete_depth_stencil_alpha_state(self, state):
pass pass
@ -335,22 +355,35 @@ class Context(Dispatcher):
return state return state
create_vs_state = _create_shader_state create_vs_state = _create_shader_state
create_tcs_state = _create_shader_state
create_tes_state = _create_shader_state
create_gs_state = _create_shader_state create_gs_state = _create_shader_state
create_fs_state = _create_shader_state create_fs_state = _create_shader_state
def bind_vs_state(self, state): def bind_vs_state(self, state):
self._state.vs.shader = state self._state.vs.shader = state
def bind_tcs_state(self, state):
self._state.tcs.shader = state
def bind_tes_state(self, state):
self._state.tes.shader = state
def bind_gs_state(self, state): def bind_gs_state(self, state):
self._state.gs.shader = state self._state.gs.shader = state
def bind_fs_state(self, state): def bind_fs_state(self, state):
self._state.fs.shader = state self._state.fs.shader = state
def bind_tcz_state(self, state):
self._state.tcs.shader = state
def _delete_shader_state(self, state): def _delete_shader_state(self, state):
return state return state
delete_vs_state = _delete_shader_state delete_vs_state = _delete_shader_state
delete_tcs_state = _delete_shader_state
delete_tes_state = _delete_shader_state
delete_gs_state = _delete_shader_state delete_gs_state = _delete_shader_state
delete_fs_state = _delete_shader_state delete_fs_state = _delete_shader_state
@ -377,15 +410,19 @@ class Context(Dispatcher):
sys.stdout.flush() sys.stdout.flush()
def _get_stage_state(self, shader): def _get_stage_state(self, shader):
if shader == PIPE_SHADER_VERTEX: if shader == 'PIPE_SHADER_VERTEX':
return self._state.vs return self._state.vs
if shader == PIPE_SHADER_GEOMETRY: if shader == 'PIPE_SHADER_TESS_CTRL':
return self._state.tcs
if shader == 'PIPE_SHADER_TESS_EVAL':
return self._state.tes
if shader == 'PIPE_SHADER_GEOMETRY':
return self._state.gs return self._state.gs
if shader == PIPE_SHADER_FRAGMENT: if shader == 'PIPE_SHADER_FRAGMENT':
return self._state.fs return self._state.fs
assert False assert False
def set_constant_buffer(self, shader, index, constant_buffer): def set_constant_buffer(self, shader, index, take_ownership, constant_buffer):
self._update(self._get_stage_state(shader).constant_buffer, index, 1, [constant_buffer]) self._update(self._get_stage_state(shader).constant_buffer, index, 1, [constant_buffer])
def set_framebuffer_state(self, state): def set_framebuffer_state(self, state):
@ -417,7 +454,7 @@ class Context(Dispatcher):
def sampler_view_destroy(self, view): def sampler_view_destroy(self, view):
pass pass
def set_sampler_views(self, shader, start, num, views): def set_sampler_views(self, shader, start, num, unbind_num_trailing_slots, take_ownership, views):
# FIXME: Handle non-zero start # FIXME: Handle non-zero start
assert start == 0 assert start == 0
self._get_stage_state(shader).sampler_views = views self._get_stage_state(shader).sampler_views = views
@ -434,9 +471,9 @@ class Context(Dispatcher):
# XXX: deprecated # XXX: deprecated
self._state.vs.sampler_views = views self._state.vs.sampler_views = views
def set_vertex_buffers(self, start_slot, num_buffers, buffers): def set_vertex_buffers(self, start_slot, num_buffers, unbind_num_trailing_slots, take_ownership, buffers):
self._update(self._state.vertex_buffers, start_slot, num_buffers, buffers) self._update(self._state.vertex_buffers, start_slot, num_buffers, buffers)
def create_vertex_elements_state(self, num_elements, elements): def create_vertex_elements_state(self, num_elements, elements):
return elements[0:num_elements] return elements[0:num_elements]
@ -449,6 +486,9 @@ class Context(Dispatcher):
def set_index_buffer(self, ib): def set_index_buffer(self, ib):
self._state.index_buffer = ib self._state.index_buffer = ib
def set_patch_vertices(self, patch_vertices):
pass
# Don't dump more than this number of indices/vertices # Don't dump more than this number of indices/vertices
MAX_ELEMENTS = 16 MAX_ELEMENTS = 16
@ -456,7 +496,7 @@ class Context(Dispatcher):
'''Merge the vertices into our state.''' '''Merge the vertices into our state.'''
index_size = self._state.index_buffer.index_size index_size = self._state.index_buffer.index_size
format = { format = {
1: 'B', 1: 'B',
2: 'H', 2: 'H',
@ -543,7 +583,13 @@ class Context(Dispatcher):
self._state.so_targets = tgs self._state.so_targets = tgs
self._state.offsets = offsets self._state.offsets = offsets
def draw_vbo(self, info): def set_sample_mask(self, sample_mask):
self._state.sample_mask = sample_mask
def set_min_samples(self, min_samples):
pass
def draw_vbo(self, info, drawid_offset, indirect, draws, num_draws):
self._draw_no += 1 self._draw_no += 1
if self.interpreter.call_no < self.interpreter.options.call and \ if self.interpreter.call_no < self.interpreter.options.call and \
@ -557,8 +603,8 @@ class Context(Dispatcher):
if info.index_size != 0: if info.index_size != 0:
min_index, max_index = self._merge_indices(info) min_index, max_index = self._merge_indices(info)
else: else:
min_index = info.start min_index = draws[0].start
max_index = info.start + info.count - 1 max_index = draws[0].start + draws[0].count - 1
self._merge_vertices(min_index, max_index - min_index + 1) self._merge_vertices(min_index, max_index - min_index + 1)
self._dump_state() self._dump_state()
@ -566,33 +612,32 @@ class Context(Dispatcher):
_dclRE = re.compile('^DCL\s+(IN|OUT|SAMP|SVIEW)\[([0-9]+)\].*$', re.MULTILINE) _dclRE = re.compile('^DCL\s+(IN|OUT|SAMP|SVIEW)\[([0-9]+)\].*$', re.MULTILINE)
def _normalize_stage_state(self, stage): def _normalize_stage_state(self, stage):
registers = {}
if stage.shader is not None and stage.shader.tokens is not None: if stage.shader is not None and stage.shader.tokens is not None:
registers = {}
for mo in self._dclRE.finditer(stage.shader.tokens): for mo in self._dclRE.finditer(stage.shader.tokens):
file_ = mo.group(1) file_ = mo.group(1)
index = mo.group(2) index = mo.group(2)
register = registers.setdefault(file_, set()) register = registers.setdefault(file_, set())
register.add(int(index)) register.add(int(index))
if 'SAMP' in registers and 'SVIEW' not in registers: if 'SAMP' in registers and 'SVIEW' not in registers:
registers['SVIEW'] = registers['SAMP'] registers['SVIEW'] = registers['SAMP']
mapping = [ mapping = [
#("CONST", "constant_buffer"), #("CONST", "constant_buffer"),
("SAMP", "sampler"), ("SAMP", "sampler"),
("SVIEW", "sampler_views"), ("SVIEW", "sampler_views"),
] ]
for fileName, attrName in mapping: for fileName, attrName in mapping:
register = registers.setdefault(fileName, set()) register = registers.setdefault(fileName, set())
attr = getattr(stage, attrName) attr = getattr(stage, attrName)
for index in range(len(attr)): for index in range(len(attr)):
if index not in register: if index not in register:
attr[index] = None attr[index] = None
while attr and attr[-1] is None: while attr and attr[-1] is None:
attr.pop() attr.pop()
def _dump_state(self): def _dump_state(self):
'''Dump our state to JSON and terminate.''' '''Dump our state to JSON and terminate.'''
@ -600,6 +645,8 @@ class Context(Dispatcher):
state = copy.deepcopy(self._state) state = copy.deepcopy(self._state)
self._normalize_stage_state(state.vs) self._normalize_stage_state(state.vs)
self._normalize_stage_state(state.tcs)
self._normalize_stage_state(state.tes)
self._normalize_stage_state(state.gs) self._normalize_stage_state(state.gs)
self._normalize_stage_state(state.fs) self._normalize_stage_state(state.fs)
@ -630,13 +677,13 @@ class Context(Dispatcher):
def is_resource_referenced(self, texture, face, level): def is_resource_referenced(self, texture, face, level):
pass pass
def get_transfer(self, texture, sr, usage, box): def get_transfer(self, texture, sr, usage, box):
if texture is None: if texture is None:
return None return None
transfer = Transfer(texture, sr, usage, box) transfer = Transfer(texture, sr, usage, box)
return transfer return transfer
def tex_transfer_destroy(self, transfer): def tex_transfer_destroy(self, transfer):
self.interpreter.unregister_object(transfer) self.interpreter.unregister_object(transfer)
@ -672,11 +719,14 @@ class Context(Dispatcher):
def clear(self, buffers, color, depth, stencil, scissor_state=None): def clear(self, buffers, color, depth, stencil, scissor_state=None):
pass pass
def clear_render_target(self, dst, rgba, dstx, dsty, width, height): def clear_render_target(self, dst, rgba, dstx, dsty, width, height, render_condition_enabled):
pass pass
def clear_depth_stencil(self, dst, clear_flags, depth, stencil, dstx, dsty, width, height): def clear_depth_stencil(self, dst, clear_flags, depth, stencil, dstx, dsty, width, height, render_condition_enabled):
pass
def clear_texture(self, res, level, box, **color):
pass pass
def create_surface(self, resource, surf_tmpl): def create_surface(self, resource, surf_tmpl):
@ -689,7 +739,7 @@ class Context(Dispatcher):
def create_query(self, query_type, index): def create_query(self, query_type, index):
return query_type return query_type
def destroy_query(self, query): def destroy_query(self, query):
pass pass
@ -710,17 +760,24 @@ class Context(Dispatcher):
class Interpreter(parser.SimpleTraceDumper): class Interpreter(parser.SimpleTraceDumper):
'''Specialization of a trace parser that interprets the calls as it goes '''Specialization of a trace parser that interprets the calls as it goes
along.''' along.'''
ignoredCalls = set(( ignoredCalls = set((
('pipe_screen', 'is_format_supported'), ('pipe_screen', 'is_format_supported'),
('pipe_screen', 'get_name'), ('pipe_screen', 'get_name'),
('pipe_screen', 'get_vendor'), ('pipe_screen', 'get_vendor'),
('pipe_screen', 'get_device_uuid'),
('pipe_screen', 'get_driver_uuid'),
('pipe_screen', 'get_compiler_options'),
('pipe_screen', 'get_param'), ('pipe_screen', 'get_param'),
('pipe_screen', 'get_paramf'), ('pipe_screen', 'get_paramf'),
('pipe_screen', 'get_shader_param'), ('pipe_screen', 'get_shader_param'),
('pipe_screen', 'get_compute_param'),
('pipe_screen', 'get_disk_shader_cache'), ('pipe_screen', 'get_disk_shader_cache'),
('pipe_context', 'clear_render_target'), # XXX workaround trace bugs ('pipe_context', 'clear_render_target'), # XXX workaround trace bugs
('pipe_context', 'flush_resource'), ('pipe_context', 'flush_resource'),
('pipe_context', 'buffer_map'),
('pipe_context', 'texture_map'),
('pipe_context', 'transfer_unmap'),
)) ))
def __init__(self, stream, options, formatter): def __init__(self, stream, options, formatter):
@ -732,7 +789,7 @@ class Interpreter(parser.SimpleTraceDumper):
def register_object(self, address, object): def register_object(self, address, object):
self.objects[address] = object self.objects[address] = object
def unregister_object(self, object): def unregister_object(self, object):
# TODO # TODO
pass pass
@ -743,7 +800,7 @@ class Interpreter(parser.SimpleTraceDumper):
except KeyError: except KeyError:
# Could happen, e.g., with user memory pointers # Could happen, e.g., with user memory pointers
return address return address
def interpret(self, trace): def interpret(self, trace):
for call in trace.calls: for call in trace.calls:
self.interpret_call(call) self.interpret_call(call)
@ -761,9 +818,9 @@ class Interpreter(parser.SimpleTraceDumper):
parser.TraceDumper.handle_call(self, call) parser.TraceDumper.handle_call(self, call)
sys.stderr.flush() sys.stderr.flush()
sys.stdout.flush() sys.stdout.flush()
args = [(str(name), self.interpret_arg(arg)) for name, arg in call.args] args = [(str(name), self.interpret_arg(arg)) for name, arg in call.args]
if call.klass: if call.klass:
name, obj = args[0] name, obj = args[0]
args = args[1:] args = args[1:]
@ -772,7 +829,7 @@ class Interpreter(parser.SimpleTraceDumper):
method = getattr(obj, call.method) method = getattr(obj, call.method)
ret = method(**dict(args)) ret = method(**dict(args))
# Keep track of created pointer objects. # Keep track of created pointer objects.
if call.ret and isinstance(call.ret, model.Pointer): if call.ret and isinstance(call.ret, model.Pointer):
if ret is None: if ret is None:
@ -787,7 +844,7 @@ class Interpreter(parser.SimpleTraceDumper):
def verbosity(self, level): def verbosity(self, level):
return self.options.verbosity >= level return self.options.verbosity >= level
class DumpStateOptions(parser.ParseOptions): class DumpStateOptions(parser.ParseOptions):