# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Locate or download a RenderDoc distribution to a known location. RenderDoc is used by the WebRender debugger (wrshell) to capture frames from a running Firefox/wrench instance. This module finds an existing RenderDoc (`librenderdoc.so` for `LD_PRELOAD`, and `qrenderdoc` to open captures), and can download/unpack the official Linux build into a cache directory if missing. It is importable from `mach wrshell` and can also be run standalone: python3 gfx/wr/wrshell/renderdoc_bootstrap.py [--version 1.44] [--cache-dir DIR] """ import os import sys import tarfile import urllib.request from pathlib import Path # Pinned default; override with --version or the WR_RENDERDOC_VERSION env var. DEFAULT_VERSION = "1.44" def default_cache_dir(): """Directory that holds downloaded RenderDoc builds (~/.mozbuild/renderdoc).""" base = os.environ.get("MOZBUILD_STATE_PATH") or os.path.join( os.path.expanduser("~"), ".mozbuild" ) return Path(base) / "renderdoc" def _paths_for(install_dir): """Return (librenderdoc.so, qrenderdoc) under an extracted RenderDoc dir.""" lib = install_dir / "lib" / "librenderdoc.so" qrd = install_dir / "bin" / "qrenderdoc" return lib, qrd def find(version=DEFAULT_VERSION, cache_dir=None): """Locate an existing RenderDoc. Returns (lib_path, bin_dir) or None. Search order: 1. $WR_RENDERDOC_DIR (an extracted RenderDoc root). 2. The cache directory (default ~/.mozbuild/renderdoc/renderdoc_). 3. A system install on $PATH (qrenderdoc) / ldconfig (librenderdoc.so). """ explicit = os.environ.get("WR_RENDERDOC_DIR") if explicit: lib, qrd = _paths_for(Path(explicit)) if lib.exists(): return lib, qrd.parent cache_dir = Path(cache_dir) if cache_dir else default_cache_dir() lib, qrd = _paths_for(cache_dir / f"renderdoc_{version}") if lib.exists(): return lib, qrd.parent # System install: librenderdoc.so on the loader path, qrenderdoc on PATH. for d in os.environ.get("PATH", "").split(os.pathsep): cand = Path(d) / "qrenderdoc" if cand.exists(): for libdir in ("/usr/lib64", "/usr/lib", "/usr/local/lib"): syslib = Path(libdir) / "librenderdoc.so" if syslib.exists(): return syslib, cand.parent return None def ensure(version=DEFAULT_VERSION, cache_dir=None, log=print): """Find RenderDoc, downloading + unpacking it into the cache if missing. Returns (lib_path, bin_dir). """ found = find(version, cache_dir) if found: log(f"RenderDoc found at {found[0]}") return found cache_dir = Path(cache_dir) if cache_dir else default_cache_dir() cache_dir.mkdir(parents=True, exist_ok=True) install_dir = cache_dir / f"renderdoc_{version}" url = f"https://renderdoc.org/stable/{version}/renderdoc_{version}.tar.gz" tarball = cache_dir / f"renderdoc_{version}.tar.gz" log(f"Downloading RenderDoc {version} from {url}") urllib.request.urlretrieve(url, tarball) log(f"Extracting to {cache_dir}") with tarfile.open(tarball) as tar: tar.extractall(cache_dir) tarball.unlink() lib, qrd = _paths_for(install_dir) if not lib.exists(): raise RuntimeError(f"librenderdoc.so not found after extracting {url}") log(f"RenderDoc ready at {lib}") return lib, qrd.parent def _main(argv): import argparse parser = argparse.ArgumentParser(description="Locate or download RenderDoc") parser.add_argument( "--version", default=os.environ.get("WR_RENDERDOC_VERSION", DEFAULT_VERSION), ) parser.add_argument("--cache-dir", default=None) args = parser.parse_args(argv) lib, bindir = ensure(args.version, args.cache_dir) print(f"librenderdoc: {lib}") print(f"bin dir: {bindir}") return 0 if __name__ == "__main__": sys.exit(_main(sys.argv[1:]))