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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user