radv: fix GPL fast-linking with libs that have retained NIR shaders
authorSamuel Pitoiset <samuel.pitoiset@gmail.com>
Thu, 26 Jan 2023 13:02:51 +0000 (14:02 +0100)
committerMarge Bot <emma+marge@anholt.net>
Tue, 31 Jan 2023 15:24:50 +0000 (15:24 +0000)
Zink creates all libaries with CREATE_RETAIN_LINK_TIME_OPTIMIZATION,
then it first creates unoptimized pipelines and it enqueues optimized
pipelines in the background with CREATE_LINK_TIME_OPTIMIZATION.

If a pipeline is linked without CREATE_LINK_TIME_OPTIMIZATION, the
driver should import binaries instead of retained NIR shaders. This
was broken because RADV wasn't compiling binaries at all in presence
of CREATE_RETAIN_LINK_TIME_OPTIMIZATIONS. Now, it always compiles
binaries in libraries but can also retain NIR if requested.

Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/8150
Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21008>

src/amd/vulkan/radv_pipeline.c

index 8c6b400..192af4f 100644 (file)
@@ -975,15 +975,18 @@ radv_graphics_pipeline_import_lib(struct radv_graphics_pipeline *pipeline,
 
    vk_graphics_pipeline_state_merge(state, &lib->graphics_state);
 
-   /* Import the NIR shaders (after SPIRV->NIR). */
-   for (uint32_t s = 0; s < ARRAY_SIZE(lib->base.base.shaders); s++) {
-      if (!lib->base.base.retained_shaders[s].nir)
-         continue;
-
-      pipeline->base.retained_shaders[s] = lib->base.base.retained_shaders[s];
-   }
+   /* When link time optimization is enabled, import the retained NIR shaders from the library.
+    * Otherwise, import the compiled binaries (ie. fast link).
+    */
+   if (link_optimize) {
+      /* Import the NIR shaders (after SPIRV->NIR). */
+      for (uint32_t s = 0; s < ARRAY_SIZE(lib->base.base.shaders); s++) {
+         if (!lib->base.base.retained_shaders[s].nir)
+            continue;
 
-   if (!link_optimize) {
+         pipeline->base.retained_shaders[s] = lib->base.base.retained_shaders[s];
+      }
+   } else {
       /* Import the compiled shaders. */
       for (uint32_t s = 0; s < ARRAY_SIZE(lib->base.base.shaders); s++) {
          if (!lib->base.base.shaders[s])
@@ -3112,14 +3115,6 @@ radv_pipeline_nir_to_asm(struct radv_pipeline *pipeline, struct radv_pipeline_st
 }
 
 static void
-radv_pipeline_stage_retain_shader(struct radv_pipeline *pipeline, struct radv_pipeline_stage *stage)
-{
-   gl_shader_stage s = stage->stage;
-
-   pipeline->retained_shaders[s].nir = stage->nir;
-}
-
-static void
 radv_pipeline_get_nir(struct radv_pipeline *pipeline, struct radv_pipeline_stage *stages,
                       const struct radv_pipeline_key *pipeline_key, bool retain_shaders)
 {
@@ -3138,14 +3133,17 @@ radv_pipeline_get_nir(struct radv_pipeline *pipeline, struct radv_pipeline_stage
       assert(retain_shaders || pipeline->shaders[s] == NULL);
 
       if (pipeline->retained_shaders[s].nir) {
+         /* Clone the NIR shader because it's imported from a library. */
          stages[s].nir = nir_shader_clone(NULL, pipeline->retained_shaders[s].nir);
       } else {
          stages[s].nir = radv_shader_spirv_to_nir(device, &stages[s], pipeline_key,
                                                   pipeline->is_internal);
       }
 
-      if (retain_shaders)
-         radv_pipeline_stage_retain_shader(pipeline, &stages[s]);
+      if (retain_shaders) {
+         /* Clone the NIR shader because NIR passes after this step will change it. */
+         pipeline->retained_shaders[s].nir = nir_shader_clone(NULL, stages[s].nir);
+      }
 
       stages[s].feedback.duration += os_time_get_nano() - stage_start;
    }
@@ -3497,11 +3495,6 @@ radv_graphics_pipeline_compile(struct radv_pipeline *pipeline,
 
    radv_pipeline_get_nir(pipeline, stages, pipeline_key, retain_shaders);
 
-   if (retain_shaders) {
-      result = VK_SUCCESS;
-      goto done;
-   }
-
    /* Force per-vertex VRS. */
    if (radv_consider_force_vrs(pipeline, noop_fs, stages, *last_vgt_api_stage)) {
       assert(*last_vgt_api_stage == MESA_SHADER_VERTEX ||