[Mesa-dev] [PATCH 2/2] i965: Refactor brw_upload_programs with a loop over each stage

Carl Worth cworth at cworth.org
Fri May 15 17:09:58 PDT 2015


This refactor idetnfies as much common code as possible across the various
stages within brw_upload_programs. The resulting code is a loop over all
relevant stages and various accessory functions (per_stage_state_dirty,
per_stage_populate_key, per_stage_codegen, and per_stage_vue_map_update),
whenever the code needs to vary from one stage to another.

This code is intended to have no functional change, and has been verified with
piglit across several Intel platforms.

>From here, any remaining conditionals within brw_upload_programs indicate code
that could benefit from some simplification, (such as combinining the FF_GS
and GS stages or otherwise reducing some special cases).

This refactoring is intended to progress toward a point where on-disk
shader-cache lookups can be inserted after brw_search_cache has been called
for each stage, but before the per_stage_codegen function has been called for
any stage. But before we can do that, the vue_map_update code will need to be
reworked in some form or another. (The current code hangs all of the vue_map
state off of prog_data such that it cannot be performed until after codegen,
but the vue_map update code also modifies state that will be examined by the
state_dirty calls of subsequent stages. So this will need to be disentangled
before we can make further progress to prepare for the shader-cache here.)
---
 src/mesa/drivers/dri/i965/brw_state_upload.c | 304 ++++++++++++++++++---------
 1 file changed, 207 insertions(+), 97 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_state_upload.c b/src/mesa/drivers/dri/i965/brw_state_upload.c
index 7fa434f..c75eef0 100644
--- a/src/mesa/drivers/dri/i965/brw_state_upload.c
+++ b/src/mesa/drivers/dri/i965/brw_state_upload.c
@@ -615,138 +615,248 @@ brw_print_dirty_count(struct dirty_bit_map *bit_map)
    }
 }
 
-static inline void
-brw_upload_programs(struct brw_context *brw,
-                    enum brw_pipeline pipeline)
+static bool
+per_stage_state_dirty(struct brw_context *brw,
+		      enum brw_cache_id stage)
+{
+   switch (stage) {
+   case BRW_CACHE_VS_PROG:
+      return brw_vs_state_dirty(brw);
+   case BRW_CACHE_FF_GS_PROG:
+      return brw_ff_gs_state_dirty(brw);
+   case BRW_CACHE_GS_PROG:
+      return brw_gs_state_dirty(brw);
+   case BRW_CACHE_FS_PROG:
+      return brw_wm_state_dirty(brw);
+   default:
+      unreachable("not reached");
+   }
+}
+
+struct key_block
 {
-   struct gl_context *ctx = &brw->ctx;
-   struct gl_shader_program **current = ctx->_Shader->CurrentProgram;
-   struct gl_shader_program *current_fp = ctx->_Shader->_CurrentFragmentProgram;
    struct brw_vs_prog_key vs_key;
    struct brw_ff_gs_prog_key ff_gs_key;
    struct brw_gs_prog_key gs_key;
    struct brw_wm_prog_key wm_key;
-   struct brw_stage_state *stage_state = &brw->gs.base;
-   struct brw_vertex_program *vp =
-      (struct brw_vertex_program *) brw->vertex_program;
-   struct brw_geometry_program *gp =
-      (struct brw_geometry_program *) brw->geometry_program;
-   struct brw_fragment_program *fp =
-      (struct brw_fragment_program *) brw->fragment_program;
+};
 
