diff --git a/.gitignore b/.gitignore index 329b876b0cb8c836d0fb24568df2d53c61c97aa6..54314a50d115608f9b2255a044fb9a56ce97bac6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ /libcapsule_*.tar.[gx]z /pressure-vessel-[0-9]*.tar.gz /relocatable-install/ +/subprojects/steam-runtime-tools/ diff --git a/THIRD-PARTY.md b/THIRD-PARTY.md index aab21266a4b48e21ad136e0fd7def75e64c02cb3..e4c524bc04063a9621c50f6779a535a16feb0f22 100644 --- a/THIRD-PARTY.md +++ b/THIRD-PARTY.md @@ -10,11 +10,17 @@ same place as pressure-vessel, or from pressure-vessel incorporates code from GNOME libglnx, variously licensed under [LGPL-2.0-or-later][] and [LGPL-2.1-or-later][]. Complete source code can be obtained from the same place as -pressure-vessel. +pressure-vessel, or from <http://repo.steampowered.com/steamrt/>. pressure-vessel incorporates code from Flatpak, licensed under [LGPL-2.1-or-later][]. Complete source code can be obtained from the -same place as pressure-vessel. +same place as pressure-vessel, or from +<http://repo.steampowered.com/steamrt/>. + +pressure-vessel includes the steam-runtime-tools library and utilities, +which are licensed under the [MIT][] license. See steam-runtime-tools.txt. +Complete source code can be obtained from the same place as pressure-vessel, +or from <http://repo.steampowered.com/steamrt/>. Binary releases of pressure-vessel include the following third-party programs and libraries: @@ -47,6 +53,9 @@ programs and libraries: - libz.so.1 from zlib: [Zlib][] license. See zlib.txt. +- libjson-glib-1.0.so.0 from json-glib: [LGPL-2.0-or-later][]. See + json-glib.txt. + Complete source code can be obtained from the same place as pressure-vessel, or from <http://repo.steampowered.com/steamrt/>. diff --git a/build-relocatable-install.py b/build-relocatable-install.py index cf86be7c5a03069468bfefe48d2bedfda3f14dcd..8bd52e776b120efcec360df4fefa9be7fe1a4a5f 100755 --- a/build-relocatable-install.py +++ b/build-relocatable-install.py @@ -78,11 +78,13 @@ ARCHS = [ DEPENDENCIES = { 'libcapsule-tools-relocatable': 'libcapsule', 'libelf1': 'elfutils', + 'libsteam-runtime-tools-0-helpers': 'steam-runtime-tools', 'zlib1g': 'zlib', } # program to install => binary package WRAPPED_PROGRAMS = { 'bwrap': 'bubblewrap', + 'steam-runtime-system-info': 'steam-runtime-tools-bin', } PRIMARY_ARCH_DEPENDENCIES = { 'bubblewrap': 'bubblewrap', @@ -90,10 +92,12 @@ PRIMARY_ARCH_DEPENDENCIES = { 'libcap2': 'libcap2', 'libffi6': 'libffi', 'libglib2.0-0': 'glib2.0', + 'libjson-glib-1.0-0': 'json-glib', 'libmount1': 'util-linux', 'libpcre3': 'pcre3', - 'libxau6': 'libxau', 'libselinux1': 'libselinux', + 'libsteam-runtime-tools-0-0': 'steam-runtime-tools', + 'libxau6': 'libxau', } SCRIPTS = [ 'pressure-vessel-locale-gen', @@ -233,6 +237,7 @@ def main(): raise RuntimeError('--output directory must not already exist') os.makedirs(os.path.join(installation, 'bin'), exist_ok=True) + os.makedirs(os.path.join(installation, 'libexec'), exist_ok=True) os.makedirs(os.path.join(installation, 'metadata'), exist_ok=True) for arch in ARCHS: @@ -291,6 +296,35 @@ def main(): os.path.join(installation, 'bin'), ) + path = '/usr/libexec/steam-runtime-tools-0' + + if not os.path.exists(path): + package = 'libsteam-runtime-tools-0-helpers' + v_check_call([ + 'apt-get', + 'download', + package + ':' + arch.name, + ], cwd=tmpdir) + v_check_call( + 'dpkg-deb -X {}_*_{}.deb build-relocatable'.format( + quote(package), + quote(arch.name), + ), + cwd=tmpdir, + shell=True, + ) + path = '{}/build-relocatable/{}'.format(tmpdir, path) + + for tool in glob.glob(os.path.join(path, arch.multiarch + '-*')): + install_exe( + tool, + os.path.join( + installation, + 'libexec', + 'steam-runtime-tools-0', + ), + ) + primary_architecture = subprocess.check_output([ 'dpkg', '--print-architecture', ]).decode('utf-8').strip() @@ -329,8 +363,10 @@ def main(): 'soname:libXau.so.6', 'soname:libcap.so.2', 'soname:libgio-2.0.so.0', + 'soname:libjson-glib-1.0.so.0', 'soname:libpcre.so.3', 'soname:libselinux.so.1', + 'soname:libsteam-runtime-tools-0.so.0', ]) for so in glob.glob( diff --git a/ci/Dockerfile.in b/ci/Dockerfile.in index 86e6adba22d4026222dc143f93f77f0b3b2c942c..29def092ee4b20e919879837633dcc094771a25a 100644 --- a/ci/Dockerfile.in +++ b/ci/Dockerfile.in @@ -17,9 +17,13 @@ apt-get -y install \ libmount1 \ libpcre3 \ libselinux1 \ + libsteam-runtime-tools-0-dev \ + libsteam-runtime-tools-0-helpers:amd64 \ + libsteam-runtime-tools-0-helpers:i386 \ libxau6 \ locales \ pandoc \ + steam-runtime-tools-bin \ zlib1g:amd64 \ zlib1g:i386 \ ${NULL+} diff --git a/debian/control b/debian/control index 8d88b32de8ef242d0b95b1bf406ea832941f6412..4db9d42c50126e90e3d3119ac242cdf7a2f9787a 100644 --- a/debian/control +++ b/debian/control @@ -6,6 +6,7 @@ Standards-Version: 4.4.0 Build-Depends: debhelper (>= 9), libglib2.0-dev, + libsteam-runtime-tools-0-dev (>= 0.20190926.0~), libxau-dev, locales <!nocheck> | locales-all <!nocheck>, meson, @@ -22,6 +23,7 @@ Multi-Arch: foreign Depends: bubblewrap, libcapsule-tools-relocatable, + steam-runtime-tools-bin, ${misc:Depends}, ${shlibs:Depends}, Recommends: @@ -37,6 +39,7 @@ Architecture: amd64 Multi-Arch: foreign Depends: libcapsule-tools-relocatable, + libsteam-runtime-tools-0-helpers, ${misc:Depends}, ${shlibs:Depends}, Description: Steam container launcher - cross-architecture dependencies @@ -49,6 +52,7 @@ Architecture: i386 Multi-Arch: foreign Depends: libcapsule-tools-relocatable, + libsteam-runtime-tools-0-helpers, ${misc:Depends}, ${shlibs:Depends}, Description: Steam container launcher - cross-architecture dependencies diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml index 430e49fcff1797fa9288e6ee73a505180b7e700c..4ff147849a8587c9d51508af9c8c019547294a24 100644 --- a/debian/gitlab-ci.yml +++ b/debian/gitlab-ci.yml @@ -29,6 +29,9 @@ variables: # Set non-empty to allow CI_ALLOW_MISSING_SOURCES: '' + STEAM_RUNTIME_TOOLS_GIT_REPO: https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.steamos.cloud/steam/steam-runtime-tools.git + STEAM_RUNTIME_TOOLS_GIT_BRANCH: master + build: variables: BUILD_IMAGE: docker.internal.steamos.cloud/steamos/package-builder:buster @@ -40,11 +43,10 @@ build:devel: - | set -eux - apt-get -y --no-install-recommends install \ - libglib2.0-dev \ - libxau-dev \ - meson \ - ${NULL+} + git clone \ + -b${STEAM_RUNTIME_TOOLS_GIT_BRANCH} \ + ${STEAM_RUNTIME_TOOLS_GIT_REPO} \ + subprojects/steam-runtime-tools meson _build ninja -C _build @@ -81,9 +83,13 @@ build:scout: libcapsule0 \ libcapsule-tools-relocatable:amd64 \ libcapsule-tools-relocatable:i386 \ + libsteam-runtime-tools-0-dev \ + libsteam-runtime-tools-0-helpers:amd64 \ + libsteam-runtime-tools-0-helpers:i386 \ libglib2.0-dev \ libxau-dev \ meson \ + steam-runtime-tools-bin ${NULL+} meson \ diff --git a/debian/tests/relocatable-install b/debian/tests/relocatable-install index 5bd50727a8e23285290c36ecbeff6aba509b3551..5a623a1dfe3ace957baf87c3ebcb4b28d0e78f86 100755 --- a/debian/tests/relocatable-install +++ b/debian/tests/relocatable-install @@ -4,9 +4,15 @@ set -eux dpkg --add-architecture amd64 dpkg --add-architecture i386 +apt-get -y update apt-get -y install \ libcapsule-tools-relocatable:amd64 \ libcapsule-tools-relocatable:i386 \ + libsteam-runtime-tools-0-0:amd64 \ + libsteam-runtime-tools-0-0:i386 \ + libsteam-runtime-tools-0-helpers:amd64 \ + libsteam-runtime-tools-0-helpers:i386 \ + steam-runtime-tools-bin \ ${NULL+} /usr/lib/pressure-vessel/relocatable/bin/pressure-vessel-build-relocatable-install \ diff --git a/meson.build b/meson.build index 295cae89abd3670b58e29f2bcbf18e1610bf5d79..30d2004f3d60e404d53b3579ddfc3af6faada974 100644 --- a/meson.build +++ b/meson.build @@ -177,6 +177,12 @@ executable( '-Wno-unused-local-typedefs', ], dependencies : [ + dependency( + 'steam-runtime-tools-0', + required : true, + fallback : ['steam-runtime-tools', 'libsteamrt_dep'], + default_options : ['gtk_doc=false'], + ), dependency('gio-unix-2.0', required : true), dependency('xau', required : true), subproject('libglnx').get_variable('libglnx_dep'), diff --git a/src/wrap.c b/src/wrap.c index a621b73653e00e2ccb0eb60751d5046945046ae1..d40ae0e9bf47cdd18fa2a198df1a081f4f0dd357 100644 --- a/src/wrap.c +++ b/src/wrap.c @@ -33,10 +33,14 @@ #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.h" +#include <steam-runtime-tools/steam-runtime-tools.h> + #include "bwrap.h" -#include "glib-backports.h" #include "flatpak-bwrap-private.h" #include "flatpak-run-private.h" #include "flatpak-utils-private.h" @@ -450,6 +454,193 @@ ensure_locales (gboolean on_host, } } +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, @@ -484,10 +675,21 @@ bind_runtime (FlatpakBwrap *bwrap, 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; 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); @@ -583,6 +785,65 @@ bind_runtime (FlatpakBwrap *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++) @@ -666,6 +927,8 @@ bind_runtime (FlatpakBwrap *bwrap, 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. */ @@ -687,6 +950,79 @@ bind_runtime (FlatpakBwrap *bwrap, 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) @@ -853,6 +1189,154 @@ bind_runtime (FlatpakBwrap *bwrap, g_debug ("Using included locale data from container"); } + 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; + + 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); + 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; + + 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); + search_path_append (vulkan_path, json_in_container); + } + } + if (!pv_bwrap_bind_usr (bwrap, "/", "/run/host", error)) return FALSE; @@ -867,6 +1351,28 @@ bind_runtime (FlatpakBwrap *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(). diff --git a/subprojects/steam-runtime-tools.wrap b/subprojects/steam-runtime-tools.wrap new file mode 100644 index 0000000000000000000000000000000000000000..f30180ac0896545be6bbb92a3f6a83a1738b9919 --- /dev/null +++ b/subprojects/steam-runtime-tools.wrap @@ -0,0 +1,4 @@ +[wrap-git] +directory = steam-runtime-tools +url = https://gitlab.steamos.cloud/steam/steam-runtime-tools.git +revision = head