/* * Copyright © 2019-2021 Collabora Ltd. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Include these before steam-runtime-tools.h so that its backport of * G_DEFINE_AUTOPTR_CLEANUP_FUNC will be visible to it */ #include "steam-runtime-tools/glib-backports-internal.h" #include "steam-runtime-tools/json-glib-backports-internal.h" #include <steam-runtime-tools/steam-runtime-tools.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <libelf.h> #include <glib.h> #include <glib/gstdio.h> #include "steam-runtime-tools/graphics-internal.h" #include "steam-runtime-tools/system-info.h" #include "steam-runtime-tools/utils-internal.h" #include "graphics-test-defines.h" #include "test-utils.h" static const char *argv0; static gchar *global_sysroots; typedef struct { gchar *srcdir; gchar *builddir; const gchar *sysroots; gchar *sysroot; gchar **fake_icds_envp; } Fixture; typedef enum { ICD_MODE_NORMAL, ICD_MODE_XDG_DIRS, ICD_MODE_FLATPAK, ICD_MODE_EXPLICIT_DIRS, ICD_MODE_EXPLICIT_FILENAMES, ICD_MODE_RELATIVE_FILENAMES, } IcdMode; typedef struct { IcdMode icd_mode; } Config; static const char * icd_mode_to_string (IcdMode mode) { switch (mode) { #define CASE(x) \ case ICD_MODE_ ## x: \ return #x; CASE (NORMAL) CASE (XDG_DIRS) CASE (FLATPAK) CASE (EXPLICIT_DIRS) CASE (EXPLICIT_FILENAMES) CASE (RELATIVE_FILENAMES) default: g_return_val_if_reached ("?"); #undef CASE } } static void setup (Fixture *f, gconstpointer context) { const Config *config = context; f->builddir = g_strdup (g_getenv ("G_TEST_BUILDDIR")); if (f->builddir == NULL) f->builddir = g_path_get_dirname (argv0); f->sysroots = global_sysroots; if (g_chdir (f->sysroots) != 0) g_error ("chdir %s: %s", f->sysroots, g_strerror (errno)); f->fake_icds_envp = g_get_environ (); f->fake_icds_envp = g_environ_unsetenv (f->fake_icds_envp, "VK_ADD_DRIVER_FILES"); f->fake_icds_envp = g_environ_unsetenv (f->fake_icds_envp, "VK_DRIVER_FILES"); f->fake_icds_envp = g_environ_unsetenv (f->fake_icds_envp, "VK_ICD_FILENAMES"); if (config != NULL && config->icd_mode == ICD_MODE_FLATPAK) { f->sysroot = g_build_filename (f->sysroots, "fake-icds-flatpak", NULL); /* Some of the mock helper programs rely on this, so we set it * even though SrtSystemInfo doesn't use it any more */ f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "SRT_TEST_SYSROOT", f->sysroot, TRUE); } else if (config == NULL || config->icd_mode != ICD_MODE_RELATIVE_FILENAMES) { f->sysroot = g_build_filename (f->sysroots, "fake-icds", NULL); /* Some of the mock helper programs rely on this, so we set it * even though SrtSystemInfo doesn't use it any more */ f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "SRT_TEST_SYSROOT", f->sysroot, TRUE); } f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "HOME", "/home", TRUE); if (config != NULL && config->icd_mode == ICD_MODE_XDG_DIRS) { f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "XDG_CONFIG_HOME", "/confhome", TRUE); f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "XDG_CONFIG_DIRS", "/confdir", TRUE); f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "XDG_DATA_HOME", "/datahome", TRUE); f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "XDG_DATA_DIRS", "/datadir", TRUE); } else { f->fake_icds_envp = g_environ_unsetenv (f->fake_icds_envp, "XDG_CONFIG_HOME"); f->fake_icds_envp = g_environ_unsetenv (f->fake_icds_envp, "XDG_CONFIG_DIRS"); f->fake_icds_envp = g_environ_unsetenv (f->fake_icds_envp, "XDG_DATA_HOME"); f->fake_icds_envp = g_environ_unsetenv (f->fake_icds_envp, "XDG_DATA_DIRS"); } if (config != NULL && config->icd_mode == ICD_MODE_EXPLICIT_FILENAMES) { f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "__EGL_VENDOR_LIBRARY_FILENAMES", "/not-a-file:" "/null.json:" "/false.json:" "/str.json:" "/no-library.json", TRUE); f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "__EGL_EXTERNAL_PLATFORM_CONFIG_FILENAMES", "/not-a-file:" "/no-library.json", TRUE); f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "VK_DRIVER_FILES", "/not-a-file:" "/null.json:" "/false.json:" "/str.json:" "/no-library.json:" "/no-api-version.json:" "/partial.json", TRUE); /* This will be ignored, because VK_DRIVER_FILES "wins" */ f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "VK_ICD_FILENAMES", "/null.json", TRUE); /* This will be ignored, because VK_DRIVER_FILES "wins" */ f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "VK_ADD_DRIVER_FILES", "/added.json", TRUE); } else if (config != NULL && config->icd_mode == ICD_MODE_RELATIVE_FILENAMES) { f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "__EGL_VENDOR_LIBRARY_FILENAMES", "fake-icds/not-a-file:" "fake-icds/usr/share/glvnd/egl_vendor.d/50_mesa.json:" "fake-icds/null.json:" "fake-icds/false.json:" "fake-icds/str.json:" "fake-icds/no-library.json", TRUE); f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "__EGL_EXTERNAL_PLATFORM_CONFIG_FILENAMES", "fake-icds/not-a-file:" "fake-icds/no-library.json", TRUE); /* Exercise the backwards-compatible VK_ICD_FILENAMES here */ f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "VK_ICD_FILENAMES", "fake-icds/not-a-file:" "fake-icds/usr/share/vulkan/icd.d/intel_icd.x86_64.json:" "fake-icds/null.json:" "fake-icds/false.json:" "fake-icds/str.json:" "fake-icds/no-library.json:" "fake-icds/no-api-version.json", TRUE); /* This will be ignored, because VK_ICD_FILENAMES "wins" */ f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "VK_ADD_DRIVER_FILES", "fake-icds/added.json", TRUE); } else if (config != NULL && config->icd_mode == ICD_MODE_XDG_DIRS) { f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "VK_ADD_DRIVER_FILES", "/added.json", TRUE); f->fake_icds_envp = g_environ_unsetenv (f->fake_icds_envp, "__EGL_VENDOR_LIBRARY_FILENAMES"); } else { f->fake_icds_envp = g_environ_unsetenv (f->fake_icds_envp, "__EGL_VENDOR_LIBRARY_FILENAMES"); } if (config != NULL && config->icd_mode == ICD_MODE_EXPLICIT_DIRS) { f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "__EGL_VENDOR_LIBRARY_DIRS", "/egl1:/egl2", TRUE); f->fake_icds_envp = g_environ_setenv (f->fake_icds_envp, "__EGL_EXTERNAL_PLATFORM_CONFIG_DIRS", "/egl1", TRUE); } else { f->fake_icds_envp = g_environ_unsetenv (f->fake_icds_envp, "__EGL_VENDOR_LIBRARY_DIRS"); f->fake_icds_envp = g_environ_unsetenv (f->fake_icds_envp, "__EGL_EXTERNAL_PLATFORM_CONFIG_DIRS"); } } static void teardown (Fixture *f, gconstpointer context) { G_GNUC_UNUSED const Config *config = context; g_free (f->builddir); g_free (f->sysroot); g_strfreev (f->fake_icds_envp); } /* * Test basic functionality of the SrtGraphics object. */ static void test_object (Fixture *f, gconstpointer context) { g_autoptr(SrtGraphics) graphics = NULL; SrtGraphicsIssues issues; SrtGraphicsLibraryVendor library_vendor; gboolean vendor_neutral; g_autofree gchar *messages = NULL; g_autofree gchar *tuple = NULL; g_autofree gchar *renderer = NULL; g_autofree gchar *version = NULL; int exit_status; int terminating_signal; g_test_message ("Entering %s", G_STRFUNC); graphics = _srt_graphics_new("mock-good", SRT_WINDOW_SYSTEM_GLX, SRT_RENDERING_INTERFACE_GL, SRT_GRAPHICS_LIBRARY_VENDOR_GLVND, SRT_TEST_GOOD_GRAPHICS_RENDERER, SRT_TEST_GOOD_GRAPHICS_VERSION, NULL, SRT_GRAPHICS_ISSUES_NONE, "", 0, 0); g_assert_cmpint (srt_graphics_get_issues (graphics), ==, SRT_GRAPHICS_ISSUES_NONE); g_assert_cmpstr (srt_graphics_get_multiarch_tuple (graphics), ==, "mock-good"); g_assert_cmpstr (srt_graphics_get_renderer_string (graphics), ==, SRT_TEST_GOOD_GRAPHICS_RENDERER); g_assert_cmpstr (srt_graphics_get_version_string (graphics), ==, SRT_TEST_GOOD_GRAPHICS_VERSION); g_assert_cmpstr (srt_graphics_get_messages (graphics), ==, NULL); vendor_neutral = srt_graphics_library_is_vendor_neutral (graphics, &library_vendor); g_assert_cmpint (library_vendor, ==, SRT_GRAPHICS_LIBRARY_VENDOR_GLVND); g_assert_cmpint (srt_graphics_get_exit_status (graphics), ==, 0); g_assert_cmpint (srt_graphics_get_terminating_signal (graphics), ==, 0); g_assert_true (vendor_neutral); g_object_get (graphics, "messages", &messages, "multiarch-tuple", &tuple, "issues", &issues, "library-vendor", &library_vendor, "renderer-string", &renderer, "version-string", &version, "exit-status", &exit_status, "terminating-signal", &terminating_signal, NULL); g_assert_cmpint (issues, ==, SRT_GRAPHICS_ISSUES_NONE); g_assert_cmpint (library_vendor, ==, SRT_GRAPHICS_LIBRARY_VENDOR_GLVND); g_assert_cmpstr (messages, ==, NULL); g_assert_cmpstr (tuple, ==, "mock-good"); g_assert_cmpstr (renderer, ==, SRT_TEST_GOOD_GRAPHICS_RENDERER); g_assert_cmpstr (version, ==, SRT_TEST_GOOD_GRAPHICS_VERSION); g_assert_cmpint (exit_status, ==, 0); g_assert_cmpint (terminating_signal, ==, 0); } /* * Test that the X11 window system is normalized correctly. */ static void test_normalize_window_system (Fixture *f, gconstpointer context) { static struct TestVector { const char *description; /* These nested structs are just to provide an obvious visual * distinction between input and output. */ struct { SrtWindowSystem winsys; SrtRenderingInterface iface; } in; struct { SrtWindowSystem winsys; const char *parameters_string; } out; } test_vectors[] = { /* * winsys iface-> GL | GLESv2 | Vulkan | * ----------+-------------+------------------+----------------+ * X11 | (glx/gl) | (egl_x11/glesv2) | x11/vulkan | * GLX | glx/gl | (!) | (!) | * EGL_X11 | egl_x11/gl | egl_x11/glesv2 | (!) | * Wayland | wayland/gl | wayland/glesv2 | wayland/vulkan | * * (We don't implement Wayland yet, but if we did, it would behave * like this.) * * Key: (x): alias for x; (!): invalid/makes no sense */ { "X11/GL is shorthand for GLX/GL", { SRT_WINDOW_SYSTEM_X11, SRT_RENDERING_INTERFACE_GL }, { SRT_WINDOW_SYSTEM_GLX, "glx/gl" } }, { "X11/GLESv2 is shorthand for EGL_X11/GLESv2", { SRT_WINDOW_SYSTEM_X11, SRT_RENDERING_INTERFACE_GLESV2 }, { SRT_WINDOW_SYSTEM_EGL_X11, "egl_x11/glesv2" } }, { "X11/Vulkan is neither GLX nor EGL", { SRT_WINDOW_SYSTEM_X11, SRT_RENDERING_INTERFACE_VULKAN }, { SRT_WINDOW_SYSTEM_X11, "x11/vulkan" } }, { "GLX/GL can be selected explicitly", { SRT_WINDOW_SYSTEM_GLX, SRT_RENDERING_INTERFACE_GL }, { SRT_WINDOW_SYSTEM_GLX, "glx/gl" } }, /* GLX/GLESv2 omitted: doesn't work in practice */ /* GLX/Vulkan omitted: makes no sense */ { "EGL_X11/GLESv2 can be selected explicitly", { SRT_WINDOW_SYSTEM_EGL_X11, SRT_RENDERING_INTERFACE_GLESV2 }, { SRT_WINDOW_SYSTEM_EGL_X11, "egl_x11/glesv2" } }, { "EGL_X11/GL can be selected explicitly", { SRT_WINDOW_SYSTEM_EGL_X11, SRT_RENDERING_INTERFACE_GL }, { SRT_WINDOW_SYSTEM_EGL_X11, "egl_x11/gl" } }, /* EGL_X11/Vulkan omitted: makes no sense */ /* Wayland row omitted: not implemented yet (scout's libwayland-* * are too old) */ }; gsize i; g_autoptr(SrtSystemInfo) info = srt_system_info_new (NULL); g_test_message ("Entering %s", G_STRFUNC); srt_system_info_set_helpers_path (info, f->builddir); for (i = 0; i < G_N_ELEMENTS (test_vectors); i++) { const struct TestVector *test_vector = &test_vectors[i]; SrtGraphics *graphics = NULL; SrtWindowSystem winsys; SrtRenderingInterface iface; gchar *tmp; g_test_message ("%s", test_vector->description); srt_system_info_check_graphics (info, "mock-good", test_vector->in.winsys, test_vector->in.iface, &graphics); g_assert_nonnull (graphics); g_assert_cmpint (srt_graphics_get_rendering_interface (graphics), ==, test_vector->in.iface); g_assert_cmpint (srt_graphics_get_window_system (graphics), ==, test_vector->out.winsys); tmp = srt_graphics_dup_parameters_string (graphics); g_assert_cmpstr (tmp, ==, test_vector->out.parameters_string); g_free (tmp); g_object_get (graphics, "rendering-interface", &iface, "window-system", &winsys, NULL); g_assert_cmpint (iface, ==, test_vector->in.iface); g_assert_cmpint (winsys, ==, test_vector->out.winsys); g_clear_object (&graphics); srt_system_info_check_graphics (info, "mock-bad", test_vector->in.winsys, test_vector->in.iface, &graphics); g_assert_nonnull (graphics); g_assert_cmpint (srt_graphics_get_rendering_interface (graphics), ==, test_vector->in.iface); g_assert_cmpint (srt_graphics_get_window_system (graphics), ==, test_vector->out.winsys); tmp = srt_graphics_dup_parameters_string (graphics); g_assert_cmpstr (tmp, ==, test_vector->out.parameters_string); g_free (tmp); g_object_get (graphics, "rendering-interface", &iface, "window-system", &winsys, NULL); g_assert_cmpint (iface, ==, test_vector->in.iface); g_assert_cmpint (winsys, ==, test_vector->out.winsys); g_clear_object (&graphics); } } /* * Test a mock system with sigusr terminating signal */ static void test_sigusr (Fixture *f, gconstpointer context) { g_autoptr(SrtGraphics) graphics = NULL; SrtGraphicsIssues issues; g_autofree gchar *tuple = NULL; int exit_status; int terminating_signal; g_test_message ("Entering %s", G_STRFUNC); g_autoptr(SrtSystemInfo) info = srt_system_info_new (NULL); srt_system_info_set_helpers_path (info, f->builddir); issues = srt_system_info_check_graphics (info, "mock-sigusr", SRT_WINDOW_SYSTEM_GLX, SRT_RENDERING_INTERFACE_GL, &graphics); g_assert_cmpint (issues, ==, SRT_GRAPHICS_ISSUES_CANNOT_LOAD); g_object_get (graphics, "multiarch-tuple", &tuple, "issues", &issues, "exit-status", &exit_status, "terminating-signal", &terminating_signal, NULL); g_assert_cmpint (issues, ==, SRT_GRAPHICS_ISSUES_CANNOT_LOAD); g_assert_cmpstr (tuple, ==, "mock-sigusr"); /* Depending on the version of timeout(1), it will have either * exited with status 128 + SIGUSR1, or killed itself with SIGUSR1 */ if (exit_status != -1) { g_assert_cmpint (exit_status, ==, 128 + SIGUSR1); } g_assert_cmpint (terminating_signal, ==, SIGUSR1); } /* * Assert that @icd is internally consistent. */ static void assert_egl_icd (SrtEglIcd *icd) { g_autoptr(GError) error = NULL; g_autoptr(GError) error_property = NULL; SrtLoadableIssues issues; g_autofree gchar *json_path = NULL; g_autofree gchar *library_path = NULL; g_autofree gchar *resolved = NULL; g_autofree gchar *resolved_property = NULL; g_assert_true (SRT_IS_EGL_ICD (icd)); g_object_get (icd, "error", &error_property, "issues", &issues, "json-path", &json_path, "library-path", &library_path, "resolved-library-path", &resolved_property, NULL); resolved = srt_egl_icd_resolve_library_path (icd); g_assert_cmpstr (json_path, !=, NULL); g_assert_cmpstr (json_path, ==, srt_egl_icd_get_json_path (icd)); g_assert_true (g_path_is_absolute (json_path)); /* These are invariants, even if they're NULL */ g_assert_cmpstr (library_path, ==, srt_egl_icd_get_library_path (icd)); g_assert_cmpstr (resolved_property, ==, resolved); g_assert_cmpint (issues, ==, srt_egl_icd_get_issues (icd)); if (error_property == NULL) { srt_egl_icd_check_error (icd, &error); g_assert_no_error (error); g_assert_true (srt_egl_icd_check_error (icd, NULL)); g_assert_true (srt_egl_icd_check_error (icd, &error)); g_assert_no_error (error); g_assert_no_error (error_property); g_assert_cmpstr (library_path, !=, NULL); g_assert_cmpstr (resolved, !=, NULL); g_assert_cmpstr (resolved_property, !=, NULL); if (strchr (resolved, '/') == NULL) { g_assert_cmpstr (resolved, ==, library_path); } else { g_assert_true (g_path_is_absolute (resolved)); } } else { g_assert_false (srt_egl_icd_check_error (icd, NULL)); g_assert_false (srt_egl_icd_check_error (icd, &error)); g_assert_nonnull (error); g_assert_error (error, error_property->domain, error_property->code); g_assert_cmpstr (error->message, ==, error_property->message); g_assert_cmpstr (library_path, ==, NULL); g_assert_cmpstr (resolved, ==, NULL); g_assert_cmpstr (resolved_property, ==, NULL); } } /* * Assert that @icd is internally consistent and in a failed state. */ static void assert_egl_icd_has_error (SrtEglIcd *icd) { g_assert_false (srt_egl_icd_check_error (icd, NULL)); assert_egl_icd (icd); } /* * Assert that @icd is internally consistent and in a successful state. */ static void assert_egl_icd_no_error (SrtEglIcd *icd) { GError *error = NULL; srt_egl_icd_check_error (icd, &error); g_assert_no_error (error); assert_egl_icd (icd); } /* * Assert that @module is internally consistent. */ static void assert_egl_external_platform (SrtEglExternalPlatform *module) { g_autoptr(GError) error = NULL; g_autoptr(GError) error_property = NULL; SrtLoadableIssues issues; g_autofree gchar *json_path = NULL; g_autofree gchar *library_path = NULL; g_autofree gchar *resolved = NULL; g_autofree gchar *resolved_property = NULL; g_assert_true (SRT_IS_EGL_EXTERNAL_PLATFORM (module)); g_object_get (module, "error", &error_property, "issues", &issues, "json-path", &json_path, "library-path", &library_path, "resolved-library-path", &resolved_property, NULL); resolved = srt_egl_external_platform_resolve_library_path (module); g_assert_cmpstr (json_path, !=, NULL); g_assert_cmpstr (json_path, ==, srt_egl_external_platform_get_json_path (module)); g_assert_true (g_path_is_absolute (json_path)); /* These are invariants, even if they're NULL */ g_assert_cmpstr (library_path, ==, srt_egl_external_platform_get_library_path (module)); g_assert_cmpstr (resolved_property, ==, resolved); g_assert_cmpint (issues, ==, srt_egl_external_platform_get_issues (module)); if (error_property == NULL) { srt_egl_external_platform_check_error (module, &error); g_assert_no_error (error); g_assert_true (srt_egl_external_platform_check_error (module, NULL)); g_assert_true (srt_egl_external_platform_check_error (module, &error)); g_assert_no_error (error); g_assert_no_error (error_property); g_assert_cmpstr (library_path, !=, NULL); g_assert_cmpstr (resolved, !=, NULL); g_assert_cmpstr (resolved_property, !=, NULL); if (strchr (resolved, '/') == NULL) { g_assert_cmpstr (resolved, ==, library_path); } else { g_assert_true (g_path_is_absolute (resolved)); } } else { g_assert_false (srt_egl_external_platform_check_error (module, NULL)); g_assert_false (srt_egl_external_platform_check_error (module, &error)); g_assert_nonnull (error); g_assert_error (error, error_property->domain, error_property->code); g_assert_cmpstr (error->message, ==, error_property->message); g_assert_cmpstr (library_path, ==, NULL); g_assert_cmpstr (resolved, ==, NULL); g_assert_cmpstr (resolved_property, ==, NULL); } } /* * Assert that @module is internally consistent and in a failed state. */ static void assert_egl_external_platform_has_error (SrtEglExternalPlatform *module) { g_assert_false (srt_egl_external_platform_check_error (module, NULL)); assert_egl_external_platform (module); } /* * Assert that @module is internally consistent and in a successful state. */ static void assert_egl_external_platform_no_error (SrtEglExternalPlatform *module) { GError *error = NULL; srt_egl_external_platform_check_error (module, &error); g_assert_no_error (error); assert_egl_external_platform (module); } /* * We don't assert that filenames are literally the same, because they * might canonicalize differently in the presence of symlinks: we just * assert that they are the same file. */ static void assert_same_file (const char *expected, const char *actual) { struct stat expected_stat, actual_stat; if (stat (expected, &expected_stat) != 0) g_error ("stat %s: %s", expected, g_strerror (errno)); if (stat (actual, &actual_stat) != 0) g_error ("stat %s: %s", actual, g_strerror (errno)); if (!_srt_is_same_stat (&expected_stat, &actual_stat)) g_error ("%s is not the same file as %s", expected, actual); } static void test_icd_egl (Fixture *f, gconstpointer context) { const Config *config = context; g_autoptr(SrtSystemInfo) info = srt_system_info_new (NULL); g_autoptr(SrtObjectList) icds = NULL; g_autofree gchar *resolved = NULL; const GList *iter; const char * const multiarchs[] = { "x86_64-mock-abi", NULL }; g_test_message ("Entering %s", G_STRFUNC); if (config != NULL) g_test_message ("Mode: %s", icd_mode_to_string (config->icd_mode)); if (f->sysroot != NULL) g_test_message ("Sysroot: %s", glnx_basename (f->sysroot)); srt_system_info_set_environ (info, f->fake_icds_envp); srt_system_info_set_sysroot (info, f->sysroot); srt_system_info_set_helpers_path (info, f->builddir); icds = srt_system_info_list_egl_icds (info, multiarchs); for (iter = icds; iter != NULL; iter = iter->next) { GError *error = NULL; g_test_message ("ICD: %s", srt_egl_icd_get_json_path (iter->data)); if (srt_egl_icd_check_error (iter->data, &error)) { g_test_message ("\tlibrary: %s", srt_egl_icd_get_library_path (iter->data)); } else { g_test_message ("\terror: %s", error->message); g_clear_error (&error); } } if (config != NULL && config->icd_mode == ICD_MODE_EXPLICIT_DIRS) { SrtEglIcd *other; iter = icds; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/egl1/AAA.json"); assert_egl_icd_has_error (iter->data); other = srt_egl_icd_new_replace_library_path (iter->data, "/run/host/libEGL_icd.so"); /* Copying an invalid ICD yields another invalid ICD. */ assert_egl_icd_has_error (iter->data); g_object_unref (other); iter = iter->next; /* We sort lexicographically with strcmp(), so BBB comes before a. */ g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/egl1/BBB.json"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/egl1/a.json"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/egl1/b.json"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/egl1/soname_zlib_dup.json"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_DUPLICATED); assert_egl_icd_no_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/egl1/z.json"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_UNSUPPORTED); assert_egl_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/egl2/absolute.json"); assert_egl_icd_no_error (iter->data); g_assert_cmpstr (srt_egl_icd_get_library_path (iter->data), ==, "/opt/libEGL_myvendor.so"); resolved = srt_egl_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "/opt/libEGL_myvendor.so"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/egl2/soname_zlib.json"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_DUPLICATED); assert_egl_icd_no_error (iter->data); iter = iter->next; g_assert_null (iter); } else if (config != NULL && config->icd_mode == ICD_MODE_EXPLICIT_FILENAMES) { iter = icds; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/not-a-file"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/null.json"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/false.json"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/str.json"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/no-library.json"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_icd_has_error (iter->data); iter = iter->next; g_assert_null (iter); } else if (config != NULL && config->icd_mode == ICD_MODE_RELATIVE_FILENAMES) { const char *path; iter = icds; g_assert_nonnull (iter); path = srt_egl_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/not-a-file")); g_assert_true (g_path_is_absolute (path)); assert_egl_icd_has_error (iter->data); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); path = srt_egl_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/usr/share/glvnd/egl_vendor.d/50_mesa.json")); g_assert_true (g_path_is_absolute (path)); assert_same_file ("fake-icds/usr/share/glvnd/egl_vendor.d/50_mesa.json", path); assert_egl_icd_no_error (iter->data); g_assert_cmpstr (srt_egl_icd_get_library_path (iter->data), ==, "libEGL_mesa.so.0"); resolved = srt_egl_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "libEGL_mesa.so.0"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); iter = iter->next; g_assert_nonnull (iter); path = srt_egl_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/null.json")); g_assert_true (g_path_is_absolute (path)); assert_same_file ("fake-icds/null.json", path); assert_egl_icd_has_error (iter->data); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); path = srt_egl_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/false.json")); g_assert_true (g_path_is_absolute (path)); assert_same_file ("fake-icds/false.json", path); assert_egl_icd_has_error (iter->data); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); path = srt_egl_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/str.json")); g_assert_true (g_path_is_absolute (path)); assert_same_file ("fake-icds/str.json", path); assert_egl_icd_has_error (iter->data); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); path = srt_egl_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/no-library.json")); g_assert_true (g_path_is_absolute (path)); assert_same_file ("fake-icds/no-library.json", path); assert_egl_icd_has_error (iter->data); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_null (iter); } else if (config != NULL && config->icd_mode == ICD_MODE_FLATPAK) { g_autoptr(SrtEglIcd) other = NULL; iter = icds; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/usr/lib/x86_64-mock-abi/GL/glvnd/egl_vendor.d/relative.json"); assert_egl_icd_no_error (iter->data); g_assert_cmpstr (srt_egl_icd_get_library_path (iter->data), ==, "../libEGL_relative.so"); resolved = srt_egl_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "/usr/lib/x86_64-mock-abi/GL/glvnd/egl_vendor.d/../libEGL_relative.so"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); other = srt_egl_icd_new_replace_library_path (iter->data, "/run/host/libEGL.so"); assert_egl_icd_no_error (iter->data); g_assert_cmpstr (srt_egl_icd_get_json_path (other), ==, srt_egl_icd_get_json_path (iter->data)); /* The pointers are not equal */ g_assert_true (srt_egl_icd_get_json_path (other) != srt_egl_icd_get_json_path (iter->data)); g_assert_cmpstr (srt_egl_icd_get_library_path (other), ==, "/run/host/libEGL.so"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); iter = iter->next; g_assert_null (iter); } else { /* EGL ICDs don't respect the XDG variables, so XDG_DIRS is the same * as NORMAL. */ iter = icds; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/etc/glvnd/egl_vendor.d/invalid.json"); /* This one is invalid. */ g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_icd_get_json_path (iter->data), ==, "/usr/share/glvnd/egl_vendor.d/50_mesa.json"); assert_egl_icd_no_error (iter->data); g_assert_cmpstr (srt_egl_icd_get_library_path (iter->data), ==, "libEGL_mesa.so.0"); resolved = srt_egl_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "libEGL_mesa.so.0"); g_assert_cmpint (srt_egl_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); iter = iter->next; g_assert_null (iter); } } static void test_egl_external_platform (Fixture *f, gconstpointer context) { const Config *config = context; g_autoptr(SrtSystemInfo) info = srt_system_info_new (NULL); g_autoptr(SrtObjectList) exts = NULL; g_autofree gchar *resolved = NULL; const GList *iter; const char * const multiarchs[] = { "x86_64-mock-abi", NULL }; g_test_message ("Entering %s", G_STRFUNC); if (config != NULL) g_test_message ("Mode: %s", icd_mode_to_string (config->icd_mode)); if (f->sysroot != NULL) g_test_message ("Sysroot: %s", glnx_basename (f->sysroot)); srt_system_info_set_environ (info, f->fake_icds_envp); srt_system_info_set_sysroot (info, f->sysroot); srt_system_info_set_helpers_path (info, f->builddir); exts = srt_system_info_list_egl_external_platforms (info, multiarchs); for (iter = exts; iter != NULL; iter = iter->next) { GError *error = NULL; g_test_message ("External platform: %s", srt_egl_external_platform_get_json_path (iter->data)); if (srt_egl_external_platform_check_error (iter->data, &error)) { g_test_message ("\tlibrary: %s", srt_egl_external_platform_get_library_path (iter->data)); } else { g_test_message ("\terror: %s", error->message); g_clear_error (&error); } } if (config != NULL && config->icd_mode == ICD_MODE_FLATPAK) { iter = exts; g_assert_null (iter); } else if (config != NULL && config->icd_mode == ICD_MODE_EXPLICIT_DIRS) { iter = exts; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_external_platform_get_json_path (iter->data), ==, "/egl1/AAA.json"); assert_egl_external_platform_has_error (iter->data); iter = iter->next; /* We sort lexicographically with strcmp(), so BBB comes before a. */ g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_external_platform_get_json_path (iter->data), ==, "/egl1/BBB.json"); g_assert_cmpint (srt_egl_external_platform_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_external_platform_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_external_platform_get_json_path (iter->data), ==, "/egl1/a.json"); g_assert_cmpint (srt_egl_external_platform_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_external_platform_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_external_platform_get_json_path (iter->data), ==, "/egl1/b.json"); g_assert_cmpint (srt_egl_external_platform_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_external_platform_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_external_platform_get_json_path (iter->data), ==, "/egl1/soname_zlib_dup.json"); /* In the ECL ICDs test case, this shows up as a duplicate, but since * we're not looking in /egl2 here, it does not */ g_assert_cmpint (srt_egl_external_platform_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); assert_egl_external_platform_no_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_external_platform_get_json_path (iter->data), ==, "/egl1/z.json"); g_assert_cmpint (srt_egl_external_platform_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_UNSUPPORTED); assert_egl_external_platform_has_error (iter->data); iter = iter->next; g_assert_null (iter); } else if (config != NULL && config->icd_mode == ICD_MODE_RELATIVE_FILENAMES) { const char *path; iter = exts; g_assert_nonnull (iter); path = srt_egl_external_platform_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/not-a-file")); g_assert_true (g_path_is_absolute (path)); assert_egl_external_platform_has_error (iter->data); g_assert_cmpint (srt_egl_external_platform_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); path = srt_egl_external_platform_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/no-library.json")); g_assert_true (g_path_is_absolute (path)); assert_same_file ("fake-icds/no-library.json", path); assert_egl_external_platform_has_error (iter->data); g_assert_cmpint (srt_egl_external_platform_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_null (iter); } else if (config != NULL && config->icd_mode == ICD_MODE_EXPLICIT_FILENAMES) { iter = exts; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_external_platform_get_json_path (iter->data), ==, "/not-a-file"); g_assert_cmpint (srt_egl_external_platform_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_external_platform_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_external_platform_get_json_path (iter->data), ==, "/no-library.json"); g_assert_cmpint (srt_egl_external_platform_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_external_platform_has_error (iter->data); iter = iter->next; g_assert_null (iter); } else { /* EGL external platforms don't respect the XDG variables, so XDG_DIRS * is the same as NORMAL. */ iter = exts; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_external_platform_get_json_path (iter->data), ==, "/etc/egl/egl_external_platform.d/invalid.json"); /* This one is invalid. */ g_assert_cmpint (srt_egl_external_platform_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_egl_external_platform_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_egl_external_platform_get_json_path (iter->data), ==, "/usr/share/egl/egl_external_platform.d/10_nvidia_wayland.json"); assert_egl_external_platform_no_error (iter->data); g_assert_cmpstr (srt_egl_external_platform_get_library_path (iter->data), ==, "libnvidia-egl-wayland.so.1"); resolved = srt_egl_external_platform_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "libnvidia-egl-wayland.so.1"); g_assert_cmpint (srt_egl_external_platform_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); iter = iter->next; g_assert_null (iter); } } /* * Assert that @icd is internally consistent. */ static void assert_vulkan_icd (SrtVulkanIcd *icd) { g_autoptr(GError) error = NULL; g_autoptr(GError) error_property = NULL; SrtLoadableIssues issues; g_autofree gchar *api_version = NULL; g_autofree gchar *json_path = NULL; g_autofree gchar *library_path = NULL; g_autofree gchar *resolved = NULL; g_autofree gchar *resolved_property = NULL; g_assert_true (SRT_IS_VULKAN_ICD (icd)); g_object_get (icd, "api-version", &api_version, "error", &error_property, "issues", &issues, "json-path", &json_path, "library-path", &library_path, "resolved-library-path", &resolved_property, NULL); resolved = srt_vulkan_icd_resolve_library_path (icd); g_assert_cmpstr (json_path, !=, NULL); g_assert_cmpstr (json_path, ==, srt_vulkan_icd_get_json_path (icd)); g_assert_true (g_path_is_absolute (json_path)); /* These are invariants, even if they're NULL */ g_assert_cmpstr (api_version, ==, srt_vulkan_icd_get_api_version (icd)); g_assert_cmpstr (library_path, ==, srt_vulkan_icd_get_library_path (icd)); g_assert_cmpstr (resolved_property, ==, resolved); g_assert_cmpint (issues, ==, srt_vulkan_icd_get_issues (icd)); if (error_property == NULL) { srt_vulkan_icd_check_error (icd, &error); g_assert_no_error (error); g_assert_true (srt_vulkan_icd_check_error (icd, NULL)); g_assert_true (srt_vulkan_icd_check_error (icd, &error)); g_assert_no_error (error); g_assert_no_error (error_property); g_assert_cmpstr (library_path, !=, NULL); g_assert_cmpstr (api_version, !=, NULL); g_assert_cmpstr (resolved, !=, NULL); g_assert_cmpstr (resolved_property, !=, NULL); if (strchr (resolved, '/') == NULL) { g_assert_cmpstr (resolved, ==, library_path); } else { g_assert_true (g_path_is_absolute (resolved)); } } else { g_assert_false (srt_vulkan_icd_check_error (icd, NULL)); g_assert_false (srt_vulkan_icd_check_error (icd, &error)); g_assert_nonnull (error); g_assert_error (error, error_property->domain, error_property->code); g_assert_cmpstr (error->message, ==, error_property->message); g_assert_cmpstr (library_path, ==, NULL); g_assert_cmpstr (api_version, ==, NULL); g_assert_cmpstr (resolved, ==, NULL); g_assert_cmpstr (resolved_property, ==, NULL); } } /* * Assert that @icd is internally consistent and in a failed state. */ static void assert_vulkan_icd_has_error (SrtVulkanIcd *icd) { g_assert_false (srt_vulkan_icd_check_error (icd, NULL)); assert_vulkan_icd (icd); } /* * Assert that @icd is internally consistent and in a successful state. */ static void assert_vulkan_icd_no_error (SrtVulkanIcd *icd) { GError *error = NULL; srt_vulkan_icd_check_error (icd, &error); g_assert_no_error (error); assert_vulkan_icd (icd); } static void assert_vulkan_icds (const SrtObjectList *icds, gconstpointer context) { const Config *config = context; const GList *iter; g_autofree gchar *resolved = NULL; for (iter = icds; iter != NULL; iter = iter->next) { GError *error = NULL; g_test_message ("ICD: %s", srt_vulkan_icd_get_json_path (iter->data)); if (srt_vulkan_icd_check_error (iter->data, &error)) { g_test_message ("\tlibrary: %s", srt_vulkan_icd_get_library_path (iter->data)); } else { g_test_message ("\terror: %s", error->message); g_clear_error (&error); } } if (config != NULL && config->icd_mode == ICD_MODE_EXPLICIT_FILENAMES) { SrtVulkanIcd *other; /* We tried to add added.json via VK_ADD_DRIVER_FILES, but * VK_DRIVER_FILES "wins" and so VK_ADD_DRIVER_FILES is ignored */ iter = icds; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/not-a-file"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_vulkan_icd_has_error (iter->data); other = srt_vulkan_icd_new_replace_library_path (iter->data, "/run/host/vulkan_icd.so"); /* Copying an invalid ICD yields another invalid ICD. */ g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_vulkan_icd_has_error (iter->data); g_object_unref (other); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/null.json"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_vulkan_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/false.json"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_vulkan_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/str.json"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_vulkan_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/no-library.json"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_vulkan_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/no-api-version.json"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); assert_vulkan_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/partial.json"); assert_vulkan_icd_no_error (iter->data); g_assert_cmpstr (srt_vulkan_icd_get_library_path (iter->data), ==, "libpartial.so"); g_assert_cmpstr (srt_vulkan_icd_get_api_version (iter->data), ==, "1.2.101"); resolved = srt_vulkan_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "libpartial.so"); g_clear_pointer (&resolved, g_free); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_API_SUBSET); iter = iter->next; g_assert_null (iter); } else if (config != NULL && config->icd_mode == ICD_MODE_RELATIVE_FILENAMES) { const char *path; /* We tried to add added.json via VK_ADD_DRIVER_FILES, but * VK_ICD_FILENAMES "wins" and so VK_ADD_DRIVER_FILES is ignored */ iter = icds; g_assert_nonnull (iter); path = srt_vulkan_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/not-a-file")); g_assert_true (g_path_is_absolute (path)); assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); path = srt_vulkan_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/usr/share/vulkan/icd.d/intel_icd.x86_64.json")); g_assert_true (g_path_is_absolute (path)); assert_same_file ("fake-icds/usr/share/vulkan/icd.d/intel_icd.x86_64.json", path); assert_vulkan_icd_no_error (iter->data); g_assert_cmpstr (srt_vulkan_icd_get_library_path (iter->data), ==, "/usr/lib/x86_64-mock-abi/libvulkan_intel.so"); g_assert_cmpstr (srt_vulkan_icd_get_api_version (iter->data), ==, "1.1.102"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); iter = iter->next; g_assert_nonnull (iter); path = srt_vulkan_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/null.json")); g_assert_true (g_path_is_absolute (path)); assert_same_file ("fake-icds/null.json", path); assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); path = srt_vulkan_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/false.json")); g_assert_true (g_path_is_absolute (path)); assert_same_file ("fake-icds/false.json", path); assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); path = srt_vulkan_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/str.json")); g_assert_true (g_path_is_absolute (path)); assert_same_file ("fake-icds/str.json", path); assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); path = srt_vulkan_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/no-library.json")); g_assert_true (g_path_is_absolute (path)); assert_same_file ("fake-icds/no-library.json", path); assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); path = srt_vulkan_icd_get_json_path (iter->data); g_assert_true (g_str_has_suffix (path, "/fake-icds/no-api-version.json")); g_assert_true (g_path_is_absolute (path)); assert_same_file ("fake-icds/no-api-version.json", path); assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_null (iter); } else if (config != NULL && config->icd_mode == ICD_MODE_FLATPAK) { SrtVulkanIcd *other; iter = icds; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/etc/xdg/vulkan/icd.d/invalid.json"); /* This is not valid JSON (it's an empty file) so loading it fails */ assert_vulkan_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/etc/vulkan/icd.d/basename.json"); assert_vulkan_icd_no_error (iter->data); g_assert_cmpstr (srt_vulkan_icd_get_library_path (iter->data), ==, "libvulkan_basename.so"); g_assert_cmpstr (srt_vulkan_icd_get_api_version (iter->data), ==, "1.2.3"); resolved = srt_vulkan_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "libvulkan_basename.so"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); g_free (resolved); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/usr/lib/x86_64-mock-abi/GL/vulkan/icd.d/invalid.json"); /* This has a JSON array, not an object, so loading it fails */ assert_vulkan_icd_has_error (iter->data); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/usr/lib/x86_64-mock-abi/vulkan/icd.d/relative.json"); assert_vulkan_icd_no_error (iter->data); resolved = srt_vulkan_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "/usr/lib/x86_64-mock-abi/vulkan/icd.d/../libvulkan_relative.so"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_DUPLICATED); g_free (resolved); other = srt_vulkan_icd_new_replace_library_path (iter->data, "/run/host/vulkan_icd.so"); assert_vulkan_icd_no_error (iter->data); g_assert_cmpstr (srt_vulkan_icd_get_json_path (other), ==, srt_vulkan_icd_get_json_path (iter->data)); /* The pointers are not equal */ g_assert_true (srt_vulkan_icd_get_json_path (other) != srt_vulkan_icd_get_json_path (iter->data)); g_assert_cmpstr (srt_vulkan_icd_get_api_version (other), ==, srt_vulkan_icd_get_api_version (iter->data)); /* The pointers are not equal */ g_assert_true (srt_vulkan_icd_get_api_version (other) != srt_vulkan_icd_get_api_version (iter->data)); g_assert_cmpstr (srt_vulkan_icd_get_library_path (other), ==, "/run/host/vulkan_icd.so"); /* The %SRT_LOADABLE_ISSUES_DUPLICATED issues flag is preserved */ g_assert_cmpint (srt_vulkan_icd_get_issues (other), ==, SRT_LOADABLE_ISSUES_DUPLICATED); g_object_unref (other); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/home/.local/share/vulkan/icd.d/relative_new.json"); assert_vulkan_icd_no_error (iter->data); resolved = srt_vulkan_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "/usr/lib/x86_64-mock-abi/vulkan/icd.d/../libvulkan_relative.so"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_DUPLICATED); g_free (resolved); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/usr/local/share/vulkan/icd.d/intel_icd.i686.json"); assert_vulkan_icd_no_error (iter->data); g_assert_cmpstr (srt_vulkan_icd_get_library_path (iter->data), ==, "/usr/lib/i386-mock-abi/libvulkan_intel.so"); g_assert_cmpstr (srt_vulkan_icd_get_api_version (iter->data), ==, "1.1.102"); resolved = srt_vulkan_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "/usr/lib/i386-mock-abi/libvulkan_intel.so"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/usr/share/vulkan/icd.d/intel_icd.x86_64.json"); assert_vulkan_icd_no_error (iter->data); g_assert_cmpstr (srt_vulkan_icd_get_library_path (iter->data), ==, "/usr/lib/x86_64-mock-abi/libvulkan_intel.so"); g_assert_cmpstr (srt_vulkan_icd_get_api_version (iter->data), ==, "1.1.102"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); iter = iter->next; g_assert_null (iter); } else if (config != NULL && config->icd_mode == ICD_MODE_XDG_DIRS) { iter = icds; /* Added via VK_ADD_DRIVER_FILES */ g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/added.json"); assert_vulkan_icd_no_error (iter->data); g_assert_cmpstr (srt_vulkan_icd_get_library_path (iter->data), ==, "libadded.so"); g_assert_cmpstr (srt_vulkan_icd_get_api_version (iter->data), ==, "1.1.102"); resolved = srt_vulkan_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "libadded.so"); g_clear_pointer (&resolved, g_free); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); iter = iter->next; /* Vulkan-Loader >= 1.2.198 respects XDG_CONFIG_HOME */ g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/confhome/vulkan/icd.d/invalid.json"); /* Not format 1.0.x, so we can't be confident that we're reading * it correctly */ assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_UNSUPPORTED); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/confdir/vulkan/icd.d/invalid.json"); /* Not format 1.0.x, so we can't be confident that we're reading * it correctly */ assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_UNSUPPORTED); iter = iter->next; g_assert_nonnull (iter); /* /etc is unaffected by XDG variables */ g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/etc/vulkan/icd.d/basename.json"); assert_vulkan_icd_no_error (iter->data); g_assert_cmpstr (srt_vulkan_icd_get_library_path (iter->data), ==, "libvulkan_basename.so"); g_assert_cmpstr (srt_vulkan_icd_get_api_version (iter->data), ==, "1.2.3"); resolved = srt_vulkan_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "libvulkan_basename.so"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/datahome/vulkan/icd.d/invalid.json"); /* Missing API version */ assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); /* We load $XDG_DATA_HOME *as well as* ~/.local/share. * This was originally based on a mis-reading of the reference * Vulkan loader, but it's desirable to keep this until * https://github.com/ValveSoftware/steam-for-linux/issues/8337 * gets fixed. */ g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/home/.local/share/vulkan/icd.d/invalid.json"); /* This one lacks the required format version */ assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); /* We load $XDG_DATA_DIRS instead of /usr/local/share:/usr/share. * In this case it only has one item. */ g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/datadir/vulkan/icd.d/invalid.json"); /* Not format 1.0.x, so we can't be confident that we're reading * it correctly */ assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_UNSUPPORTED); iter = iter->next; g_assert_null (iter); } else { iter = icds; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/home/.config/vulkan/icd.d/invalid.json"); /* This one lacks the required format version */ assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/etc/xdg/vulkan/icd.d/invalid.json"); /* This is not valid JSON (it's an empty file) so loading it fails */ assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/etc/vulkan/icd.d/basename.json"); assert_vulkan_icd_no_error (iter->data); g_assert_cmpstr (srt_vulkan_icd_get_library_path (iter->data), ==, "libvulkan_basename.so"); g_assert_cmpstr (srt_vulkan_icd_get_api_version (iter->data), ==, "1.2.3"); resolved = srt_vulkan_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "libvulkan_basename.so"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); g_free (resolved); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/home/.local/share/vulkan/icd.d/invalid.json"); /* This one lacks the required format version */ assert_vulkan_icd_has_error (iter->data); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_CANNOT_LOAD); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/usr/local/share/vulkan/icd.d/intel_icd.i686.json"); assert_vulkan_icd_no_error (iter->data); g_assert_cmpstr (srt_vulkan_icd_get_library_path (iter->data), ==, "/usr/lib/i386-mock-abi/libvulkan_intel.so"); g_assert_cmpstr (srt_vulkan_icd_get_api_version (iter->data), ==, "1.1.102"); resolved = srt_vulkan_icd_resolve_library_path (iter->data); g_assert_cmpstr (resolved, ==, "/usr/lib/i386-mock-abi/libvulkan_intel.so"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); iter = iter->next; g_assert_nonnull (iter); g_assert_cmpstr (srt_vulkan_icd_get_json_path (iter->data), ==, "/usr/share/vulkan/icd.d/intel_icd.x86_64.json"); assert_vulkan_icd_no_error (iter->data); g_assert_cmpstr (srt_vulkan_icd_get_library_path (iter->data), ==, "/usr/lib/x86_64-mock-abi/libvulkan_intel.so"); g_assert_cmpstr (srt_vulkan_icd_get_api_version (iter->data), ==, "1.1.102"); g_assert_cmpint (srt_vulkan_icd_get_issues (iter->data), ==, SRT_LOADABLE_ISSUES_NONE); iter = iter->next; g_assert_null (iter); } } static void test_icd_vulkan_explicit_multiarch (Fixture *f, gconstpointer context) { const Config *config = context; g_autoptr(SrtSystemInfo) info = srt_system_info_new (NULL); g_autoptr(SrtObjectList) icds = NULL; const char * const multiarchs[] = { "x86_64-mock-abi", NULL }; g_test_message ("Entering %s", G_STRFUNC); if (config != NULL) g_test_message ("Mode: %s", icd_mode_to_string (config->icd_mode)); if (f->sysroot != NULL) g_test_message ("Sysroot: %s", glnx_basename (f->sysroot)); srt_system_info_set_environ (info, f->fake_icds_envp); srt_system_info_set_sysroot (info, f->sysroot); srt_system_info_set_helpers_path (info, f->builddir); icds = srt_system_info_list_vulkan_icds (info, multiarchs); assert_vulkan_icds (icds, context); } static void test_icd_vulkan_implicit_multiarch (Fixture *f, gconstpointer context) { const Config *config = context; g_autoptr(SrtSystemInfo) info = srt_system_info_new (NULL); g_autoptr(SrtObjectList) icds = NULL; const char * const multiarchs[] = { "x86_64-mock-abi", NULL }; g_test_message ("Entering %s", G_STRFUNC); if (config != NULL) g_test_message ("Mode: %s", icd_mode_to_string (config->icd_mode)); if (f->sysroot != NULL) g_test_message ("Sysroot: %s", glnx_basename (f->sysroot)); srt_system_info_set_environ (info, f->fake_icds_envp); srt_system_info_set_sysroot (info, f->sysroot); srt_system_info_set_helpers_path (info, f->builddir); srt_system_info_set_multiarch_tuples (info, multiarchs); icds = srt_system_info_list_vulkan_icds (info, NULL); assert_vulkan_icds (icds, context); } typedef struct { const gchar *name; const gchar *description; const gchar *library_path; const gchar *api_version; const gchar *component_layers[5]; /* This needs to be an explicit value because, if in input we had a single * JSON with multiple layers, we write it to the filesystem as separated JSON * files. So the output is not always exactly the same as the input JSON */ const gchar *json_to_compare; SrtLoadableIssues issues; const gchar *error_message_suffix; const gchar *error_domain; gint error_code; } VulkanLayerTest; typedef struct { const gchar *description; const gchar *sysroot; const gchar *vk_add_layer_path; const gchar *vk_layer_path; const gchar *home; const gchar *xdg_config_dirs; const gchar *xdg_data_dirs; VulkanLayerTest explicit_layers[5]; VulkanLayerTest implicit_layers[5]; } VulkanLayersTest; static const VulkanLayersTest vulkan_layers_test[] = { { .description = "Good single VK_LAYER_PATH dir", .sysroot = "debian10", .vk_layer_path = "/custom_path", .explicit_layers = { { .name = "VK_LAYER_MANGOHUD_overlay", .description = "Vulkan Hud Overlay", .library_path = "/usr/$LIB/libMangoHud.so", .api_version = "1.2.135", .json_to_compare = "expectations/MangoHud.json", }, { .name = "VK_LAYER_LUNARG_overlay", .description = "LunarG HUD layer", .library_path = "vkOverlayLayer.so", .api_version = "1.1.5", .json_to_compare = "custom_path/Single-good-layer.json", }, }, /* Implicit layers are not affected by VK_LAYER_PATH env */ .implicit_layers = { { .name = "VK_LAYER_first", .description = "Vulkan first layer", .library_path = "libFirst.so", .api_version = "1.0.13", .json_to_compare = "expectations/MultiLayers_part1.json", }, { .name = "VK_LAYER_second", .description = "Vulkan second layer", .library_path = "libSecond.so", .api_version = "1.0.13", .json_to_compare = "expectations/MultiLayers_part2.json", }, }, }, { .description = "Good implicit dirs", .sysroot = "debian10", .home = "/home/debian", .xdg_config_dirs = "/usr/local/etc:::", .vk_add_layer_path = "/custom_path", .explicit_layers = { /* VK_ADD_LAYER_PATH is searched before the default search path */ { .name = "VK_LAYER_MANGOHUD_overlay", .description = "Vulkan Hud Overlay", .api_version = "1.2.135", .library_path = "/usr/$LIB/libMangoHud.so", .json_to_compare = "expectations/MangoHud.json", }, { .name = "VK_LAYER_LUNARG_overlay", .description = "LunarG HUD layer", .api_version = "1.1.5", .library_path = "vkOverlayLayer.so", .json_to_compare = "custom_path/Single-good-layer.json", }, { .name = "VK_LAYER_MESA_overlay", .description = "Mesa Overlay layer", .library_path = "libVkLayer_MESA_overlay.so", .api_version = "1.1.73", .json_to_compare = "usr/local/etc/vulkan/explicit_layer.d/VkLayer_MESA_overlay.json", }, }, .implicit_layers = { { .name = "VK_LAYER_VALVE_steam_overlay_64", .description = "Steam Overlay Layer", .library_path = "/home/debian/.local/share/Steam/ubuntu12_64/steamoverlayvulkanlayer.so", .api_version = "1.2.136", .json_to_compare = "home/debian/.local/share/vulkan/implicit_layer.d/steamoverlay_x86_64.json", }, { .name = "VK_LAYER_first", .description = "Vulkan first layer", .library_path = "libFirst.so", .api_version = "1.0.13", .json_to_compare = "expectations/MultiLayers_part1.json", }, { .name = "VK_LAYER_second", .description = "Vulkan second layer", .library_path = "libSecond.so", .api_version = "1.0.13", .json_to_compare = "expectations/MultiLayers_part2.json", }, }, }, { .description = "Layers with missing required fields and unsupported version", .sysroot = "fedora", .implicit_layers = { // incomplete_layer.json { .issues = SRT_LOADABLE_ISSUES_CANNOT_LOAD, .error_message_suffix = "cannot be parsed because it is missing a required field", .error_domain = "g-io-error-quark", .error_code = G_IO_ERROR_FAILED, }, // newer_layer.json { .issues = SRT_LOADABLE_ISSUES_UNSUPPORTED, .error_message_suffix = "is not supported", .error_domain = "g-io-error-quark", .error_code = G_IO_ERROR_FAILED, }, }, }, { .description = "Meta layer", .sysroot = "fedora", .vk_layer_path = "/custom_path:/custom_path2:/custom_path3", /* /usr/local/etc is not searched because VK_LAYER_PATH "wins" */ .vk_add_layer_path = "/usr/local/etc", .explicit_layers = { { .name = "VK_LAYER_META_layer", .description = "Meta-layer example", .api_version = "1.0.9000", .component_layers = { "VK_LAYER_KHRONOS_validation", "VK_LAYER_LUNARG_api_dump", }, .json_to_compare = "custom_path/meta_layer.json", }, { .name = "VK_LAYER_MANGOHUD_overlay", .description = "Vulkan Hud Overlay", .library_path = "/usr/$LIB/libMangoHud.so", .api_version = "1.2.135", .json_to_compare = "custom_path2/MangoHud.json", .issues = SRT_LOADABLE_ISSUES_DUPLICATED, }, { .name = "VK_LAYER_MANGOHUD_overlay", .description = "Vulkan Hud Overlay", .library_path = "/usr/lib32/libMangoHud.so", .api_version = "1.2.135", .json_to_compare = "custom_path3/MangoHud_i386.json", .issues = SRT_LOADABLE_ISSUES_DUPLICATED, }, }, .implicit_layers = { // incomplete_layer.json { .issues = SRT_LOADABLE_ISSUES_CANNOT_LOAD, .error_message_suffix = "cannot be parsed because it is missing a required field", .error_domain = "g-io-error-quark", .error_code = G_IO_ERROR_FAILED, }, // newer_layer.json { .issues = SRT_LOADABLE_ISSUES_UNSUPPORTED, .error_message_suffix = "is not supported", .error_domain = "g-io-error-quark", .error_code = G_IO_ERROR_FAILED, }, }, }, { .description = "Special case for Flatpak", .sysroot = "fake-icds-flatpak", .explicit_layers = { /* /usr/lib/x86_64-mock-abi/GL/vulkan/explicit_layer.d/glext.json */ { .name = "VK_LAYER_GLEXT_explicit", .description = "GL extension's explicit layer", .library_path = "libVkLayer_GLEXT_explicit.so", .api_version = "1.1.73", }, /* /usr/lib/x86_64-mock-abi/vulkan/explicit_layer.d/runtime.json */ { .name = "VK_LAYER_RUNTIME_explicit", .description = "Runtime's explicit layer", .library_path = "libVkLayer_RUNTIME_explicit.so", .api_version = "1.1.73", }, /* /usr/lib/extensions/vulkan/share/vulkan/explicit_layer.d/mr3398.json */ { .name = "VK_LAYER_MESA_overlay", .description = "Mesa Overlay layer", .library_path = "libVkLayer_MESA_overlay.so", .api_version = "1.1.73", }, }, .implicit_layers = { /* /usr/lib/x86_64-mock-abi/GL/vulkan/implicit_layer.d/glext.json */ { .name = "VK_LAYER_GLEXT_implicit", .description = "GL extension's implicit layer", .library_path = "/usr/$LIB/GL/implicit/libLayer.so", .api_version = "1.2.135", }, /* /usr/lib/x86_64-mock-abi/vulkan/implicit_layer.d/runtime.json */ { .name = "VK_LAYER_RUNTIME_implicit", .description = "Runtime's implicit layer", .library_path = "/usr/$LIB/implicit/libLayer.so", .api_version = "1.2.135", }, /* /usr/lib/extensions/vulkan/share/vulkan/implicit_layer.d/mr3398.json */ { .name = "VK_LAYER_MANGOHUD_overlay", .description = "Vulkan Hud Overlay", .library_path = "/usr/lib/extensions/vulkan/$LIB/mangohud/libMangoHud.so", .api_version = "1.2.135", }, }, }, }; static void _test_layer_values (SrtVulkanLayer *layer, const VulkanLayerTest *test, const gchar *test_dir, const gchar *sysroot) { g_autoptr(GError) error = NULL; g_autoptr(SrtVulkanLayer) layer_dup = NULL; if (test->error_message_suffix != NULL) { g_assert_false (srt_vulkan_layer_check_error (layer, &error)); g_assert_true (g_str_has_suffix (error->message, test->error_message_suffix)); g_assert_cmpstr (g_quark_to_string (error->domain), ==, test->error_domain); g_assert_cmpint (error->code, ==, test->error_code); return; } g_assert_cmpstr (test->name, ==, srt_vulkan_layer_get_name (layer)); g_assert_cmpstr (test->description, ==, srt_vulkan_layer_get_description (layer)); g_assert_cmpstr (test->library_path, ==, srt_vulkan_layer_get_library_path (layer)); g_assert_cmpstr (test->api_version, ==, srt_vulkan_layer_get_api_version (layer)); g_assert_cmpint (test->issues, ==, srt_vulkan_layer_get_issues (layer)); layer_dup = srt_vulkan_layer_new_replace_library_path (layer, "/run/host/vulkan_layer.json"); g_assert_cmpstr (test->name, ==, srt_vulkan_layer_get_name (layer_dup)); g_assert_cmpstr (test->description, ==, srt_vulkan_layer_get_description (layer_dup)); g_assert_cmpstr (test->api_version, ==, srt_vulkan_layer_get_api_version (layer_dup)); g_assert_cmpint (test->issues, ==, srt_vulkan_layer_get_issues (layer_dup)); /* If library_path was NULL, this means we have a meta-layer. So even * after calling the replace function we still expect to have a * NULL library_path. */ if (test->library_path == NULL) g_assert_cmpstr (NULL, ==, srt_vulkan_layer_get_library_path (layer_dup)); else g_assert_cmpstr ("/run/host/vulkan_layer.json", ==, srt_vulkan_layer_get_library_path (layer_dup)); if (test->json_to_compare != NULL) { g_autofree gchar *input_contents = NULL; g_autofree gchar *output_contents = NULL; g_autofree gchar *input_json = NULL; g_autofree gchar *output_file = NULL; g_autoptr(JsonParser) parser = NULL; g_autoptr(JsonGenerator) generator = NULL; JsonNode *node = NULL; /* not owned */ output_file = g_build_filename (test_dir, test->name, NULL); srt_vulkan_layer_write_to_file (layer, output_file, &error); g_assert_no_error (error); g_file_get_contents (output_file, &output_contents, NULL, &error); g_assert_no_error (error); input_json = g_build_filename (sysroot, test->json_to_compare, NULL); parser = json_parser_new (); json_parser_load_from_file (parser, input_json, &error); g_assert_no_error (error); node = json_parser_get_root (parser); g_assert_nonnull (node); generator = json_generator_new (); json_generator_set_root (generator, node); json_generator_set_pretty (generator, TRUE); input_contents = json_generator_to_data (generator, NULL); g_assert_cmpstr (input_contents, ==, output_contents); } } static void test_layer_vulkan (Fixture *f, gconstpointer context) { g_auto(GStrv) vulkan_layer_envp = g_get_environ (); g_autofree gchar *tmp_dir = NULL; g_autoptr(GError) error = NULL; gsize i; const char * const multiarchs[] = { "x86_64-mock-abi", "i386-mock-abi", NULL }; g_test_message ("Entering %s", G_STRFUNC); tmp_dir = g_dir_make_tmp ("layers-test-XXXXXX", &error); g_assert_no_error (error); for (i = 0; i < G_N_ELEMENTS (vulkan_layers_test); i++) { const VulkanLayersTest *test = &vulkan_layers_test[i]; VulkanLayerTest layer_test; g_autoptr(SrtSystemInfo) info = NULL; g_autoptr(SrtObjectList) explicit_layers = NULL; g_autoptr(SrtObjectList) implicit_layers = NULL; g_autofree gchar *sysroot = NULL; /* Create a new empty temp sub directory for every test */ g_autofree gchar *test_num = g_strdup_printf ("%" G_GSIZE_FORMAT, i); g_autofree gchar *this_test_dir = g_build_filename (tmp_dir, test_num, NULL); const GList *iter; gsize j; g_test_message ("%s: %s", test->sysroot, test->description); g_mkdir (this_test_dir, 0755); sysroot = g_build_filename (f->sysroots, test->sysroot, NULL); vulkan_layer_envp = g_environ_setenv (vulkan_layer_envp, "SRT_TEST_SYSROOT", sysroot, TRUE); if (test->vk_layer_path == NULL) vulkan_layer_envp = g_environ_unsetenv (vulkan_layer_envp, "VK_LAYER_PATH"); else vulkan_layer_envp = g_environ_setenv (vulkan_layer_envp, "VK_LAYER_PATH", test->vk_layer_path, TRUE); if (test->vk_add_layer_path == NULL) vulkan_layer_envp = g_environ_unsetenv (vulkan_layer_envp, "VK_ADD_LAYER_PATH"); else vulkan_layer_envp = g_environ_setenv (vulkan_layer_envp, "VK_ADD_LAYER_PATH", test->vk_add_layer_path, TRUE); if (test->home == NULL) vulkan_layer_envp = g_environ_unsetenv (vulkan_layer_envp, "HOME"); else vulkan_layer_envp = g_environ_setenv (vulkan_layer_envp, "HOME", test->home, TRUE); if (test->xdg_config_dirs == NULL) vulkan_layer_envp = g_environ_unsetenv (vulkan_layer_envp, "XDG_CONFIG_DIRS"); else vulkan_layer_envp = g_environ_setenv (vulkan_layer_envp, "XDG_CONFIG_DIRS", test->xdg_config_dirs, TRUE); if (test->xdg_data_dirs == NULL) vulkan_layer_envp = g_environ_unsetenv (vulkan_layer_envp, "XDG_DATA_DIRS"); else vulkan_layer_envp = g_environ_setenv (vulkan_layer_envp, "XDG_DATA_DIRS", test->xdg_data_dirs, TRUE); info = srt_system_info_new (NULL); g_assert_nonnull (info); srt_system_info_set_environ (info, vulkan_layer_envp); srt_system_info_set_sysroot (info, sysroot); srt_system_info_set_multiarch_tuples (info, multiarchs); srt_system_info_set_helpers_path (info, f->builddir); explicit_layers = srt_system_info_list_explicit_vulkan_layers (info); for (iter = explicit_layers, j = 0; iter != NULL; iter = iter->next, j++) { layer_test = test->explicit_layers[j]; _test_layer_values (iter->data, &layer_test, this_test_dir, sysroot); } g_assert_cmpstr (test->explicit_layers[j].name, ==, NULL); implicit_layers = srt_system_info_list_implicit_vulkan_layers (info); for (iter = implicit_layers, j = 0; iter != NULL; iter = iter->next, j++) { layer_test = test->implicit_layers[j]; _test_layer_values (iter->data, &layer_test, this_test_dir, sysroot); } g_assert_cmpstr (test->implicit_layers[j].name, ==, NULL); /* No need to keep this around */ if (!_srt_rm_rf (this_test_dir)) g_debug ("Unable to remove the temp layers directory: %s", this_test_dir); } if (!_srt_rm_rf (tmp_dir)) g_debug ("Unable to remove the temp layers directory: %s", tmp_dir); } static void check_list_suffixes (const GList *list, const gchar * const *suffixes, SrtGraphicsModule module) { const gchar *value = NULL; const GList *iter; gsize i; for (i = 0; suffixes[i] != NULL; i++) g_test_message ("Expecting: %s", suffixes[i]); for (iter = list, i = 0; iter != NULL; iter = iter->next, i++) { switch (module) { case SRT_GRAPHICS_DRI_MODULE: value = srt_dri_driver_get_library_path (iter->data); break; case SRT_GRAPHICS_VAAPI_MODULE: value = srt_va_api_driver_get_library_path (iter->data); break; case SRT_GRAPHICS_VDPAU_MODULE: value = srt_vdpau_driver_get_library_path (iter->data); break; case SRT_GRAPHICS_GLX_MODULE: value = srt_glx_icd_get_library_soname (iter->data); break; case NUM_SRT_GRAPHICS_MODULES: default: g_return_if_reached (); } g_test_message ("Got: %s", value); g_assert_nonnull (suffixes[i]); g_assert_true (g_str_has_suffix (value, suffixes[i])); } g_assert_cmpstr (suffixes[i], ==, NULL); } static void check_list_extra (const GList *list, gsize non_extra, SrtGraphicsModule module) { gsize i = 0; for (const GList *iter = list; iter != NULL; iter = iter->next, i++) { gboolean is_extra = (i >= non_extra); switch (module) { case SRT_GRAPHICS_DRI_MODULE: g_assert_cmpint (is_extra, ==, srt_dri_driver_is_extra (iter->data)); break; case SRT_GRAPHICS_VAAPI_MODULE: g_assert_cmpint (is_extra, ==, srt_va_api_driver_is_extra (iter->data)); break; case SRT_GRAPHICS_VDPAU_MODULE: g_assert_cmpint (is_extra, ==, srt_vdpau_driver_is_extra (iter->data)); break; case SRT_GRAPHICS_GLX_MODULE: case NUM_SRT_GRAPHICS_MODULES: default: g_return_if_reached (); } } } static void check_list_links (const GList *list, const gchar * const *suffixes, SrtGraphicsModule module) { const gchar *value = NULL; gsize i = 0; for (const GList *iter = list; iter != NULL; iter = iter->next) { switch (module) { case SRT_GRAPHICS_VDPAU_MODULE: value = srt_vdpau_driver_get_library_link (iter->data); break; case SRT_GRAPHICS_GLX_MODULE: value = srt_glx_icd_get_library_path (iter->data); break; case SRT_GRAPHICS_VAAPI_MODULE: case SRT_GRAPHICS_DRI_MODULE: case NUM_SRT_GRAPHICS_MODULES: default: g_return_if_reached (); } /* If we don't expect any more symlinks, then "value" should be NULL too */ if (suffixes[i] == NULL) g_assert_cmpstr (value, ==, NULL); if (value == NULL) continue; g_assert_true (g_str_has_suffix (value, suffixes[i])); i++; } g_assert_cmpstr (suffixes[i], ==, NULL); } static void check_paths_are_absolute (const GList *list, SrtGraphicsModule module) { const gchar *library_path = NULL; for (const GList *iter = list; iter != NULL; iter = iter->next) { g_autofree gchar *absolute_path = NULL; switch (module) { case SRT_GRAPHICS_DRI_MODULE: library_path = srt_dri_driver_get_library_path (iter->data); absolute_path = srt_dri_driver_resolve_library_path (iter->data); break; case SRT_GRAPHICS_VDPAU_MODULE: library_path = srt_vdpau_driver_get_library_path (iter->data); absolute_path = srt_vdpau_driver_resolve_library_path (iter->data); break; case SRT_GRAPHICS_VAAPI_MODULE: library_path = srt_va_api_driver_get_library_path (iter->data); absolute_path = srt_va_api_driver_resolve_library_path (iter->data); break; case SRT_GRAPHICS_GLX_MODULE: case NUM_SRT_GRAPHICS_MODULES: default: g_return_if_reached (); } g_assert_cmpstr (library_path, ==, absolute_path); g_assert_nonnull (library_path); g_assert_cmpint (library_path[0], ==, '/'); } } static void check_paths_are_relative (const GList *list, SrtGraphicsModule module) { const gchar *library_path = NULL; gsize i = 0; for (const GList *iter = list; iter != NULL; iter = iter->next, i++) { g_autofree gchar *absolute_path = NULL; switch (module) { case SRT_GRAPHICS_DRI_MODULE: library_path = srt_dri_driver_get_library_path (iter->data); absolute_path = srt_dri_driver_resolve_library_path (iter->data); break; case SRT_GRAPHICS_VDPAU_MODULE: library_path = srt_vdpau_driver_get_library_path (iter->data); absolute_path = srt_vdpau_driver_resolve_library_path (iter->data); break; case SRT_GRAPHICS_VAAPI_MODULE: library_path = srt_va_api_driver_get_library_path (iter->data); absolute_path = srt_va_api_driver_resolve_library_path (iter->data); break; case SRT_GRAPHICS_GLX_MODULE: case NUM_SRT_GRAPHICS_MODULES: default: g_return_if_reached (); } g_assert_cmpstr (library_path, !=, absolute_path); g_assert_nonnull (library_path); g_assert_nonnull (absolute_path); g_assert_cmpint (library_path[0], !=, '/'); g_assert_cmpint (absolute_path[0], ==, '/'); assert_same_file (library_path, absolute_path); } } static void test_dri_debian10 (Fixture *f, gconstpointer context) { g_autoptr(SrtSystemInfo) info = NULL; g_auto(GStrv) envp = NULL; g_autofree gchar *sysroot = NULL; GList *dri; GList *va_api; const gchar *multiarch_tuples[] = {"i386-mock-debian", "x86_64-mock-debian", NULL}; const gchar *dri_suffixes_i386[] = {"/lib/i386-linux-gnu/dri/i965_dri.so", "/lib/i386-linux-gnu/dri/r300_dri.so", "/lib/i386-linux-gnu/dri/radeonsi_dri.so", NULL}; const gchar *dri_suffixes_x86_64[] = {"/lib/x86_64-linux-gnu/dri/i965_dri.so", "/lib/x86_64-linux-gnu/dri/r600_dri.so", "/lib/x86_64-linux-gnu/dri/radeon_dri.so", NULL}; const gchar *va_api_suffixes_i386[] = {"/lib/i386-linux-gnu/dri/r600_drv_video.so", NULL}; const gchar *va_api_suffixes_x86_64[] = {"/lib/x86_64-linux-gnu/dri/r600_drv_video.so", "/lib/x86_64-linux-gnu/dri/radeonsi_drv_video.so", NULL}; g_test_message ("Entering %s", G_STRFUNC); sysroot = g_build_filename (f->sysroots, "debian10", NULL); envp = g_get_environ (); envp = g_environ_setenv (envp, "SRT_TEST_SYSROOT", sysroot, TRUE); envp = g_environ_unsetenv (envp, "LIBGL_DRIVERS_PATH"); envp = g_environ_unsetenv (envp, "LIBVA_DRIVERS_PATH"); info = srt_system_info_new (NULL); srt_system_info_set_environ (info, envp); srt_system_info_set_sysroot (info, sysroot); srt_system_info_set_helpers_path (info, f->builddir); /* The output is guaranteed to be in aphabetical order */ g_test_message ("i386 DRI drivers..."); dri = srt_system_info_list_dri_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (dri, dri_suffixes_i386, SRT_GRAPHICS_DRI_MODULE); check_paths_are_absolute (dri, SRT_GRAPHICS_DRI_MODULE); g_list_free_full (dri, g_object_unref); g_test_message ("x86_64 DRI drivers..."); dri = srt_system_info_list_dri_drivers (info, multiarch_tuples[1], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (dri, dri_suffixes_x86_64, SRT_GRAPHICS_DRI_MODULE); check_paths_are_absolute (dri, SRT_GRAPHICS_DRI_MODULE); g_list_free_full (dri, g_object_unref); /* The output is guaranteed to be in aphabetical order */ g_test_message ("i386 VA-API drivers..."); va_api = srt_system_info_list_va_api_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (va_api, va_api_suffixes_i386, SRT_GRAPHICS_VAAPI_MODULE); check_paths_are_absolute (va_api, SRT_GRAPHICS_VAAPI_MODULE); g_list_free_full (va_api, g_object_unref); g_test_message ("x86_64 VA-API drivers..."); va_api = srt_system_info_list_va_api_drivers (info, multiarch_tuples[1], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (va_api, va_api_suffixes_x86_64, SRT_GRAPHICS_VAAPI_MODULE); check_paths_are_absolute (va_api, SRT_GRAPHICS_VAAPI_MODULE); g_list_free_full (va_api, g_object_unref); /* Do it again, this time using the cached result. * While doing it we also try to get the "extra" drivers. * We expect to receive the same drivers list as before because we are using * a multiarch tuple that is different from what we have in debian10/usr/lib * so _srt_get_extra_modules_folder will fail to split the path. * Anyway, even if the folder had the same name as the multiarch tuple, * we still would be unable to get extras because the drivers that we are * using (e.g. libGL.so.1) are just empty files, so `elf_begin` would fail. */ g_test_message ("i386 DRI drivers, from cache, with extras..."); dri = srt_system_info_list_dri_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_INCLUDE_ALL); check_list_suffixes (dri, dri_suffixes_i386, SRT_GRAPHICS_DRI_MODULE); g_list_free_full (dri, g_object_unref); g_test_message ("x86_64 DRI drivers, from cache, with extras..."); dri = srt_system_info_list_dri_drivers (info, multiarch_tuples[1], SRT_DRIVER_FLAGS_INCLUDE_ALL); check_list_suffixes (dri, dri_suffixes_x86_64, SRT_GRAPHICS_DRI_MODULE); g_list_free_full (dri, g_object_unref); g_test_message ("i386 VA-API drivers, from cache, with extras..."); va_api = srt_system_info_list_va_api_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_INCLUDE_ALL); check_list_suffixes (va_api, va_api_suffixes_i386, SRT_GRAPHICS_VAAPI_MODULE); g_list_free_full (va_api, g_object_unref); g_test_message ("x86_64 VA-API drivers, from cache, with extras..."); va_api = srt_system_info_list_va_api_drivers (info, multiarch_tuples[1], SRT_DRIVER_FLAGS_INCLUDE_ALL); check_list_suffixes (va_api, va_api_suffixes_x86_64, SRT_GRAPHICS_VAAPI_MODULE); g_list_free_full (va_api, g_object_unref); } static void test_dri_fedora (Fixture *f, gconstpointer context) { g_autoptr(SrtSystemInfo) info = NULL; g_auto(GStrv) envp = NULL; g_autofree gchar *sysroot = NULL; GList *dri; GList *va_api; const gchar *multiarch_tuples[] = {"i386-mock-fedora", "x86_64-mock-fedora", NULL}; const gchar *dri_suffixes_32[] = {"/usr/lib/dri/i965_dri.so", "/usr/lib/dri/r300_dri.so", "/usr/lib/dri/radeonsi_dri.so", NULL}; const gchar *dri_suffixes_64[] = {"/usr/lib64/dri/i965_dri.so", "/usr/lib64/dri/r600_dri.so", "/usr/lib64/dri/radeon_dri.so", NULL}; const gchar *va_api_suffixes_32[] = {"/usr/lib/dri/r600_drv_video.so", NULL}; const gchar *va_api_suffixes_64[] = {"/usr/lib64/dri/r600_drv_video.so", "/usr/lib64/dri/radeonsi_drv_video.so", NULL}; g_test_message ("Entering %s", G_STRFUNC); sysroot = g_build_filename (f->sysroots, "fedora", NULL); envp = g_get_environ (); envp = g_environ_setenv (envp, "SRT_TEST_SYSROOT", sysroot, TRUE); envp = g_environ_unsetenv (envp, "LIBGL_DRIVERS_PATH"); envp = g_environ_unsetenv (envp, "LIBVA_DRIVERS_PATH"); info = srt_system_info_new (NULL); srt_system_info_set_environ (info, envp); srt_system_info_set_sysroot (info, sysroot); srt_system_info_set_helpers_path (info, f->builddir); g_test_message ("i386 DRI drivers..."); dri = srt_system_info_list_dri_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (dri, dri_suffixes_32, SRT_GRAPHICS_DRI_MODULE); g_list_free_full (dri, g_object_unref); g_test_message ("x86_64 DRI drivers..."); dri = srt_system_info_list_dri_drivers (info, multiarch_tuples[1], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (dri, dri_suffixes_64, SRT_GRAPHICS_DRI_MODULE); g_list_free_full (dri, g_object_unref); g_test_message ("i386 VA-API drivers..."); va_api = srt_system_info_list_va_api_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (va_api, va_api_suffixes_32, SRT_GRAPHICS_VAAPI_MODULE); g_list_free_full (va_api, g_object_unref); g_test_message ("x86_64 VA-API drivers..."); va_api = srt_system_info_list_va_api_drivers (info, multiarch_tuples[1], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (va_api, va_api_suffixes_64, SRT_GRAPHICS_VAAPI_MODULE); g_list_free_full (va_api, g_object_unref); } static void test_dri_ubuntu16 (Fixture *f, gconstpointer context) { g_autoptr(SrtSystemInfo) info = NULL; g_auto(GStrv) envp = NULL; g_autofree gchar *sysroot = NULL; GList *dri; GList *va_api; const gchar *multiarch_tuples[] = {"x86_64-mock-ubuntu", NULL}; const gchar *dri_suffixes[] = {NULL}; const gchar *dri_suffixes_extra[] = {"/lib/dri/radeonsi_dri.so", "/lib/x86_64-mock-ubuntu/dri/i965_dri.so", "/lib/x86_64-mock-ubuntu/dri/radeon_dri.so", NULL}; const gchar *va_api_suffixes[] = {"/lib/x86_64-mock-ubuntu/dri/radeonsi_drv_video.so", NULL}; g_test_message ("Entering %s", G_STRFUNC); sysroot = g_build_filename (f->sysroots, "ubuntu16", NULL); envp = g_get_environ (); envp = g_environ_setenv (envp, "SRT_TEST_SYSROOT", sysroot, TRUE); envp = g_environ_setenv (envp, "SRT_TEST_ELF_CLASS_FROM_PATH", "1", TRUE); envp = g_environ_unsetenv (envp, "LIBGL_DRIVERS_PATH"); envp = g_environ_unsetenv (envp, "LIBVA_DRIVERS_PATH"); info = srt_system_info_new (NULL); srt_system_info_set_environ (info, envp); srt_system_info_set_sysroot (info, sysroot); srt_system_info_set_helpers_path (info, f->builddir); g_test_message ("DRI drivers..."); dri = srt_system_info_list_dri_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (dri, dri_suffixes, SRT_GRAPHICS_DRI_MODULE); g_list_free_full (dri, g_object_unref); g_test_message ("DRI drivers (all)..."); dri = srt_system_info_list_dri_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_INCLUDE_ALL); check_list_suffixes (dri, dri_suffixes_extra, SRT_GRAPHICS_DRI_MODULE); g_list_free_full (dri, g_object_unref); g_test_message ("VA-API drivers..."); va_api = srt_system_info_list_va_api_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (va_api, va_api_suffixes, SRT_GRAPHICS_VAAPI_MODULE); g_list_free_full (va_api, g_object_unref); g_test_message ("VA-API drivers (all)..."); va_api = srt_system_info_list_va_api_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_INCLUDE_ALL); check_list_suffixes (va_api, va_api_suffixes, SRT_GRAPHICS_VAAPI_MODULE); g_list_free_full (va_api, g_object_unref); } static void test_dri_with_env (Fixture *f, gconstpointer context) { g_autoptr(SrtSystemInfo) info = NULL; g_auto(GStrv) envp = NULL; g_autofree gchar *sysroot = NULL; const gchar *libgl = NULL; const gchar *libgl2 = NULL; const gchar *libgl3 = NULL; const gchar *libva = NULL; const gchar *libva2 = NULL; const gchar *libva3 = NULL; g_autofree gchar *libgl_combined = NULL; g_autofree gchar *libva_combined = NULL; GList *dri; GList *va_api; const gchar *multiarch_tuples[] = {"i386-mock-fedora", NULL}; const gchar *dri_suffixes[] = {"custom_path32/dri/r600_dri.so", "custom_path32/dri/radeon_dri.so", "custom_path32_2/dri/r300_dri.so", NULL}; const gchar *dri_suffixes_with_extras[] = {"custom_path32/dri/r600_dri.so", "custom_path32/dri/radeon_dri.so", "custom_path32_2/dri/r300_dri.so", "/usr/lib/dri/i965_dri.so", "/usr/lib/dri/radeonsi_dri.so", NULL}; const gchar *va_api_suffixes[] = {"custom_path32/va/r600_drv_video.so", "custom_path32/va/radeonsi_drv_video.so", "custom_path32_2/va/nouveau_drv_video.so", NULL}; const gchar *va_api_suffixes_with_extras[] = {"custom_path32/va/r600_drv_video.so", "custom_path32/va/radeonsi_drv_video.so", "custom_path32_2/va/nouveau_drv_video.so", "/usr/lib/dri/r600_drv_video.so", NULL}; g_test_message ("Entering %s", G_STRFUNC); #ifndef _SRT_MULTIARCH g_test_skip ("Unsupported architecture"); return; #endif sysroot = g_build_filename (f->sysroots, "no-os-release", NULL); libgl = "/custom_path32/dri"; libva = "/custom_path32/va"; libgl2 = "/custom_path32_2/dri"; libva2 = "/custom_path32_2/va"; /* We have these two 64bit directories but we are using only one mock 32bit executable. * So we expect to not receive the content of these directories because we should * find 32bit only libraries. */ libgl3 = "/custom_path64/dri"; libva3 = "/custom_path64/va"; libgl_combined = g_strjoin (":", libgl, libgl2, libgl3, NULL); libva_combined = g_strjoin (":", libva, libva2, libva3, NULL); envp = g_get_environ (); envp = g_environ_setenv (envp, "SRT_TEST_SYSROOT", sysroot, TRUE); envp = g_environ_setenv (envp, "LIBGL_DRIVERS_PATH", libgl_combined, TRUE); envp = g_environ_setenv (envp, "LIBVA_DRIVERS_PATH", libva_combined, TRUE); info = srt_system_info_new (NULL); srt_system_info_set_environ (info, envp); srt_system_info_set_sysroot (info, sysroot); srt_system_info_set_helpers_path (info, f->builddir); /* The output is guaranteed to be in aphabetical order */ g_test_message ("DRI drivers..."); dri = srt_system_info_list_dri_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (dri, dri_suffixes, SRT_GRAPHICS_DRI_MODULE); check_paths_are_absolute (dri, SRT_GRAPHICS_DRI_MODULE); g_list_free_full (dri, g_object_unref); /* The output is guaranteed to be in aphabetical order */ g_test_message ("VA-API drivers..."); va_api = srt_system_info_list_va_api_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (va_api, va_api_suffixes, SRT_GRAPHICS_VAAPI_MODULE); check_paths_are_absolute (va_api, SRT_GRAPHICS_VAAPI_MODULE); g_list_free_full (va_api, g_object_unref); /* Do it again, this time including the extras */ g_test_message ("DRI drivers (all)..."); dri = srt_system_info_list_dri_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_INCLUDE_ALL); check_list_suffixes (dri, dri_suffixes_with_extras, SRT_GRAPHICS_DRI_MODULE); /* Minus one to not count the NULL terminator */ check_list_extra (dri, G_N_ELEMENTS(dri_suffixes)-1, SRT_GRAPHICS_DRI_MODULE); check_paths_are_absolute (dri, SRT_GRAPHICS_DRI_MODULE); g_list_free_full (dri, g_object_unref); g_test_message ("VA-API drivers (all)..."); va_api = srt_system_info_list_va_api_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_INCLUDE_ALL); check_list_suffixes (va_api, va_api_suffixes_with_extras, SRT_GRAPHICS_VAAPI_MODULE); /* Minus one to not count the NULL terminator */ check_list_extra (va_api, G_N_ELEMENTS(va_api_suffixes)-1, SRT_GRAPHICS_VAAPI_MODULE); check_paths_are_absolute (va_api, SRT_GRAPHICS_VAAPI_MODULE); g_list_free_full (va_api, g_object_unref); /* Test relative path. * Move to the sysroots path because otherwise we can't use the * relative paths */ if (g_chdir (sysroot) != 0) g_error ("chdir %s: %s", sysroot, g_strerror (errno)); g_free (libgl_combined); g_free (libva_combined); /* Plus one to remove the leading "/" */ libgl_combined = g_strjoin (":", libgl + 1, libgl2 + 1, libgl3 + 1, NULL); libva_combined = g_strjoin (":", libva + 1, libva2 + 1, libva3 + 1, NULL); envp = g_environ_setenv (envp, "LIBGL_DRIVERS_PATH", libgl_combined, TRUE); envp = g_environ_setenv (envp, "LIBVA_DRIVERS_PATH", libva_combined, TRUE); srt_system_info_set_environ (info, envp); g_test_message ("DRI drivers (with relative path)..."); dri = srt_system_info_list_dri_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (dri, dri_suffixes, SRT_GRAPHICS_DRI_MODULE); check_paths_are_relative (dri, SRT_GRAPHICS_DRI_MODULE); g_list_free_full (dri, g_object_unref); g_test_message ("VA-API drivers (with relative path)..."); va_api = srt_system_info_list_va_api_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (va_api, va_api_suffixes, SRT_GRAPHICS_VAAPI_MODULE); check_paths_are_relative (va_api, SRT_GRAPHICS_VAAPI_MODULE); g_list_free_full (va_api, g_object_unref); } static void test_dri_flatpak (Fixture *f, gconstpointer context) { g_autoptr(SrtSystemInfo) info; g_auto(GStrv) envp = NULL; g_autofree gchar *sysroot = NULL; g_autoptr(SrtObjectList) dri = NULL; g_autoptr(SrtObjectList) va_api = NULL; const gchar *multiarch_tuples[] = { "x86_64-mock-abi", NULL }; const gchar *dri_suffixes[] = {"/usr/lib/x86_64-mock-abi/GL/lib/dri/i965_dri.so", NULL}; const gchar *va_api_suffixes[] = {"/usr/lib/x86_64-mock-abi/dri/radeonsi_drv_video.so", "/usr/lib/x86_64-mock-abi/dri/intel-vaapi-driver/i965_drv_video.so", "/usr/lib/x86_64-mock-abi/GL/lib/dri/r600_drv_video.so", NULL}; g_test_message ("Entering %s", G_STRFUNC); sysroot = g_build_filename (f->sysroots, "flatpak-example", NULL); envp = g_get_environ (); envp = g_environ_setenv (envp, "SRT_TEST_SYSROOT", sysroot, TRUE); envp = g_environ_unsetenv (envp, "LIBGL_DRIVERS_PATH"); envp = g_environ_unsetenv (envp, "LIBVA_DRIVERS_PATH"); info = srt_system_info_new (NULL); srt_system_info_set_environ (info, envp); srt_system_info_set_sysroot (info, sysroot); srt_system_info_set_helpers_path (info, f->builddir); g_test_message ("DRI drivers..."); dri = srt_system_info_list_dri_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (dri, dri_suffixes, SRT_GRAPHICS_DRI_MODULE); g_test_message ("VA-API drivers..."); va_api = srt_system_info_list_va_api_drivers (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); check_list_suffixes (va_api, va_api_suffixes, SRT_GRAPHICS_VAAPI_MODULE); } typedef struct { const gchar *description; const gchar *multiarch_tuple; const gchar *sysroot; const gchar *vdpau_suffixes[5]; const gchar *vdpau_links[5]; const gchar *vdpau_suffixes_extra[6]; const gchar *vdpau_path_env; const gchar *vdpau_driver_env; const gchar *ld_library_path_env; } VdpauTest; static const VdpauTest vdpau_test[] = { { .description = "debian 10 i386", .multiarch_tuple = "i386-mock-debian", .sysroot = "debian10", .vdpau_suffixes = { "/lib/i386-linux-gnu/vdpau/libvdpau_r600.so", "/lib/i386-linux-gnu/vdpau/libvdpau_radeonsi.so", "/lib/i386-linux-gnu/vdpau/libvdpau_radeonsi.so.1", NULL }, /* These symlinks are provided by "libvdpau_radeonsi.so" and "libvdpau_radeonsi.so.1" */ .vdpau_links = { "libvdpau_radeonsi.so.1.0.0", "libvdpau_radeonsi.so.1.0.0", NULL }, }, { .description = "debian 10 x86_64", .multiarch_tuple = "x86_64-mock-debian", .sysroot = "debian10", .vdpau_suffixes = { "/lib/x86_64-linux-gnu/vdpau/libvdpau_r600.so.1", "/lib/x86_64-linux-gnu/vdpau/libvdpau_radeonsi.so", "/lib/x86_64-linux-gnu/vdpau/libvdpau_radeonsi.so.1", NULL }, /* These symlinks are provided by "libvdpau_r600.so", "libvdpau_radeonsi.so" * and "libvdpau_radeonsi.so.1" */ .vdpau_links = { "libvdpau_r600.so.1.0.0", "libvdpau_radeonsi.so.1.0.0", "libvdpau_radeonsi.so.1.0.0", NULL }, }, { .description = "fedora 32 bit", .multiarch_tuple = "i386-mock-fedora", .sysroot = "fedora", .vdpau_suffixes = { "/usr/lib/vdpau/libvdpau_nouveau.so.1", "/usr/lib/vdpau/libvdpau_r600.so", "/usr/lib/vdpau/libvdpau_radeonsi.so", "/usr/lib/vdpau/libvdpau_radeonsi.so.1", NULL }, /* These symlinks are provided by "libvdpau_radeonsi.so" and "libvdpau_radeonsi.so.1" */ .vdpau_links = { "libvdpau_radeonsi.so.1.0.0", "libvdpau_radeonsi.so.1.0.0", NULL }, }, { .description = "fedora 64 bit", .multiarch_tuple = "x86_64-mock-fedora", .sysroot = "fedora", .vdpau_suffixes = { "/usr/lib64/vdpau/libvdpau_r300.so", "/usr/lib64/vdpau/libvdpau_r300.so.1", "/usr/lib64/vdpau/libvdpau_radeonsi.so", "/usr/lib64/vdpau/libvdpau_radeonsi.so.1", NULL }, /* These symlinks are provided by "libvdpau_r300.so.1" and "libvdpau_radeonsi.so.1" */ .vdpau_links = { "libvdpau_r300.so", "libvdpau_radeonsi.so", NULL }, }, { .description = "vdpau with environment", .multiarch_tuple = "i386-mock-fedora", .sysroot = "no-os-release", .vdpau_suffixes = { "custom_path32/vdpau/libvdpau_r600.so.1", "custom_path32/vdpau/libvdpau_radeonsi.so.1", NULL }, .vdpau_suffixes_extra = { "/custom_path32/vdpau/libvdpau_r600.so.1", "/custom_path32/vdpau/libvdpau_radeonsi.so.1", "/usr/lib/vdpau/libvdpau_nouveau.so.1", "/another_custom_path/libvdpau_custom.so", "/usr/lib/libvdpau_r9000.so", NULL }, .vdpau_path_env = "custom_path32", .vdpau_driver_env = "r9000", .ld_library_path_env = "/another_custom_path", }, { .description = "flatpak", .multiarch_tuple = "x86_64-mock-abi", .sysroot = "flatpak-example", .vdpau_suffixes = { "/usr/lib/x86_64-mock-abi/vdpau/libvdpau_radeonsi.so.1", NULL }, }, }; static void test_vdpau (Fixture *f, gconstpointer context) { g_test_message ("Entering %s", G_STRFUNC); for (gsize i = 0; i < G_N_ELEMENTS (vdpau_test); i++) { const VdpauTest *test = &vdpau_test[i]; g_autoptr(SrtSystemInfo) info = NULL; g_auto(GStrv) envp = NULL; g_autofree gchar *sysroot = NULL; g_autofree gchar *vdpau_path = NULL; g_autofree gchar *vdpau_relative_path = NULL; GList *vdpau; g_test_message ("%s: %s", test->sysroot, test->description); sysroot = g_build_filename (f->sysroots, test->sysroot, NULL); envp = g_get_environ (); envp = g_environ_setenv (envp, "SRT_TEST_SYSROOT", sysroot, TRUE); if (test->vdpau_path_env == NULL) { envp = g_environ_unsetenv (envp, "VDPAU_DRIVER_PATH"); } else { g_assert_cmpint (test->vdpau_path_env[0], !=, '/'); vdpau_path = g_build_filename ("/", test->vdpau_path_env, "vdpau", NULL); vdpau_relative_path = g_build_filename (test->vdpau_path_env, "vdpau", NULL); envp = g_environ_setenv (envp, "VDPAU_DRIVER_PATH", vdpau_path, TRUE); } if (test->vdpau_driver_env == NULL) envp = g_environ_unsetenv (envp, "VDPAU_DRIVER"); else envp = g_environ_setenv (envp, "VDPAU_DRIVER", test->vdpau_driver_env, TRUE); if (test->ld_library_path_env == NULL) envp = g_environ_unsetenv (envp, "LD_LIBRARY_PATH"); else envp = g_environ_setenv (envp, "LD_LIBRARY_PATH", test->ld_library_path_env, TRUE); info = srt_system_info_new (NULL); srt_system_info_set_environ (info, envp); srt_system_info_set_sysroot (info, sysroot); srt_system_info_set_helpers_path (info, f->builddir); /* The output is guaranteed to be in aphabetical order */ vdpau = srt_system_info_list_vdpau_drivers (info, test->multiarch_tuple, SRT_DRIVER_FLAGS_NONE); check_list_suffixes (vdpau, test->vdpau_suffixes, SRT_GRAPHICS_VDPAU_MODULE); check_list_links (vdpau, test->vdpau_links, SRT_GRAPHICS_VDPAU_MODULE); check_paths_are_absolute (vdpau, SRT_GRAPHICS_VDPAU_MODULE); g_list_free_full (vdpau, g_object_unref); if (test->vdpau_suffixes_extra[0] != NULL) { /* Do it again, this time including the extras */ vdpau = srt_system_info_list_vdpau_drivers (info, test->multiarch_tuple, SRT_DRIVER_FLAGS_INCLUDE_ALL); check_list_suffixes (vdpau, test->vdpau_suffixes_extra, SRT_GRAPHICS_VDPAU_MODULE); check_paths_are_absolute (vdpau, SRT_GRAPHICS_VDPAU_MODULE); gulong non_extras = 0; for (; test->vdpau_suffixes[non_extras] != NULL; non_extras++) continue; check_list_extra (vdpau, non_extras, SRT_GRAPHICS_VDPAU_MODULE); g_list_free_full (vdpau, g_object_unref); } if (vdpau_relative_path != NULL) { envp = g_environ_setenv (envp, "VDPAU_DRIVER_PATH", vdpau_relative_path, TRUE); /* Move to the build directory because otherwise we can't use the relative sysroots path */ if (g_chdir (sysroot) != 0) g_error ("chdir %s: %s", sysroot, g_strerror (errno)); srt_system_info_set_environ (info, envp); vdpau = srt_system_info_list_vdpau_drivers (info, test->multiarch_tuple, SRT_DRIVER_FLAGS_NONE); check_list_suffixes (vdpau, test->vdpau_suffixes, SRT_GRAPHICS_VDPAU_MODULE); check_list_links (vdpau, test->vdpau_links, SRT_GRAPHICS_VDPAU_MODULE); check_paths_are_relative (vdpau, SRT_GRAPHICS_VDPAU_MODULE); g_list_free_full (vdpau, g_object_unref); } } } typedef struct { SrtGraphicsIssues issues; const gchar *name; const gchar *api_version; const gchar *driver_version; const gchar *vendor_id; const gchar *device_id; const gchar *messages; SrtVkPhysicalDeviceType type; } GraphicsDeviceTest; typedef struct { const gchar *description; SrtWindowSystem window_system; SrtRenderingInterface rendering_interface; SrtGraphicsLibraryVendor library_vendor; SrtGraphicsIssues issues; SrtTestFlags test_flags; const gchar *multiarch_tuple; const gchar *renderer_string; const gchar *version_string; const gchar *messages; /* Arbitrary size, increase it if necessary */ GraphicsDeviceTest devices[4]; int exit_status; gboolean vendor_neutral; } GraphicsTest; static const GraphicsTest graphics_test[] = { { .description = "good vdpau", .window_system = SRT_WINDOW_SYSTEM_X11, .rendering_interface = SRT_RENDERING_INTERFACE_VDPAU, .issues = SRT_GRAPHICS_ISSUES_NONE, .multiarch_tuple = "mock-good", .renderer_string = SRT_TEST_GOOD_VDPAU_RENDERER, .vendor_neutral = TRUE, }, { .description = "bad vdpau", .window_system = SRT_WINDOW_SYSTEM_X11, .rendering_interface = SRT_RENDERING_INTERFACE_VDPAU, .issues = SRT_GRAPHICS_ISSUES_CANNOT_DRAW, .multiarch_tuple = "mock-bad", .messages = SRT_TEST_BAD_VDPAU_MESSAGES, .exit_status = 1, .vendor_neutral = TRUE, }, { .description = "good gl", .window_system = SRT_WINDOW_SYSTEM_GLX, .rendering_interface = SRT_RENDERING_INTERFACE_GL, .issues = SRT_GRAPHICS_ISSUES_NONE, .multiarch_tuple = "mock-good", .renderer_string = SRT_TEST_GOOD_GRAPHICS_RENDERER, .version_string = SRT_TEST_GOOD_GRAPHICS_VERSION, }, { .description = "no graphics stack", .window_system = SRT_WINDOW_SYSTEM_GLX, .rendering_interface = SRT_RENDERING_INTERFACE_GL, .issues = SRT_GRAPHICS_ISSUES_CANNOT_LOAD, .multiarch_tuple = "mock-bad", .messages = "warning: this warning should always be logged\n" "Waffle error: 0x2 WAFFLE_ERROR_UNKNOWN: XOpenDisplay failed\n" "info: you used LIBGL_DEBUG=verbose\n", /* We used "mock-bad" for the architecture so, when checking the library vendor, * we will not be able to call the helper `mock-bad-check-library`. * For this reason we expect %SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN */ .library_vendor = SRT_GRAPHICS_LIBRARY_VENDOR_UNKNOWN, .exit_status = 1, }, { .description = "graphics timeout", .window_system = SRT_WINDOW_SYSTEM_GLX, .rendering_interface = SRT_RENDERING_INTERFACE_GL, .issues = (SRT_GRAPHICS_ISSUES_CANNOT_LOAD | SRT_GRAPHICS_ISSUES_TIMEOUT), .test_flags = SRT_TEST_FLAGS_TIME_OUT_SOONER, .multiarch_tuple = "mock-hanging", // Timeout has exit code 124 .exit_status = 124, }, { .description = "software rendering", .window_system = SRT_WINDOW_SYSTEM_GLX, .rendering_interface = SRT_RENDERING_INTERFACE_GL, .issues = SRT_GRAPHICS_ISSUES_SOFTWARE_RENDERING, .multiarch_tuple = "mock-software", .renderer_string = SRT_TEST_SOFTWARE_GRAPHICS_RENDERER, .version_string = SRT_TEST_SOFTWARE_GRAPHICS_VERSION, .messages = "warning: this warning should always be logged\n" "info: you used LIBGL_DEBUG=verbose\n", }, { .description = "gl driver ok but check-gl fails", .window_system = SRT_WINDOW_SYSTEM_GLX, .rendering_interface = SRT_RENDERING_INTERFACE_GL, .issues = SRT_GRAPHICS_ISSUES_CANNOT_DRAW, .multiarch_tuple = "mock-mixed", .renderer_string = SRT_TEST_GOOD_GRAPHICS_RENDERER, .version_string = SRT_TEST_GOOD_GRAPHICS_VERSION, .messages = "warning: this warning should always be logged\n" "Waffle error: 0x2 WAFFLE_ERROR_UNKNOWN: XOpenDisplay failed\n" "info: you used LIBGL_DEBUG=verbose\n", .exit_status = 1, }, { .description = "good vulkan", .window_system = SRT_WINDOW_SYSTEM_X11, .rendering_interface = SRT_RENDERING_INTERFACE_VULKAN, .issues = SRT_GRAPHICS_ISSUES_NONE, .multiarch_tuple = "mock-good", .renderer_string = SRT_TEST_GOOD_GRAPHICS_RENDERER, .version_string = SRT_TEST_GOOD_VULKAN_VERSION, .messages = SRT_TEST_GOOD_VULKAN_MESSAGES, .devices = { { .name = SRT_TEST_GOOD_GRAPHICS_RENDERER, .api_version = SRT_TEST_GOOD_GRAPHICS_API_VERSION, .driver_version = SRT_TEST_GOOD_GRAPHICS_DRIVER_VERSION, .vendor_id = SRT_TEST_GOOD_GRAPHICS_VENDOR_ID, .device_id = SRT_TEST_GOOD_GRAPHICS_DEVICE_ID, .type = SRT_VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, }, { .name = SRT_TEST_SOFTWARE_GRAPHICS_RENDERER, .api_version = SRT_TEST_SOFTWARE_GRAPHICS_API_VERSION, .driver_version = SRT_TEST_SOFTWARE_GRAPHICS_DRIVER_VERSION, .vendor_id = SRT_TEST_SOFTWARE_GRAPHICS_VENDOR_ID, .device_id = SRT_TEST_SOFTWARE_GRAPHICS_DEVICE_ID, .type = SRT_VK_PHYSICAL_DEVICE_TYPE_CPU, .issues = SRT_GRAPHICS_ISSUES_SOFTWARE_RENDERING, }, }, .vendor_neutral = TRUE, }, { .description = "bad vulkan", .window_system = SRT_WINDOW_SYSTEM_X11, .rendering_interface = SRT_RENDERING_INTERFACE_VULKAN, .issues = SRT_GRAPHICS_ISSUES_CANNOT_LOAD | SRT_GRAPHICS_ISSUES_CANNOT_DRAW, .multiarch_tuple = "mock-bad", .messages = SRT_TEST_BAD_VULKAN_MESSAGES, .exit_status = 1, .vendor_neutral = TRUE, }, { .description = "good vulkan driver but drawing test fails", .window_system = SRT_WINDOW_SYSTEM_X11, .rendering_interface = SRT_RENDERING_INTERFACE_VULKAN, .issues = SRT_GRAPHICS_ISSUES_CANNOT_DRAW, .multiarch_tuple = "mock-mixed", .renderer_string = SRT_TEST_GOOD_GRAPHICS_RENDERER, .version_string = SRT_TEST_GOOD_VULKAN_VERSION, .messages = SRT_TEST_GOOD_VULKAN_MESSAGES, .exit_status = 1, .devices = { { .name = SRT_TEST_GOOD_GRAPHICS_RENDERER, .api_version = SRT_TEST_GOOD_GRAPHICS_API_VERSION, .driver_version = SRT_TEST_GOOD_GRAPHICS_DRIVER_VERSION, .vendor_id = SRT_TEST_GOOD_GRAPHICS_VENDOR_ID, .device_id = SRT_TEST_GOOD_GRAPHICS_DEVICE_ID, .type = SRT_VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, .messages = SRT_TEST_MIXED_VULKAN_MESSAGES_1, .issues = SRT_GRAPHICS_ISSUES_CANNOT_DRAW, }, { .name = SRT_TEST_SOFTWARE_GRAPHICS_RENDERER, .api_version = SRT_TEST_SOFTWARE_GRAPHICS_API_VERSION, .driver_version = SRT_TEST_SOFTWARE_GRAPHICS_DRIVER_VERSION, .vendor_id = SRT_TEST_SOFTWARE_GRAPHICS_VENDOR_ID, .device_id = SRT_TEST_SOFTWARE_GRAPHICS_DEVICE_ID, .type = SRT_VK_PHYSICAL_DEVICE_TYPE_CPU, .messages = SRT_TEST_MIXED_VULKAN_MESSAGES_2, .issues = SRT_GRAPHICS_ISSUES_CANNOT_DRAW | SRT_GRAPHICS_ISSUES_SOFTWARE_RENDERING, }, }, .vendor_neutral = TRUE, }, { .description = "good va-api", .window_system = SRT_WINDOW_SYSTEM_X11, .rendering_interface = SRT_RENDERING_INTERFACE_VAAPI, .issues = SRT_GRAPHICS_ISSUES_NONE, .multiarch_tuple = "mock-good", .renderer_string = SRT_TEST_GOOD_VAAPI_RENDERER, .vendor_neutral = TRUE, }, { .description = "bad va-api", .window_system = SRT_WINDOW_SYSTEM_X11, .rendering_interface = SRT_RENDERING_INTERFACE_VAAPI, .issues = SRT_GRAPHICS_ISSUES_CANNOT_DRAW, .multiarch_tuple = "mock-bad", .messages = SRT_TEST_BAD_VAAPI_MESSAGES, .exit_status = 1, .vendor_neutral = TRUE, }, }; static void test_check_graphics (Fixture *f, gconstpointer context) { g_test_message ("Entering %s", G_STRFUNC); for (gsize i = 0; i < G_N_ELEMENTS (graphics_test); i++) { const GraphicsTest *test = &graphics_test[i]; g_autoptr(SrtGraphics) graphics = NULL; g_autoptr(SrtObjectList) devices = NULL; SrtGraphicsIssues issues; g_autofree gchar *tuple = NULL; g_autofree gchar *renderer = NULL; g_autofree gchar *version = NULL; g_autofree gchar *messages = NULL; int exit_status; int terminating_signal; gboolean vendor_neutral; SrtGraphicsLibraryVendor library_vendor; GList *iter; gsize j; g_test_message ("%s", test->description); g_autoptr(SrtSystemInfo) info = srt_system_info_new (NULL); srt_system_info_set_helpers_path (info, f->builddir); srt_system_info_set_test_flags (info, test->test_flags); issues = srt_system_info_check_graphics (info, test->multiarch_tuple, test->window_system, test->rendering_interface, &graphics); g_assert_cmpint (issues, ==, test->issues); g_assert_cmpstr (srt_graphics_get_renderer_string (graphics), ==, test->renderer_string); g_assert_cmpstr (srt_graphics_get_version_string (graphics), ==, test->version_string); g_assert_cmpstr (srt_graphics_get_messages (graphics), ==, test->messages); g_assert_cmpint (srt_graphics_get_exit_status (graphics), ==, test->exit_status); g_assert_cmpint (srt_graphics_get_terminating_signal (graphics), ==, 0); devices = srt_graphics_get_devices (graphics); for (j = 0, iter = devices; iter != NULL; iter = iter->next, j++) { g_autofree gchar *name = NULL; g_autofree gchar *api_version = NULL; g_autofree gchar *driver_version = NULL; g_autofree gchar *vendor_id = NULL; g_autofree gchar *device_id = NULL; SrtVkPhysicalDeviceType type; g_assert_cmpstr (srt_graphics_device_get_name (iter->data), ==, test->devices[j].name); g_assert_cmpstr (srt_graphics_device_get_api_version (iter->data), ==, test->devices[j].api_version); g_assert_cmpstr (srt_graphics_device_get_driver_version (iter->data), ==, test->devices[j].driver_version); g_assert_cmpstr (srt_graphics_device_get_vendor_id (iter->data), ==, test->devices[j].vendor_id); g_assert_cmpstr (srt_graphics_device_get_device_id (iter->data), ==, test->devices[j].device_id); g_assert_cmpint (srt_graphics_device_get_device_type (iter->data), ==, test->devices[j].type); g_assert_cmpstr (srt_graphics_device_get_messages (iter->data), ==, test->devices[j].messages); g_assert_cmpint (srt_graphics_device_get_issues (iter->data), ==, test->devices[j].issues); g_object_get (iter->data, "name", &name, "api-version", &api_version, "driver-version", &driver_version, "vendor-id", &vendor_id, "device-id", &device_id, "type", &type, "issues", &issues, NULL); g_assert_cmpstr (name, ==, test->devices[j].name); g_assert_cmpstr (api_version, ==, test->devices[j].api_version); g_assert_cmpstr (driver_version, ==, test->devices[j].driver_version); g_assert_cmpstr (vendor_id, ==, test->devices[j].vendor_id); g_assert_cmpstr (device_id, ==, test->devices[j].device_id); g_assert_cmpint (type, ==, test->devices[j].type); g_assert_cmpint (issues, ==, test->devices[j].issues); } vendor_neutral = srt_graphics_library_is_vendor_neutral (graphics, &library_vendor); g_assert_cmpint (library_vendor, ==, test->library_vendor); g_assert_cmpint (vendor_neutral, ==, test->vendor_neutral); g_object_get (graphics, "multiarch-tuple", &tuple, "issues", &issues, "renderer-string", &renderer, "version-string", &version, "messages", &messages, "exit-status", &exit_status, "terminating-signal", &terminating_signal, NULL); g_assert_cmpint (issues, ==, test->issues); g_assert_cmpstr (tuple, ==, test->multiarch_tuple); g_assert_cmpstr (renderer, ==, test->renderer_string); g_assert_cmpstr (version, ==, test->version_string); g_assert_cmpstr (messages, ==, test->messages); g_assert_cmpint (exit_status, ==, test->exit_status); g_assert_cmpint (terminating_signal, ==, 0); } } static gint glx_icd_compare (SrtGlxIcd *a, SrtGlxIcd *b) { return g_strcmp0 (srt_glx_icd_get_library_soname (a), srt_glx_icd_get_library_soname (b)); } static void test_glx_debian (Fixture *f, gconstpointer context) { g_autoptr(SrtSystemInfo) info = NULL; g_auto(GStrv) envp = NULL; g_autofree gchar *sysroot = NULL; GList *glx; const gchar *multiarch_tuples[] = {"i386-mock-debian", "x86_64-mock-debian", NULL}; const gchar *glx_suffixes_i386[] = {"libGLX_mesa.so.0", "libGLX_nvidia.so.0", NULL}; const gchar *glx_paths_i386[] = {"/lib/i386-linux-gnu/libGLX_mesa.so.0", "/lib/i386-linux-gnu/libGLX_nvidia.so.0", NULL}; const gchar *glx_suffixes_x86_64[] = {"libGLX_mesa.so.0", NULL}; const gchar *glx_paths_x86_64[] = {"/lib/x86_64-linux-gnu/libGLX_mesa.so.0", NULL}; g_test_message ("Entering %s", G_STRFUNC); sysroot = g_build_filename (f->sysroots, "debian10", NULL); envp = g_get_environ (); envp = g_environ_setenv (envp, "SRT_TEST_SYSROOT", sysroot, TRUE); info = srt_system_info_new (NULL); srt_system_info_set_environ (info, envp); srt_system_info_set_sysroot (info, sysroot); srt_system_info_set_helpers_path (info, f->builddir); g_test_message ("i386..."); glx = srt_system_info_list_glx_icds (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); /* The icds are not provided in a guaranteed order. Sort them before checking * with the expectations */ glx = g_list_sort (glx, (GCompareFunc) glx_icd_compare); check_list_suffixes (glx, glx_suffixes_i386, SRT_GRAPHICS_GLX_MODULE); check_list_links (glx, glx_paths_i386, SRT_GRAPHICS_GLX_MODULE); g_list_free_full (glx, g_object_unref); g_test_message ("x86_64..."); glx = srt_system_info_list_glx_icds (info, multiarch_tuples[1], SRT_DRIVER_FLAGS_NONE); /* The icds are not provided in a guaranteed order. Sort them before checking * with the expectations */ glx = g_list_sort (glx, (GCompareFunc) glx_icd_compare); check_list_suffixes (glx, glx_suffixes_x86_64, SRT_GRAPHICS_GLX_MODULE); check_list_links (glx, glx_paths_x86_64, SRT_GRAPHICS_GLX_MODULE); g_list_free_full (glx, g_object_unref); } static void test_glx_container (Fixture *f, gconstpointer context) { g_autoptr(SrtSystemInfo) info = NULL; g_auto(GStrv) envp = NULL; g_autofree gchar *sysroot = NULL; GList *glx; const gchar *multiarch_tuples[] = {"i386-mock-container", "x86_64-mock-container", NULL}; const gchar *glx_suffixes_i386[] = {"libGLX_nvidia.so.0", NULL}; const gchar *glx_paths_i386[] = {"/lib/i386-linux-gnu/libGLX_nvidia.so.0", NULL}; const gchar *glx_suffixes_x86_64[] = {"libGLX_custom.so.0", "libGLX_mesa.so.0", NULL}; const gchar *glx_paths_x86_64[] = {"/lib/x86_64-linux-gnu/libGLX_custom.so.0", "/lib/x86_64-linux-gnu/libGLX_mesa.so.0", NULL}; g_test_message ("Entering %s", G_STRFUNC); sysroot = g_build_filename (f->sysroots, "steamrt", NULL); envp = g_get_environ (); envp = g_environ_setenv (envp, "SRT_TEST_SYSROOT", sysroot, TRUE); info = srt_system_info_new (NULL); srt_system_info_set_environ (info, envp); srt_system_info_set_sysroot (info, sysroot); srt_system_info_set_helpers_path (info, f->builddir); g_test_message ("i386..."); glx = srt_system_info_list_glx_icds (info, multiarch_tuples[0], SRT_DRIVER_FLAGS_NONE); /* The icds are not provided in a guaranteed order. Sort them before checking * with the expectations */ glx = g_list_sort (glx, (GCompareFunc) glx_icd_compare); check_list_suffixes (glx, glx_suffixes_i386, SRT_GRAPHICS_GLX_MODULE); check_list_links (glx, glx_paths_i386, SRT_GRAPHICS_GLX_MODULE); g_list_free_full (glx, g_object_unref); g_test_message ("x86_64..."); glx = srt_system_info_list_glx_icds (info, multiarch_tuples[1], SRT_DRIVER_FLAGS_NONE); /* The icds are not provided in a guaranteed order. Sort them before checking * with the expectations */ glx = g_list_sort (glx, (GCompareFunc) glx_icd_compare); check_list_suffixes (glx, glx_suffixes_x86_64, SRT_GRAPHICS_GLX_MODULE); check_list_links (glx, glx_paths_x86_64, SRT_GRAPHICS_GLX_MODULE); g_list_free_full (glx, g_object_unref); } static const Config dir_config = { ICD_MODE_EXPLICIT_DIRS }; static const Config filename_config = { ICD_MODE_EXPLICIT_FILENAMES }; static const Config flatpak_config = { ICD_MODE_FLATPAK }; static const Config relative_config = { ICD_MODE_RELATIVE_FILENAMES }; static const Config xdg_config = { ICD_MODE_XDG_DIRS }; int main (int argc, char **argv) { int ret; argv0 = argv[0]; _srt_tests_init (&argc, &argv, NULL); global_sysroots = _srt_global_setup_sysroots (argv0); g_test_add ("/graphics/object", Fixture, NULL, setup, test_object, teardown); g_test_add ("/graphics/normalize_window_system", Fixture, NULL, setup, test_normalize_window_system, teardown); g_test_add ("/graphics/sigusr", Fixture, NULL, setup, test_sigusr, teardown); g_test_add ("/graphics/icd/egl/basic", Fixture, NULL, setup, test_icd_egl, teardown); g_test_add ("/graphics/icd/egl/dirs", Fixture, &dir_config, setup, test_icd_egl, teardown); g_test_add ("/graphics/icd/egl/filenames", Fixture, &filename_config, setup, test_icd_egl, teardown); g_test_add ("/graphics/icd/egl/flatpak", Fixture, &flatpak_config, setup, test_icd_egl, teardown); g_test_add ("/graphics/icd/egl/relative", Fixture, &relative_config, setup, test_icd_egl, teardown); g_test_add ("/graphics/icd/egl/xdg", Fixture, &xdg_config, setup, test_icd_egl, teardown); g_test_add ("/graphics/icd/egl_external_platform/basic", Fixture, NULL, setup, test_egl_external_platform, teardown); g_test_add ("/graphics/icd/egl_external_platform/dirs", Fixture, &dir_config, setup, test_egl_external_platform, teardown); g_test_add ("/graphics/icd/egl_external_platform/filenames", Fixture, &filename_config, setup, test_egl_external_platform, teardown); g_test_add ("/graphics/icd/egl_external_platform/relative", Fixture, &relative_config, setup, test_egl_external_platform, teardown); g_test_add ("/graphics/icd/vulkan_exp/basic", Fixture, NULL, setup, test_icd_vulkan_explicit_multiarch, teardown); g_test_add ("/graphics/icd/vulkan_exp/filenames", Fixture, &filename_config, setup, test_icd_vulkan_explicit_multiarch, teardown); g_test_add ("/graphics/icd/vulkan_exp/flatpak", Fixture, &flatpak_config, setup, test_icd_vulkan_explicit_multiarch, teardown); g_test_add ("/graphics/icd/vulkan_exp/relative", Fixture, &relative_config, setup, test_icd_vulkan_explicit_multiarch, teardown); g_test_add ("/graphics/icd/vulkan_exp/xdg", Fixture, &xdg_config, setup, test_icd_vulkan_explicit_multiarch, teardown); g_test_add ("/graphics/icd/vulkan_imp/basic", Fixture, NULL, setup, test_icd_vulkan_implicit_multiarch, teardown); g_test_add ("/graphics/icd/vulkan_imp/filenames", Fixture, &filename_config, setup, test_icd_vulkan_implicit_multiarch, teardown); g_test_add ("/graphics/icd/vulkan_imp/flatpak", Fixture, &flatpak_config, setup, test_icd_vulkan_implicit_multiarch, teardown); g_test_add ("/graphics/icd/vulkan_imp/relative", Fixture, &relative_config, setup, test_icd_vulkan_implicit_multiarch, teardown); g_test_add ("/graphics/icd/vulkan_imp/xdg", Fixture, &xdg_config, setup, test_icd_vulkan_implicit_multiarch, teardown); g_test_add ("/graphics/layers/vulkan/xdg", Fixture, NULL, setup, test_layer_vulkan, teardown); g_test_add ("/graphics/dri/debian10", Fixture, NULL, setup, test_dri_debian10, teardown); g_test_add ("/graphics/dri/fedora", Fixture, NULL, setup, test_dri_fedora, teardown); g_test_add ("/graphics/dri/ubuntu16", Fixture, NULL, setup, test_dri_ubuntu16, teardown); g_test_add ("/graphics/dri/with_env", Fixture, NULL, setup, test_dri_with_env, teardown); g_test_add ("/graphics/dri/flatpak", Fixture, NULL, setup, test_dri_flatpak, teardown); g_test_add ("/graphics/vdpau/basic", Fixture, NULL, setup, test_vdpau, teardown); g_test_add ("/graphics/check", Fixture, NULL, setup, test_check_graphics, teardown); g_test_add ("/graphics/glx/debian", Fixture, NULL, setup, test_glx_debian, teardown); g_test_add ("/graphics/glx/container", Fixture, NULL, setup, test_glx_container, teardown); ret = g_test_run (); _srt_global_teardown_sysroots (); g_clear_pointer (&global_sysroots, g_free); return ret; }