Skip to content
Snippets Groups Projects
graphics.c 137 KiB
Newer Older
      },
      /* /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++)
Ludovico de Nittis's avatar
Ludovico de Nittis committed
      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;

Ludovico de Nittis's avatar
Ludovico de Nittis committed
          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;

Ludovico de Nittis's avatar
Ludovico de Nittis committed
          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;
          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;
          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;
  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",
  const gchar *va_api_suffixes[] = {"/lib/x86_64-mock-ubuntu/dri/radeonsi_drv_video.so",
  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",
  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",
  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",
  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",
  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);
}

  const gchar *description;
  const gchar *multiarch_tuple;
  const gchar *sysroot;
  const gchar *vdpau_suffixes[5];
  const gchar *vdpau_links[5];
  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",
    .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",
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");
        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);
        }
    }