diff --git a/debian/control b/debian/control
index 4db9d42c50126e90e3d3119ac242cdf7a2f9787a..eb432da46c0315b5e1a8b2d96c272611dd957158 100644
--- a/debian/control
+++ b/debian/control
@@ -5,6 +5,7 @@ Maintainer: Simon McVittie <smcv@collabora.com>
 Standards-Version: 4.4.0
 Build-Depends:
  debhelper (>= 9),
+ g++ (>= 4:4.8) | g++-4.8,
  libglib2.0-dev,
  libsteam-runtime-tools-0-dev (>= 0.20190926.0~),
  libxau-dev,
diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml
index ac6ce36c75925cebb4e5835fd1fb90a0d6c0817b..889471f255d95d54a777a1f319cb57d15290bb72 100644
--- a/debian/gitlab-ci.yml
+++ b/debian/gitlab-ci.yml
@@ -131,6 +131,9 @@ build:scout:
               ${NULL+}
             fi
 
+            # g++ 4.6 is too old for the submodule (see also debian/rules)
+            export CXX=g++-4.8
+
             meson \
               --prefix="$(pwd)/_build/prefix" \
               -Dsrcdir=src \
diff --git a/debian/rules b/debian/rules
index e5c89d9ff9ff4a524f0991354415edd9363435b4..20f722eaf75dc4ec912b2737c62a7f5b77ae69dc 100755
--- a/debian/rules
+++ b/debian/rules
@@ -7,6 +7,10 @@ export LC_ALL=C.UTF-8
 
 include /usr/share/dpkg/default.mk
 
+ifeq ($(shell dpkg --compare-versions `c++ -dumpversion || echo 0` ge 4.8 || echo old),old)
+export CXX = g++-4.8
+endif
+
 meson_options =
 
 ifeq ($(DEB_DISTRIBUTION),UNRELEASED)
diff --git a/meson.build b/meson.build
index c01943700924a4e0633e58a6dbde38500df81654..89efe5df86e2375f527a38b447d09c2b05c7bafa 100644
--- a/meson.build
+++ b/meson.build
@@ -24,10 +24,13 @@
 project(
   'pressure-vessel', 'c',
   default_options: [
+    'c_std=c99',
+    'cpp_std=c++11',
     'warning_level=2',
   ],
 )
 
+gnome = import('gnome')
 prove = find_program('prove', required : false)
 sh = find_program('sh', required : true)
 
@@ -105,6 +108,7 @@ project_warning_cflags = [
 
 project_include_dirs = include_directories(
     '.',
+    'src',
     'subprojects',
 )
 
@@ -176,6 +180,16 @@ add_project_arguments(
   language : 'c',
 )
 
+# Headers to scan for enum/flags types.
+headers = [
+  'src/runtime.h',
+]
+
+enums = gnome.mkenums_simple(
+  'enumtypes',
+  sources : headers,
+)
+
 executable(
   'pressure-vessel-with-lock',
   sources : [
@@ -222,12 +236,14 @@ executable(
     'src/flatpak-utils-base-private.h',
     'src/flatpak-utils.c',
     'src/flatpak-utils-private.h',
+    'src/runtime.c',
+    'src/runtime.h',
     'src/utils.c',
     'src/utils.h',
     'src/wrap.c',
     'src/wrap-interactive.c',
     'src/wrap-interactive.h',
-  ],
+  ] + enums,
   c_args : [
     '-Wno-unused-local-typedefs',
   ],
diff --git a/pressure-vessel-test-ui b/pressure-vessel-test-ui
index a0b5270e96d5df9f1cef256a91ac29b42d631cc9..dbb93d93975ddb1c826c474a3a7d2e741a6b5bc4 100755
--- a/pressure-vessel-test-ui
+++ b/pressure-vessel-test-ui
@@ -61,6 +61,23 @@ def tristate_environment(name):
     return None
 
 
+def boolean_environment(name, default):
+    # type: (str, bool) -> bool
+    value = os.getenv(name)
+
+    if value is None:
+        return default
+
+    if value == '1':
+        return True
+
+    if value in ('', '0'):
+        return False
+
+    logger.warning('Unrecognised value %r for $%s', value, name)
+    return default
+
+
 class Gui:
     def __init__(self):
         # type: (...) -> None
@@ -145,6 +162,30 @@ class Gui:
 
         row += 1
 
+        self.host_graphics_check = Gtk.CheckButton.new_with_label(
+            'Use host-system graphics stack'
+        )
+        value = boolean_environment('PRESSURE_VESSEL_HOST_GRAPHICS', True)
+        self.host_graphics_check.set_active(value)
+        self.grid.attach(self.host_graphics_check, 1, row, 1, 1)
+        row += 1
+
+        label = Gtk.Label.new('')
+        label.set_markup(
+            '<small><i>'
+            "Most games and GPUs won't work when this is disabled."
+            '</i></small>'
+        )
+        label.set_halign(Gtk.Align.START)
+        label.set_line_wrap(True)
+        self.grid.attach(label, 1, row, 1, 1)
+        row += 1
+
+        self._container_runtime_changed(self.container_runtime_combo)
+        self.container_runtime_combo.connect(
+            'changed',
+            self._container_runtime_changed)
+
         self.unshare_home_check = Gtk.CheckButton.new_with_label(
             'Use a separate home directory per game'
         )
@@ -258,6 +299,12 @@ class Gui:
         else:
             self.xterm_check.set_sensitive(True)
 
+    def _container_runtime_changed(self, combo):
+        if combo.get_active_id() == '/':
+            self.host_graphics_check.set_sensitive(False)
+        else:
+            self.host_graphics_check.set_sensitive(True)
+
     def _describe_runtime(
         self,
         path        # type: str
@@ -362,6 +409,11 @@ class Gui:
             argv.append('--runtime')
             argv.append(os.path.join(id, 'files'))
 
+        if self.host_graphics_check.get_active():
+            argv.append('--with-host-graphics')
+        else:
+            argv.append('--without-host-graphics')
+
         if self.unshare_home_check.get_active():
             argv.append('--unshare-home')
         else:
diff --git a/src/bwrap.c b/src/bwrap.c
index cadd9c83d53fd5056c707f9ff43dc67d66f60306..5f5e7701df7dfd9bec3d4466547caa3803ae3835 100644
--- a/src/bwrap.c
+++ b/src/bwrap.c
@@ -404,3 +404,19 @@ pv_bwrap_add_api_filesystems (FlatpakBwrap *bwrap)
                             "--dev-bind", "/dev/shm", "/dev/shm",
                             NULL);
 }
+
+FlatpakBwrap *
+pv_bwrap_copy (FlatpakBwrap *bwrap)
+{
+  FlatpakBwrap *ret;
+
+  g_return_val_if_fail (bwrap != NULL, NULL);
+  g_return_val_if_fail (!pv_bwrap_was_finished (bwrap), NULL);
+  /* bwrap can't own any fds, because if it did,
+   * flatpak_bwrap_append_bwrap() would steal them. */
+  g_return_val_if_fail (bwrap->fds == NULL || bwrap->fds->len == 0, NULL);
+
+  ret = flatpak_bwrap_new (NULL);
+  flatpak_bwrap_append_bwrap (ret, bwrap);
+  return ret;
+}
diff --git a/src/bwrap.h b/src/bwrap.h
index 792db2a7e2c6b7653e949de7b021d85021f3d1c2..2a02a7923dfc6aad4036c97375135b7034090e62 100644
--- a/src/bwrap.h
+++ b/src/bwrap.h
@@ -49,3 +49,5 @@ pv_bwrap_was_finished (FlatpakBwrap *bwrap)
   return (bwrap->argv->len >= 1 &&
           bwrap->argv->pdata[bwrap->argv->len - 1] == NULL);
 }
