llvmpipe: introduce variant building infrastrucutre.

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>
This commit is contained in:
Dave Airlie
2019-08-27 14:50:27 +10:00
parent fc01fafdbc
commit 6ea41df94c
+185 -1
View File
@@ -24,13 +24,15 @@
**************************************************************************/
#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