[Mesa-dev] [PATCH 15/21] anv/pipeline: Add a separate "link" stage

Jason Ekstrand jason at jlekstrand.net
Sat Oct 28 18:36:23 UTC 2017


This breaks compilation up a bit into "link" and "compile".  In the
"link" stage, new anv_pipeline_link_* helpers are called which are
responsible for setting up the binding table and doing anything needed
to properly link with the next stage in the pipeline if one exists.
They are called in reverse order starting with the fragment shader so
you can assume linking in later stages is already done.
---
 src/intel/vulkan/anv_pipeline.c | 236 +++++++++++++++++++++++++---------------
 1 file changed, 149 insertions(+), 87 deletions(-)

diff --git a/src/intel/vulkan/anv_pipeline.c b/src/intel/vulkan/anv_pipeline.c
index 0f28245..42deaa6 100644
--- a/src/intel/vulkan/anv_pipeline.c
+++ b/src/intel/vulkan/anv_pipeline.c
@@ -541,6 +541,14 @@ anv_pipeline_upload_kernel(struct anv_pipeline *pipeline,
 }
 
 
+static void
+anv_pipeline_link_vs(const struct brw_compiler *compiler,
+                     struct anv_pipeline_stage *vs_stage,
+                     struct anv_pipeline_stage *next_stage)
+{
+   anv_fill_binding_table(&vs_stage->prog_data.vs.base.base, 0);
+}
+
 static VkResult
 anv_pipeline_compile_vs(struct anv_pipeline *pipeline,
                         struct anv_pipeline_cache *cache,
@@ -553,8 +561,6 @@ anv_pipeline_compile_vs(struct anv_pipeline *pipeline,
    if (bin == NULL) {
       void *mem_ctx = ralloc_context(NULL);
 
-      anv_fill_binding_table(&stage->prog_data.vs.base.base, 0);
-
       brw_compute_vue_map(&pipeline->device->info,
                           &stage->prog_data.vs.base.vue_map,
                           stage->nir->info.outputs_written,
@@ -629,13 +635,54 @@ merge_tess_info(struct shader_info *tes_info,
    tes_info->tess.point_mode |= tcs_info->tess.point_mode;
 }
 
+static void
+anv_pipeline_link_tcs(const struct brw_compiler *compiler,
+                      struct anv_pipeline_stage *tcs_stage,
+                      struct anv_pipeline_stage *tes_stage)
+{
+   assert(tes_stage && tes_stage->stage == MESA_SHADER_TESS_EVAL);
+
+   anv_fill_binding_table(&tcs_stage->prog_data.tcs.base.base, 0);
+
+   nir_lower_tes_patch_vertices(tes_stage->nir,
+                                tcs_stage->nir->info.tess.tcs_vertices_out);
+
+   /* Copy TCS info into the TES info */
+   merge_tess_info(&tes_stage->nir->info, &tcs_stage->nir->info);
+
+   /* Whacking the key after cache lookup is a bit sketchy, but all of
+    * this comes from the SPIR-V, which is part of the hash used for the
+    * pipeline cache.  So it should be safe.
+    */
+   tcs_stage->key.tcs.tes_primitive_mode =
+      tes_stage->nir->info.tess.primitive_mode;
+   tcs_stage->key.tcs.outputs_written = tcs_stage->nir->info.outputs_written;
+   tcs_stage->key.tcs.patch_outputs_written =
+      tcs_stage->nir->info.patch_outputs_written;
+   tcs_stage->key.tcs.quads_workaround =
+      compiler->devinfo->gen < 9 &&
+      tes_stage->nir->info.tess.primitive_mode == 7 /* GL_QUADS */ &&
+      tes_stage->nir->info.tess.spacing == TESS_SPACING_EQUAL;
+
+   tes_stage->key.tes.inputs_read = tcs_stage->nir->info.outputs_written;
+   tes_stage->key.tes.patch_inputs_read =
+      tcs_stage->nir->info.patch_outputs_written;
+}
+
+static void
+anv_pipeline_link_tes(const struct brw_compiler *compiler,
+                      struct anv_pipeline_stage *tes_stage,
+                      struct anv_pipeline_stage *next_stage)
+{
+   anv_fill_binding_table(&tes_stage->prog_data.tes.base.base, 0);
+}
+
 static VkResult
 anv_pipeline_compile_tcs_tes(struct anv_pipeline *pipeline,
                              struct anv_pipeline_cache *cache,
                              struct anv_pipeline_stage *tcs_stage,
                              struct anv_pipeline_stage *tes_stage)
 {
-   const struct gen_device_info *devinfo = &pipeline->device->info;
    const struct brw_compiler *compiler =
       pipeline->device->instance->physicalDevice.compiler;
    struct anv_shader_bin *tcs_bin = NULL;
@@ -644,33 +691,6 @@ anv_pipeline_compile_tcs_tes(struct anv_pipeline *pipeline,
    if (tcs_bin == NULL || tes_bin == NULL) {
       void *mem_ctx = ralloc_context(NULL);
 
-      nir_lower_tes_patch_vertices(tes_stage->nir,
-                                   tcs_stage->nir->info.tess.tcs_vertices_out);
-
-      /* Copy TCS info into the TES info */
-      merge_tess_info(&tes_stage->nir->info, &tcs_stage->nir->info);
-
-      anv_fill_binding_table(&tcs_stage->prog_data.tcs.base.base, 0);
-      anv_fill_binding_table(&tes_stage->prog_data.tes.base.base, 0);
-
-      /* Whacking the key after cache lookup is a bit sketchy, but all of
-       * this comes from the SPIR-V, which is part of the hash used for the
-       * pipeline cache.  So it should be safe.
-       */
-      tcs_stage->key.tcs.tes_primitive_mode =
-         tes_stage->nir->info.tess.primitive_mode;
-      tcs_stage->key.tcs.outputs_written = tcs_stage->nir->info.outputs_written;
-      tcs_stage->key.tcs.patch_outputs_written =
-         tcs_stage->nir->info.patch_outputs_written;
-      tcs_stage->key.tcs.quads_workaround =
-         devinfo->gen < 9 &&
-         tes_stage->nir->info.tess.primitive_mode == 7 /* GL_QUADS */ &&
-         tes_stage->nir->info.tess.spacing == TESS_SPACING_EQUAL;
-
-      tes_stage->key.tes.inputs_read = tcs_stage->nir->info.outputs_written;
-      tes_stage->key.tes.patch_inputs_read =
-         tcs_stage->nir->info.patch_outputs_written;
-
       const int shader_time_index = -1;
       const unsigned *shader_code;
 
@@ -728,6 +748,14 @@ anv_pipeline_compile_tcs_tes(struct anv_pipeline *pipeline,
    return VK_SUCCESS;
 }
 
+static void
+anv_pipeline_link_gs(const struct brw_compiler *compiler,
+                     struct anv_pipeline_stage *gs_stage,
+                     struct anv_pipeline_stage *next_stage)
+{
+   anv_fill_binding_table(&gs_stage->prog_data.gs.base.base, 0);
+}
+
 static VkResult
 anv_pipeline_compile_gs(struct anv_pipeline *pipeline,
                         struct anv_pipeline_cache *cache,
@@ -740,8 +768,6 @@ anv_pipeline_compile_gs(struct anv_pipeline *pipeline,
    if (bin == NULL) {
       void *mem_ctx = ralloc_context(NULL);
 
-      anv_fill_binding_table(&stage->prog_data.gs.base.base, 0);
-
       brw_compute_vue_map(&pipeline->device->info,
                           &stage->prog_data.gs.base.vue_map,
                           stage->nir->info.outputs_written,
@@ -778,6 +804,66 @@ anv_pipeline_compile_gs(struct anv_pipeline *pipeline,
    return VK_SUCCESS;
 }
 
+static void
+anv_pipeline_link_fs(const struct brw_compiler *compiler,
+                     struct anv_pipeline_stage *stage)
+{
+   unsigned num_rts = 0;
+   struct anv_pipeline_binding rt_bindings[8];
+   nir_function_impl *impl = nir_shader_get_entrypoint(stage->nir);
+   nir_foreach_variable_safe(var, &stage->nir->outputs) {
+      if (var->data.location < FRAG_RESULT_DATA0)
+         continue;
+
+      unsigned rt = var->data.location - FRAG_RESULT_DATA0;
+      if (rt >= stage->key.wm.nr_color_regions) {
+         /* Out-of-bounds, throw it away */
+         var->data.mode = nir_var_local;
+         exec_node_remove(&var->node);
+         exec_list_push_tail(&impl->locals, &var->node);
+         continue;
+      }
+
+      /* Give it a new, compacted, location */
+      var->data.location = FRAG_RESULT_DATA0 + num_rts;
+
+      unsigned array_len =
+         glsl_type_is_array(var->type) ? glsl_get_length(var->type) : 1;
+      assert(num_rts + array_len <= 8);
+
+      for (unsigned i = 0; i < array_len; i++) {
+         rt_bindings[num_rts + i] = (struct anv_pipeline_binding) {
+            .set = ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS,
+            .binding = 0,
+            .index = rt + i,
+         };
+      }
+
+      num_rts += array_len;
+   }
+
+   if (num_rts == 0) {
+      /* If we have no render targets, we need a null render target */
+      rt_bindings[0] = (struct anv_pipeline_binding) {
+         .set = ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS,
+         .binding = 0,
+         .index = UINT32_MAX,
+      };
+      num_rts = 1;
+   }
+
+   assert(num_rts <= 8);
+   assert(stage->bind_map.surface_count + num_rts <= 256);
+   memmove(stage->bind_map.surface_to_descriptor + num_rts,
+           stage->bind_map.surface_to_descriptor,
+           stage->bind_map.surface_count *
+           sizeof(*stage->bind_map.surface_to_descriptor));
+   typed_memcpy(stage->bind_map.surface_to_descriptor, rt_bindings, num_rts);
+   stage->bind_map.surface_count += num_rts;
+
+   anv_fill_binding_table(&stage->prog_data.wm.base, num_rts);
+}
+
 static VkResult
 anv_pipeline_compile_fs(struct anv_pipeline *pipeline,
                         struct anv_pipeline_cache *cache,
@@ -797,61 +883,6 @@ anv_pipeline_compile_fs(struct anv_pipeline *pipeline,
    if (bin == NULL) {
       void *mem_ctx = ralloc_context(NULL);
 
-      unsigned num_rts = 0;
-      struct anv_pipeline_binding rt_bindings[8];
-      nir_function_impl *impl = nir_shader_get_entrypoint(stage->nir);
-      nir_foreach_variable_safe(var, &stage->nir->outputs) {
-         if (var->data.location < FRAG_RESULT_DATA0)
-            continue;
-
-         unsigned rt = var->data.location - FRAG_RESULT_DATA0;
-         if (rt >= stage->key.wm.nr_color_regions) {
-            /* Out-of-bounds, throw it away */
-            var->data.mode = nir_var_local;
-            exec_node_remove(&var->node);
-            exec_list_push_tail(&impl->locals, &var->node);
-            continue;
-         }
-
-         /* Give it a new, compacted, location */
-         var->data.location = FRAG_RESULT_DATA0 + num_rts;
-
-         unsigned array_len =
-            glsl_type_is_array(var->type) ? glsl_get_length(var->type) : 1;
-         assert(num_rts + array_len <= 8);
-
-         for (unsigned i = 0; i < array_len; i++) {
-            rt_bindings[num_rts + i] = (struct anv_pipeline_binding) {
-               .set = ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS,
-               .binding = 0,
-               .index = rt + i,
-            };
-         }
-
-         num_rts += array_len;
-      }
-
-      if (num_rts == 0) {
-         /* If we have no render targets, we need a null render target */
-         rt_bindings[0] = (struct anv_pipeline_binding) {
-            .set = ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS,
-            .binding = 0,
-            .index = UINT32_MAX,
-         };
-         num_rts = 1;
-      }
-
-      assert(num_rts <= 8);
-      assert(stage->bind_map.surface_count + num_rts <= 256);
-      memmove(stage->bind_map.surface_to_descriptor + num_rts,
-              stage->bind_map.surface_to_descriptor,
-              stage->bind_map.surface_count *
-              sizeof(*stage->bind_map.surface_to_descriptor));
-      typed_memcpy(stage->bind_map.surface_to_descriptor, rt_bindings, num_rts);
-      stage->bind_map.surface_count += num_rts;
-
-      anv_fill_binding_table(&stage->prog_data.wm.base, num_rts);
-
       const unsigned *shader_code =
          brw_compile_fs(compiler, NULL, mem_ctx, &stage->key.wm,
                         &stage->prog_data.wm, stage->nir,
@@ -887,6 +918,8 @@ anv_pipeline_compile_graphics(struct anv_pipeline *pipeline,
                               struct anv_pipeline_cache *cache,
                               const VkGraphicsPipelineCreateInfo *info)
 {
+   const struct brw_compiler *compiler =
+      pipeline->device->instance->physicalDevice.compiler;
    struct anv_pipeline_stage stages[MESA_SHADER_STAGES] = {};
 
    pipeline->active_stages = 0;
@@ -1004,6 +1037,35 @@ anv_pipeline_compile_graphics(struct anv_pipeline *pipeline,
          goto fail;
    }
 
+   /* Walk backwards to link */
+   struct anv_pipeline_stage *next_stage = NULL;
+   for (int s = MESA_SHADER_STAGES - 1; s >= 0; s--) {
+      if (!stages[s].entrypoint)
+         continue;
+
+      switch (s) {
+      case MESA_SHADER_VERTEX:
+         anv_pipeline_link_vs(compiler, &stages[s], next_stage);
+         break;
+      case MESA_SHADER_TESS_CTRL:
+         anv_pipeline_link_tcs(compiler, &stages[s], next_stage);
+         break;
+      case MESA_SHADER_TESS_EVAL:
+         anv_pipeline_link_tes(compiler, &stages[s], next_stage);
+         break;
+      case MESA_SHADER_GEOMETRY:
+         anv_pipeline_link_gs(compiler, &stages[s], next_stage);
+         break;
+      case MESA_SHADER_FRAGMENT:
+         anv_pipeline_link_fs(compiler, &stages[s]);
+         break;
+      default:
+         unreachable("Invalid graphics shader stage");
+      }
+
+      next_stage = &stages[s];
+   }
+
    for (unsigned s = 0; s < MESA_SHADER_STAGES; s++) {
       if (!stages[s].entrypoint)
          continue;
-- 
2.5.0.400.gff86faf



More information about the mesa-dev mailing list