From 3b66327b7c74becd149e2d2457e353914346b5dc Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 10 Dec 2020 16:59:51 +0000
Subject: [PATCH] runtime: Factor out a nested loop

Instead of having a function to make a list of Vulkan layers and/or
ICDs available, let's have a function to act on a single layer or ICD.

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 pressure-vessel/runtime.c | 245 +++++++++++++++++++++++---------------
 1 file changed, 148 insertions(+), 97 deletions(-)

diff --git a/pressure-vessel/runtime.c b/pressure-vessel/runtime.c
index cd3c368a7..e15f2e026 100644
--- a/pressure-vessel/runtime.c
+++ b/pressure-vessel/runtime.c
@@ -2399,125 +2399,175 @@ pv_runtime_search_in_path_and_bin (PvRuntime *self,
   return NULL;
 }
 
+/*
+ * setup_vulkan_loadable_json:
+ * @self: The runtime
+ * @bwrap: Append arguments to this bubblewrap invocation to make files
+ *  available in the container
+ * @sub_dir: `icd.d`, `explicit_layer.d` or `implicit_layer.d`
+ * @write_to_dir: Path to `/overrides/share/vulkan/${sub_dir}` in the
+ *  current execution environment
+ * @details: An #IcdDetails holding a #SrtVulkanLayer or #SrtVulkanIcd,
+ *  whichever is appropriate for @sub_dir
+ * @seq: Sequence number of @details, used to make unique filenames
+ * @vulkan_path: Used to build `$VK_ICD_FILENAMES` or a similar search path
+ * @error: Used to raise an error on failure
+ *
+ * Make a single Vulkan layer or ICD available in the container.
+ */
 static gboolean
 setup_vulkan_loadable_json (PvRuntime *self,
                             FlatpakBwrap *bwrap,
                             const gchar *sub_dir,
-                            GPtrArray *vulkan_details,
+                            const gchar *write_to_dir,
+                            IcdDetails *details,
+                            gsize seq,
                             GString *vulkan_path,
                             GError **error)
 {
-  gsize i, j;
-  g_autofree gchar *write_to_dir = NULL;
+  SrtVulkanLayer *layer = NULL;
+  SrtVulkanIcd *icd = NULL;
+  gboolean need_provider_json = FALSE;
+  gsize i;
 
-  write_to_dir = g_build_filename (self->overrides,
-                                  "share", "vulkan", sub_dir, NULL);
+  if (SRT_IS_VULKAN_LAYER (details->icd))
+    layer = SRT_VULKAN_LAYER (details->icd);
+  else if (SRT_IS_VULKAN_ICD (details->icd))
+    icd = SRT_VULKAN_ICD (details->icd);
+  else
+    g_return_val_if_reached (FALSE);
 
-  if (g_mkdir_with_parents (write_to_dir, 0700) != 0)
+  /* If the layer failed to load, there's nothing to make available */
+  if (layer != NULL)
     {
-      glnx_throw_errno_prefix (error, "Unable to create %s", write_to_dir);
-      return FALSE;
+      if (!srt_vulkan_layer_check_error (layer, NULL))
+        return TRUE;
     }
-
-  for (j = 0; j < vulkan_details->len; j++)
+  else
     {
-      SrtVulkanLayer *layer = NULL;
-      SrtVulkanIcd *icd = NULL;
-      IcdDetails *details = g_ptr_array_index (vulkan_details, j);
-      gboolean need_provider_json = FALSE;
+      if (!srt_vulkan_icd_check_error (icd, NULL))
+        return TRUE;
+    }
 
-      if (SRT_IS_VULKAN_LAYER (details->icd))
-        layer = SRT_VULKAN_LAYER (details->icd);
-      else if (SRT_IS_VULKAN_ICD (details->icd))
-        icd = SRT_VULKAN_ICD (details->icd);
-      else
-        g_return_val_if_reached (FALSE);
+  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
+    {
+      g_assert (i < G_N_ELEMENTS (details->kinds));
+      g_assert (i < G_N_ELEMENTS (details->paths_in_container));
 
-      if (layer != NULL)
+      if (details->kinds[i] == ICD_KIND_ABSOLUTE)
         {
-          if (!srt_vulkan_layer_check_error (layer, NULL))
-            continue;
-        }
-      else
-        {
-          if (!srt_vulkan_icd_check_error (icd, NULL))
-            continue;
-        }
+          g_autofree gchar *write_to_file = NULL;
+          g_autofree gchar *json_in_container = NULL;
+          g_autofree gchar *json_base = NULL;
 
-      for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
-        {
-          g_assert (i < G_N_ELEMENTS (details->kinds));
-          g_assert (i < G_N_ELEMENTS (details->paths_in_container));
+          g_assert (details->paths_in_container[i] != NULL);
 
-          if (details->kinds[i] == ICD_KIND_ABSOLUTE)
+          json_base = g_strdup_printf ("%" G_GSIZE_FORMAT "-%s.json",
+                                       seq, multiarch_tuples[i]);
+          write_to_file = g_build_filename (write_to_dir, json_base, NULL);
+          json_in_container = g_build_filename (self->overrides_in_container,
+                                                "share", "vulkan", sub_dir,
+                                                json_base, NULL);
+
+          if (layer != NULL)
             {
-              g_autofree gchar *write_to_file = NULL;
-              g_autofree gchar *json_in_container = NULL;
-              g_autofree gchar *json_base = NULL;
+              g_autoptr(SrtVulkanLayer) replacement = NULL;
+              replacement = srt_vulkan_layer_new_replace_library_path (layer,
+                                                                       details->paths_in_container[i]);
 
-              g_assert (details->paths_in_container[i] != NULL);
+              if (!srt_vulkan_layer_write_to_file (replacement, write_to_file, error))
+                return FALSE;
+            }
+          else
+            {
+              g_autoptr(SrtVulkanIcd) replacement = NULL;
+              replacement = srt_vulkan_icd_new_replace_library_path (icd,
+                                                                     details->paths_in_container[i]);
 
-              json_base = g_strdup_printf ("%" G_GSIZE_FORMAT "-%s.json",
-                                           j, multiarch_tuples[i]);
-              write_to_file = g_build_filename (write_to_dir, json_base, NULL);
-              json_in_container = g_build_filename (self->overrides_in_container,
-                                                    "share", "vulkan", sub_dir,
-                                                    json_base, NULL);
+              if (!srt_vulkan_icd_write_to_file (replacement, write_to_file, error))
+                return FALSE;
+            }
 
-              if (layer != NULL)
-                {
-                  g_autoptr(SrtVulkanLayer) replacement = NULL;
-                  replacement = srt_vulkan_layer_new_replace_library_path (layer,
-                                                                           details->paths_in_container[i]);
+          pv_search_path_append (vulkan_path, json_in_container);
+        }
+      else if (details->kinds[i] == ICD_KIND_SONAME
+               || details->kinds[i] == ICD_KIND_META_LAYER)
+        {
+          need_provider_json = TRUE;
+        }
+    }
 
-                  if (!srt_vulkan_layer_write_to_file (replacement, write_to_file, error))
-                    return FALSE;
-                }
-              else
-                {
-                  g_autoptr(SrtVulkanIcd) replacement = NULL;
-                  replacement = srt_vulkan_icd_new_replace_library_path (icd,
-                                                                         details->paths_in_container[i]);
+  if (need_provider_json)
+    {
+      g_autofree gchar *json_in_container = NULL;
+      g_autofree gchar *json_base = NULL;
+      const char *json_in_provider = NULL;
+      if (layer != NULL)
+        json_in_provider = srt_vulkan_layer_get_json_path (layer);
+      else
+        json_in_provider = srt_vulkan_icd_get_json_path (icd);
 
-                  if (!srt_vulkan_icd_write_to_file (replacement, write_to_file, error))
-                    return FALSE;
-                }
+      json_base = g_strdup_printf ("%" G_GSIZE_FORMAT ".json", seq);
+      json_in_container = g_build_filename (self->overrides_in_container,
+                                            "share", "vulkan", sub_dir,
+                                            json_base, NULL);
 
+      if (!pv_runtime_take_from_provider (self, bwrap,
+                                          json_in_provider,
+                                          json_in_container,
+                                          TAKE_FROM_PROVIDER_FLAGS_COPY_FALLBACK,
+                                          error))
+        return FALSE;
 
-              pv_search_path_append (vulkan_path, json_in_container);
-            }
-          else if (details->kinds[i] == ICD_KIND_SONAME
-                   || details->kinds[i] == ICD_KIND_META_LAYER)
-            {
-              need_provider_json = TRUE;
-            }
-        }
+      pv_search_path_append (vulkan_path, json_in_container);
+    }
 