-   if (pipeline == BRW_RENDER_PIPELINE) {
+static void
+per_stage_populate_key(struct brw_context *brw,
+                       enum brw_cache_id stage,
+                       struct key_block *key_block,
+                       void **key_ret,
+                       size_t *key_size_ret,
+                       uint32_t **prog_offset_ret,
+                       void **prog_data_ret)
+{
+   switch (stage) {
+   case BRW_CACHE_VS_PROG:
+      brw_vs_populate_key(brw, &key_block->vs_key);
+      *key_ret = &key_block->vs_key;
+      *key_size_ret = sizeof(key_block->vs_key);
+      *prog_offset_ret = &brw->vs.base.prog_offset;
+      *prog_data_ret = &brw->vs.prog_data;
+      break;
+   case BRW_CACHE_FF_GS_PROG:
+      brw_ff_gs_populate_key(brw, &key_block->ff_gs_key);
+      *key_ret = &key_block->ff_gs_key;
+      *key_size_ret = sizeof(key_block->ff_gs_key);
+      *prog_offset_ret = &brw->ff_gs.prog_offset;
+      *prog_data_ret = &brw->ff_gs.prog_data;
+      break;
+   case BRW_CACHE_GS_PROG:
+      brw_gs_populate_key(brw, &key_block->gs_key);
+      *key_ret = &key_block->gs_key;
+      *key_size_ret = sizeof(key_block->gs_key);
+      *prog_offset_ret = &brw->gs.base.prog_offset;
+      *prog_data_ret = &brw->gs.prog_data;
+      break;
+   case BRW_CACHE_FS_PROG:
+      brw_wm_populate_key(brw, &key_block->wm_key);
+      *key_ret = &key_block->wm_key;
+      *key_size_ret = sizeof(key_block->wm_key);
+      *prog_offset_ret = &brw->wm.base.prog_offset;
+      *prog_data_ret = &brw->wm.prog_data;
+      break;
+   default:
+      unreachable("not reached");
+      break;
+   }
+}
 
-      if (brw_vs_state_dirty(brw)) {
+static bool
+per_stage_codegen(struct brw_context *brw,
+                  enum brw_cache_id stage,
+                  struct key_block *key_block)
+{
+   struct gl_context *ctx = &brw->ctx;
 
-         brw_vs_populate_key(brw, &vs_key);
+   switch (stage) {
+   case BRW_CACHE_VS_PROG:
+   {
+      struct brw_vertex_program *vp =
+	 (struct brw_vertex_program *) brw->vertex_program;
+      return brw_codegen_vs_prog(brw,
+                                 ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX],
+                                 vp, &key_block->vs_key);
+   }
+   case BRW_CACHE_FF_GS_PROG:
+      brw_codegen_ff_gs_prog(brw, &key_block->ff_gs_key);
+      return true;
+   case BRW_CACHE_GS_PROG:
+   {
+      struct brw_geometry_program *gp =
+	 (struct brw_geometry_program *) brw->geometry_program;
+      return brw_codegen_gs_prog(brw,
+                                 ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY],
+                                 gp, &key_block->gs_key);
+   }
+   case BRW_CACHE_FS_PROG:
+   {
+      struct brw_fragment_program *fp =
+	 (struct brw_fragment_program *) brw->fragment_program;
+      return brw_codegen_wm_prog(brw, ctx->_Shader->_CurrentFragmentProgram,
+                                 fp, &key_block->wm_key);
+   }
+   default:
+      unreachable("not reached");
+      break;
+   }
+}
 