+
+FlatpakBwrap *pv_bwrap_copy (FlatpakBwrap *bwrap);
diff --git a/src/runtime.c b/src/runtime.c
new file mode 100644
index 0000000000000000000000000000000000000000..576c48eea33f0a0f992c015f65b7d631daf15c9d
--- /dev/null
+++ b/src/runtime.c
@@ -0,0 +1,1863 @@
+/*
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "src/runtime.h"
+
+#include <sysexits.h>
+
+#include <gio/gio.h>
+
+/* Include these before steam-runtime-tools.h so that their backport of
+ * G_DEFINE_AUTOPTR_CLEANUP_FUNC will be visible to it */
+#include "glib-backports.h"
+#include "libglnx/libglnx.h"
+
+#include <steam-runtime-tools/steam-runtime-tools.h>
+
+#include "bwrap.h"
+#include "bwrap-lock.h"
+#include "enumtypes.h"
+#include "flatpak-run-private.h"
+#include "utils.h"
+
+/*
+ * PvRuntime:
+ *
+ * Object representing a runtime to be used as the /usr for a game.
+ */
+
+struct _PvRuntime
+{
+  GObject parent;
+
+  gchar *bubblewrap;
+  gchar *source_files;
+  gchar *tools_dir;
+  PvBwrapLock *runtime_lock;
+
+  gchar *tmpdir;
+  gchar *overrides;
+  gchar *overrides_bin;
+  gchar *container_access;
+  FlatpakBwrap *container_access_adverb;
+  gchar *runtime_usr;           /* either source_files or that + "/usr" */
+
+  PvRuntimeFlags flags;
+  gboolean any_libc_from_host;
+  gboolean all_libc_from_host;
+};
+
+struct _PvRuntimeClass
+{
+  GObjectClass parent;
+};
+
+enum {
+  PROP_0,
+  PROP_BUBBLEWRAP,
+  PROP_FLAGS,
+  PROP_SOURCE_FILES,
+  PROP_TOOLS_DIRECTORY,
+  N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL };
+
+static void pv_runtime_initable_iface_init (GInitableIface *iface,
+                                            gpointer unused);
+
+G_DEFINE_TYPE_WITH_CODE (PvRuntime, pv_runtime, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                pv_runtime_initable_iface_init))
+
+/*
+ * Supported Debian-style multiarch tuples
+ */
+static const char * const multiarch_tuples[] =
+{
+  "x86_64-linux-gnu",
+  "i386-linux-gnu",
+  NULL
+};
+
+/*
+ * Directories other than /usr/lib that we must search for loadable
+ * modules, in the same order as multiarch_tuples
+ */
+static const char * const libquals[] =
+{
+  "lib64",
+  "lib32"
+};
+
+static gboolean pv_runtime_use_host_graphics_stack (PvRuntime *self,
+                                                    FlatpakBwrap *bwrap,
+                                                    GError **error);
+static void pv_runtime_set_search_paths (PvRuntime *self,
+                                         FlatpakBwrap *bwrap);
+
+static void
+pv_runtime_init (PvRuntime *self)
+{
+  self->any_libc_from_host = FALSE;
+  self->all_libc_from_host = FALSE;
+}
+
+static void
+pv_runtime_get_property (GObject *object,
+                         guint prop_id,
+                         GValue *value,
+                         GParamSpec *pspec)
+{
+  PvRuntime *self = PV_RUNTIME (object);
+
+  switch (prop_id)
+    {
+      case PROP_BUBBLEWRAP:
+        g_value_set_string (value, self->bubblewrap);
+        break;
+
+      case PROP_FLAGS:
+        g_value_set_flags (value, self->flags);
+        break;
+
+      case PROP_SOURCE_FILES:
+        g_value_set_string (value, self->source_files);
+        break;
+
+      case PROP_TOOLS_DIRECTORY:
+        g_value_set_string (value, self->tools_dir);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+pv_runtime_set_property (GObject *object,
+                         guint prop_id,
+                         const GValue *value,
+                         GParamSpec *pspec)
+{
+  PvRuntime *self = PV_RUNTIME (object);
+
+  switch (prop_id)
+    {
+      case PROP_BUBBLEWRAP:
+        /* Construct-only */
+        g_return_if_fail (self->bubblewrap == NULL);
+        self->bubblewrap = g_value_dup_string (value);
+        break;
+
+      case PROP_FLAGS:
+        self->flags = g_value_get_flags (value);
+        break;
+
+      case PROP_SOURCE_FILES:
+        /* Construct-only */
+        g_return_if_fail (self->source_files == NULL);
+        self->source_files = g_value_dup_string (value);
+        break;
+
+      case PROP_TOOLS_DIRECTORY:
+        /* Construct-only */
+        g_return_if_fail (self->tools_dir == NULL);
+        self->tools_dir = g_value_dup_string (value);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+pv_runtime_constructed (GObject *object)
+{
+  PvRuntime *self = PV_RUNTIME (object);
+
+  G_OBJECT_CLASS (pv_runtime_parent_class)->constructed (object);
+
+  g_return_if_fail (self->bubblewrap != NULL);
+  g_return_if_fail (self->source_files != NULL);
+  g_return_if_fail (self->tools_dir != NULL);
+}
+
+static gboolean
+pv_runtime_initable_init (GInitable *initable,
+                          GCancellable *cancellable G_GNUC_UNUSED,
+                          GError **error)
+{
+  PvRuntime *self = PV_RUNTIME (initable);
+  g_autofree gchar *files_ref = NULL;
+
+  g_return_val_if_fail (PV_IS_RUNTIME (self), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  if (!g_file_test (self->bubblewrap, G_FILE_TEST_IS_EXECUTABLE))
+    {
+      return glnx_throw (error, "\"%s\" is not executable",
+                         self->bubblewrap);
+    }
+
+  if (!g_file_test (self->source_files, G_FILE_TEST_IS_DIR))
+    {
+      return glnx_throw (error, "\"%s\" is not a directory",
+                         self->source_files);
+    }
+
+  if (!g_file_test (self->tools_dir, G_FILE_TEST_IS_DIR))
+    {
+      return glnx_throw (error, "\"%s\" is not a directory",
+                         self->tools_dir);
+    }
+
+  /* Take a lock on the runtime until we're finished with setup,
+   * to make sure it doesn't get deleted. */
+  files_ref = g_build_filename (self->source_files, ".ref", NULL);
+  self->runtime_lock = pv_bwrap_lock_new (files_ref,
+                                          PV_BWRAP_LOCK_FLAGS_CREATE,
+                                          error);
+
+  /* If the runtime is being deleted, ... don't use it, I suppose? */
+  if (self->runtime_lock == NULL)
+    return FALSE;
+
+  g_debug ("Creating temporary directories...");
+
+  /* Using a runtime requires a temporary directory */
+  self->tmpdir = g_dir_make_tmp ("pressure-vessel-wrap.XXXXXX", error);
+
+  if (self->tmpdir == NULL)
+    return FALSE;
+
+  self->overrides = g_build_filename (self->tmpdir, "overrides", NULL);
+  g_mkdir (self->overrides, 0700);
+  self->overrides_bin = g_build_filename (self->overrides, "bin", NULL);
+  g_mkdir (self->overrides_bin, 0700);
+
+  self->runtime_usr = g_build_filename (self->source_files, "usr", NULL);
+
+  if (!g_file_test (self->runtime_usr, G_FILE_TEST_IS_DIR))
+    {
+      /* source_files is just a merged /usr. */
+      g_free (self->runtime_usr);
+      self->runtime_usr = g_strdup (self->source_files);
+    }
+
+  return TRUE;
+}
+
+void
+pv_runtime_cleanup (PvRuntime *self)
+{
+  g_autoptr(GError) local_error = NULL;
+
+  g_return_if_fail (PV_IS_RUNTIME (self));
+
+  if (self->tmpdir != NULL &&
+      !glnx_shutil_rm_rf_at (-1, self->tmpdir, NULL, &local_error))
+    {
+      g_warning ("Unable to delete temporary directory: %s",
+                 local_error->message);
+    }
+
+  g_clear_pointer (&self->overrides_bin, g_free);
+  g_clear_pointer (&self->overrides, g_free);
+  g_clear_pointer (&self->container_access, g_free);
+  g_clear_pointer (&self->container_access_adverb, flatpak_bwrap_free);
+  g_clear_pointer (&self->tmpdir, g_free);
+}
+
+static void
+pv_runtime_finalize (GObject *object)
+{
+  PvRuntime *self = PV_RUNTIME (object);
+
+  pv_runtime_cleanup (self);
+  g_free (self->bubblewrap);
+  g_free (self->runtime_usr);
+  g_free (self->source_files);
+  g_free (self->tools_dir);
+  pv_bwrap_lock_free (self->runtime_lock);
+
+  G_OBJECT_CLASS (pv_runtime_parent_class)->finalize (object);
+}
+
+static void
+pv_runtime_class_init (PvRuntimeClass *cls)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (cls);
+
+  object_class->get_property = pv_runtime_get_property;
+  object_class->set_property = pv_runtime_set_property;
+  object_class->constructed = pv_runtime_constructed;
+  object_class->finalize = pv_runtime_finalize;
+
+  properties[PROP_BUBBLEWRAP] =
+    g_param_spec_string ("bubblewrap", "Bubblewrap",
+                         "Bubblewrap executable",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+  properties[PROP_FLAGS] =
+    g_param_spec_flags ("flags", "Flags",
+                        "Flags affecting how we set up the runtime",
+                        PV_TYPE_RUNTIME_FLAGS, PV_RUNTIME_FLAGS_NONE,
+                        (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS));
+
+  properties[PROP_SOURCE_FILES] =
+    g_param_spec_string ("source-files", "Source files",
+                         ("Path to read-only runtime files (merged-/usr "
+                          "or sysroot) on host system"),
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+  properties[PROP_TOOLS_DIRECTORY] =
+    g_param_spec_string ("tools-directory", "Tools directory",
+                         "Path to pressure-vessel/bin on host system",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+}
+
+PvRuntime *
+pv_runtime_new (const char *source_files,
+                const char *bubblewrap,
+                const char *tools_dir,
+                PvRuntimeFlags flags,
+                GError **error)
+{
+  g_return_val_if_fail (source_files != NULL, NULL);
+  g_return_val_if_fail (bubblewrap != NULL, NULL);
+  g_return_val_if_fail (tools_dir != NULL, NULL);
+  g_return_val_if_fail ((flags & ~(PV_RUNTIME_FLAGS_HOST_GRAPHICS_STACK)) == 0,
+                        NULL);
+
+  return g_initable_new (PV_TYPE_RUNTIME,
+                         NULL,
+                         error,
+                         "bubblewrap", bubblewrap,
+                         "source-files", source_files,
+                         "tools-directory", tools_dir,
+                         "flags", flags,
+                         NULL);
+}
+
+/* If we are using a runtime, pass the lock fd to the executed process,
+ * and make it act as a subreaper for the game itself.
+ *
+ * If we were using --unshare-pid then we could use bwrap --sync-fd
+ * and rely on bubblewrap's init process for this, but we currently
+ * can't do that without breaking gameoverlayrender.so's assumptions. */
+void
+pv_runtime_append_lock_adverb (PvRuntime *self,
+                               FlatpakBwrap *bwrap)
+{
+  g_return_if_fail (PV_IS_RUNTIME (self));
+  g_return_if_fail (!pv_bwrap_was_finished (bwrap));
+
+  flatpak_bwrap_add_args (bwrap,
+                          "/run/pressure-vessel/bin/pressure-vessel-with-lock",
+                          "--subreaper",
+                          NULL);
+
+  if (pv_bwrap_lock_is_ofd (self->runtime_lock))
+    {
+      int fd = pv_bwrap_lock_steal_fd (self->runtime_lock);
+      g_autofree gchar *fd_str = NULL;
+
+      g_debug ("Passing lock fd %d down to with-lock", fd);
+      flatpak_bwrap_add_fd (bwrap, fd);
+      fd_str = g_strdup_printf ("%d", fd);
+      flatpak_bwrap_add_args (bwrap,
+                              "--fd", fd_str,
+                              NULL);
+    }
+  else
+    {
+      /*
+       * We were unable to take out an open file descriptor lock,
+       * so it will be released on fork(). Tell the with-lock process
+       * to take out its own compatible lock instead. There will be
+       * a short window during which we have lost our lock but the
+       * with-lock process has not taken its lock - that's unavoidable
+       * if we want to use exec() to replace ourselves with the
+       * container.
+       *
+       * pv_bwrap_bind_usr() arranges for /.ref to either be a
+       * symbolic link to /usr/.ref which is the runtime_lock
+       * (if opt_runtime is a merged /usr), or the runtime_lock
+       * itself (otherwise).
+       */
+      g_debug ("Telling process in container to lock /.ref");
+      flatpak_bwrap_add_args (bwrap,
+                              "--lock-file", "/.ref",
+                              NULL);
+    }
+
+  flatpak_bwrap_add_args (bwrap,
+                          "--",
+                          NULL);
+}
+
+/*
+ * Set self->container_access_adverb to a (possibly empty) command prefix
+ * that will result in the container being available at
+ * self->container_access, with write access to self->overrides, and
+ * read-only access to everything else.
+ */
+static gboolean
+pv_runtime_provide_container_access (PvRuntime *self,
+                                     GError **error)
+{
+  /* TODO: Avoid using bwrap if we don't need to: when run from inside
+   * a Flatpak, it won't work.
+   *
+   * If we are working with a non-merged-/usr runtime, we can just
+   * set self->container_access to its path.
+   *
+   * Similarly, if we are working with a writeable copy of a runtime
+   * that we are editing in-place, we can set self->container_access to
+   * that. */
+
+  if (self->container_access_adverb == NULL)
+    {
+      self->container_access = g_build_filename (self->tmpdir, "mnt", NULL);
+
+      g_mkdir (self->container_access, 0700);
+      self->container_access = self->container_access;
+
+      self->container_access_adverb = flatpak_bwrap_new (NULL);
+      flatpak_bwrap_add_args (self->container_access_adverb,
+                              self->bubblewrap,
+                              "--ro-bind", "/", "/",
+                              "--bind", self->overrides, self->overrides,
+                              "--tmpfs", self->container_access,
+                              NULL);
+      if (!pv_bwrap_bind_usr (self->container_access_adverb,
+                              self->source_files,
+                              self->container_access,
+                              error))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+try_bind_dri (PvRuntime *self,
+              FlatpakBwrap *bwrap,
+              const char *tool_path,
+              const char *libdir,
+              const char *libdir_on_host,
+              GError **error)
+{
+  g_autofree gchar *dri = g_build_filename (libdir, "dri", NULL);
+  g_autofree gchar *s2tc = g_build_filename (libdir, "libtxc_dxtn.so", NULL);
+
+  if (g_file_test (dri, G_FILE_TEST_IS_DIR))
+    {
+      g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
+      g_autofree gchar *expr = NULL;
+      g_autofree gchar *host_dri = NULL;
+      g_autofree gchar *dest_dri = NULL;
+
+      expr = g_strdup_printf ("only-dependencies:if-exists:path-match:%s/dri/*.so",
+                              libdir);
+
+      if (!pv_runtime_provide_container_access (self, error))
+        return FALSE;
+
+      temp_bwrap = pv_bwrap_copy (self->container_access_adverb);
+      flatpak_bwrap_add_args (temp_bwrap,
+                              tool_path,
+                              "--container", self->container_access,
+                              "--link-target", "/run/host",
+                              "--dest", libdir_on_host,
+                              "--provider", "/",
+                              expr,
+                              NULL);
+      flatpak_bwrap_finish (temp_bwrap);
+
+      if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+        return FALSE;
+
+      g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+      /* TODO: If we're already in a container, rely on /run/host
+       * already being mounted, so we don't need to re-enter a container
+       * here. */
+      host_dri = g_build_filename ("/run/host", libdir, "dri", NULL);
+      dest_dri = g_build_filename (libdir_on_host, "dri", NULL);
+      temp_bwrap = flatpak_bwrap_new (NULL);
+      flatpak_bwrap_add_args (temp_bwrap,
+                              self->bubblewrap,
+                              "--ro-bind", "/", "/",
+                              "--tmpfs", "/run",
+                              "--ro-bind", "/", "/run/host",
+                              "--bind", self->overrides, self->overrides,
+                              "sh", "-c",
+                              "ln -fns \"$1\"/* \"$2\"",
+                              "sh",   /* $0 */
+                              host_dri,
+                              dest_dri,
+                              NULL);
+      flatpak_bwrap_finish (temp_bwrap);
+
+      if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+        return FALSE;
+    }
+
+  if (g_file_test (s2tc, G_FILE_TEST_EXISTS))
+    {
+      g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
+      g_autofree gchar *expr = NULL;
+
+      expr = g_strdup_printf ("path-match:%s", s2tc);
+
+      if (!pv_runtime_provide_container_access (self, error))
+        return FALSE;
+
+      temp_bwrap = pv_bwrap_copy (self->container_access_adverb);
+      flatpak_bwrap_add_args (temp_bwrap,
+                              tool_path,
+                              "--container", self->container_access,
+                              "--link-target", "/run/host",
+                              "--dest", libdir_on_host,
+                              "--provider", "/",
+                              expr,
+                              NULL);
+      flatpak_bwrap_finish (temp_bwrap);
+
+      if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+/*
+ * Try to make sure we have all the locales we need, by running
+ * the helper from steam-runtime-tools in the container. If this
+ * fails, it isn't fatal - carry on anyway.
+ *
+ * @bwrap must be set up to have the same libc that we will be using
+ * for the container.
+ */
+static void
+ensure_locales (PvRuntime *self,
+                gboolean on_host,
+                FlatpakBwrap *bwrap)
+{
+  g_autoptr(GError) local_error = NULL;
+  g_autoptr(FlatpakBwrap) run_locale_gen = NULL;
+  g_autofree gchar *locale_gen = NULL;
+  g_autofree gchar *locales = g_build_filename (self->overrides, "locales", NULL);
+  g_autoptr(GDir) dir = NULL;
+  int exit_status;
+
+  /* bwrap can't own any fds yet, because if it did,
+   * flatpak_bwrap_append_bwrap() would steal them. */
+  g_return_if_fail (bwrap->fds == NULL || bwrap->fds->len == 0);
+
+  g_mkdir (locales, 0700);
+
+  run_locale_gen = flatpak_bwrap_new (NULL);
+
+  if (on_host)
+    {
+      locale_gen = g_build_filename (self->tools_dir,
+                                     "pressure-vessel-locale-gen",
+                                     NULL);
+
+      flatpak_bwrap_add_args (run_locale_gen,
+                              self->bubblewrap,
+                              "--ro-bind", "/", "/",
+                              NULL);
+      pv_bwrap_add_api_filesystems (run_locale_gen);
+      flatpak_bwrap_add_args (run_locale_gen,
+                              "--bind", locales, locales,
+                              "--chdir", locales,
+                              locale_gen,
+                              "--verbose",
+                              NULL);
+    }
+  else
+    {
+      locale_gen = g_build_filename ("/run/host/tools",
+                                     "pressure-vessel-locale-gen",
+                                     NULL);
+
+      flatpak_bwrap_append_bwrap (run_locale_gen, bwrap);
+      pv_bwrap_copy_tree (run_locale_gen, self->overrides, "/overrides");
+
+      if (!flatpak_bwrap_bundle_args (run_locale_gen, 1, -1, FALSE,
+                                      &local_error))
+        {
+          g_warning ("Unable to set up locale-gen command: %s",
+                     local_error->message);
+          g_clear_error (&local_error);
+        }
+
+      flatpak_bwrap_add_args (run_locale_gen,
+                              "--ro-bind", self->tools_dir, "/run/host/tools",
+                              "--bind", locales, "/overrides/locales",
+                              "--chdir", "/overrides/locales",
+                              locale_gen,
+                              "--verbose",
+                              NULL);
+    }
+
+  flatpak_bwrap_finish (run_locale_gen);
+
+  /* locale-gen exits 72 (EX_OSFILE) if it had to correct for
+   * missing locales at OS level. This is not an error. */
+  if (!pv_bwrap_run_sync (run_locale_gen, &exit_status, &local_error))
+    {
+      if (exit_status == EX_OSFILE)
+        g_debug ("pressure-vessel-locale-gen created missing locales");
+      else
+        g_warning ("Unable to generate locales: %s", local_error->message);
+
+      g_clear_error (&local_error);
+    }
+  else
+    {
+      g_debug ("No locales generated");
+    }
+
+  dir = g_dir_open (locales, 0, NULL);
+
+  /* If the directory is not empty, make it the container's LOCPATH */
+  if (dir != NULL && g_dir_read_name (dir) != NULL)
+    {
+      g_autoptr(GString) locpath = NULL;
+
+      g_debug ("%s is non-empty", locales);
+
+      locpath = g_string_new ("/overrides/locales");
+      pv_search_path_append (locpath, g_getenv ("LOCPATH"));
+      flatpak_bwrap_add_args (bwrap,
+                              "--setenv", "LOCPATH", locpath->str,
+                              NULL);
+    }
+  else
+    {
+      g_debug ("%s is empty", locales);
+    }
+}
+
+typedef enum
+{
+  ICD_KIND_NONEXISTENT,
+  ICD_KIND_ABSOLUTE,
+  ICD_KIND_SONAME
+} IcdKind;
+
+typedef struct
+{
+  /* (type SrtEglIcd) or (type SrtVulkanIcd) */
+  gpointer icd;
+  gchar *resolved_library;
+  /* Last entry is always NONEXISTENT */
+  IcdKind kinds[G_N_ELEMENTS (multiarch_tuples)];
+  /* Last entry is always NULL */
+  gchar *paths_in_container[G_N_ELEMENTS (multiarch_tuples)];
+} IcdDetails;
+
+static IcdDetails *
+icd_details_new (gpointer icd)
+{
+  IcdDetails *self;
+  gsize i;
+
+  g_return_val_if_fail (G_IS_OBJECT (icd), NULL);
+  g_return_val_if_fail (SRT_IS_EGL_ICD (icd) || SRT_IS_VULKAN_ICD (icd),
+                        NULL);
+
+  self = g_slice_new0 (IcdDetails);
+  self->icd = g_object_ref (icd);
+  self->resolved_library = NULL;
+
+  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
+    {
+      self->kinds[i] = ICD_KIND_NONEXISTENT;
+      self->paths_in_container[i] = NULL;
+    }
+
+  return self;
+}
+
+static void
+icd_details_free (IcdDetails *self)
+{
+  gsize i;
+
+  g_object_unref (self->icd);
+  g_free (self->resolved_library);
+
+  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
+    g_free (self->paths_in_container[i]);
+
+  g_slice_free (IcdDetails, self);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (IcdDetails, icd_details_free)
+
+static gboolean
+bind_icd (PvRuntime *self,
+          gsize multiarch_index,
+          gsize sequence_number,
+          const char *tool_path,
+          const char *libdir_on_host,
+          const char *libdir_in_container,
+          const char *subdir,
+          IcdDetails *details,
+          GError **error)
+{
+  static const char options[] = "if-exists:if-same-abi";
+  g_autofree gchar *on_host = NULL;
+  g_autofree gchar *pattern = NULL;
+  g_autofree gchar *dependency_pattern = NULL;
+  g_autofree gchar *seq_str = NULL;
+  const char *mode;
+  g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
+
+  g_return_val_if_fail (tool_path != NULL, FALSE);
+  g_return_val_if_fail (libdir_on_host != NULL, FALSE);
+  g_return_val_if_fail (subdir != NULL, FALSE);
+  g_return_val_if_fail (multiarch_index < G_N_ELEMENTS (multiarch_tuples) - 1,
+                        FALSE);
+  g_return_val_if_fail (details != NULL, FALSE);
+  g_return_val_if_fail (details->resolved_library != NULL, FALSE);
+  g_return_val_if_fail (details->kinds[multiarch_index] == ICD_KIND_NONEXISTENT,
+                        FALSE);
+  g_return_val_if_fail (details->paths_in_container[multiarch_index] == NULL,
+                        FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  if (g_path_is_absolute (details->resolved_library))
+    {
+      details->kinds[multiarch_index] = ICD_KIND_ABSOLUTE;
+      mode = "path";
+
+      /* Because the ICDs might have collisions among their
+       * basenames (might differ only by directory), we put each
+       * in its own numbered directory. */
+      seq_str = g_strdup_printf ("%" G_GSIZE_FORMAT, sequence_number);
+      on_host = g_build_filename (libdir_on_host, subdir, seq_str, NULL);
+
+      g_debug ("Ensuring %s exists", on_host);
+
+      if (g_mkdir_with_parents (on_host, 0700) != 0)
+        return glnx_throw_errno_prefix (error, "Unable to create %s", on_host);
+    }
+  else
+    {
+      /* ICDs in the default search path by definition can't collide:
+       * one of them is the first one we find, and we use that one. */
+      details->kinds[multiarch_index] = ICD_KIND_SONAME;
+      mode = "soname";
+    }
+
+  pattern = g_strdup_printf ("no-dependencies:even-if-older:%s:%s:%s",
+                             options, mode, details->resolved_library);
+  dependency_pattern = g_strdup_printf ("only-dependencies:%s:%s:%s",
+                                        options, mode, details->resolved_library);
+
+  if (!pv_runtime_provide_container_access (self, error))
+    return FALSE;
+
+  temp_bwrap = pv_bwrap_copy (self->container_access_adverb);
+  flatpak_bwrap_add_args (temp_bwrap,
+                          tool_path,
+                          "--container", self->container_access,
+                          "--link-target", "/run/host",
+                          "--dest", on_host == NULL ? libdir_on_host : on_host,
+                          "--provider", "/",
+                          pattern,
+                          NULL);
+  flatpak_bwrap_finish (temp_bwrap);
+
+  if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+    return FALSE;
+
+  g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+  if (on_host != NULL)
+    {
+      /* Try to remove the directory we created. If it succeeds, then we
+       * can optimize slightly by not capturing the dependencies: there's
+       * no point, because we know we didn't create a symlink to the ICD
+       * itself. (It must have been nonexistent or for a different ABI.) */
+      if (g_rmdir (on_host) == 0)
+        {
+          details->kinds[multiarch_index] = ICD_KIND_NONEXISTENT;
+          return TRUE;
+        }
+    }
+
+  temp_bwrap = pv_bwrap_copy (self->container_access_adverb);
+  flatpak_bwrap_add_args (temp_bwrap,
+                          tool_path,
+                          "--container", self->container_access,
+                          "--link-target", "/run/host",
+                          "--dest", libdir_on_host,
+                          "--provider", "/",
+                          dependency_pattern,
+                          NULL);
+  flatpak_bwrap_finish (temp_bwrap);
+
+  if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+    return FALSE;
+
+  g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+  if (details->kinds[multiarch_index] == ICD_KIND_ABSOLUTE)
+    {
+      g_assert (seq_str != NULL);
+      g_assert (on_host != NULL);
+      details->paths_in_container[multiarch_index] = g_build_filename (libdir_in_container,
+                                                                       subdir,
+                                                                       seq_str,
+                                                                       glnx_basename (details->resolved_library),
+                                                                       NULL);
+    }
+
+  return TRUE;
+}
+
+static gboolean
+bind_runtime (PvRuntime *self,
+              FlatpakBwrap *bwrap,
+              GError **error)
+{
+  static const char * const bind_mutable[] =
+  {
+    "etc",
+    "var/cache",
+    "var/lib"
+  };
+  static const char * const dont_bind[] =
+  {
+    "/etc/group",
+    "/etc/passwd",
+    "/etc/host.conf",
+    "/etc/hosts",
+    "/etc/localtime",
+    "/etc/machine-id",
+    "/etc/resolv.conf",
+    "/var/lib/dbus",
+    "/var/lib/dhcp",
+    "/var/lib/sudo",
+    "/var/lib/urandom",
+    NULL
+  };
+  g_autofree gchar *xrd = g_strdup_printf ("/run/user/%ld", (long) geteuid ());
+  gsize i;
+  const gchar *member;
+
+  g_return_val_if_fail (PV_IS_RUNTIME (self), FALSE);
+  g_return_val_if_fail (!pv_bwrap_was_finished (bwrap), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  if (!pv_bwrap_bind_usr (bwrap, self->source_files, "/", error))
+    return FALSE;
+
+  flatpak_bwrap_add_args (bwrap,
+                          "--setenv", "XDG_RUNTIME_DIR", xrd,
+                          "--tmpfs", "/run",
+                          "--tmpfs", "/tmp",
+                          "--tmpfs", "/var",
+                          "--symlink", "../run", "/var/run",
+                          NULL);
+
+  if (!pv_bwrap_bind_usr (bwrap, "/", "/run/host", error))
+    return FALSE;
+
+  for (i = 0; i < G_N_ELEMENTS (bind_mutable); i++)
+    {
+      g_autofree gchar *path = g_build_filename (self->source_files,
+                                                 bind_mutable[i],
+                                                 NULL);
+      g_autoptr(GDir) dir = NULL;
+
+      dir = g_dir_open (path, 0, NULL);
+
+      if (dir == NULL)
+        continue;
+
+      for (member = g_dir_read_name (dir);
+           member != NULL;
+           member = g_dir_read_name (dir))
+        {
+          g_autofree gchar *dest = g_build_filename ("/", bind_mutable[i],
+                                                     member, NULL);
+          g_autofree gchar *full = NULL;
+          g_autofree gchar *target = NULL;
+
+          if (g_strv_contains (dont_bind, dest))
+            continue;
+
+          full = g_build_filename (self->source_files,
+                                   bind_mutable[i],
+                                   member,
+                                   NULL);
+          target = glnx_readlinkat_malloc (-1, full, NULL, NULL);
+
+          if (target != NULL)
+            flatpak_bwrap_add_args (bwrap, "--symlink", target, dest, NULL);
+          else
+            flatpak_bwrap_add_args (bwrap, "--ro-bind", full, dest, NULL);
+        }
+    }
+
+  if (g_file_test ("/etc/machine-id", G_FILE_TEST_EXISTS))
+    {
+      flatpak_bwrap_add_args (bwrap,
+                              "--ro-bind", "/etc/machine-id", "/etc/machine-id",
+                              "--symlink", "/etc/machine-id",
+                              "/var/lib/dbus/machine-id",
+                              NULL);
+    }
+  else if (g_file_test ("/var/lib/dbus/machine-id", G_FILE_TEST_EXISTS))
+    {
+      flatpak_bwrap_add_args (bwrap,
+                              "--ro-bind", "/var/lib/dbus/machine-id",
+                              "/etc/machine-id",
+                              "--symlink", "/etc/machine-id",
+                              "/var/lib/dbus/machine-id",
+                              NULL);
+    }
+
+  if (g_file_test ("/etc/resolv.conf", G_FILE_TEST_EXISTS))
+    flatpak_bwrap_add_args (bwrap,
+                            "--ro-bind", "/etc/resolv.conf", "/etc/resolv.conf",
+                            NULL);
+  if (g_file_test ("/etc/host.conf", G_FILE_TEST_EXISTS))
+    flatpak_bwrap_add_args (bwrap,
+                            "--ro-bind", "/etc/host.conf", "/etc/host.conf",
+                            NULL);
+  if (g_file_test ("/etc/hosts", G_FILE_TEST_EXISTS))
+    flatpak_bwrap_add_args (bwrap,
+                            "--ro-bind", "/etc/hosts", "/etc/hosts",
+                            NULL);
+
+  /* TODO: Synthesize a passwd with only the user and nobody,
+   * like Flatpak does? */
+  if (g_file_test ("/etc/passwd", G_FILE_TEST_EXISTS))
+    flatpak_bwrap_add_args (bwrap,
+                            "--ro-bind", "/etc/passwd", "/etc/passwd",
+                            NULL);
+  if (g_file_test ("/etc/group", G_FILE_TEST_EXISTS))
+    flatpak_bwrap_add_args (bwrap,
+                            "--ro-bind", "/etc/group", "/etc/group",
+                            NULL);
+
+  if (self->flags & PV_RUNTIME_FLAGS_HOST_GRAPHICS_STACK)
+    {
+      if (!pv_runtime_use_host_graphics_stack (self, bwrap, error))
+        return FALSE;
+    }
+
+  /* This needs to be done after pv_runtime_use_host_graphics_stack()
+   * has decided whether to bring in the host system's libc. */
+  ensure_locales (self, self->any_libc_from_host, bwrap);
+
+  /* These can add data fds to @bwrap, so they must come last - after
+   * other functions stop using @bwrap as a basis for their own bwrap
+   * invocations with flatpak_bwrap_append_bwrap().
+   * Otherwise, when flatpak_bwrap_append_bwrap() calls
+   * flatpak_bwrap_steal_fds(), it will make the original FlatpakBwrap
+   * unusable. */
+
+  flatpak_run_add_wayland_args (bwrap);
+  flatpak_run_add_x11_args (bwrap, TRUE);
+  flatpak_run_add_pulseaudio_args (bwrap);
+  flatpak_run_add_session_dbus_args (bwrap);
+  flatpak_run_add_system_dbus_args (bwrap);
+  pv_bwrap_copy_tree (bwrap, self->overrides, "/overrides");
+
+  /* /etc/localtime and /etc/resolv.conf can not exist (or be symlinks to
+   * non-existing targets), in which case we don't want to attempt to create
+   * bogus symlinks or bind mounts, as that will cause flatpak run to fail.
+   */
+  if (g_file_test ("/etc/localtime", G_FILE_TEST_EXISTS))
+    {
+      g_autofree char *target = NULL;
+      gboolean is_reachable = FALSE;
+      g_autofree char *tz = flatpak_get_timezone ();
+      g_autofree char *timezone_content = g_strdup_printf ("%s\n", tz);
+
+      target = glnx_readlinkat_malloc (-1, "/etc/localtime", NULL, NULL);
+
+      if (target != NULL)
+        {
+          g_autoptr(GFile) base_file = NULL;
+          g_autoptr(GFile) target_file = NULL;
+          g_autofree char *target_canonical = NULL;
+
+          base_file = g_file_new_for_path ("/etc");
+          target_file = g_file_resolve_relative_path (base_file, target);
+          target_canonical = g_file_get_path (target_file);
+
+          is_reachable = g_str_has_prefix (target_canonical, "/usr/");
+        }
+
+      if (is_reachable)
+        {
+          flatpak_bwrap_add_args (bwrap,
+                                  "--symlink", target, "/etc/localtime",
+                                  NULL);
+        }
+      else
+        {
+          flatpak_bwrap_add_args (bwrap,
+                                  "--ro-bind", "/etc/localtime", "/etc/localtime",
+                                  NULL);
+        }
+
+      flatpak_bwrap_add_args_data (bwrap, "timezone",
+                                   timezone_content, -1, "/etc/timezone",
+                                   NULL);
+    }
+
+  return TRUE;
+}
+
+static gboolean
+pv_runtime_use_host_graphics_stack (PvRuntime *self,
+                                    FlatpakBwrap *bwrap,
+                                    GError **error)
+{
+  gsize i, j;
+  g_autoptr(GString) dri_path = g_string_new ("");
+  g_autoptr(GString) egl_path = g_string_new ("");
+  g_autoptr(GString) vulkan_path = g_string_new ("");
+  gboolean any_architecture_works = FALSE;
+  g_autofree gchar *localedef = NULL;
+  g_autofree gchar *dir_on_host = NULL;
+  g_autoptr(SrtSystemInfo) system_info = srt_system_info_new (NULL);
+  g_autoptr(SrtObjectList) egl_icds = NULL;
+  g_autoptr(SrtObjectList) vulkan_icds = NULL;
+  g_autoptr(GPtrArray) egl_icd_details = NULL;      /* (element-type IcdDetails) */
+  g_autoptr(GPtrArray) vulkan_icd_details = NULL;   /* (element-type IcdDetails) */
+  guint n_egl_icds;
+  guint n_vulkan_icds;
+  const GList *icd_iter;
+  gboolean all_libdrm_from_host = TRUE;
+  g_autoptr(GHashTable) libdrm_data_from_host = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                                       g_free, NULL);
+  g_autofree gchar *libdrm_data_in_runtime = NULL;
+  g_autofree gchar *best_libdrm_data_from_host = NULL;
+
+  g_return_val_if_fail (PV_IS_RUNTIME (self), FALSE);
+  g_return_val_if_fail (!pv_bwrap_was_finished (bwrap), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  if (!pv_runtime_provide_container_access (self, error))
+    return FALSE;
+
+  g_debug ("Enumerating EGL ICDs on host system...");
+  egl_icds = srt_system_info_list_egl_icds (system_info, multiarch_tuples);
+  n_egl_icds = g_list_length (egl_icds);
+
+  egl_icd_details = g_ptr_array_new_full (n_egl_icds,
+                                          (GDestroyNotify) G_CALLBACK (icd_details_free));
+
+  for (icd_iter = egl_icds, j = 0;
+       icd_iter != NULL;
+       icd_iter = icd_iter->next, j++)
+    {
+      SrtEglIcd *icd = icd_iter->data;
+      const gchar *path = srt_egl_icd_get_json_path (icd);
+      GError *local_error = NULL;
+
+      if (!srt_egl_icd_check_error (icd, &local_error))
+        {
+          g_debug ("Failed to load EGL ICD #%" G_GSIZE_FORMAT  " from %s: %s",
+                   j, path, local_error->message);
+          g_clear_error (&local_error);
+          continue;
+        }
+
+      g_debug ("EGL ICD #%" G_GSIZE_FORMAT " at %s: %s",
+               j, path, srt_egl_icd_get_library_path (icd));
+
+      g_ptr_array_add (egl_icd_details, icd_details_new (icd));
+    }
+
+  g_debug ("Enumerating Vulkan ICDs on host system...");
+  vulkan_icds = srt_system_info_list_vulkan_icds (system_info,
+                                                  multiarch_tuples);
+  n_vulkan_icds = g_list_length (vulkan_icds);
+
+  vulkan_icd_details = g_ptr_array_new_full (n_vulkan_icds,
+                                             (GDestroyNotify) G_CALLBACK (icd_details_free));
+
+  for (icd_iter = vulkan_icds, j = 0;
+       icd_iter != NULL;
+       icd_iter = icd_iter->next, j++)
+    {
+      SrtVulkanIcd *icd = icd_iter->data;
+      const gchar *path = srt_vulkan_icd_get_json_path (icd);
+      GError *local_error = NULL;
+
+      if (!srt_vulkan_icd_check_error (icd, &local_error))
+        {
+          g_debug ("Failed to load Vulkan ICD #%" G_GSIZE_FORMAT " from %s: %s",
+                   j, path, local_error->message);
+          g_clear_error (&local_error);
+          continue;
+        }
+
+      g_debug ("Vulkan ICD #%" G_GSIZE_FORMAT " at %s: %s",
+               j, path, srt_vulkan_icd_get_library_path (icd));
+
+      g_ptr_array_add (vulkan_icd_details, icd_details_new (icd));
+    }
+
+  g_assert (multiarch_tuples[G_N_ELEMENTS (multiarch_tuples) - 1] == NULL);
+
+  /* We set this FALSE later if we decide not to use the host libc for
+   * some architecture. */
+  self->all_libc_from_host = TRUE;
+
+  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
+    {
+      g_autofree gchar *tool = g_strdup_printf ("%s-capsule-capture-libs",
+                                                multiarch_tuples[i]);
+      g_autofree gchar *tool_path = NULL;
+      g_autofree gchar *ld_so = NULL;
+      const gchar *argv[] = { NULL, "--print-ld.so", NULL };
+
+      g_debug ("Checking for %s libraries...", multiarch_tuples[i]);
+
+      tool_path = g_build_filename (self->tools_dir, tool, NULL);
+      argv[0] = tool_path;
+
+      /* This has the side-effect of testing whether we can run binaries
+       * for this architecture on the host system. */
+      ld_so = pv_capture_output (argv, NULL);
+
+      if (ld_so != NULL)
+        {
+          g_auto(GStrv) dirs = NULL;
+          g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
+          g_autofree gchar *libdir_in_container = g_build_filename ("/overrides",
+                                                                    "lib",
+                                                                    multiarch_tuples[i],
+                                                                    NULL);
+          g_autofree gchar *libdir_on_host = g_build_filename (self->overrides, "lib",
+                                                               multiarch_tuples[i],
+                                                               NULL);
+          g_autofree gchar *this_dri_path_on_host = g_build_filename (libdir_on_host,
+                                                                      "dri", NULL);
+          g_autofree gchar *this_dri_path_in_container = g_build_filename (libdir_in_container,
+                                                                           "dri", NULL);
+          g_autofree gchar *libc = NULL;
+          g_autofree gchar *ld_so_in_runtime = NULL;
+          g_autofree gchar *libdrm = NULL;
+          const gchar *libqual = NULL;
+
+          temp_bwrap = flatpak_bwrap_new (NULL);
+          flatpak_bwrap_add_args (temp_bwrap,
+                                  self->bubblewrap,
+                                  NULL);
+
+          if (!pv_bwrap_bind_usr (temp_bwrap,
+                                  self->source_files,
+                                  "/",
+                                  error))
+            return FALSE;
+
+          flatpak_bwrap_add_args (temp_bwrap,
+                                  "readlink", "-e", ld_so,
+                                  NULL);
+          flatpak_bwrap_finish (temp_bwrap);
+
+          ld_so_in_runtime = pv_capture_output ((const char * const *) temp_bwrap->argv->pdata,
+                                                NULL);
+
+          g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+          if (ld_so_in_runtime == NULL)
+            {
+              g_debug ("Container does not have %s so it cannot run "
+                       "%s binaries", ld_so, multiarch_tuples[i]);
+              continue;
+            }
+
+          any_architecture_works = TRUE;
+          g_debug ("Container path: %s -> %s", ld_so, ld_so_in_runtime);
+
+          pv_search_path_append (dri_path, this_dri_path_in_container);
+
+          g_mkdir_with_parents (libdir_on_host, 0755);
+          g_mkdir_with_parents (this_dri_path_on_host, 0755);
+
+          g_debug ("Collecting GLX drivers from host system...");
+
+          temp_bwrap = pv_bwrap_copy (self->container_access_adverb);
+          flatpak_bwrap_add_args (temp_bwrap,
+                                  tool_path,
+                                  "--container", self->container_access,
+                                  "--link-target", "/run/host",
+                                  "--dest", libdir_on_host,
+                                  "--provider", "/",
+                                  "gl:",
+                                  NULL);
+          flatpak_bwrap_finish (temp_bwrap);
+
+          if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+            return FALSE;
+
+          g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+          temp_bwrap = pv_bwrap_copy (self->container_access_adverb);
+          flatpak_bwrap_add_args (temp_bwrap,
+                                  tool_path,
+                                  "--container", self->container_access,
+                                  "--link-target", "/run/host",
+                                  "--dest", libdir_on_host,
+                                  "--provider", "/",
+                                  "if-exists:even-if-older:soname-match:libEGL.so.*",
+                                  "if-exists:even-if-older:soname-match:libEGL_nvidia.so.*",
+                                  "if-exists:even-if-older:soname-match:libGL.so.*",
+                                  "if-exists:even-if-older:soname-match:libGLESv1_CM.so.*",
+                                  "if-exists:even-if-older:soname-match:libGLESv1_CM_nvidia.so.*",
+                                  "if-exists:even-if-older:soname-match:libGLESv2.so.*",
+                                  "if-exists:even-if-older:soname-match:libGLESv2_nvidia.so.*",
+                                  "if-exists:even-if-older:soname-match:libGLX.so.*",
+                                  "if-exists:even-if-older:soname-match:libGLX_nvidia.so.*",
+                                  "if-exists:even-if-older:soname-match:libGLX_indirect.so.*",
+                                  "if-exists:even-if-older:soname-match:libGLdispatch.so.*",
+                                  "if-exists:even-if-older:soname-match:libOpenGL.so.*",
+                                  "if-exists:even-if-older:soname-match:libcuda.so.*",
+                                  "if-exists:even-if-older:soname-match:libglx.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-cbl.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-cfg.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-compiler.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-egl-wayland.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-eglcore.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-encode.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-fatbinaryloader.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-fbc.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-glcore.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-glsi.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-glvkspirv.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-ifr.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-ml.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-opencl.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-opticalflow.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-ptxjitcompiler.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-rtcore.so.*",
+                                  "if-exists:even-if-older:soname-match:libnvidia-tls.so.*",
+                                  "if-exists:even-if-older:soname-match:libOpenCL.so.*",
+                                  "if-exists:even-if-older:soname-match:libvdpau_nvidia.so.*",
+                                  NULL);
+          flatpak_bwrap_finish (temp_bwrap);
+
+          if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+            return FALSE;
+
+          g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+          g_debug ("Collecting %s EGL drivers from host system...",
+                   multiarch_tuples[i]);
+
+          for (j = 0; j < egl_icd_details->len; j++)
+            {
+              IcdDetails *details = g_ptr_array_index (egl_icd_details, j);
+              SrtEglIcd *icd = SRT_EGL_ICD (details->icd);
+
+              if (!srt_egl_icd_check_error (icd, NULL))
+                continue;
+
+              details->resolved_library = srt_egl_icd_resolve_library_path (icd);
+              g_assert (details->resolved_library != NULL);
+
+              if (!bind_icd (self,
+                             i,
+                             j,
+                             tool_path,
+                             libdir_on_host,
+                             libdir_in_container,
+                             "glvnd",
+                             details,
+                             error))
+                return FALSE;
+            }
+
+          g_debug ("Collecting %s Vulkan drivers from host system...",
+                   multiarch_tuples[i]);
+
+          temp_bwrap = pv_bwrap_copy (self->container_access_adverb);
+          flatpak_bwrap_add_args (temp_bwrap,
+                                  tool_path,
+                                  "--container", self->container_access,
+                                  "--link-target", "/run/host",
+                                  "--dest", libdir_on_host,
+                                  "--provider", "/",
+                                  "if-exists:if-same-abi:soname:libvulkan.so.1",
+                                  NULL);
+          flatpak_bwrap_finish (temp_bwrap);
+
+          if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+            return FALSE;
+
+          g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+          for (j = 0; j < vulkan_icd_details->len; j++)
+            {
+              IcdDetails *details = g_ptr_array_index (vulkan_icd_details, j);
+              SrtVulkanIcd *icd = SRT_VULKAN_ICD (details->icd);
+
+              if (!srt_vulkan_icd_check_error (icd, NULL))
+                continue;
+
+              details->resolved_library = srt_vulkan_icd_resolve_library_path (icd);
+              g_assert (details->resolved_library != NULL);
+
+              if (!bind_icd (self,
+                             i,
+                             j,
+                             tool_path,
+                             libdir_on_host,
+                             libdir_in_container,
+                             "vulkan",
+                             details,
+                             error))
+                return FALSE;
+            }
+
+          libc = g_build_filename (libdir_on_host, "libc.so.6", NULL);
+
+          /* If we are going to use the host system's libc6 (likely)
+           * then we have to use its ld.so too. */
+          if (g_file_test (libc, G_FILE_TEST_IS_SYMLINK))
+            {
+              g_autofree gchar *ld_so_in_host = NULL;
+
+              g_debug ("Making host ld.so visible in container");
+
+              ld_so_in_host = flatpak_canonicalize_filename (ld_so);
+              g_debug ("Host path: %s -> %s", ld_so, ld_so_in_host);
+
+              g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+              temp_bwrap = flatpak_bwrap_new (NULL);
+              flatpak_bwrap_add_args (temp_bwrap,
+                                      self->bubblewrap,
+                                      NULL);
+
+              if (!pv_bwrap_bind_usr (temp_bwrap,
+                                      self->source_files,
+                                      "/",
+                                      error))
+                return FALSE;
+
+              flatpak_bwrap_add_args (temp_bwrap,
+                                      "readlink", "-f", ld_so,
+                                      NULL);
+              flatpak_bwrap_finish (temp_bwrap);
+
+              g_debug ("Container path: %s -> %s", ld_so, ld_so_in_runtime);
+              flatpak_bwrap_add_args (bwrap,
+                                      "--ro-bind", ld_so_in_host,
+                                      ld_so_in_runtime,
+                                      NULL);
+
+              /* Collect miscellaneous libraries that libc might dlopen.
+               * At the moment this is just libidn2. */
+              temp_bwrap = pv_bwrap_copy (self->container_access_adverb);
+              flatpak_bwrap_add_args (temp_bwrap,
+                                      tool_path,
+                                      "--container", self->container_access,
+                                      "--link-target", "/run/host",
+                                      "--dest", libdir_on_host,
+                                      "--provider", "/",
+                                      "if-exists:libidn2.so.0",
+                                      NULL);
+              flatpak_bwrap_finish (temp_bwrap);
+
+              if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+                return FALSE;
+
+              g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+              self->any_libc_from_host = TRUE;
+            }
+          else
+            {
+              self->all_libc_from_host = FALSE;
+            }
+
+          libdrm = g_build_filename (libdir_on_host, "libdrm.so.2", NULL);
+
+          /* If we have libdrm.so.2 in overrides we also want to mount
+           * ${prefix}/share/libdrm from the host. ${prefix} is derived from
+           * the absolute path of libdrm.so.2 */
+          if (g_file_test (libdrm, G_FILE_TEST_IS_SYMLINK))
+            {
+              g_autofree char *target = NULL;
+              target = glnx_readlinkat_malloc (-1, libdrm, NULL, NULL);
+
+              if (target != NULL)
+                {
+                  g_autofree gchar *dir = NULL;
+                  g_autofree gchar *lib_multiarch = NULL;
+                  g_autofree gchar *libdrm_dir_in_host = NULL;
+
+                  dir = g_path_get_dirname (target);
+
+                  lib_multiarch = g_build_filename ("/lib", multiarch_tuples[i], NULL);
+                  if (g_str_has_suffix (dir, lib_multiarch))
+                    dir[strlen (dir) - strlen (lib_multiarch)] = '\0';
+                  else if (g_str_has_suffix (dir, "/lib64"))
+                    dir[strlen (dir) - strlen ("/lib64")] = '\0';
+                  else if (g_str_has_suffix (dir, "/lib32"))
+                    dir[strlen (dir) - strlen ("/lib32")] = '\0';
+                  else if (g_str_has_suffix (dir, "/lib"))
+                    dir[strlen (dir) - strlen ("/lib")] = '\0';
+
+                  if (g_str_has_prefix (dir, "/run/host"))
+                    memmove (dir, dir + strlen ("/run/host"), strlen (dir) - strlen ("/run/host") + 1);
+
+                  libdrm_dir_in_host = g_build_filename (dir, "share", "libdrm", NULL);
+
+                  if (g_file_test (libdrm_dir_in_host, G_FILE_TEST_IS_DIR))
+                    {
+                      g_hash_table_add (libdrm_data_from_host, g_steal_pointer (&libdrm_dir_in_host));
+                    }
+                  else
+                    {
+                      g_debug ("We were expecting to have the libdrm directory in the host "
+                               "to be located in \"%s\", but instead it is missing",
+                               libdrm_dir_in_host);
+                    }
+                }
+            }
+          else
+            {
+              /* For at least a single architecture, libdrm is newer in the container */
+              all_libdrm_from_host = FALSE;
+            }
+
+          /* /lib32 or /lib64 */
+          g_assert (i < G_N_ELEMENTS (libquals));
+          libqual = libquals[i];
+
+          dirs = g_new0 (gchar *, 7);
+          dirs[0] = g_build_filename ("/lib", multiarch_tuples[i], NULL);
+          dirs[1] = g_build_filename ("/usr", "lib", multiarch_tuples[i], NULL);
+          dirs[2] = g_strdup ("/lib");
+          dirs[3] = g_strdup ("/usr/lib");
+          dirs[4] = g_build_filename ("/", libqual, NULL);
+          dirs[5] = g_build_filename ("/usr", libqual, NULL);
+
+          for (j = 0; j < 6; j++)
+            {
+              if (!try_bind_dri (self, bwrap, tool_path, dirs[j],
+                                 libdir_on_host, error))
+                return FALSE;
+            }
+        }
+      else
+        {
+          g_debug ("Cannot determine ld.so for %s", multiarch_tuples[i]);
+        }
+    }
+
+  if (!any_architecture_works)
+    {
+      GString *archs = g_string_new ("");
+
+      g_assert (multiarch_tuples[G_N_ELEMENTS (multiarch_tuples) - 1] == NULL);
+
+      for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
+        {
+          if (archs->len > 0)
+            g_string_append (archs, ", ");
+
+          g_string_append (archs, multiarch_tuples[i]);
+        }
+
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "None of the supported CPU architectures are common to "
+                   "the host system and the container (tried: %s)",
+                   archs->str);
+      g_string_free (archs, TRUE);
+      return FALSE;
+    }
+
+  if (self->any_libc_from_host && !self->all_libc_from_host)
+    {
+      /*
+       * This shouldn't happen. It would mean that there exist at least
+       * two architectures (let's say aaa and bbb) for which we have:
+       * host libc6:aaa < container libc6 < host libc6:bbb
+       * (we know that the container's libc6:aaa and libc6:bbb are
+       * constrained to be the same version because that's how multiarch
+       * works).
+       *
+       * If the host system locales work OK with both the aaa and bbb
+       * versions, let's assume they will also work with the intermediate
+       * version from the container...
+       */
+      g_warning ("Using glibc from host system for some but not all "
+                 "architectures! Arbitrarily using host locales.");
+    }
+
+  if (self->any_libc_from_host)
+    {
+      g_debug ("Making host locale data visible in container");
+
+      if (g_file_test ("/usr/lib/locale", G_FILE_TEST_EXISTS))
+        flatpak_bwrap_add_args (bwrap,
+                                "--ro-bind", "/usr/lib/locale",
+                                "/usr/lib/locale",
+                                NULL);
+
+      if (g_file_test ("/usr/share/i18n", G_FILE_TEST_EXISTS))
+        flatpak_bwrap_add_args (bwrap,
+                                "--ro-bind", "/usr/share/i18n",
+                                "/usr/share/i18n",
+                                NULL);
+
+      localedef = g_find_program_in_path ("localedef");
+
+      if (localedef == NULL)
+        {
+          g_warning ("Cannot find localedef in PATH");
+        }
+      else
+        {
+          g_autofree gchar *target = g_build_filename ("/run/host",
+                                                       localedef, NULL);
+
+          flatpak_bwrap_add_args (bwrap,
+                                  "--symlink", target,
+                                      "/overrides/bin/localedef",
+                                  NULL);
+        }
+    }
+  else
+    {
+      g_debug ("Using included locale data from container");
+    }
+
+  if (g_hash_table_size (libdrm_data_from_host) > 0 && !all_libdrm_from_host)
+    {
+      /* See the explanation in the similar "any_libc_from_host && !all_libc_from_host"
+       * case, above */
+      g_warning ("Using libdrm.so.2 from host system for some but not all "
+                 "architectures! Will take /usr/share/libdrm from host.");
+    }
+
+  if (g_hash_table_size (libdrm_data_from_host) == 1)
+    {
+      best_libdrm_data_from_host = g_strdup (pv_hash_table_get_arbitrary_key (libdrm_data_from_host));
+    }
+  else if (g_hash_table_size (libdrm_data_from_host) > 1)
+    {
+      g_warning ("Found more than one possible libdrm data directory from host");
+      /* Prioritize "/usr/share/libdrm" if available. Otherwise randomly pick
+       * the first directory in the hash table */
+      if (g_hash_table_contains (libdrm_data_from_host, "/usr/share/libdrm"))
+        best_libdrm_data_from_host = g_strdup ("/usr/share/libdrm");
+      else
+        best_libdrm_data_from_host = g_strdup (pv_hash_table_get_arbitrary_key (libdrm_data_from_host));
+    }
+
+  libdrm_data_in_runtime = g_build_filename (self->runtime_usr, "share", "libdrm", NULL);
+
+  if (best_libdrm_data_from_host != NULL &&
+      g_file_test (libdrm_data_in_runtime, G_FILE_TEST_IS_DIR))
+    {
+      flatpak_bwrap_add_args (bwrap,
+                              "--ro-bind", best_libdrm_data_from_host, "/usr/share/libdrm",
+                              NULL);
+    }
+
+  g_debug ("Setting up EGL ICD JSON...");
+
+  dir_on_host = g_build_filename (self->overrides,
+                                  "share", "glvnd", "egl_vendor.d", NULL);
+
+  if (g_mkdir_with_parents (dir_on_host, 0700) != 0)
+    {
+      glnx_throw_errno_prefix (error, "Unable to create %s", dir_on_host);
+      return FALSE;
+    }
+
+  for (j = 0; j < egl_icd_details->len; j++)
+    {
+      IcdDetails *details = g_ptr_array_index (egl_icd_details, j);
+      SrtEglIcd *icd = SRT_EGL_ICD (details->icd);
+      gboolean need_host_json = FALSE;
+
+      if (!srt_egl_icd_check_error (icd, NULL))
+        continue;
+
+      for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
+        {
+          g_assert (i < G_N_ELEMENTS (details->kinds));
+          g_assert (i < G_N_ELEMENTS (details->paths_in_container));
+
+          if (details->kinds[i] == ICD_KIND_ABSOLUTE)
+            {
+              g_autoptr(SrtEglIcd) replacement = NULL;
+              g_autofree gchar *json_on_host = NULL;
+              g_autofree gchar *json_in_container = NULL;
+              g_autofree gchar *json_base = NULL;
+
+              g_assert (details->paths_in_container[i] != NULL);
+
+              json_base = g_strdup_printf ("%" G_GSIZE_FORMAT "-%s.json",
+                                           j, multiarch_tuples[i]);
+              json_on_host = g_build_filename (dir_on_host, json_base, NULL);
+              json_in_container = g_build_filename ("/overrides", "share",
+                                                    "glvnd", "egl_vendor.d",
+                                                    json_base, NULL);
+
+              replacement = srt_egl_icd_new_replace_library_path (icd,
+                                                                  details->paths_in_container[i]);
+
+              if (!srt_egl_icd_write_to_file (replacement, json_on_host,
+                                                 error))
+                return FALSE;
+
+              pv_search_path_append (egl_path, json_in_container);
+            }
+          else if (details->kinds[i] == ICD_KIND_SONAME)
+            {
+              need_host_json = TRUE;
+            }
+        }
+
+      if (need_host_json)
+        {
+          g_autofree gchar *json_in_container = NULL;
+          g_autofree gchar *json_base = NULL;
+          const char *json_on_host = srt_egl_icd_get_json_path (icd);
+
+          json_base = g_strdup_printf ("%" G_GSIZE_FORMAT ".json", j);
+          json_in_container = g_build_filename ("/overrides", "share",
+                                                "glvnd", "egl_vendor.d",
+                                                json_base, NULL);
+
+          flatpak_bwrap_add_args (bwrap,
+                                  "--ro-bind", json_on_host, json_in_container,
+                                  NULL);
+          pv_search_path_append (egl_path, json_in_container);
+        }
+    }
+
+  g_debug ("Setting up Vulkan ICD JSON...");
+
+  dir_on_host = g_build_filename (self->overrides,
+                                  "share", "vulkan", "icd.d", NULL);
+
+  if (g_mkdir_with_parents (dir_on_host, 0700) != 0)
+    {
+      glnx_throw_errno_prefix (error, "Unable to create %s", dir_on_host);
+      return FALSE;
+    }
+
+  for (j = 0; j < vulkan_icd_details->len; j++)
+    {
+      IcdDetails *details = g_ptr_array_index (vulkan_icd_details, j);
+      SrtVulkanIcd *icd = SRT_VULKAN_ICD (details->icd);
+      gboolean need_host_json = FALSE;
+
+      if (!srt_vulkan_icd_check_error (icd, NULL))
+        continue;
+
+      for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
+        {
+          g_assert (i < G_N_ELEMENTS (details->kinds));
+          g_assert (i < G_N_ELEMENTS (details->paths_in_container));
+
+          if (details->kinds[i] == ICD_KIND_ABSOLUTE)
+            {
+              g_autoptr(SrtVulkanIcd) replacement = NULL;
+              g_autofree gchar *json_on_host = NULL;
+              g_autofree gchar *json_in_container = NULL;
+              g_autofree gchar *json_base = NULL;
+
+              g_assert (details->paths_in_container[i] != NULL);
+
+              json_base = g_strdup_printf ("%" G_GSIZE_FORMAT "-%s.json",
+                                           j, multiarch_tuples[i]);
+              json_on_host = g_build_filename (dir_on_host, json_base, NULL);
+              json_in_container = g_build_filename ("/overrides", "share",
+                                                    "vulkan", "icd.d",
+                                                    json_base, NULL);
+
+              replacement = srt_vulkan_icd_new_replace_library_path (icd,
+                                                                     details->paths_in_container[i]);
+
+              if (!srt_vulkan_icd_write_to_file (replacement, json_on_host,
+                                                 error))
+                return FALSE;
+
+              pv_search_path_append (vulkan_path, json_in_container);
+            }
+          else if (details->kinds[i] == ICD_KIND_SONAME)
+            {
+              need_host_json = TRUE;
+            }
+        }
+
+      if (need_host_json)
+        {
+          g_autofree gchar *json_in_container = NULL;
+          g_autofree gchar *json_base = NULL;
+          const char *json_on_host = srt_vulkan_icd_get_json_path (icd);
+
+          json_base = g_strdup_printf ("%" G_GSIZE_FORMAT ".json", j);
+          json_in_container = g_build_filename ("/overrides", "share",
+                                                "vulkan", "icd.d",
+                                                json_base, NULL);
+
+          flatpak_bwrap_add_args (bwrap,
+                                  "--ro-bind", json_on_host, json_in_container,
+                                  NULL);
+          pv_search_path_append (vulkan_path, json_in_container);
+        }
+    }
+
+  if (dri_path->len != 0)
+      flatpak_bwrap_add_args (bwrap,
+                              "--setenv", "LIBGL_DRIVERS_PATH", dri_path->str,
+                              NULL);
+  else
+      flatpak_bwrap_add_args (bwrap,
+                              "--unsetenv", "LIBGL_DRIVERS_PATH",
+                              NULL);
+
+  if (egl_path->len != 0)
+      flatpak_bwrap_add_args (bwrap,
+                              "--setenv", "__EGL_VENDOR_LIBRARY_FILENAMES",
+                              egl_path->str, NULL);
+  else
+      flatpak_bwrap_add_args (bwrap,
+                              "--unsetenv", "__EGL_VENDOR_LIBRARY_FILENAMES",
+                              NULL);
+
+  flatpak_bwrap_add_args (bwrap,
+                          "--unsetenv", "__EGL_VENDOR_LIBRARY_DIRS",
+                          NULL);
+
+  if (vulkan_path->len != 0)
+      flatpak_bwrap_add_args (bwrap,
+                              "--setenv", "VK_ICD_FILENAMES",
+                              vulkan_path->str, NULL);
+  else
+      flatpak_bwrap_add_args (bwrap,
+                              "--unsetenv", "VK_ICD_FILENAMES",
+                              NULL);
+
+  return TRUE;
+}
+
+gboolean
+pv_runtime_bind (PvRuntime *self,
+                 FlatpakBwrap *bwrap,
+                 GError **error)
+{
+  g_autofree gchar *pressure_vessel_prefix = NULL;
+
+  g_return_val_if_fail (PV_IS_RUNTIME (self), FALSE);
+  g_return_val_if_fail (!pv_bwrap_was_finished (bwrap), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  /* Start with just the root tmpfs (which appears automatically)
+   * and the standard API filesystems */
+  pv_bwrap_add_api_filesystems (bwrap);
+
+  if (!bind_runtime (self, bwrap, error))
+    return FALSE;
+
+  pressure_vessel_prefix = g_path_get_dirname (self->tools_dir);
+
+  /* Make sure pressure-vessel itself is visible there. */
+  flatpak_bwrap_add_args (bwrap,
+                          "--ro-bind",
+                          pressure_vessel_prefix,
+                          "/run/pressure-vessel",
+                          NULL);
+
+  pv_runtime_set_search_paths (self, bwrap);
+
+  return TRUE;
+}
+
+void
+pv_runtime_set_search_paths (PvRuntime *self,
+                             FlatpakBwrap *bwrap)
+{
+  g_autoptr(GString) ld_library_path = g_string_new ("");
+  g_autoptr(GString) bin_path = g_string_new ("");
+  gsize i;
+
+  pv_search_path_append (bin_path, "/overrides/bin");
+  pv_search_path_append (bin_path, g_getenv ("PATH"));
+  flatpak_bwrap_add_args (bwrap,
+                          "--setenv", "PATH",
+                          bin_path->str,
+                          NULL);
+
+  /* TODO: Adapt the use_ld_so_cache code from Flatpak instead
+   * of setting LD_LIBRARY_PATH, for better robustness against
+   * games that set their own LD_LIBRARY_PATH ignoring what they
+   * got from the environment */
+  g_assert (multiarch_tuples[G_N_ELEMENTS (multiarch_tuples) - 1] == NULL);
+
+    for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
+      {
+        g_autofree gchar *ld_path = NULL;
+
+        ld_path = g_build_filename ("/overrides", "lib",
+                                   multiarch_tuples[i], NULL);
+
+        pv_search_path_append (ld_library_path, ld_path);
+      }
+
+  /* This would be filtered out by a setuid bwrap, so we have to go
+   * via --setenv. */
+  flatpak_bwrap_add_args (bwrap,
+                          "--setenv", "LD_LIBRARY_PATH",
+                          ld_library_path->str,
+                          NULL);
+}
+
+static void
+pv_runtime_initable_iface_init (GInitableIface *iface,
+                                gpointer unused G_GNUC_UNUSED)
+{
+  iface->init = pv_runtime_initable_init;
+}
diff --git a/src/runtime.h b/src/runtime.h
new file mode 100644
index 0000000000000000000000000000000000000000..0fc2ec30ef2e625aba24a281122556f1c1a5ca61
--- /dev/null
+++ b/src/runtime.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+
+#include "glib-backports.h"
+#include "libglnx/libglnx.h"
+
+#include "flatpak-bwrap-private.h"
+#include "flatpak-utils-base-private.h"
+
+/**
+ * PvRuntimeFlags:
+ * @PV_RUNTIME_FLAGS_HOST_GRAPHICS_STACK: Use host system graphics stack
+ * @PV_RUNTIME_FLAGS_NONE: None of the above
+ *
+ * Flags affecting how we set up the runtime.
+ */
+typedef enum
+{
+  PV_RUNTIME_FLAGS_HOST_GRAPHICS_STACK = (1 << 0),
+  PV_RUNTIME_FLAGS_NONE = 0
+} PvRuntimeFlags;
+
+typedef struct _PvRuntime PvRuntime;
+typedef struct _PvRuntimeClass PvRuntimeClass;
+
+#define PV_TYPE_RUNTIME (pv_runtime_get_type ())
+#define PV_RUNTIME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_RUNTIME, PvRuntime))
+#define PV_RUNTIME_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST ((cls), PV_TYPE_RUNTIME, PvRuntimeClass))
+#define PV_IS_RUNTIME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_RUNTIME))
+#define PV_IS_RUNTIME_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE ((cls), PV_TYPE_RUNTIME))
+#define PV_RUNTIME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PV_TYPE_RUNTIME, PvRuntimeClass)
+GType pv_runtime_get_type (void);
+
+PvRuntime *pv_runtime_new (const char *source_files,
+                           const char *bubblewrap,
+                           const char *tools_dir,
+                           PvRuntimeFlags flags,
+                           GError **error);
+
+void pv_runtime_append_lock_adverb (PvRuntime *self,
+                                    FlatpakBwrap *bwrap);
+gboolean pv_runtime_bind (PvRuntime *self,
+                          FlatpakBwrap *bwrap,
+                          GError **error);
+void pv_runtime_cleanup (PvRuntime *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (PvRuntime, g_object_unref)
diff --git a/src/wrap.c b/src/wrap.c
index 1eb31fea39781ef39eb23041ff5c016d77b85b83..f70843a123f3d26d5a812bbb33256336063305de 100644
--- a/src/wrap.c
+++ b/src/wrap.c
@@ -28,44 +28,19 @@
 
 #include <locale.h>
 #include <stdlib.h>
-#include <sysexits.h>
 
-/* Include these before steam-runtime-tools.h so that their backport of
- * G_DEFINE_AUTOPTR_CLEANUP_FUNC will be visible to it */
 #include "glib-backports.h"
 #include "libglnx/libglnx.h"
 
-#include <steam-runtime-tools/steam-runtime-tools.h>
-
 #include "bwrap.h"
 #include "bwrap-lock.h"
 #include "flatpak-bwrap-private.h"
-#include "flatpak-run-private.h"
 #include "flatpak-utils-base-private.h"
 #include "flatpak-utils-private.h"
+#include "runtime.h"
 #include "utils.h"
 #include "wrap-interactive.h"
 
-/*
- * Supported Debian-style multiarch tuples
- */
-static const char * const multiarch_tuples[] =
-{
-  "x86_64-linux-gnu",
-  "i386-linux-gnu",
-  NULL
-};
-
-/*
- * Directories other than /usr/lib that we must search for loadable
- * modules, in the same order as multiarch_tuples
- */
-static const char * const libquals[] =
-{
-  "lib64",
-  "lib32"
-};
-
 static gchar *
 find_executable_dir (GError **error)
 {
@@ -184,1337 +159,6 @@ check_bwrap (const char *tools_dir)
   return NULL;
 }
 
-static gboolean
-try_bind_dri (FlatpakBwrap *bwrap,
-              FlatpakBwrap *mount_runtime_on_scratch,
-              const char *overrides,
-              const char *scratch,
-              const char *tool_path,
-              const char *libdir,
-              const char *libdir_on_host,
-              GError **error)
-{
-  g_autofree gchar *dri = g_build_filename (libdir, "dri", NULL);
-  g_autofree gchar *s2tc = g_build_filename (libdir, "libtxc_dxtn.so", NULL);
-
-  /* mount_runtime_on_scratch can't own any fds, because if it did,
-   * flatpak_bwrap_append_bwrap() would steal them. */
-  g_return_val_if_fail (mount_runtime_on_scratch->fds == NULL
-                        || mount_runtime_on_scratch->fds->len == 0,
-                        FALSE);
-
-  if (g_file_test (dri, G_FILE_TEST_IS_DIR))
-    {
-      g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
-      g_autofree gchar *expr = NULL;
-      g_autofree gchar *host_dri = NULL;
-      g_autofree gchar *dest_dri = NULL;
-
-      expr = g_strdup_printf ("only-dependencies:if-exists:path-match:%s/dri/*.so",
-                              libdir);
-
-      temp_bwrap = flatpak_bwrap_new (NULL);
-      g_warn_if_fail (mount_runtime_on_scratch->fds == NULL
-                      || mount_runtime_on_scratch->fds->len == 0);
-      flatpak_bwrap_append_bwrap (temp_bwrap, mount_runtime_on_scratch);
-      flatpak_bwrap_add_args (temp_bwrap,
-                              tool_path,
-                              "--container", scratch,
-                              "--link-target", "/run/host",
-                              "--dest", libdir_on_host,
-                              "--provider", "/",
-                              expr,
-                              NULL);
-      flatpak_bwrap_finish (temp_bwrap);
-
-      if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
-        return FALSE;
-
-      g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
-
-      host_dri = g_build_filename ("/run/host", libdir, "dri", NULL);
-      dest_dri = g_build_filename (libdir_on_host, "dri", NULL);
-      temp_bwrap = flatpak_bwrap_new (NULL);
-      flatpak_bwrap_add_args (temp_bwrap,
-                              bwrap->argv->pdata[0],
-                              "--ro-bind", "/", "/",
-                              "--tmpfs", "/run",
-                              "--ro-bind", "/", "/run/host",
-                              "--bind", overrides, overrides,
-                              "sh", "-c",
-                              "ln -fns \"$1\"/* \"$2\"",
-                              "sh",   /* $0 */
-                              host_dri,
-                              dest_dri,
-                              NULL);
-      flatpak_bwrap_finish (temp_bwrap);
-
-      if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
-        return FALSE;
-    }
-
-  if (g_file_test (s2tc, G_FILE_TEST_EXISTS))
-    {
-      g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
-      g_autofree gchar *expr = NULL;
-
-      expr = g_strdup_printf ("path-match:%s", s2tc);
-      temp_bwrap = flatpak_bwrap_new (NULL);
-      g_warn_if_fail (mount_runtime_on_scratch->fds == NULL
-                      || mount_runtime_on_scratch->fds->len == 0);
-      flatpak_bwrap_append_bwrap (temp_bwrap, mount_runtime_on_scratch);
-      flatpak_bwrap_add_args (temp_bwrap,
-                              tool_path,
-                              "--container", scratch,
-                              "--link-target", "/run/host",
-                              "--dest", libdir_on_host,
-                              "--provider", "/",
-                              expr,
-                              NULL);
-      flatpak_bwrap_finish (temp_bwrap);
-
-      if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
-        return FALSE;
-    }
-
-  return TRUE;
-}
-
-/*
- * Try to make sure we have all the locales we need, by running
- * the helper from steam-runtime-tools in the container. If this
- * fails, it isn't fatal - carry on anyway.
- *
- * @bwrap must be set up to have the same libc that we will be using
- * for the container.
- */
-static void
-ensure_locales (gboolean on_host,
-                const char *tools_dir,
-                FlatpakBwrap *bwrap,
-                const char *overrides)
-{
-  g_autoptr(GError) local_error = NULL;
-  g_autoptr(FlatpakBwrap) run_locale_gen = NULL;
-  g_autofree gchar *locale_gen = NULL;
-  g_autofree gchar *locales = g_build_filename (overrides, "locales", NULL);
-  g_autoptr(GDir) dir = NULL;
-  int exit_status;
-
-  /* bwrap can't own any fds yet, because if it did,
-   * flatpak_bwrap_append_bwrap() would steal them. */
-  g_return_if_fail (bwrap->fds == NULL || bwrap->fds->len == 0);
-
-  g_mkdir (locales, 0700);
-
-  run_locale_gen = flatpak_bwrap_new (NULL);
-
-  if (on_host)
-    {
-      locale_gen = g_build_filename (tools_dir,
-                                     "pressure-vessel-locale-gen",
-                                     NULL);
-
-      flatpak_bwrap_add_args (run_locale_gen,
-                              bwrap->argv->pdata[0],
-                              "--ro-bind", "/", "/",
-                              NULL);
-      pv_bwrap_add_api_filesystems (run_locale_gen);
-      flatpak_bwrap_add_args (run_locale_gen,
-                              "--bind", locales, locales,
-                              "--chdir", locales,
-                              locale_gen,
-                              "--verbose",
-                              NULL);
-    }
-  else
-    {
-      locale_gen = g_build_filename ("/run/host/tools",
-                                     "pressure-vessel-locale-gen",
-                                     NULL);
-
-      flatpak_bwrap_append_bwrap (run_locale_gen, bwrap);
-      pv_bwrap_copy_tree (run_locale_gen, overrides, "/overrides");
-
-      if (!flatpak_bwrap_bundle_args (run_locale_gen, 1, -1, FALSE,
-                                      &local_error))
-        {
-          g_warning ("Unable to set up locale-gen command: %s",
-                     local_error->message);
-          g_clear_error (&local_error);
-        }
-
-      flatpak_bwrap_add_args (run_locale_gen,
-                              "--ro-bind", tools_dir, "/run/host/tools",
-                              "--bind", locales, "/overrides/locales",
-                              "--chdir", "/overrides/locales",
-                              locale_gen,
-                              "--verbose",
-                              NULL);
-    }
-
-  flatpak_bwrap_finish (run_locale_gen);
-
-  /* locale-gen exits 72 (EX_OSFILE) if it had to correct for
-   * missing locales at OS level. This is not an error. */
-  if (!pv_bwrap_run_sync (run_locale_gen, &exit_status, &local_error))
-    {
-      if (exit_status == EX_OSFILE)
-        g_debug ("pressure-vessel-locale-gen created missing locales");
-      else
-        g_warning ("Unable to generate locales: %s", local_error->message);
-
-      g_clear_error (&local_error);
-    }
-  else
-    {
-      g_debug ("No locales generated");
-    }
-
-  dir = g_dir_open (locales, 0, NULL);
-
-  /* If the directory is not empty, make it the container's LOCPATH */
-  if (dir != NULL && g_dir_read_name (dir) != NULL)
-    {
-      g_autoptr(GString) locpath = NULL;
-
-      g_debug ("%s is non-empty", locales);
-
-      locpath = g_string_new ("/overrides/locales");
-      pv_search_path_append (locpath, g_getenv ("LOCPATH"));
-      flatpak_bwrap_add_args (bwrap,
-                              "--setenv", "LOCPATH", locpath->str,
-                              NULL);
-    }
-  else
-    {
-      g_debug ("%s is empty", locales);
-    }
-}
-
-typedef enum
-{
-  ICD_KIND_NONEXISTENT,
-  ICD_KIND_ABSOLUTE,
-  ICD_KIND_SONAME
-} IcdKind;
-
-typedef struct
-{
-  /* (type SrtEglIcd) or (type SrtVulkanIcd) */
-  gpointer icd;
-  gchar *resolved_library;
-  /* Last entry is always NONEXISTENT */
-  IcdKind kinds[G_N_ELEMENTS (multiarch_tuples)];
-  /* Last entry is always NULL */
-  gchar *paths_in_container[G_N_ELEMENTS (multiarch_tuples)];
-} IcdDetails;
-
-static IcdDetails *
-icd_details_new (gpointer icd)
-{
-  IcdDetails *self;
-  gsize i;
-
-  g_return_val_if_fail (G_IS_OBJECT (icd), NULL);
-  g_return_val_if_fail (SRT_IS_EGL_ICD (icd) || SRT_IS_VULKAN_ICD (icd),
-                        NULL);
-
-  self = g_slice_new0 (IcdDetails);
-  self->icd = g_object_ref (icd);
-  self->resolved_library = NULL;
-
-  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
-    {
-      self->kinds[i] = ICD_KIND_NONEXISTENT;
-      self->paths_in_container[i] = NULL;
-    }
-
-  return self;
-}
-
-static void
-icd_details_free (IcdDetails *self)
-{
-  gsize i;
-
-  g_object_unref (self->icd);
-  g_free (self->resolved_library);
-
-  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
-    g_free (self->paths_in_container[i]);
-
-  g_slice_free (IcdDetails, self);
-}
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (IcdDetails, icd_details_free)
-
-static gboolean
-bind_icd (gsize multiarch_index,
-          gsize sequence_number,
-          const char *tool_path,
-          FlatpakBwrap *mount_runtime_on_scratch,
-          const char *scratch,
-          const char *libdir_on_host,
-          const char *libdir_in_container,
-          const char *subdir,
-          IcdDetails *details,
-          GError **error)
-{
-  static const char options[] = "if-exists:if-same-abi";
-  g_autofree gchar *on_host = NULL;
-  g_autofree gchar *pattern = NULL;
-  g_autofree gchar *dependency_pattern = NULL;
-  g_autofree gchar *seq_str = NULL;
-  const char *mode;
-  g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
-
-  g_return_val_if_fail (tool_path != NULL, FALSE);
-  g_return_val_if_fail (mount_runtime_on_scratch != NULL, FALSE);
-  g_return_val_if_fail (mount_runtime_on_scratch->fds == NULL
-                        || mount_runtime_on_scratch->fds->len == 0,
-                        FALSE);
-  g_return_val_if_fail (scratch != NULL, FALSE);
-  g_return_val_if_fail (libdir_on_host != NULL, FALSE);
-  g_return_val_if_fail (subdir != NULL, FALSE);
-  g_return_val_if_fail (multiarch_index < G_N_ELEMENTS (multiarch_tuples) - 1,
-                        FALSE);
-  g_return_val_if_fail (details != NULL, FALSE);
-  g_return_val_if_fail (details->resolved_library != NULL, FALSE);
-  g_return_val_if_fail (details->kinds[multiarch_index] == ICD_KIND_NONEXISTENT,
-                        FALSE);
-  g_return_val_if_fail (details->paths_in_container[multiarch_index] == NULL,
-                        FALSE);
-  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-  if (g_path_is_absolute (details->resolved_library))
-    {
-      details->kinds[multiarch_index] = ICD_KIND_ABSOLUTE;
-      mode = "path";
-
-      /* Because the ICDs might have collisions among their
-       * basenames (might differ only by directory), we put each
-       * in its own numbered directory. */
-      seq_str = g_strdup_printf ("%" G_GSIZE_FORMAT, sequence_number);
-      on_host = g_build_filename (libdir_on_host, subdir, seq_str, NULL);
-
-      g_debug ("Ensuring %s exists", on_host);
-
-      if (g_mkdir_with_parents (on_host, 0700) != 0)
-        return glnx_throw_errno_prefix (error, "Unable to create %s", on_host);
-    }
-  else
-    {
-      /* ICDs in the default search path by definition can't collide:
-       * one of them is the first one we find, and we use that one. */
-      details->kinds[multiarch_index] = ICD_KIND_SONAME;
-      mode = "soname";
-    }
-
-  pattern = g_strdup_printf ("no-dependencies:even-if-older:%s:%s:%s",
-                             options, mode, details->resolved_library);
-  dependency_pattern = g_strdup_printf ("only-dependencies:%s:%s:%s",
-                                        options, mode, details->resolved_library);
-
-  temp_bwrap = flatpak_bwrap_new (NULL);
-  flatpak_bwrap_append_bwrap (temp_bwrap, mount_runtime_on_scratch);
-  flatpak_bwrap_add_args (temp_bwrap,
-                          tool_path,
-                          "--container", scratch,
-                          "--link-target", "/run/host",
-                          "--dest", on_host == NULL ? libdir_on_host : on_host,
-                          "--provider", "/",
-                          pattern,
-                          NULL);
-  flatpak_bwrap_finish (temp_bwrap);
-
-  if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
-    return FALSE;
-
-  g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
-
-  if (on_host != NULL)
-    {
-      /* Try to remove the directory we created. If it succeeds, then we
-       * can optimize slightly by not capturing the dependencies: there's
-       * no point, because we know we didn't create a symlink to the ICD
-       * itself. (It must have been nonexistent or for a different ABI.) */
-      if (g_rmdir (on_host) == 0)
-        {
-          details->kinds[multiarch_index] = ICD_KIND_NONEXISTENT;
-          return TRUE;
-        }
-    }
-
-  temp_bwrap = flatpak_bwrap_new (NULL);
-  g_warn_if_fail (mount_runtime_on_scratch->fds == NULL
-                  || mount_runtime_on_scratch->fds->len == 0);
-  flatpak_bwrap_append_bwrap (temp_bwrap, mount_runtime_on_scratch);
-  flatpak_bwrap_add_args (temp_bwrap,
-                          tool_path,
-                          "--container", scratch,
-                          "--link-target", "/run/host",
-                          "--dest", libdir_on_host,
-                          "--provider", "/",
-                          dependency_pattern,
-                          NULL);
-  flatpak_bwrap_finish (temp_bwrap);
-
-  if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
-    return FALSE;
-
-  g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
-
-  if (details->kinds[multiarch_index] == ICD_KIND_ABSOLUTE)
-    {
-      g_assert (seq_str != NULL);
-      g_assert (on_host != NULL);
-      details->paths_in_container[multiarch_index] = g_build_filename (libdir_in_container,
-                                                                       subdir,
-                                                                       seq_str,
-                                                                       glnx_basename (details->resolved_library),
-                                                                       NULL);
-    }
-
-  return TRUE;
-}
-
-static gboolean
-bind_runtime (FlatpakBwrap *bwrap,
-              const char *tools_dir,
-              const char *runtime,
-              const char *overrides,
-              const char *scratch,
-              GError **error)
-{
-  static const char * const bind_mutable[] =
-  {
-    "etc",
-    "var/cache",
-    "var/lib"
-  };
-  static const char * const dont_bind[] =
-  {
-    "/etc/group",
-    "/etc/passwd",
-    "/etc/host.conf",
-    "/etc/hosts",
-    "/etc/localtime",
-    "/etc/machine-id",
-    "/etc/resolv.conf",
-    "/var/lib/dbus",
-    "/var/lib/dhcp",
-    "/var/lib/sudo",
-    "/var/lib/urandom",
-    NULL
-  };
-  g_autofree gchar *xrd = g_strdup_printf ("/run/user/%ld", (long) geteuid ());
-  gsize i, j;
-  const gchar *member;
-  g_autoptr(GString) dri_path = g_string_new ("");
-  g_autoptr(GString) egl_path = g_string_new ("");
-  g_autoptr(GString) vulkan_path = g_string_new ("");
-  gboolean any_architecture_works = FALSE;
-  gboolean any_libc_from_host = FALSE;
-  gboolean all_libc_from_host = TRUE;
-  gboolean all_libdrm_from_host = TRUE;
-  g_autoptr(GHashTable) libdrm_data_from_host = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                                                       g_free, NULL);
-  g_autofree gchar *libdrm_data_in_runtime = NULL;
-  g_autofree gchar *best_libdrm_data_from_host = NULL;
-  g_autofree gchar *localedef = NULL;
-  g_autofree gchar *dir_on_host = NULL;
-  g_autoptr(SrtSystemInfo) system_info = srt_system_info_new (NULL);
-  g_autoptr(SrtObjectList) egl_icds = NULL;
-  g_autoptr(SrtObjectList) vulkan_icds = NULL;
-  g_autoptr(GPtrArray) egl_icd_details = NULL;      /* (element-type IcdDetails) */
-  g_autoptr(GPtrArray) vulkan_icd_details = NULL;   /* (element-type IcdDetails) */
-  guint n_egl_icds;
-  guint n_vulkan_icds;
-  const GList *icd_iter;
-
-  g_return_val_if_fail (tools_dir != NULL, FALSE);
-  g_return_val_if_fail (runtime != NULL, FALSE);
-  g_return_val_if_fail (overrides != NULL, FALSE);
-  g_return_val_if_fail (scratch != NULL, FALSE);
-  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-  if (!pv_bwrap_bind_usr (bwrap, runtime, "/", error))
-    return FALSE;
-
-  flatpak_bwrap_add_args (bwrap,
-                          "--setenv", "XDG_RUNTIME_DIR", xrd,
-                          "--tmpfs", "/run",
-                          "--tmpfs", "/tmp",
-                          "--tmpfs", "/var",
-                          "--symlink", "../run", "/var/run",
-                          NULL);
-
-  for (i = 0; i < G_N_ELEMENTS (bind_mutable); i++)
-    {
-      g_autofree gchar *path = g_build_filename (runtime, bind_mutable[i],
-                                                 NULL);
-      g_autoptr(GDir) dir = NULL;
-
-      dir = g_dir_open (path, 0, NULL);
-
-      if (dir == NULL)
-        continue;
-
-      for (member = g_dir_read_name (dir);
-           member != NULL;
-           member = g_dir_read_name (dir))
-        {
-          g_autofree gchar *dest = g_build_filename ("/", bind_mutable[i],
-                                                     member, NULL);
-          g_autofree gchar *full = NULL;
-          g_autofree gchar *target = NULL;
-
-          if (g_strv_contains (dont_bind, dest))
-            continue;
-
-          full = g_build_filename (runtime, bind_mutable[i], member, NULL);
-          target = glnx_readlinkat_malloc (-1, full, NULL, NULL);
-
-          if (target != NULL)
-            flatpak_bwrap_add_args (bwrap, "--symlink", target, dest, NULL);
-          else
-            flatpak_bwrap_add_args (bwrap, "--ro-bind", full, dest, NULL);
-        }
-    }
-
-  if (g_file_test ("/etc/machine-id", G_FILE_TEST_EXISTS))
-    {
-      flatpak_bwrap_add_args (bwrap,
-                              "--ro-bind", "/etc/machine-id", "/etc/machine-id",
-                              "--symlink", "/etc/machine-id",
-                              "/var/lib/dbus/machine-id",
-                              NULL);
-    }
-  else if (g_file_test ("/var/lib/dbus/machine-id", G_FILE_TEST_EXISTS))
-    {
-      flatpak_bwrap_add_args (bwrap,
-                              "--ro-bind", "/var/lib/dbus/machine-id",
-                              "/etc/machine-id",
-                              "--symlink", "/etc/machine-id",
-                              "/var/lib/dbus/machine-id",
-                              NULL);
-    }
-
-  if (g_file_test ("/etc/resolv.conf", G_FILE_TEST_EXISTS))
-    flatpak_bwrap_add_args (bwrap,
-                            "--ro-bind", "/etc/resolv.conf", "/etc/resolv.conf",
-                            NULL);
-  if (g_file_test ("/etc/host.conf", G_FILE_TEST_EXISTS))
-    flatpak_bwrap_add_args (bwrap,
-                            "--ro-bind", "/etc/host.conf", "/etc/host.conf",
-                            NULL);
-  if (g_file_test ("/etc/hosts", G_FILE_TEST_EXISTS))
-    flatpak_bwrap_add_args (bwrap,
-                            "--ro-bind", "/etc/hosts", "/etc/hosts",
-                            NULL);
-
-  /* TODO: Synthesize a passwd with only the user and nobody,
-   * like Flatpak does? */
-  if (g_file_test ("/etc/passwd", G_FILE_TEST_EXISTS))
-    flatpak_bwrap_add_args (bwrap,
-                            "--ro-bind", "/etc/passwd", "/etc/passwd",
-                            NULL);
-  if (g_file_test ("/etc/group", G_FILE_TEST_EXISTS))
-    flatpak_bwrap_add_args (bwrap,
-                            "--ro-bind", "/etc/group", "/etc/group",
-                            NULL);
-
-  g_debug ("Enumerating EGL ICDs on host system...");
-  egl_icds = srt_system_info_list_egl_icds (system_info, multiarch_tuples);
-  n_egl_icds = g_list_length (egl_icds);
-
-  egl_icd_details = g_ptr_array_new_full (n_egl_icds,
-                                          (GDestroyNotify) G_CALLBACK (icd_details_free));
-
-  for (icd_iter = egl_icds, j = 0;
-       icd_iter != NULL;
-       icd_iter = icd_iter->next, j++)
-    {
-      SrtEglIcd *icd = icd_iter->data;
-      const gchar *path = srt_egl_icd_get_json_path (icd);
-      GError *local_error = NULL;
-
-      if (!srt_egl_icd_check_error (icd, &local_error))
-        {
-          g_debug ("Failed to load EGL ICD #%" G_GSIZE_FORMAT  " from %s: %s",
-                   j, path, local_error->message);
-          g_clear_error (&local_error);
-          continue;
-        }
-
-      g_debug ("EGL ICD #%" G_GSIZE_FORMAT " at %s: %s",
-               j, path, srt_egl_icd_get_library_path (icd));
-
-      g_ptr_array_add (egl_icd_details, icd_details_new (icd));
-    }
-
-  g_debug ("Enumerating Vulkan ICDs on host system...");
-  vulkan_icds = srt_system_info_list_vulkan_icds (system_info,
-                                                  multiarch_tuples);
-  n_vulkan_icds = g_list_length (vulkan_icds);
-
-  vulkan_icd_details = g_ptr_array_new_full (n_vulkan_icds,
-                                             (GDestroyNotify) G_CALLBACK (icd_details_free));
-
-  for (icd_iter = vulkan_icds, j = 0;
-       icd_iter != NULL;
-       icd_iter = icd_iter->next, j++)
-    {
-      SrtVulkanIcd *icd = icd_iter->data;
-      const gchar *path = srt_vulkan_icd_get_json_path (icd);
-      GError *local_error = NULL;
-
-      if (!srt_vulkan_icd_check_error (icd, &local_error))
-        {
-          g_debug ("Failed to load Vulkan ICD #%" G_GSIZE_FORMAT " from %s: %s",
-                   j, path, local_error->message);
-          g_clear_error (&local_error);
-          continue;
-        }
-
-      g_debug ("Vulkan ICD #%" G_GSIZE_FORMAT " at %s: %s",
-               j, path, srt_vulkan_icd_get_library_path (icd));
-
-      g_ptr_array_add (vulkan_icd_details, icd_details_new (icd));
-    }
-
-  g_assert (multiarch_tuples[G_N_ELEMENTS (multiarch_tuples) - 1] == NULL);
-
-  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
-    {
-      g_autofree gchar *tool = g_strdup_printf ("%s-capsule-capture-libs",
-                                                multiarch_tuples[i]);
-      g_autofree gchar *tool_path = NULL;
-      g_autofree gchar *ld_so = NULL;
-      const gchar *argv[] = { NULL, "--print-ld.so", NULL };
-
-      g_debug ("Checking for %s libraries...", multiarch_tuples[i]);
-
-      tool_path = g_build_filename (tools_dir, tool, NULL);
-      argv[0] = tool_path;
-
-      /* This has the side-effect of testing whether we can run binaries
-       * for this architecture on the host system. */
-      ld_so = pv_capture_output (argv, NULL);
-
-      if (ld_so != NULL)
-        {
-          g_auto(GStrv) dirs = NULL;
-          g_autoptr(FlatpakBwrap) mount_runtime_on_scratch = NULL;
-          g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
-          g_autofree gchar *libdir_in_container = g_build_filename ("/overrides",
-                                                                    "lib",
-                                                                    multiarch_tuples[i],
-                                                                    NULL);
-          g_autofree gchar *libdir_on_host = g_build_filename (overrides, "lib",
-                                                               multiarch_tuples[i],
-                                                               NULL);
-          g_autofree gchar *this_dri_path_on_host = g_build_filename (libdir_on_host,
-                                                                      "dri", NULL);
-          g_autofree gchar *this_dri_path_in_container = g_build_filename (libdir_in_container,
-                                                                           "dri", NULL);
-          g_autofree gchar *libc = NULL;
-          g_autofree gchar *ld_so_in_runtime = NULL;
-          g_autofree gchar *libdrm = NULL;
-          const gchar *libqual = NULL;
-
-          temp_bwrap = flatpak_bwrap_new (NULL);
-          flatpak_bwrap_add_args (temp_bwrap,
-                                  bwrap->argv->pdata[0],
-                                  NULL);
-
-          if (!pv_bwrap_bind_usr (temp_bwrap, runtime, "/", error))
-            return FALSE;
-
-          flatpak_bwrap_add_args (temp_bwrap,
-                                  "readlink", "-e", ld_so,
-                                  NULL);
-          flatpak_bwrap_finish (temp_bwrap);
-
-          ld_so_in_runtime = pv_capture_output ((const char * const *) temp_bwrap->argv->pdata,
-                                                NULL);
-
-          g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
-
-          if (ld_so_in_runtime == NULL)
-            {
-              g_debug ("Container does not have %s so it cannot run "
-                       "%s binaries", ld_so, multiarch_tuples[i]);
-              continue;
-            }
-
-          any_architecture_works = TRUE;
-          g_debug ("Container path: %s -> %s", ld_so, ld_so_in_runtime);
-
-          pv_search_path_append (dri_path, this_dri_path_in_container);
-
-          g_mkdir_with_parents (libdir_on_host, 0755);
-          g_mkdir_with_parents (this_dri_path_on_host, 0755);
-
-          mount_runtime_on_scratch = flatpak_bwrap_new (NULL);
-          flatpak_bwrap_add_args (mount_runtime_on_scratch,
-                                  bwrap->argv->pdata[0],
-                                  "--ro-bind", "/", "/",
-                                  "--bind", overrides, overrides,
-                                  "--tmpfs", scratch,
-                                  NULL);
-          if (!pv_bwrap_bind_usr (mount_runtime_on_scratch, runtime, scratch,
-                         error))
-            return FALSE;
-
-          g_debug ("Collecting GLX drivers from host system...");
-
-          temp_bwrap = flatpak_bwrap_new (NULL);
-          /* mount_runtime_on_scratch can't own any fds, because if it did,
-           * flatpak_bwrap_append_bwrap() would steal them. */
-          g_warn_if_fail (mount_runtime_on_scratch->fds == NULL
-                          || mount_runtime_on_scratch->fds->len == 0);
-          flatpak_bwrap_append_bwrap (temp_bwrap, mount_runtime_on_scratch);
-          flatpak_bwrap_add_args (temp_bwrap,
-                                  tool_path,
-                                  "--container", scratch,
-                                  "--link-target", "/run/host",
-                                  "--dest", libdir_on_host,
-                                  "--provider", "/",
-                                  "gl:",
-                                  NULL);
-          flatpak_bwrap_finish (temp_bwrap);
-
-          if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
-            return FALSE;
-
-          g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
-
-          temp_bwrap = flatpak_bwrap_new (NULL);
-          g_warn_if_fail (mount_runtime_on_scratch->fds == NULL
-                          || mount_runtime_on_scratch->fds->len == 0);
-          flatpak_bwrap_append_bwrap (temp_bwrap, mount_runtime_on_scratch);
-          flatpak_bwrap_add_args (temp_bwrap,
-                                  tool_path,
-                                  "--container", scratch,
-                                  "--link-target", "/run/host",
-                                  "--dest", libdir_on_host,
-                                  "--provider", "/",
-                                  "if-exists:even-if-older:soname-match:libEGL.so.*",
-                                  "if-exists:even-if-older:soname-match:libEGL_nvidia.so.*",
-                                  "if-exists:even-if-older:soname-match:libGL.so.*",
-                                  "if-exists:even-if-older:soname-match:libGLESv1_CM.so.*",
-                                  "if-exists:even-if-older:soname-match:libGLESv1_CM_nvidia.so.*",
-                                  "if-exists:even-if-older:soname-match:libGLESv2.so.*",
-                                  "if-exists:even-if-older:soname-match:libGLESv2_nvidia.so.*",
-                                  "if-exists:even-if-older:soname-match:libGLX.so.*",
-                                  "if-exists:even-if-older:soname-match:libGLX_nvidia.so.*",
-                                  "if-exists:even-if-older:soname-match:libGLX_indirect.so.*",
-                                  "if-exists:even-if-older:soname-match:libGLdispatch.so.*",
-                                  "if-exists:even-if-older:soname-match:libOpenGL.so.*",
-                                  "if-exists:even-if-older:soname-match:libcuda.so.*",
-                                  "if-exists:even-if-older:soname-match:libglx.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-cbl.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-cfg.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-compiler.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-egl-wayland.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-eglcore.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-encode.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-fatbinaryloader.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-fbc.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-glcore.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-glsi.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-glvkspirv.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-ifr.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-ml.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-opencl.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-opticalflow.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-ptxjitcompiler.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-rtcore.so.*",
-                                  "if-exists:even-if-older:soname-match:libnvidia-tls.so.*",
-                                  "if-exists:even-if-older:soname-match:libOpenCL.so.*",
-                                  "if-exists:even-if-older:soname-match:libvdpau_nvidia.so.*",
-                                  NULL);
-          flatpak_bwrap_finish (temp_bwrap);
-
-          if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
-            return FALSE;
-
-          g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
-
-          g_debug ("Collecting %s EGL drivers from host system...",
-                   multiarch_tuples[i]);
-
-          for (j = 0; j < egl_icd_details->len; j++)
-            {
-              IcdDetails *details = g_ptr_array_index (egl_icd_details, j);
-              SrtEglIcd *icd = SRT_EGL_ICD (details->icd);
-
-              if (!srt_egl_icd_check_error (icd, NULL))
-                continue;
-
-              details->resolved_library = srt_egl_icd_resolve_library_path (icd);
-              g_assert (details->resolved_library != NULL);
-
-              if (!bind_icd (i,
-                             j,
-                             tool_path,
-                             mount_runtime_on_scratch,
-                             scratch,
-                             libdir_on_host,
-                             libdir_in_container,
-                             "glvnd",
-                             details,
-                             error))
-                return FALSE;
-            }
-
-          g_debug ("Collecting %s Vulkan drivers from host system...",
-                   multiarch_tuples[i]);
-
-          temp_bwrap = flatpak_bwrap_new (NULL);
-          g_warn_if_fail (mount_runtime_on_scratch->fds == NULL
-                          || mount_runtime_on_scratch->fds->len == 0);
-          flatpak_bwrap_append_bwrap (temp_bwrap, mount_runtime_on_scratch);
-          flatpak_bwrap_add_args (temp_bwrap,
-                                  tool_path,
-                                  "--container", scratch,
-                                  "--link-target", "/run/host",
-                                  "--dest", libdir_on_host,
-                                  "--provider", "/",
-                                  "if-exists:if-same-abi:soname:libvulkan.so.1",
-                                  NULL);
-          flatpak_bwrap_finish (temp_bwrap);
-
-          if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
-            return FALSE;
-
-          g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
-
-          for (j = 0; j < vulkan_icd_details->len; j++)
-            {
-              IcdDetails *details = g_ptr_array_index (vulkan_icd_details, j);
-              SrtVulkanIcd *icd = SRT_VULKAN_ICD (details->icd);
-
-              if (!srt_vulkan_icd_check_error (icd, NULL))
-                continue;
-
-              details->resolved_library = srt_vulkan_icd_resolve_library_path (icd);
-              g_assert (details->resolved_library != NULL);
-
-              if (!bind_icd (i,
-                             j,
-                             tool_path,
-                             mount_runtime_on_scratch,
-                             scratch,
-                             libdir_on_host,
-                             libdir_in_container,
-                             "vulkan",
-                             details,
-                             error))
-                return FALSE;
-            }
-
-          libc = g_build_filename (libdir_on_host, "libc.so.6", NULL);
-
-          /* If we are going to use the host system's libc6 (likely)
-           * then we have to use its ld.so too. */
-          if (g_file_test (libc, G_FILE_TEST_IS_SYMLINK))
-            {
-              g_autofree gchar *ld_so_in_host = NULL;
-
-              g_debug ("Making host ld.so visible in container");
-
-              ld_so_in_host = flatpak_canonicalize_filename (ld_so);
-              g_debug ("Host path: %s -> %s", ld_so, ld_so_in_host);
-
-              g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
-
-              temp_bwrap = flatpak_bwrap_new (NULL);
-              flatpak_bwrap_add_args (temp_bwrap,
-                                      bwrap->argv->pdata[0],
-                                      NULL);
-
-              if (!pv_bwrap_bind_usr (temp_bwrap, runtime, "/", error))
-                return FALSE;
-
-              flatpak_bwrap_add_args (temp_bwrap,
-                                      "readlink", "-f", ld_so,
-                                      NULL);
-              flatpak_bwrap_finish (temp_bwrap);
-
-              g_debug ("Container path: %s -> %s", ld_so, ld_so_in_runtime);
-              flatpak_bwrap_add_args (bwrap,
-                                      "--ro-bind", ld_so_in_host,
-                                      ld_so_in_runtime,
-                                      NULL);
-
-              /* Collect miscellaneous libraries that libc might dlopen.
-               * At the moment this is just libidn2. */
-              temp_bwrap = flatpak_bwrap_new (NULL);
-              g_warn_if_fail (mount_runtime_on_scratch->fds == NULL
-                              || mount_runtime_on_scratch->fds->len == 0);
-              flatpak_bwrap_append_bwrap (temp_bwrap, mount_runtime_on_scratch);
-              flatpak_bwrap_add_args (temp_bwrap,
-                                      tool_path,
-                                      "--container", scratch,
-                                      "--link-target", "/run/host",
-                                      "--dest", libdir_on_host,
-                                      "--provider", "/",
-                                      "if-exists:libidn2.so.0",
-                                      NULL);
-              flatpak_bwrap_finish (temp_bwrap);
-
-              if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
-                return FALSE;
-
-              g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
-
-              any_libc_from_host = TRUE;
-            }
-          else
-            {
-              all_libc_from_host = FALSE;
-            }
-
-          libdrm = g_build_filename (libdir_on_host, "libdrm.so.2", NULL);
-
-          /* If we have libdrm.so.2 in overrides we also want to mount
-           * ${prefix}/share/libdrm from the host. ${prefix} is derived from
-           * the absolute path of libdrm.so.2 */
-          if (g_file_test (libdrm, G_FILE_TEST_IS_SYMLINK))
-            {
-              g_autofree char *target = NULL;
-              target = glnx_readlinkat_malloc (-1, libdrm, NULL, NULL);
-
-              if (target != NULL)
-                {
-                  g_autofree gchar *dir = NULL;
-                  g_autofree gchar *lib_multiarch = NULL;
-                  g_autofree gchar *libdrm_dir_in_host = NULL;
-
-                  dir = g_path_get_dirname (target);
-
-                  lib_multiarch = g_build_filename ("/lib", multiarch_tuples[i], NULL);
-                  if (g_str_has_suffix (dir, lib_multiarch))
-                    dir[strlen (dir) - strlen (lib_multiarch)] = '\0';
-                  else if (g_str_has_suffix (dir, "/lib64"))
-                    dir[strlen (dir) - strlen ("/lib64")] = '\0';
-                  else if (g_str_has_suffix (dir, "/lib32"))
-                    dir[strlen (dir) - strlen ("/lib32")] = '\0';
-                  else if (g_str_has_suffix (dir, "/lib"))
-                    dir[strlen (dir) - strlen ("/lib")] = '\0';
-
-                  if (g_str_has_prefix (dir, "/run/host"))
-                    memmove (dir, dir + strlen ("/run/host"), strlen (dir) - strlen ("/run/host") + 1);
-
-                  libdrm_dir_in_host = g_build_filename (dir, "share", "libdrm", NULL);
-
-                  if (g_file_test (libdrm_dir_in_host, G_FILE_TEST_IS_DIR))
-                    {
-                      g_hash_table_add (libdrm_data_from_host, g_steal_pointer (&libdrm_dir_in_host));
-                    }
-                  else
-                    {
-                      g_debug ("We were expecting to have the libdrm directory in the host "
-                               "to be located in \"%s\", but instead it is missing",
-                               libdrm_dir_in_host);
-                    }
-                }
-            }
-          else
-            {
-              /* For at least a single architecture, libdrm is newer in the container */
-              all_libdrm_from_host = FALSE;
-            }
-
-          /* /lib32 or /lib64 */
-          g_assert (i < G_N_ELEMENTS (libquals));
-          libqual = libquals[i];
-
-          dirs = g_new0 (gchar *, 7);
-          dirs[0] = g_build_filename ("/lib", multiarch_tuples[i], NULL);
-          dirs[1] = g_build_filename ("/usr", "lib", multiarch_tuples[i], NULL);
-          dirs[2] = g_strdup ("/lib");
-          dirs[3] = g_strdup ("/usr/lib");
-          dirs[4] = g_build_filename ("/", libqual, NULL);
-          dirs[5] = g_build_filename ("/usr", libqual, NULL);
-
-          for (j = 0; j < 6; j++)
-            {
-              if (!try_bind_dri (bwrap, mount_runtime_on_scratch,
-                                 overrides, scratch, tool_path, dirs[j],
-                                 libdir_on_host, error))
-                return FALSE;
-            }
-        }
-      else
-        {
-          g_debug ("Cannot determine ld.so for %s", multiarch_tuples[i]);
-        }
-    }
-
-  if (!any_architecture_works)
-    {
-      GString *archs = g_string_new ("");
-
-      g_assert (multiarch_tuples[G_N_ELEMENTS (multiarch_tuples) - 1] == NULL);
-
-      for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
-        {
-          if (archs->len > 0)
-            g_string_append (archs, ", ");
-
-          g_string_append (archs, multiarch_tuples[i]);
-        }
-
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "None of the supported CPU architectures are common to "
-                   "the host system and the container (tried: %s)",
-                   archs->str);
-      g_string_free (archs, TRUE);
-      return FALSE;
-    }
-
-  if (any_libc_from_host && !all_libc_from_host)
-    {
-      /*
-       * This shouldn't happen. It would mean that there exist at least
-       * two architectures (let's say aaa and bbb) for which we have:
-       * host libc6:aaa < container libc6 < host libc6:bbb
-       * (we know that the container's libc6:aaa and libc6:bbb are
-       * constrained to be the same version because that's how multiarch
-       * works).
-       *
-       * If the host system locales work OK with both the aaa and bbb
-       * versions, let's assume they will also work with the intermediate
-       * version from the container...
-       */
-      g_warning ("Using glibc from host system for some but not all "
-                 "architectures! Arbitrarily using host locales.");
-    }
-
-  if (any_libc_from_host)
-    {
-      g_debug ("Making host locale data visible in container");
-
-      if (g_file_test ("/usr/lib/locale", G_FILE_TEST_EXISTS))
-        flatpak_bwrap_add_args (bwrap,
-                                "--ro-bind", "/usr/lib/locale",
-                                "/usr/lib/locale",
-                                NULL);
-
-      if (g_file_test ("/usr/share/i18n", G_FILE_TEST_EXISTS))
-        flatpak_bwrap_add_args (bwrap,
-                                "--ro-bind", "/usr/share/i18n",
-                                "/usr/share/i18n",
-                                NULL);
-
-      localedef = g_find_program_in_path ("localedef");
-
-      if (localedef == NULL)
-        {
-          g_warning ("Cannot find localedef in PATH");
-        }
-      else
-        {
-          g_autofree gchar *target = g_build_filename ("/run/host",
-                                                       localedef, NULL);
-
-          flatpak_bwrap_add_args (bwrap,
-                                  "--symlink", target,
-                                      "/overrides/bin/localedef",
-                                  NULL);
-        }
-    }
-  else
-    {
-      g_debug ("Using included locale data from container");
-    }
-
-  if (g_hash_table_size (libdrm_data_from_host) > 0 && !all_libdrm_from_host)
-    {
-      /* See the explanation in the similar "any_libc_from_host && !all_libc_from_host"
-       * case, above */
-      g_warning ("Using libdrm.so.2 from host system for some but not all "
-                 "architectures! Will take /usr/share/libdrm from host.");
-    }
-
-  if (g_hash_table_size (libdrm_data_from_host) == 1)
-    {
-      best_libdrm_data_from_host = g_strdup (pv_hash_table_get_arbitrary_key (libdrm_data_from_host));
-    }
-  else if (g_hash_table_size (libdrm_data_from_host) > 1)
-    {
-      g_warning ("Found more than one possible libdrm data directory from host");
-      /* Prioritize "/usr/share/libdrm" if available. Otherwise randomly pick
-       * the first directory in the hash table */
-      if (g_hash_table_contains (libdrm_data_from_host, "/usr/share/libdrm"))
-        best_libdrm_data_from_host = g_strdup ("/usr/share/libdrm");
-      else
-        best_libdrm_data_from_host = g_strdup (pv_hash_table_get_arbitrary_key (libdrm_data_from_host));
-    }
-
-  g_autofree gchar *runtime_usr = g_build_filename (runtime, "usr", NULL);
-  if (g_file_test (runtime_usr, G_FILE_TEST_IS_DIR))
-    libdrm_data_in_runtime = g_build_filename (runtime_usr, "share", "libdrm", NULL);
-  else
-    libdrm_data_in_runtime = g_build_filename (runtime, "share", "libdrm", NULL);
-
-  if (best_libdrm_data_from_host != NULL &&
-      g_file_test (libdrm_data_in_runtime, G_FILE_TEST_IS_DIR))
-    {
-      flatpak_bwrap_add_args (bwrap,
-                              "--ro-bind", best_libdrm_data_from_host, "/usr/share/libdrm",
-                              NULL);
-    }
-
-  g_debug ("Setting up EGL ICD JSON...");
-
-  dir_on_host = g_build_filename (overrides,
-                                  "share", "glvnd", "egl_vendor.d", NULL);
-
-  if (g_mkdir_with_parents (dir_on_host, 0700) != 0)
-    {
-      glnx_throw_errno_prefix (error, "Unable to create %s", dir_on_host);
-      return FALSE;
-    }
-
-  for (j = 0; j < egl_icd_details->len; j++)
-    {
-      IcdDetails *details = g_ptr_array_index (egl_icd_details, j);
-      SrtEglIcd *icd = SRT_EGL_ICD (details->icd);
-      gboolean need_host_json = FALSE;
-
-      if (!srt_egl_icd_check_error (icd, NULL))
-        continue;
-
-      for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
-        {
-          g_assert (i < G_N_ELEMENTS (details->kinds));
-          g_assert (i < G_N_ELEMENTS (details->paths_in_container));
-
-          if (details->kinds[i] == ICD_KIND_ABSOLUTE)
-            {
-              g_autoptr(SrtEglIcd) replacement = NULL;
-              g_autofree gchar *json_on_host = NULL;
-              g_autofree gchar *json_in_container = NULL;
-              g_autofree gchar *json_base = NULL;
-
-              g_assert (details->paths_in_container[i] != NULL);
-
-              json_base = g_strdup_printf ("%" G_GSIZE_FORMAT "-%s.json",
-                                           j, multiarch_tuples[i]);
-              json_on_host = g_build_filename (dir_on_host, json_base, NULL);
-              json_in_container = g_build_filename ("/overrides", "share",
-                                                    "glvnd", "egl_vendor.d",
-                                                    json_base, NULL);
-
-              replacement = srt_egl_icd_new_replace_library_path (icd,
-                                                                  details->paths_in_container[i]);
-
-              if (!srt_egl_icd_write_to_file (replacement, json_on_host,
-                                                 error))
-                return FALSE;
-
-              pv_search_path_append (egl_path, json_in_container);
-            }
-          else if (details->kinds[i] == ICD_KIND_SONAME)
-            {
-              need_host_json = TRUE;
-            }
-        }
-
-      if (need_host_json)
-        {
-          g_autofree gchar *json_in_container = NULL;
-          g_autofree gchar *json_base = NULL;
-          const char *json_on_host = srt_egl_icd_get_json_path (icd);
-
-          json_base = g_strdup_printf ("%" G_GSIZE_FORMAT ".json", j);
-          json_in_container = g_build_filename ("/overrides", "share",
-                                                "glvnd", "egl_vendor.d",
-                                                json_base, NULL);
-
-          flatpak_bwrap_add_args (bwrap,
-                                  "--ro-bind", json_on_host, json_in_container,
-                                  NULL);
-          pv_search_path_append (egl_path, json_in_container);
-        }
-    }
-
-  g_debug ("Setting up Vulkan ICD JSON...");
-
-  dir_on_host = g_build_filename (overrides,
-                                  "share", "vulkan", "icd.d", NULL);
-
-  if (g_mkdir_with_parents (dir_on_host, 0700) != 0)
-    {
-      glnx_throw_errno_prefix (error, "Unable to create %s", dir_on_host);
-      return FALSE;
-    }
-
-  for (j = 0; j < vulkan_icd_details->len; j++)
-    {
-      IcdDetails *details = g_ptr_array_index (vulkan_icd_details, j);
-      SrtVulkanIcd *icd = SRT_VULKAN_ICD (details->icd);
-      gboolean need_host_json = FALSE;
-
-      if (!srt_vulkan_icd_check_error (icd, NULL))
-        continue;
-
-      for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
-        {
-          g_assert (i < G_N_ELEMENTS (details->kinds));
-          g_assert (i < G_N_ELEMENTS (details->paths_in_container));
-
-          if (details->kinds[i] == ICD_KIND_ABSOLUTE)
-            {
-              g_autoptr(SrtVulkanIcd) replacement = NULL;
-              g_autofree gchar *json_on_host = NULL;
-              g_autofree gchar *json_in_container = NULL;
-              g_autofree gchar *json_base = NULL;
-
-              g_assert (details->paths_in_container[i] != NULL);
-
-              json_base = g_strdup_printf ("%" G_GSIZE_FORMAT "-%s.json",
-                                           j, multiarch_tuples[i]);
-              json_on_host = g_build_filename (dir_on_host, json_base, NULL);
-              json_in_container = g_build_filename ("/overrides", "share",
-                                                    "vulkan", "icd.d",
-                                                    json_base, NULL);
-
-              replacement = srt_vulkan_icd_new_replace_library_path (icd,
-                                                                     details->paths_in_container[i]);
-
-              if (!srt_vulkan_icd_write_to_file (replacement, json_on_host,
-                                                 error))
-                return FALSE;
-
-              pv_search_path_append (vulkan_path, json_in_container);
-            }
-          else if (details->kinds[i] == ICD_KIND_SONAME)
-            {
-              need_host_json = TRUE;
-            }
-        }
-
-      if (need_host_json)
-        {
-          g_autofree gchar *json_in_container = NULL;
-          g_autofree gchar *json_base = NULL;
-          const char *json_on_host = srt_vulkan_icd_get_json_path (icd);
-
-          json_base = g_strdup_printf ("%" G_GSIZE_FORMAT ".json", j);
-          json_in_container = g_build_filename ("/overrides", "share",
-                                                "vulkan", "icd.d",
-                                                json_base, NULL);
-
-          flatpak_bwrap_add_args (bwrap,
-                                  "--ro-bind", json_on_host, json_in_container,
-                                  NULL);
-          pv_search_path_append (vulkan_path, json_in_container);
-        }
-    }
-
-  if (!pv_bwrap_bind_usr (bwrap, "/", "/run/host", error))
-    return FALSE;
-
-  ensure_locales (any_libc_from_host, tools_dir, bwrap, overrides);
-
-  if (dri_path->len != 0)
-      flatpak_bwrap_add_args (bwrap,
-                              "--setenv", "LIBGL_DRIVERS_PATH", dri_path->str,
-                              NULL);
-  else
-      flatpak_bwrap_add_args (bwrap,
-                              "--unsetenv", "LIBGL_DRIVERS_PATH",
-                              NULL);
-
-  if (egl_path->len != 0)
-      flatpak_bwrap_add_args (bwrap,
-                              "--setenv", "__EGL_VENDOR_LIBRARY_FILENAMES",
-                              egl_path->str, NULL);
-  else
-      flatpak_bwrap_add_args (bwrap,
-                              "--unsetenv", "__EGL_VENDOR_LIBRARY_FILENAMES",
-                              NULL);
-
-  flatpak_bwrap_add_args (bwrap,
-                          "--unsetenv", "__EGL_VENDOR_LIBRARY_DIRS",
-                          NULL);
-
-  if (vulkan_path->len != 0)
-      flatpak_bwrap_add_args (bwrap,
-                              "--setenv", "VK_ICD_FILENAMES",
-                              vulkan_path->str, NULL);
-  else
-      flatpak_bwrap_add_args (bwrap,
-                              "--unsetenv", "VK_ICD_FILENAMES",
-                              NULL);
-
-  /* These can add data fds to @bwrap, so they must come last - after
-   * other functions stop using @bwrap as a basis for their own bwrap
-   * invocations with flatpak_bwrap_append_bwrap().
-   * Otherwise, when flatpak_bwrap_append_bwrap() calls
-   * flatpak_bwrap_steal_fds(), it will make the original FlatpakBwrap
-   * unusable. */
-
-  flatpak_run_add_wayland_args (bwrap);
-  flatpak_run_add_x11_args (bwrap, TRUE);
-  flatpak_run_add_pulseaudio_args (bwrap);
-  flatpak_run_add_session_dbus_args (bwrap);
-  flatpak_run_add_system_dbus_args (bwrap);
-  pv_bwrap_copy_tree (bwrap, overrides, "/overrides");
-
-  /* /etc/localtime and /etc/resolv.conf can not exist (or be symlinks to
-   * non-existing targets), in which case we don't want to attempt to create
-   * bogus symlinks or bind mounts, as that will cause flatpak run to fail.
-   */
-  if (g_file_test ("/etc/localtime", G_FILE_TEST_EXISTS))
-    {
-      g_autofree char *target = NULL;
-      gboolean is_reachable = FALSE;
-      g_autofree char *tz = flatpak_get_timezone ();
-      g_autofree char *timezone_content = g_strdup_printf ("%s\n", tz);
-
-      target = glnx_readlinkat_malloc (-1, "/etc/localtime", NULL, NULL);
-
-      if (target != NULL)
-        {
-          g_autoptr(GFile) base_file = NULL;
-          g_autoptr(GFile) target_file = NULL;
-          g_autofree char *target_canonical = NULL;
-
-          base_file = g_file_new_for_path ("/etc");
-          target_file = g_file_resolve_relative_path (base_file, target);
-          target_canonical = g_file_get_path (target_file);
-
-          is_reachable = g_str_has_prefix (target_canonical, "/usr/");
-        }
-
-      if (is_reachable)
-        {
-          flatpak_bwrap_add_args (bwrap,
-                                  "--symlink", target, "/etc/localtime",
-                                  NULL);
-        }
-      else
-        {
-          flatpak_bwrap_add_args (bwrap,
-                                  "--ro-bind", "/etc/localtime", "/etc/localtime",
-                                  NULL);
-        }
-
-      flatpak_bwrap_add_args_data (bwrap, "timezone",
-                                   timezone_content, -1, "/etc/timezone",
-                                   NULL);
-    }
-
-  return TRUE;
-}
-
 /* Order matters here: root, steam and steambeta are or might be symlinks
  * to the root of the Steam installation, so we want to bind-mount their
  * targets before we deal with the rest. */
@@ -1678,6 +322,7 @@ static char *opt_freedesktop_app_id = NULL;
 static char *opt_steam_app_id = NULL;
 static char *opt_home = NULL;
 static gboolean opt_host_fallback = FALSE;
+static gboolean opt_host_graphics = TRUE;
 static PvShell opt_shell = PV_SHELL_NONE;
 static GPtrArray *opt_ld_preload = NULL;
 static char *opt_runtime_base = NULL;
@@ -1939,6 +584,14 @@ static GOptionEntry options[] =
   { "version-only", '\0',
     G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_version_only,
     "Print version number (no other information) and exit.", NULL },
+  { "with-host-graphics", '\0',
+    G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &opt_host_graphics,
+    "If using --runtime, use the host graphics stack (default)", NULL },
+  { "without-host-graphics", '\0',
+    G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &opt_host_graphics,
+    "If using --runtime, don't use the host graphics stack. "
+    "This is likely to result in software rendering or a crash.",
+    NULL },
   { "test", '\0',
     G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &opt_test,
     "Smoke test pressure-vessel-wrap and exit.", NULL },
@@ -2002,22 +655,15 @@ main (int argc,
   int original_argc = argc;
   g_autoptr(FlatpakBwrap) bwrap = NULL;
   g_autoptr(FlatpakBwrap) wrapped_command = NULL;
-  g_autofree gchar *tmpdir = NULL;
-  g_autofree gchar *pressure_vessel_prefix = NULL;
-  g_autofree gchar *scratch = NULL;
-  g_autofree gchar *overrides = NULL;
-  g_autofree gchar *overrides_bin = NULL;
   g_autofree gchar *bwrap_executable = NULL;
-  g_autoptr(GString) ld_library_path = g_string_new ("");
-  g_autoptr(GString) bin_path = g_string_new ("");
   g_autoptr(GString) adjusted_ld_preload = g_string_new ("");
   g_autofree gchar *cwd_p = NULL;
   g_autofree gchar *cwd_l = NULL;
-  g_autoptr(PvBwrapLock) runtime_lock = NULL;
   const gchar *home;
   g_autofree gchar *bwrap_help = NULL;
   g_autofree gchar *tools_dir = NULL;
   const gchar *bwrap_help_argv[] = { "<bwrap>", "--help", NULL };
+  g_autoptr(PvRuntime) runtime = NULL;
 
   setlocale (LC_ALL, "");
   pv_avoid_gvfs ();
@@ -2055,6 +701,8 @@ main (int argc,
     g_clear_pointer (&opt_home, g_free);
 
   opt_share_home = tristate_environment ("PRESSURE_VESSEL_SHARE_HOME");
+  opt_host_graphics = boolean_environment ("PRESSURE_VESSEL_HOST_GRAPHICS",
+                                           TRUE);
   opt_verbose = boolean_environment ("PRESSURE_VESSEL_VERBOSE", FALSE);
 
   if (!opt_shell_cb ("$PRESSURE_VESSEL_SHELL",
@@ -2259,8 +907,6 @@ main (int argc,
 
   g_debug ("Found executable directory: %s", tools_dir);
 
-  pressure_vessel_prefix = g_path_get_dirname (tools_dir);
-
   wrapped_command = flatpak_bwrap_new (NULL);
 
   switch (opt_terminal)
@@ -2373,19 +1019,6 @@ main (int argc,
   if (bwrap_help == NULL)
     goto out;
 
-  g_debug ("Creating temporary directories...");
-  tmpdir = g_dir_make_tmp ("pressure-vessel-wrap.XXXXXX", error);
-
-  if (tmpdir == NULL)
-    goto out;
-
-  scratch = g_build_filename (tmpdir, "scratch", NULL);
-  g_mkdir (scratch, 0700);
-  overrides = g_build_filename (tmpdir, "overrides", NULL);
-  g_mkdir (overrides, 0700);
-  overrides_bin = g_build_filename (overrides, "bin", NULL);
-  g_mkdir (overrides_bin, 0700);
-
   bwrap = flatpak_bwrap_new (NULL);
   flatpak_bwrap_add_arg (bwrap, bwrap_executable);
 
@@ -2397,65 +1030,24 @@ main (int argc,
 
   if (opt_runtime != NULL && opt_runtime[0] != '\0')
     {
-      g_autofree gchar *files_ref = NULL;
+      PvRuntimeFlags flags = PV_RUNTIME_FLAGS_NONE;
 
-      g_debug ("Configuring runtime...");
+      if (opt_host_graphics)
+        flags |= PV_RUNTIME_FLAGS_HOST_GRAPHICS_STACK;
 
-      /* Start with just the root tmpfs (which appears automatically)
-       * and the standard API filesystems */
-      pv_bwrap_add_api_filesystems (bwrap);
+      g_debug ("Configuring runtime %s...", opt_runtime);
 
-      /* Take a lock on the runtime until we're finished with setup,
-       * to make sure it doesn't get deleted. */
-      files_ref = g_build_filename (opt_runtime, ".ref", NULL);
-      runtime_lock = pv_bwrap_lock_new (files_ref,
-                                        PV_BWRAP_LOCK_FLAGS_CREATE,
-                                        error);
+      runtime = pv_runtime_new (opt_runtime,
+                                bwrap_executable,
+                                tools_dir,
+                                flags,
+                                error);
 
-      /* If the runtime is being deleted, ... don't use it, I suppose? */
-      if (runtime_lock == NULL)
+      if (runtime == NULL)
         goto out;
 
-      pv_search_path_append (bin_path, "/overrides/bin");
-      pv_search_path_append (bin_path, g_getenv ("PATH"));
-      flatpak_bwrap_add_args (bwrap,
-                              "--setenv", "PATH",
-                              bin_path->str,
-                              NULL);
-
-      /* TODO: Adapt the use_ld_so_cache code from Flatpak instead
-       * of setting LD_LIBRARY_PATH, for better robustness against
-       * games that set their own LD_LIBRARY_PATH ignoring what they
-       * got from the environment */
-      g_assert (multiarch_tuples[G_N_ELEMENTS (multiarch_tuples) - 1] == NULL);
-
-      for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
-        {
-          g_autofree gchar *ld_path = NULL;
-
-          ld_path = g_build_filename ("/overrides", "lib",
-                                     multiarch_tuples[i], NULL);
-
-          pv_search_path_append (ld_library_path, ld_path);
-        }
-
-      /* This would be filtered out by a setuid bwrap, so we have to go
-       * via --setenv. */
-      flatpak_bwrap_add_args (bwrap,
-                              "--setenv", "LD_LIBRARY_PATH",
-                              ld_library_path->str,
-                              NULL);
-
-      if (!bind_runtime (bwrap, tools_dir, opt_runtime, overrides,
-                         scratch, error))
+      if (!pv_runtime_bind (runtime, bwrap, error))
         goto out;
-
-      /* Make sure pressure-vessel itself is visible there. */
-      flatpak_bwrap_add_args (bwrap,
-                              "--ro-bind",
-                              pressure_vessel_prefix,
-                              "/run/pressure-vessel",
-                              NULL);
     }
   else
     {
@@ -2510,8 +1102,7 @@ main (int argc,
 
           if (g_file_test (preload, G_FILE_TEST_EXISTS))
             {
-              if (opt_runtime != NULL
-                  && opt_runtime[0] != '\0'
+              if (runtime != NULL
                   && (g_str_has_prefix (preload, "/usr/")
                       || g_str_has_prefix (preload, "/lib")))
                 {
@@ -2580,7 +1171,7 @@ main (int argc,
 
   /* Put Steam Runtime environment variables back, if /usr is mounted
    * from the host. */
-  if (opt_runtime == NULL || opt_runtime[0] == '\0')
+  if (runtime == NULL)
     {
       g_debug ("Making Steam Runtime available...");
 
@@ -2630,57 +1221,8 @@ main (int argc,
   if (!flatpak_bwrap_bundle_args (bwrap, 1, -1, FALSE, error))
     goto out;
 
-  /* If we are using a runtime, pass the lock fd to the executed process,
-   * and make it act as a subreaper for the game itself.
-   *
-   * If we were using --unshare-pid then we could use bwrap --sync-fd
-   * and rely on bubblewrap's init process for this, but we currently
-   * can't do that without breaking gameoverlayrender.so's assumptions. */
-  if (runtime_lock != NULL)
-    {
-      flatpak_bwrap_add_args (bwrap,
-                              "/run/pressure-vessel/bin/pressure-vessel-with-lock",
-                              "--subreaper",
-                              NULL);
-
-      if (pv_bwrap_lock_is_ofd (runtime_lock))
-        {
-          int fd = pv_bwrap_lock_steal_fd (runtime_lock);
-          g_autofree gchar *fd_str = NULL;
-
-          g_debug ("Passing lock fd %d down to with-lock", fd);
-          flatpak_bwrap_add_fd (bwrap, fd);
-          fd_str = g_strdup_printf ("%d", fd);
-          flatpak_bwrap_add_args (bwrap,
-                                  "--fd", fd_str,
-                                  NULL);
-        }
-      else
-        {
-          /*
-           * We were unable to take out an open file descriptor lock,
-           * so it will be released on fork(). Tell the with-lock process
-           * to take out its own compatible lock instead. There will be
-           * a short window during which we have lost our lock but the
-           * with-lock process has not taken its lock - that's unavoidable
-           * if we want to use exec() to replace ourselves with the
-           * container.
-           *
-           * pv_bwrap_bind_usr() arranges for /.ref to either be a
-           * symbolic link to /usr/.ref which is the runtime_lock
-           * (if opt_runtime is a merged /usr), or the runtime_lock
-           * itself (otherwise).
-           */
-          g_debug ("Telling process in container to lock /.ref");
-          flatpak_bwrap_add_args (bwrap,
-                                  "--lock-file", "/.ref",
-                                  NULL);
-        }
-
-      flatpak_bwrap_add_args (bwrap,
-                              "--",
-                              NULL);
-    }
+  if (runtime != NULL)
+    pv_runtime_append_lock_adverb (runtime, bwrap);
 
   g_debug ("Adding wrapped command...");
   flatpak_bwrap_append_args (bwrap, wrapped_command->argv);
@@ -2709,15 +1251,8 @@ main (int argc,
     }
 
   /* Clean up temporary directory before running our long-running process */
-  if (tmpdir != NULL &&
-      !glnx_shutil_rm_rf_at (-1, tmpdir, NULL, error))
-    {
-      g_warning ("Unable to delete temporary directory: %s",
-                 local_error->message);
-      g_clear_error (&local_error);
-    }
-
-  g_clear_pointer (&tmpdir, g_free);
+  if (runtime != NULL)
+    pv_runtime_cleanup (runtime);
 
   flatpak_bwrap_finish (bwrap);
   pv_bwrap_execve (bwrap, error);
@@ -2726,14 +1261,6 @@ out:
   if (local_error != NULL)
     g_warning ("%s", local_error->message);
 
-  if (tmpdir != NULL &&
-      !glnx_shutil_rm_rf_at (-1, tmpdir, NULL, error))
-    {
-      g_warning ("Unable to delete temporary directory: %s",
-                 local_error->message);
-      g_clear_error (&local_error);
-    }
-
   g_clear_pointer (&opt_ld_preload, g_ptr_array_unref);
   g_clear_pointer (&opt_env_if_host, g_strfreev);
   g_clear_pointer (&opt_freedesktop_app_id, g_free);