-      if (need_provider_json)
-        {
-          g_autofree gchar *json_in_container = NULL;
-          g_autofree gchar *json_base = NULL;
-          const char *json_in_provider = NULL;
-          if (layer != NULL)
-            json_in_provider = srt_vulkan_layer_get_json_path (layer);
-          else
-            json_in_provider = srt_vulkan_icd_get_json_path (icd);
+  return TRUE;
+}
 
-          json_base = g_strdup_printf ("%" G_GSIZE_FORMAT ".json", j);
-          json_in_container = g_build_filename (self->overrides_in_container,
-                                                "share", "vulkan", sub_dir,
-                                                json_base, NULL);
+/*
+ * setup_vulkan_loadable_json:
+ * @self: The runtime
+ * @bwrap: Append arguments to this bubblewrap invocation to make files
+ *  available in the container
+ * @sub_dir: `icd.d`, `explicit_layer.d` or `implicit_layer.d`
+ * @write_to_dir: Path to `/overrides/share/vulkan/${sub_dir}` in the
+ *  current execution environment
+ * @vulkan_details: (element-type IcdDetails): A list of #IcdDetails
+ *  holding #SrtVulkanLayer or #SrtVulkanIcd, as appropriate for @sub_dir
+ * @vulkan_path: Used to build `$VK_ICD_FILENAMES` or a similar search path
+ * @error: Used to raise an error on failure
+ *
+ * Make a list of Vulkan layers or ICDs available in the container.
+ */
+static gboolean
+setup_each_vulkan_loadable_json (PvRuntime *self,
+                                 FlatpakBwrap *bwrap,
+                                 const gchar *sub_dir,
+                                 GPtrArray *vulkan_details,
+                                 GString *vulkan_path,
+                                 GError **error)
+{
+  gsize j;
+  g_autofree gchar *write_to_dir = NULL;
 
-          if (!pv_runtime_take_from_provider (self, bwrap,
-                                              json_in_provider,
-                                              json_in_container,
-                                              TAKE_FROM_PROVIDER_FLAGS_COPY_FALLBACK,
-                                              error))
-            return FALSE;
+  write_to_dir = g_build_filename (self->overrides,
+                                  "share", "vulkan", sub_dir, NULL);
 
-          pv_search_path_append (vulkan_path, json_in_container);
-        }
+  if (g_mkdir_with_parents (write_to_dir, 0700) != 0)
+    {
+      glnx_throw_errno_prefix (error, "Unable to create %s", write_to_dir);
+      return FALSE;
     }
