#include "lp_scene.h"
#include "lp_fence.h"
#include "lp_debug.h"
+#include "lp_context.h"
+#include "lp_state_fs.h"
#define RESOURCE_REF_SZ 32
struct resource_ref *next;
};
+#define SHADER_REF_SZ 32
+/** List of shader variant references */
+struct shader_ref {
+ struct lp_fragment_shader_variant *variant[SHADER_REF_SZ];
+ int count;
+ struct shader_ref *next;
+};
+
/**
* Create a new scene object.
j, scene->resource_reference_size);
}
+ /* Decrement shader variant ref counts
+ */
+ {
+ struct shader_ref *ref;
+ int i, j = 0;
+
+ for (ref = scene->frag_shaders; ref; ref = ref->next) {
+ for (i = 0; i < ref->count; i++) {
+ if (LP_DEBUG & DEBUG_SETUP)
+ debug_printf("shader %d: %p\n", j, (void *) ref->variant[i]);
+ j++;
+ lp_fs_variant_reference(llvmpipe_context(scene->pipe), &ref->variant[i], NULL);
+ }
+ }
+ }
+
/* Free all scene data blocks:
*/
{
lp_fence_reference(&scene->fence, NULL);
scene->resources = NULL;
+ scene->frag_shaders = NULL;
scene->scene_size = 0;
scene->resource_reference_size = 0;
}
+/**
+ * Add a reference to a fragment shader variant
+ */
+boolean
+lp_scene_add_frag_shader_reference(struct lp_scene *scene,
+ struct lp_fragment_shader_variant *variant)
+{
+ struct shader_ref *ref, **last = &scene->frag_shaders;
+ int i;
+
+ /* Look at existing resource blocks:
+ */
+ for (ref = scene->frag_shaders; ref; ref = ref->next) {
+ last = &ref->next;
+
+ /* Search for this resource:
+ */
+ for (i = 0; i < ref->count; i++)
+ if (ref->variant[i] == variant)
+ return TRUE;
+
+ if (ref->count < SHADER_REF_SZ) {
+ /* If the block is half-empty, then append the reference here.
+ */
+ break;
+ }
+ }
+
+ /* Create a new block if no half-empty block was found.
+ */
+ if (!ref) {
+ assert(*last == NULL);
+ *last = lp_scene_alloc(scene, sizeof *ref);
+ if (*last == NULL)
+ return FALSE;
+
+ ref = *last;
+ memset(ref, 0, sizeof *ref);
+ }
+
+ /* Append the reference to the reference block.
+ */
+ lp_fs_variant_reference(llvmpipe_context(scene->pipe), &ref->variant[ref->count++], variant);
+
+ return TRUE;
+}
+
/**
* Does this scene have a reference to the given resource?
*/
struct resource_ref;
+struct shader_ref;
+
/**
* All bins and bin data are contained here.
* Per-bin data goes into the 'tile' bins.
/** list of resources referenced by the scene commands */
struct resource_ref *resources;
+ /** list of frag shaders referenced by the scene commands */
+ struct shader_ref *frag_shaders;
+
/** Total memory used by the scene (in bytes). This sums all the
* data blocks and counts all bins, state, resource references and
* other random allocations within the scene.
boolean lp_scene_is_resource_referenced(const struct lp_scene *scene,
const struct pipe_resource *resource );
+boolean lp_scene_add_frag_shader_reference(struct lp_scene *scene,
+ struct lp_fragment_shader_variant *variant);
+
+
/**
* Allocate space for a command/data in the bin's data buffer.
setup->constants[i].stored_size = 0;
setup->constants[i].stored_data = NULL;
}
+
setup->fs.stored = NULL;
setup->dirty = ~0;
{
LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__,
variant);
- /* FIXME: reference count */
setup->fs.current.variant = variant;
setup->dirty |= LP_SETUP_NEW_FS;
return FALSE;
}
- memcpy(stored,
- &setup->fs.current,
- sizeof setup->fs.current);
+ memcpy(&stored->jit_context,
+ &setup->fs.current.jit_context,
+ sizeof setup->fs.current.jit_context);
+ stored->variant = setup->fs.current.variant;
+
+ if (!lp_scene_add_frag_shader_reference(scene,
+ setup->fs.current.variant))
+ return FALSE;
setup->fs.stored = stored;
/* The scene now references the textures in the rasterization
snprintf(module_name, sizeof(module_name), "fs%u_variant%u",
shader->no, shader->variants_created);
- variant->shader = shader;
+ pipe_reference_init(&variant->reference, 1);
+ lp_fs_reference(lp, &variant->shader, shader);
+
memcpy(&variant->key, key, shader->variant_key_size);
if (shader->base.ir.nir) {
if (!shader)
return NULL;
+ pipe_reference_init(&shader->reference, 1);
shader->no = fs_no++;
make_empty_list(&shader->variants);
draw_bind_fragment_shader(llvmpipe->draw,
(lp_fs ? lp_fs->draw_data : NULL));
- llvmpipe->fs = lp_fs;
+ lp_fs_reference(llvmpipe, &llvmpipe->fs, lp_fs);
+ /* invalidate the setup link, NEW_FS will make it update */
+ lp_setup_set_fs_variant(llvmpipe->setup, NULL);
llvmpipe->dirty |= LP_NEW_FS;
}
* Remove shader variant from two lists: the shader's variant list
* and the context's variant list.
*/
-static void
-llvmpipe_remove_shader_variant(struct llvmpipe_context *lp,
- struct lp_fragment_shader_variant *variant)
+
+static
+void llvmpipe_remove_shader_variant(struct llvmpipe_context *lp,
+ struct lp_fragment_shader_variant *variant)
{
if ((LP_DEBUG & DEBUG_FS) || (gallivm_debug & GALLIVM_DEBUG_IR)) {
debug_printf("llvmpipe: del fs #%u var %u v created %u v cached %u "
lp->nr_fs_variants, variant->nr_instrs, lp->nr_fs_instrs);
}
- gallivm_destroy(variant->gallivm);
-
/* remove from shader's list */
remove_from_list(&variant->list_item_local);
variant->shader->variants_cached--;
remove_from_list(&variant->list_item_global);
lp->nr_fs_variants--;
lp->nr_fs_instrs -= variant->nr_instrs;
+}
+
+void
+llvmpipe_destroy_shader_variant(struct llvmpipe_context *lp,
+ struct lp_fragment_shader_variant *variant)
+{
+ gallivm_destroy(variant->gallivm);
+
+ lp_fs_reference(lp, &variant->shader, NULL);
FREE(variant);
}
+void
+llvmpipe_destroy_fs(struct llvmpipe_context *llvmpipe,
+ struct lp_fragment_shader *shader)
+{
+ /* Delete draw module's data */
+ draw_delete_fragment_shader(llvmpipe->draw, shader->draw_data);
+
+ if (shader->base.ir.nir)
+ ralloc_free(shader->base.ir.nir);
+ assert(shader->variants_cached == 0);
+ FREE((void *) shader->base.tokens);
+ FREE(shader);
+}
static void
llvmpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
struct lp_fragment_shader *shader = fs;
struct lp_fs_variant_list_item *li;
- assert(fs != llvmpipe->fs);
-
- /*
- * XXX: we need to flush the context until we have some sort of reference
- * counting in fragment shaders as they may still be binned
- * Flushing alone might not sufficient we need to wait on it too.
- */
- llvmpipe_finish(pipe, __FUNCTION__);
-
/* Delete all the variants */
li = first_elem(&shader->variants);
while(!at_end(&shader->variants, li)) {
struct lp_fs_variant_list_item *next = next_elem(li);
+ struct lp_fragment_shader_variant *variant;
+ variant = li->base;
llvmpipe_remove_shader_variant(llvmpipe, li->base);
+ lp_fs_variant_reference(llvmpipe, &variant, NULL);
li = next;
}
- /* Delete draw module's data */
- draw_delete_fragment_shader(llvmpipe->draw, shader->draw_data);
-
- if (shader->base.ir.nir)
- ralloc_free(shader->base.ir.nir);
- assert(shader->variants_cached == 0);
- FREE((void *) shader->base.tokens);
- FREE(shader);
+ lp_fs_reference(llvmpipe, &shader, NULL);
}
-
-
static void
llvmpipe_set_constant_buffer(struct pipe_context *pipe,
enum pipe_shader_type shader, uint index,
if (variants_to_cull ||
lp->nr_fs_instrs >= LP_MAX_SHADER_INSTRUCTIONS) {
- struct pipe_context *pipe = &lp->pipe;
-
if (gallivm_debug & GALLIVM_DEBUG_PERF) {
debug_printf("Evicting FS: %u fs variants,\t%u total variants,"
"\t%u instrs,\t%u instrs/variant\n",
lp->nr_fs_instrs / lp->nr_fs_variants);
}
- /*
- * XXX: we need to flush the context until we have some sort of
- * reference counting in fragment shaders as they may still be binned
- * Flushing alone might not be sufficient we need to wait on it too.
- */
- llvmpipe_finish(pipe, __FUNCTION__);
-
/*
* We need to re-check lp->nr_fs_variants because an arbitrarliy large
* number of shader variants (potentially all of them) could be
assert(item);
assert(item->base);
llvmpipe_remove_shader_variant(lp, item->base);
+ lp_fs_variant_reference(lp, &item->base, NULL);
}
}
#include "gallivm/lp_bld_sample.h" /* for struct lp_sampler_static_state */
#include "gallivm/lp_bld_tgsi.h" /* for lp_tgsi_info */
#include "lp_bld_interp.h" /* for struct lp_shader_input */
-
+#include "util/u_inlines.h"
struct tgsi_token;
struct lp_fragment_shader;
struct lp_fragment_shader_variant
{
-
+ struct pipe_reference reference;
boolean opaque;
struct gallivm_state *gallivm;
{
struct pipe_shader_state base;
+ struct pipe_reference reference;
struct lp_tgsi_info info;
struct lp_fs_variant_list_item variants;
void
lp_debug_fs_variant(struct lp_fragment_shader_variant *variant);
+void
+llvmpipe_destroy_fs(struct llvmpipe_context *llvmpipe,
+ struct lp_fragment_shader *shader);
+
+static inline void
+lp_fs_reference(struct llvmpipe_context *llvmpipe,
+ struct lp_fragment_shader **ptr,
+ struct lp_fragment_shader *shader)
+{
+ struct lp_fragment_shader *old_ptr = *ptr;
+ if (pipe_reference(old_ptr ? &(*ptr)->reference : NULL, shader ? &shader->reference : NULL)) {
+ llvmpipe_destroy_fs(llvmpipe, old_ptr);
+ }
+ *ptr = shader;
+}
+
+void
+llvmpipe_destroy_shader_variant(struct llvmpipe_context *lp,
+ struct lp_fragment_shader_variant *variant);
+
+static inline void
+lp_fs_variant_reference(struct llvmpipe_context *llvmpipe,
+ struct lp_fragment_shader_variant **ptr,
+ struct lp_fragment_shader_variant *variant)
+{
+ struct lp_fragment_shader_variant *old_ptr = *ptr;
+ if (pipe_reference(old_ptr ? &(*ptr)->reference : NULL, variant ? &variant->reference : NULL)) {
+ llvmpipe_destroy_shader_variant(llvmpipe, old_ptr);
+ }
+ *ptr = variant;
+}
+
#endif /* LP_STATE_FS_H_ */