llvmpipe: introduce variant building infrastrucutre.
authorDave Airlie <airlied@redhat.com>
Tue, 27 Aug 2019 04:50:27 +0000 (14:50 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 4 Sep 2019 05:22:20 +0000 (15:22 +1000)
This doesn't actually build any of the shaders yet, but just
builds up the framework necessary to start building the shaders
and variants.

Reviewed-by: Roland Scheidegger <sroland@vmware.com>
src/gallium/drivers/llvmpipe/lp_state_cs.c

index 0da862626bcfdc7e23e7f074e42cd52d0d017fe7..cf47d1e8f06b771d7b04e1ee79a98ad332cb017e 100644 (file)
  **************************************************************************/
 #include "util/u_memory.h"
 #include "util/simple_list.h"
-
+#include "util/os_time.h"
+#include "tgsi/tgsi_dump.h"
 #include "tgsi/tgsi_parse.h"
 #include "gallivm/lp_bld_debug.h"
 #include "lp_state_cs.h"
 #include "lp_context.h"
 #include "lp_debug.h"
 #include "lp_state.h"
+#include "lp_perf.h"
 
 static void *
 llvmpipe_create_compute_state(struct pipe_context *pipe,
@@ -114,12 +116,194 @@ llvmpipe_delete_compute_state(struct pipe_context *pipe,
    FREE(shader);
 }
 
+static void
+make_variant_key(struct llvmpipe_context *lp,
+                 struct lp_compute_shader *shader,
+                 struct lp_compute_shader_variant_key *key)
+{
+   memset(key, 0, shader->variant_key_size);
+}
+
+static void
+dump_cs_variant_key(const struct lp_compute_shader_variant_key *key)
+{
+   debug_printf("cs variant %p:\n", (void *) key);
+}
+
+static void
+lp_debug_cs_variant(const struct lp_compute_shader_variant *variant)
+{
+   debug_printf("llvmpipe: Compute shader #%u variant #%u:\n",
+                variant->shader->no, variant->no);
+   tgsi_dump(variant->shader->base.tokens, 0);
+   dump_cs_variant_key(&variant->key);
+   debug_printf("\n");
+}
+
+static struct lp_compute_shader_variant *
+generate_variant(struct llvmpipe_context *lp,
+                 struct lp_compute_shader *shader,
+                 const struct lp_compute_shader_variant_key *key)
+{
+   struct lp_compute_shader_variant *variant;
+   char module_name[64];
+
+   variant = CALLOC_STRUCT(lp_compute_shader_variant);
+   if (!variant)
+      return NULL;
+
+   snprintf(module_name, sizeof(module_name), "cs%u_variant%u",
+            shader->no, shader->variants_created);
+
+   variant->gallivm = gallivm_create(module_name, lp->context);
+   if (!variant->gallivm) {
+      FREE(variant);
+      return NULL;
+   }
+
+   variant->shader = shader;
+   variant->list_item_global.base = variant;
+   variant->list_item_local.base = variant;
+   variant->no = shader->variants_created++;
+
+   memcpy(&variant->key, key, shader->variant_key_size);
+
+   if ((LP_DEBUG & DEBUG_CS) || (gallivm_debug & GALLIVM_DEBUG_IR)) {
+      lp_debug_cs_variant(variant);
+   }
+
+   lp_jit_init_cs_types(variant);
+
+   gallivm_free_ir(variant->gallivm);
+   return variant;
+}
+
+static void
+lp_cs_ctx_set_cs_variant( struct lp_cs_context *csctx,
+                          struct lp_compute_shader_variant *variant)
+{
+   csctx->cs.current.variant = variant;
+}
+
+static void
+llvmpipe_update_cs(struct llvmpipe_context *lp)
+{
+   struct lp_compute_shader *shader = lp->cs;
+
+   struct lp_compute_shader_variant_key key;
+   struct lp_compute_shader_variant *variant = NULL;
+   struct lp_cs_variant_list_item *li;
+
+   make_variant_key(lp, shader, &key);
+
+   /* Search the variants for one which matches the key */
+   li = first_elem(&shader->variants);
+   while(!at_end(&shader->variants, li)) {
+      if(memcmp(&li->base->key, &key, shader->variant_key_size) == 0) {
+         variant = li->base;
+         break;
+      }
+      li = next_elem(li);
+   }
+
+   if (variant) {
+      /* Move this variant to the head of the list to implement LRU
+       * deletion of shader's when we have too many.
+       */
+      move_to_head(&lp->cs_variants_list, &variant->list_item_global);
+   }
+   else {
+      /* variant not found, create it now */
+      int64_t t0, t1, dt;
+      unsigned i;
+      unsigned variants_to_cull;
+
+      if (LP_DEBUG & DEBUG_CS) {
+         debug_printf("%u variants,\t%u instrs,\t%u instrs/variant\n",
+                      lp->nr_cs_variants,
+                      lp->nr_cs_instrs,
+                      lp->nr_cs_variants ? lp->nr_cs_instrs / lp->nr_cs_variants : 0);
+      }
+
+      /* First, check if we've exceeded the max number of shader variants.
+       * If so, free 6.25% of them (the least recently used ones).
+       */
+      variants_to_cull = lp->nr_cs_variants >= LP_MAX_SHADER_VARIANTS ? LP_MAX_SHADER_VARIANTS / 16 : 0;
+
+      if (variants_to_cull ||
+          lp->nr_cs_instrs >= LP_MAX_SHADER_INSTRUCTIONS) {
+         if (gallivm_debug & GALLIVM_DEBUG_PERF) {
+            debug_printf("Evicting CS: %u cs variants,\t%u total variants,"
+                         "\t%u instrs,\t%u instrs/variant\n",
+                         shader->variants_cached,
+                         lp->nr_cs_variants, lp->nr_cs_instrs,
+                         lp->nr_cs_instrs / lp->nr_cs_variants);
+         }
+
+         /*
+          * We need to re-check lp->nr_cs_variants because an arbitrarliy large
+          * number of shader variants (potentially all of them) could be
+          * pending for destruction on flush.
+          */
+
+         for (i = 0; i < variants_to_cull || lp->nr_cs_instrs >= LP_MAX_SHADER_INSTRUCTIONS; i++) {
+            struct lp_cs_variant_list_item *item;
+            if (is_empty_list(&lp->cs_variants_list)) {
+               break;
+            }
+            item = last_elem(&lp->cs_variants_list);
+            assert(item);
+            assert(item->base);
+            llvmpipe_remove_cs_shader_variant(lp, item->base);
+         }
+      }
+      /*
+       * Generate the new variant.
+       */
+      t0 = os_time_get();
+      variant = generate_variant(lp, shader, &key);
+      t1 = os_time_get();
+      dt = t1 - t0;
+      LP_COUNT_ADD(llvm_compile_time, dt);
+      LP_COUNT_ADD(nr_llvm_compiles, 2);  /* emit vs. omit in/out test */
+
+      /* Put the new variant into the list */
+      if (variant) {
+         insert_at_head(&shader->variants, &variant->list_item_local);
+         insert_at_head(&lp->cs_variants_list, &variant->list_item_global);
+         lp->nr_cs_variants++;
+         lp->nr_cs_instrs += variant->nr_instrs;
+         shader->variants_cached++;
+      }
+   }
+   /* Bind this variant */
+   lp_cs_ctx_set_cs_variant(lp->csctx, variant);
+}
+
+static void
+llvmpipe_cs_update_derived(struct llvmpipe_context *llvmpipe)
+{
+   if (llvmpipe->cs_dirty & (LP_CSNEW_CS))
+      llvmpipe_update_cs(llvmpipe);
+
+   llvmpipe->cs_dirty = 0;
+}
+
+static void llvmpipe_launch_grid(struct pipe_context *pipe,
+                                 const struct pipe_grid_info *info)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   llvmpipe_cs_update_derived(llvmpipe);
+}
+
 void
 llvmpipe_init_compute_funcs(struct llvmpipe_context *llvmpipe)
 {
    llvmpipe->pipe.create_compute_state = llvmpipe_create_compute_state;
    llvmpipe->pipe.bind_compute_state = llvmpipe_bind_compute_state;
    llvmpipe->pipe.delete_compute_state = llvmpipe_delete_compute_state;
+   llvmpipe->pipe.launch_grid = llvmpipe_launch_grid;
 }
 
 void