+
+  for (j = 0; j < vulkan_details->len; j++)
+    {
+      if (!setup_vulkan_loadable_json (self, bwrap, sub_dir, write_to_dir,
+                                       g_ptr_array_index (vulkan_details, j),
+                                       j, vulkan_path, error))
+        return FALSE;
+    }
+
   return TRUE;
 }
 
@@ -3512,22 +3562,23 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
     }
 
   g_debug ("Setting up Vulkan ICD JSON...");
-  if (!setup_vulkan_loadable_json (self, bwrap, "icd.d", vulkan_icd_details,
-                                   vulkan_path, error))
+  if (!setup_each_vulkan_loadable_json (self, bwrap, "icd.d",
+                                        vulkan_icd_details,
+                                        vulkan_path, error))
     return FALSE;
 
   if (self->flags & PV_RUNTIME_FLAGS_IMPORT_VULKAN_LAYERS)
     {
       g_debug ("Setting up Vulkan explicit layer JSON...");
-      if (!setup_vulkan_loadable_json (self, bwrap, "explicit_layer.d",
-                                       vulkan_exp_layer_details,
-                                       vulkan_exp_layer_path, error))
+      if (!setup_each_vulkan_loadable_json (self, bwrap, "explicit_layer.d",
+                                            vulkan_exp_layer_details,
+                                            vulkan_exp_layer_path, error))
         return FALSE;
 
       g_debug ("Setting up Vulkan implicit layer JSON...");
-      if (!setup_vulkan_loadable_json (self, bwrap, "implicit_layer.d",
-                                       vulkan_imp_layer_details,
-                                       vulkan_imp_layer_path, error))
+      if (!setup_each_vulkan_loadable_json (self, bwrap, "implicit_layer.d",
+                                            vulkan_imp_layer_details,
+                                            vulkan_imp_layer_path, error))
         return FALSE;
     }
 
-- 
GitLab