diff options
Diffstat (limited to '.gitlab-ci/tracie/dump_trace_images.py')
-rw-r--r-- | .gitlab-ci/tracie/dump_trace_images.py | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/.gitlab-ci/tracie/dump_trace_images.py b/.gitlab-ci/tracie/dump_trace_images.py new file mode 100644 index 00000000000..66a99f7efe2 --- /dev/null +++ b/.gitlab-ci/tracie/dump_trace_images.py @@ -0,0 +1,134 @@ +#!/usr/bin/python3 + +# Copyright (c) 2019 Collabora Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# SPDX-License-Identifier: MIT + +import argparse +import os +import sys +import subprocess +from pathlib import Path +from traceutil import trace_type_from_filename, TraceType + +def log(severity, msg, end='\n'): + print("[dump_trace_images] %s: %s" % (severity, msg), flush=True, end=end) + +def log_result(msg): + print(msg, flush=True) + +def run_logged_command(cmd, log_path): + ret = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + logoutput = ("[dump_trace_images] Running: %s\n" % " ".join(cmd)).encode() + \ + ret.stdout + log_path.parent.mkdir(parents=True, exist_ok=True) + with log_path.open(mode='wb') as log: + log.write(logoutput) + if ret.returncode: + raise RuntimeError( + logoutput.decode(errors='replace') + + "[dump_traces_images] Process failed with error code: %d" % ret.returncode) + +def get_last_apitrace_frame_call(trace_path): + cmd = ["apitrace", "dump", "--calls=frame", str(trace_path)] + ret = subprocess.run(cmd, stdout=subprocess.PIPE) + for l in reversed(ret.stdout.decode(errors='replace').splitlines()): + s = l.split(None, 1) + if len(s) >= 1 and s[0].isnumeric(): + return int(s[0]) + return -1 + +def dump_with_apitrace(trace_path, calls, device_name): + outputdir = str(trace_path.parent / "test" / device_name) + os.makedirs(outputdir, exist_ok=True) + outputprefix = str(Path(outputdir) / trace_path.name) + "-" + if len(calls) == 0: + calls = [str(get_last_apitrace_frame_call(trace_path))] + cmd = ["apitrace", "dump-images", "--calls=" + ','.join(calls), + "-o", outputprefix, str(trace_path)] + log_path = Path(outputdir) / (trace_path.name + ".log") + run_logged_command(cmd, log_path) + +def dump_with_renderdoc(trace_path, calls, device_name): + outputdir = str(trace_path.parent / "test" / device_name) + script_path = Path(os.path.dirname(os.path.abspath(__file__))) + cmd = [str(script_path / "renderdoc_dump_images.py"), str(trace_path), outputdir] + cmd.extend(calls) + log_path = Path(outputdir) / (trace_path.name + ".log") + run_logged_command(cmd, log_path) + +def dump_with_testtrace(trace_path, calls, device_name): + from PIL import Image + outputdir_path = trace_path.parent / "test" / device_name + outputdir_path.mkdir(parents=True, exist_ok=True) + with trace_path.open() as f: + rgba = f.read() + color = [int(rgba[0:2], 16), int(rgba[2:4], 16), + int(rgba[4:6], 16), int(rgba[6:8], 16)] + if len(calls) == 0: calls = ["0"] + for c in calls: + outputfile = str(outputdir_path / trace_path.name) + "-" + c + ".png" + log_path = outputdir_path / (trace_path.name + ".log") + with log_path.open(mode='w') as log: + log.write("Writing RGBA: %s to %s" % (rgba, outputfile)) + Image.frombytes('RGBA', (32, 32), bytes(color * 32 * 32)).save(outputfile) + +def dump_from_trace(trace_path, calls, device_name): + log("Info", "Dumping trace %s" % trace_path, end='... ') + trace_type = trace_type_from_filename(trace_path.name) + try: + if trace_type == TraceType.APITRACE: + dump_with_apitrace(trace_path, calls, device_name) + elif trace_type == TraceType.RENDERDOC: + dump_with_renderdoc(trace_path, calls, device_name) + elif trace_type == TraceType.TESTTRACE: + dump_with_testtrace(trace_path, calls, device_name) + else: + raise RuntimeError("Unknown tracefile extension") + log_result("OK") + return True + except Exception as e: + log_result("ERROR") + log("Debug", "=== Failure log start ===") + print(e) + log("Debug", "=== Failure log end ===") + return False + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('tracepath', help="trace to dump") + parser.add_argument('--device-name', required=True, + help="the name of the graphics device used to produce images") + parser.add_argument('--calls', required=False, + help="the call numbers from the trace to dump (default: last frame)") + + args = parser.parse_args() + if args.calls is not None: + args.calls = args.calls.split(",") + else: + args.calls = [] + + success = dump_from_trace(Path(args.tracepath), args.calls, args.device_name) + + sys.exit(0 if success else 1) + +if __name__ == "__main__": + main() |