-         if (!brw_search_cache(&brw->cache, BRW_CACHE_VS_PROG,
-                               &vs_key, sizeof(vs_key),
-                               &brw->vs.base.prog_offset, &brw->vs.prog_data)) {
-            bool success = brw_codegen_vs_prog(brw, current[MESA_SHADER_VERTEX],
-                                               vp, &vs_key);
-            (void) success;
-            assert(success);
-         }
-         brw->vs.base.prog_data = &brw->vs.prog_data->base.base;
-
-         if (memcmp(&brw->vs.prog_data->base.vue_map, &brw->vue_map_geom_out,
-                    sizeof(brw->vue_map_geom_out)) != 0) {
-            brw->vue_map_vs = brw->vs.prog_data->base.vue_map;
-            brw->ctx.NewDriverState |= BRW_NEW_VUE_MAP_VS;
-            if (brw->gen < 6) {
-               /* No geometry shader support, so the VS VUE map is the VUE map
-                * for the output of the "geometry" portion of the pipeline.
-                */
-               brw->vue_map_geom_out = brw->vue_map_vs;
-               brw->ctx.NewDriverState |= BRW_NEW_VUE_MAP_GEOM_OUT;
-            }
+static void
+per_stage_vue_map_update(struct brw_context *brw, enum brw_cache_id stage)
+{
+   switch (stage) {
+   case BRW_CACHE_VS_PROG:
+      brw->vs.base.prog_data = &brw->vs.prog_data->base.base;
+
+      if (memcmp(&brw->vs.prog_data->base.vue_map, &brw->vue_map_geom_out,
+                 sizeof(brw->vue_map_geom_out)) != 0) {
+         brw->vue_map_vs = brw->vs.prog_data->base.vue_map;
+         brw->ctx.NewDriverState |= BRW_NEW_VUE_MAP_VS;
+         if (brw->gen < 6) {
+            /* No geometry shader support, so the VS VUE map is the VUE map
+             * for the output of the "geometry" portion of the pipeline.
+             */
+            brw->vue_map_geom_out = brw->vue_map_vs;
+            brw->ctx.NewDriverState |= BRW_NEW_VUE_MAP_GEOM_OUT;
          }
       }
+      break;
+   case BRW_CACHE_GS_PROG:
+      brw->gs.base.prog_data = &brw->gs.prog_data->base.base;
+
+      if (memcmp(&brw->gs.prog_data->base.vue_map, &brw->vue_map_geom_out,
+                 sizeof(brw->vue_map_geom_out)) != 0) {
+         brw->vue_map_geom_out = brw->gs.prog_data->base.vue_map;
+         brw->ctx.NewDriverState |= BRW_NEW_VUE_MAP_GEOM_OUT;
+      }
+      break;
+   case BRW_CACHE_FS_PROG:
+      brw->wm.base.prog_data = &brw->wm.prog_data->base;
+      break;
+   default:
+      break;
+   }
+}
 
-      if (brw->gen < 6) {
+static inline void
+brw_upload_programs(struct brw_context *brw,
+                    enum brw_pipeline pipeline)
+{
+#define NUM_STAGES 4
+   bool need_new[NUM_STAGES];
+   enum brw_cache_id stage;
+   enum brw_cache_id stages[NUM_STAGES] = {BRW_CACHE_VS_PROG,
+                                           BRW_CACHE_FF_GS_PROG,
+                                           BRW_CACHE_GS_PROG,
+                                           BRW_CACHE_FS_PROG};
+   struct key_block key_block;
+   void *key;
+   uint32_t *prog_offset;
+   void *prog_data;
+   size_t key_size;
+   struct brw_geometry_program *gp =
+      (struct brw_geometry_program *) brw->geometry_program;
+   bool need_ff_gs = false;
+   int i;
 
-      UPLOAD_FF_GS_PROG:
+   if (pipeline == BRW_COMPUTE_PIPELINE) {
+      brw_upload_cs_prog(brw);
+      return;
+   }
 
-         if (brw_ff_gs_state_dirty(brw)) {
+   if (pipeline != BRW_RENDER_PIPELINE) {
+      return;
+   }
 
-            /* Populate the key:
-             */
-            brw_ff_gs_populate_key(brw, &ff_gs_key);
+   if (brw->gen < 6 ||
+       (gp == NULL && brw->gen == 6 &&
+        (brw->ctx.NewDriverState & BRW_NEW_TRANSFORM_FEEDBACK)))
+   {
+      need_ff_gs = true;
+   }
 
-            if (brw->ff_gs.prog_active != ff_gs_key.need_gs_prog) {
-               brw->ctx.NewDriverState |= BRW_NEW_FF_GS_PROG_DATA;
-               brw->ff_gs.prog_active = ff_gs_key.need_gs_prog;
-            }
+   for (i = 0; i < NUM_STAGES; i++) {
 
-            if (brw->ff_gs.prog_active) {
-               if (!brw_search_cache(&brw->cache, BRW_CACHE_FF_GS_PROG,
-                                     &ff_gs_key, sizeof(ff_gs_key),
-                                     &brw->ff_gs.prog_offset, &brw->ff_gs.prog_data)) {
-                  brw_codegen_ff_gs_prog(brw, &ff_gs_key);
-               }
-            }
-         }
-      } else {
+      stage = stages[i];
+      need_new[i] = per_stage_state_dirty(brw, stage);
 
-         if (brw_gs_state_dirty(brw)) {
+      if (stage == BRW_CACHE_FF_GS_PROG && !need_ff_gs)
+         continue;
 
-            if (gp == NULL) {
-               /* No geometry shader.  Vertex data just passes straight through. */
-               if (brw->ctx.NewDriverState & BRW_NEW_VUE_MAP_VS) {
-                  brw->vue_map_geom_out = brw->vue_map_vs;
-                  brw->ctx.NewDriverState |= BRW_NEW_VUE_MAP_GEOM_OUT;
-               }
+      if (stage == BRW_CACHE_GS_PROG && need_ff_gs)
+         continue;
 
-               if (brw->gen == 6 &&
-                   (brw->ctx.NewDriverState & BRW_NEW_TRANSFORM_FEEDBACK)) {
-                  goto UPLOAD_FF_GS_PROG;
-               }
+      if (need_new[i]) {
 
+         if ((stage == BRW_CACHE_FF_GS_PROG ||
+              stage == BRW_CACHE_GS_PROG) && gp == NULL)
+         {
+            /* No geometry shader.  Vertex data just passes straight
+             * through. */
+            if (brw->ctx.NewDriverState & BRW_NEW_VUE_MAP_VS) {
+               brw->vue_map_geom_out = brw->vue_map_vs;
+               brw->ctx.NewDriverState |= BRW_NEW_VUE_MAP_GEOM_OUT;
+            }
+
+            if (stage == BRW_CACHE_GS_PROG) {
                /* Other state atoms had better not try to access prog_data,
                 * since there's no GS program.
                 */
                brw->gs.prog_data = NULL;
                brw->gs.base.prog_data = NULL;
-            } else {
-
-               brw_gs_populate_key(brw, &gs_key);
-
-               if (!brw_search_cache(&brw->cache, BRW_CACHE_GS_PROG,
-                                     &gs_key, sizeof(gs_key),
-                                     &stage_state->prog_offset, &brw->gs.prog_data)) {
-                  bool success = brw_codegen_gs_prog(brw, current[MESA_SHADER_GEOMETRY],
-                                                     gp, &gs_key);
-                  assert(success);
-                  (void)success;
-               }
-               brw->gs.base.prog_data = &brw->gs.prog_data->base.base;
-
-               if (memcmp(&brw->gs.prog_data->base.vue_map, &brw->vue_map_geom_out,
-                          sizeof(brw->vue_map_geom_out)) != 0) {
-                  brw->vue_map_geom_out = brw->gs.prog_data->base.vue_map;
-                  brw->ctx.NewDriverState |= BRW_NEW_VUE_MAP_GEOM_OUT;
-               }
+
+               continue;
             }
          }
-      }
 
-      if (brw_wm_state_dirty(brw)) {
+         per_stage_populate_key (brw, stage, &key_block, &key, &key_size,
+                                 &prog_offset, &prog_data);
 
-         brw_wm_populate_key(brw, &wm_key);
+         if (stage == BRW_CACHE_FF_GS_PROG) {
 
-         if (!brw_search_cache(&brw->cache, BRW_CACHE_FS_PROG,
-                               &wm_key, sizeof(wm_key),
-                               &brw->wm.base.prog_offset, &brw->wm.prog_data)) {
-            bool success = brw_codegen_wm_prog(brw, current_fp, fp, &wm_key);
+            if (brw->ff_gs.prog_active != key_block.ff_gs_key.need_gs_prog) {
+               brw->ctx.NewDriverState |= BRW_NEW_FF_GS_PROG_DATA;
+               brw->ff_gs.prog_active = key_block.ff_gs_key.need_gs_prog;
+            }
+
+            if (!brw->ff_gs.prog_active)
+               continue;
+         }
+
+         if (!brw_search_cache(&brw->cache, stage, key, key_size,
+                               prog_offset, prog_data)) {
+            
+            bool success = per_stage_codegen(brw, stage, &key_block);
             (void) success;
             assert(success);
          }
-         brw->wm.base.prog_data = &brw->wm.prog_data->base;
-      }
 
-   } else if (pipeline == BRW_COMPUTE_PIPELINE) {
-      brw_upload_cs_prog(brw);
+         per_stage_vue_map_update(brw, stage);
+      }
    }
 }
 
-- 
2.1.4



More information about the mesa-dev mailing list