summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/llvmpipe
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/llvmpipe')
-rw-r--r--src/gallium/drivers/llvmpipe/lp_context.c3
-rw-r--r--src/gallium/drivers/llvmpipe/lp_context.h3
-rw-r--r--src/gallium/drivers/llvmpipe/lp_limits.h5
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_fs.c118
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_fs.h13
5 files changed, 107 insertions, 35 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_context.c b/src/gallium/drivers/llvmpipe/lp_context.c
index 9e88a6e09f..06689c20eb 100644
--- a/src/gallium/drivers/llvmpipe/lp_context.c
+++ b/src/gallium/drivers/llvmpipe/lp_context.c
@@ -36,6 +36,7 @@
#include "util/u_inlines.h"
#include "util/u_math.h"
#include "util/u_memory.h"
+#include "util/u_simple_list.h"
#include "lp_clear.h"
#include "lp_context.h"
#include "lp_flush.h"
@@ -94,6 +95,8 @@ llvmpipe_create_context( struct pipe_screen *screen, void *priv )
memset(llvmpipe, 0, sizeof *llvmpipe);
+ make_empty_list(&llvmpipe->fs_variants_list);
+
llvmpipe->pipe.winsys = screen->winsys;
llvmpipe->pipe.screen = screen;
llvmpipe->pipe.priv = priv;
diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h
index cb04d4a4d5..1bdd0f79e1 100644
--- a/src/gallium/drivers/llvmpipe/lp_context.h
+++ b/src/gallium/drivers/llvmpipe/lp_context.h
@@ -38,6 +38,7 @@
#include "lp_tex_sample.h"
#include "lp_jit.h"
#include "lp_setup.h"
+#include "lp_state_fs.h"
struct llvmpipe_vbuf_render;
@@ -105,6 +106,8 @@ struct llvmpipe_context {
unsigned tex_timestamp;
boolean no_rast;
+ struct lp_fs_variant_list_item fs_variants_list;
+ unsigned nr_fs_variants;
};
diff --git a/src/gallium/drivers/llvmpipe/lp_limits.h b/src/gallium/drivers/llvmpipe/lp_limits.h
index 4102a9df67..d1c431475d 100644
--- a/src/gallium/drivers/llvmpipe/lp_limits.h
+++ b/src/gallium/drivers/llvmpipe/lp_limits.h
@@ -66,5 +66,10 @@
*/
#define LP_MAX_SCENE_SIZE (512 * 1024 * 1024)
+/**
+ * Max number of shader variants (for all shaders combined,
+ * per context) that will be kept around.
+ */
+#define LP_MAX_SHADER_VARIANTS 1024
#endif /* LP_LIMITS_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c
index 2619e043fd..48c7754e41 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_fs.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c
@@ -68,6 +68,7 @@
#include "util/u_format.h"
#include "util/u_dump.h"
#include "util/u_string.h"
+#include "util/u_simple_list.h"
#include "os/os_time.h"
#include "pipe/p_shader_tokens.h"
#include "draw/draw_context.h"
@@ -95,6 +96,7 @@
#include "lp_setup.h"
#include "lp_state.h"
#include "lp_tex_sample.h"
+#include "lp_flush.h"
#include <llvm-c/Analysis.h>
@@ -936,7 +938,10 @@ generate_variant(struct llvmpipe_context *lp,
if(!variant)
return NULL;
- variant->no = shader->variant_no++;
+ variant->lpfs = shader;
+ variant->list_item_global.base = variant;
+ variant->list_item_local.base = variant;
+ variant->no = shader->variants_created++;
memcpy(&variant->key, key, sizeof *key);
@@ -962,10 +967,6 @@ generate_variant(struct llvmpipe_context *lp,
!shader->info.uses_kill
? TRUE : FALSE;
- /* insert new variant into linked list */
- variant->next = shader->variants;
- shader->variants = variant;
-
return variant;
}
@@ -981,6 +982,7 @@ llvmpipe_create_fs_state(struct pipe_context *pipe,
return NULL;
shader->no = fs_no++;
+ make_empty_list(&shader->variants);
/* get/save the summary info for this shader */
tgsi_scan_shader(templ->tokens, &shader->info);
@@ -1024,14 +1026,40 @@ llvmpipe_bind_fs_state(struct pipe_context *pipe, void *fs)
llvmpipe->dirty |= LP_NEW_FS;
}
+static void
+remove_shader_variant(struct llvmpipe_context *lp,
+ struct lp_fragment_shader_variant *variant)
+{
+ struct llvmpipe_screen *screen = llvmpipe_screen(lp->pipe.screen);
+ unsigned i;
+
+ if (gallivm_debug & GALLIVM_DEBUG_IR) {
+ debug_printf("llvmpipe: del fs #%u var #%u v created #%u v cached #%u v total cached #%u\n",
+ variant->lpfs->no, variant->no, variant->lpfs->variants_created,
+ variant->lpfs->variants_cached, lp->nr_fs_variants);
+ }
+ for (i = 0; i < Elements(variant->function); i++) {
+ if (variant->function[i]) {
+ if (variant->jit_function[i])
+ LLVMFreeMachineCodeForFunction(screen->engine,
+ variant->function[i]);
+ LLVMDeleteFunction(variant->function[i]);
+ }
+ }
+ remove_from_list(&variant->list_item_local);
+ variant->lpfs->variants_cached--;
+ remove_from_list(&variant->list_item_global);
+ lp->nr_fs_variants--;
+ FREE(variant);
+}
static void
llvmpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
{
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
- struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
+ struct pipe_fence_handle *fence = NULL;
struct lp_fragment_shader *shader = fs;
- struct lp_fragment_shader_variant *variant;
+ struct lp_fs_variant_list_item *li;
assert(fs != llvmpipe->fs);
(void) llvmpipe;
@@ -1039,29 +1067,23 @@ llvmpipe_delete_fs_state(struct pipe_context *pipe, void *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.
*/
- draw_flush(llvmpipe->draw);
- lp_setup_flush(llvmpipe->setup, 0);
-
- variant = shader->variants;
- while(variant) {
- struct lp_fragment_shader_variant *next = variant->next;
- unsigned i;
- for (i = 0; i < Elements(variant->function); i++) {
- if (variant->function[i]) {
- if (variant->jit_function[i])
- LLVMFreeMachineCodeForFunction(screen->engine,
- variant->function[i]);
- LLVMDeleteFunction(variant->function[i]);
- }
- }
+ llvmpipe_flush(pipe, 0, &fence);
- FREE(variant);
+ if (fence) {
+ pipe->screen->fence_finish(pipe->screen, fence, 0);
+ pipe->screen->fence_reference(pipe->screen, &fence, NULL);
+ }
- variant = next;
+ li = first_elem(&shader->variants);
+ while(!at_end(&shader->variants, li)) {
+ remove_shader_variant(llvmpipe, li->base);
+ li = next_elem(li);
}
+ assert(shader->variants_cached == 0);
FREE((void *) shader->base.tokens);
FREE(shader);
}
@@ -1215,7 +1237,6 @@ make_variant_key(struct llvmpipe_context *lp,
lp_sampler_static_state(&key->sampler[i], lp->fragment_sampler_views[i], lp->sampler[i]);
}
-
/**
* Update fragment state. This is called just prior to drawing
* something when some fragment-related state has changed.
@@ -1225,21 +1246,47 @@ llvmpipe_update_fs(struct llvmpipe_context *lp)
{
struct lp_fragment_shader *shader = lp->fs;
struct lp_fragment_shader_variant_key key;
- struct lp_fragment_shader_variant *variant;
+ struct lp_fragment_shader_variant *variant = NULL;
+ struct lp_fs_variant_list_item *li;
make_variant_key(lp, shader, &key);
- variant = shader->variants;
- while(variant) {
- if(memcmp(&variant->key, &key, sizeof key) == 0)
+ li = first_elem(&shader->variants);
+ while(!at_end(&shader->variants, li)) {
+ if(memcmp(&li->base->key, &key, sizeof key) == 0) {
+ variant = li->base;
break;
-
- variant = variant->next;
+ }
+ li = next_elem(li);
}
- if (!variant) {
+ if (variant) {
+ move_to_head(&lp->fs_variants_list, &variant->list_item_global);
+ }
+ else {
int64_t t0, t1;
int64_t dt;
+ unsigned i;
+ if (lp->nr_fs_variants >= LP_MAX_SHADER_VARIANTS) {
+ struct pipe_context *pipe = &lp->pipe;
+ struct pipe_fence_handle *fence = NULL;
+
+ /*
+ * 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_flush(pipe, 0, &fence);
+
+ if (fence) {
+ pipe->screen->fence_finish(pipe->screen, fence, 0);
+ pipe->screen->fence_reference(pipe->screen, &fence, NULL);
+ }
+ for (i = 0; i < LP_MAX_SHADER_VARIANTS / 4; i++) {
+ struct lp_fs_variant_list_item *item = last_elem(&lp->fs_variants_list);
+ remove_shader_variant(lp, item->base);
+ }
+ }
t0 = os_time_get();
variant = generate_variant(lp, shader, &key);
@@ -1248,6 +1295,13 @@ llvmpipe_update_fs(struct llvmpipe_context *lp)
dt = t1 - t0;
LP_COUNT_ADD(llvm_compile_time, dt);
LP_COUNT_ADD(nr_llvm_compiles, 2); /* emit vs. omit in/out test */
+
+ if (variant) {
+ insert_at_head(&shader->variants, &variant->list_item_local);
+ insert_at_head(&lp->fs_variants_list, &variant->list_item_global);
+ lp->nr_fs_variants++;
+ shader->variants_cached++;
+ }
}
lp_setup_set_fs_variant(lp->setup, variant);
diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.h b/src/gallium/drivers/llvmpipe/lp_state_fs.h
index 64ead2a997..272c9269ea 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_fs.h
+++ b/src/gallium/drivers/llvmpipe/lp_state_fs.h
@@ -64,10 +64,16 @@ struct lp_fragment_shader_variant_key
struct lp_sampler_static_state sampler[PIPE_MAX_SAMPLERS];
};
+struct lp_fs_variant_list_item
+{
+ struct lp_fragment_shader_variant *base;
+ struct lp_fs_variant_list_item *next, *prev;
+};
struct lp_fragment_shader_variant
{
struct lp_fragment_shader_variant_key key;
+ struct lp_fragment_shader *lpfs;
boolean opaque;
@@ -75,7 +81,7 @@ struct lp_fragment_shader_variant
lp_jit_frag_func jit_function[2];
- struct lp_fragment_shader_variant *next;
+ struct lp_fs_variant_list_item list_item_global, list_item_local;
/* For debugging/profiling purposes */
unsigned no;
@@ -89,11 +95,12 @@ struct lp_fragment_shader
struct tgsi_shader_info info;
- struct lp_fragment_shader_variant *variants;
+ struct lp_fs_variant_list_item variants;
/* For debugging/profiling purposes */
unsigned no;
- unsigned variant_no;
+ unsigned variants_created;
+ unsigned variants_cached;
};