summaryrefslogtreecommitdiff
path: root/src/gallium/auxiliary/cso_cache
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/auxiliary/cso_cache')
-rw-r--r--src/gallium/auxiliary/cso_cache/cso_cache.c196
-rw-r--r--src/gallium/auxiliary/cso_cache/cso_cache.h87
-rw-r--r--src/gallium/auxiliary/cso_cache/cso_hash.c45
-rw-r--r--src/gallium/auxiliary/cso_cache/cso_hash.h22
4 files changed, 313 insertions, 37 deletions
diff --git a/src/gallium/auxiliary/cso_cache/cso_cache.c b/src/gallium/auxiliary/cso_cache/cso_cache.c
index 9e77e0774d..b427b509f8 100644
--- a/src/gallium/auxiliary/cso_cache/cso_cache.c
+++ b/src/gallium/auxiliary/cso_cache/cso_cache.c
@@ -28,9 +28,22 @@
/* Authors: Zack Rusin <zack@tungstengraphics.com>
*/
+#include "pipe/p_util.h"
+
#include "cso_cache.h"
#include "cso_hash.h"
+
+struct cso_cache {
+ struct cso_hash *blend_hash;
+ struct cso_hash *depth_stencil_hash;
+ struct cso_hash *fs_hash;
+ struct cso_hash *vs_hash;
+ struct cso_hash *rasterizer_hash;
+ struct cso_hash *sampler_hash;
+ int max_size;
+};
+
#if 1
static unsigned hash_key(const void *key, unsigned key_size)
{
@@ -114,12 +127,106 @@ static int _cso_size_for_type(enum cso_cache_type type)
return 0;
}
+
+static void delete_blend_state(void *state, void *data)
+{
+ struct cso_blend *cso = (struct cso_blend *)state;
+ if (cso->delete_state && cso->data != &cso->state)
+ cso->delete_state(cso->context, cso->data);
+}
+
+static void delete_depth_stencil_state(void *state, void *data)
+{
+ struct cso_depth_stencil_alpha *cso = (struct cso_depth_stencil_alpha *)state;
+ if (cso->delete_state && cso->data != &cso->state)
+ cso->delete_state(cso->context, cso->data);
+}
+
+static void delete_sampler_state(void *state, void *data)
+{
+ struct cso_sampler *cso = (struct cso_sampler *)state;
+ if (cso->delete_state && cso->data != &cso->state)
+ cso->delete_state(cso->context, cso->data);
+}
+
+static void delete_rasterizer_state(void *state, void *data)
+{
+ struct cso_rasterizer *cso = (struct cso_rasterizer *)state;
+ if (cso->delete_state && cso->data != &cso->state)
+ cso->delete_state(cso->context, cso->data);
+}
+
+static void delete_fs_state(void *state, void *data)
+{
+ struct cso_fragment_shader *cso = (struct cso_fragment_shader *)state;
+ if (cso->delete_state && cso->data != &cso->state)
+ cso->delete_state(cso->context, cso->data);
+}
+
+static void delete_vs_state(void *state, void *data)
+{
+ struct cso_vertex_shader *cso = (struct cso_vertex_shader *)state;
+ if (cso->delete_state && cso->data != &cso->state)
+ cso->delete_state(cso->context, cso->data);
+}
+
+
+static INLINE void delete_cso(void *state, enum cso_cache_type type)
+{
+ switch (type) {
+ case CSO_BLEND: {
+ delete_blend_state(state, 0);
+ }
+ break;
+ case CSO_SAMPLER: {
+ delete_sampler_state(state, 0);
+ }
+ break;
+ case CSO_DEPTH_STENCIL_ALPHA: {
+ delete_depth_stencil_state(state, 0);
+ }
+ break;
+ case CSO_RASTERIZER: {
+ delete_rasterizer_state(state, 0);
+ }
+ break;
+ case CSO_FRAGMENT_SHADER: {
+ delete_fs_state(state, 0);
+ }
+ break;
+ case CSO_VERTEX_SHADER: {
+ delete_vs_state(state, 0);
+ }
+ break;
+ }
+ FREE(state);
+}
+
+static INLINE void sanitize_hash(struct cso_hash *hash, enum cso_cache_type type,
+ int max_size)
+{
+ /* if we're approach the maximum size, remove fourth of the entries
+ * otherwise every subsequent call will go through the same */
+ int max_entries = (max_size > cso_hash_size(hash)) ? max_size : cso_hash_size(hash);
+ int to_remove = (max_size < max_entries) * max_entries/4;
+ while (to_remove) {
+ /*remove elements until we're good */
+ /*fixme: currently we pick the nodes to remove at random*/
+ struct cso_hash_iter iter = cso_hash_first_node(hash);
+ void *cso = cso_hash_take(hash, cso_hash_iter_key(iter));
+ delete_cso(cso, type);
+ --to_remove;
+ }
+}
+
struct cso_hash_iter
cso_insert_state(struct cso_cache *sc,
unsigned hash_key, enum cso_cache_type type,
void *state)
{
struct cso_hash *hash = _cso_hash_for_type(sc, type);
+ sanitize_hash(hash, type, sc->max_size);
+
return cso_hash_insert(hash, hash_key, state);
}
@@ -132,6 +239,26 @@ cso_find_state(struct cso_cache *sc,
return cso_hash_find(hash, hash_key);
}
+
+void *cso_hash_find_data_from_template( struct cso_hash *hash,
+ unsigned hash_key,
+ void *templ,
+ int size )
+{
+ struct cso_hash_iter iter = cso_hash_find(hash, hash_key);
+ while (!cso_hash_iter_is_null(iter)) {
+ void *iter_data = cso_hash_iter_data(iter);
+ if (!memcmp(iter_data, templ, size)) {
+ /* Return the payload:
+ */
+ return (unsigned char *)iter_data + size;
+ }
+ iter = cso_hash_iter_next(iter);
+ }
+ return NULL;
+}
+
+
struct cso_hash_iter cso_find_state_template(struct cso_cache *sc,
unsigned hash_key, enum cso_cache_type type,
void *templ)
@@ -156,8 +283,9 @@ void * cso_take_state(struct cso_cache *sc,
struct cso_cache *cso_cache_create(void)
{
- struct cso_cache *sc = malloc(sizeof(struct cso_cache));
+ struct cso_cache *sc = MALLOC_STRUCT(cso_cache);
+ sc->max_size = 4096;
sc->blend_hash = cso_hash_create();
sc->sampler_hash = cso_hash_create();
sc->depth_stencil_hash = cso_hash_create();
@@ -168,14 +296,78 @@ struct cso_cache *cso_cache_create(void)
return sc;
}
+void cso_for_each_state(struct cso_cache *sc, enum cso_cache_type type,
+ cso_state_callback func, void *user_data)
+{
+ struct cso_hash *hash = 0;
+ struct cso_hash_iter iter;
+
+ switch (type) {
+ case CSO_BLEND:
+ hash = sc->blend_hash;
+ break;
+ case CSO_SAMPLER:
+ hash = sc->sampler_hash;
+ break;
+ case CSO_DEPTH_STENCIL_ALPHA:
+ hash = sc->depth_stencil_hash;
+ break;
+ case CSO_RASTERIZER:
+ hash = sc->rasterizer_hash;
+ break;
+ case CSO_FRAGMENT_SHADER:
+ hash = sc->fs_hash;
+ break;
+ case CSO_VERTEX_SHADER:
+ hash = sc->vs_hash;
+ break;
+ }
+
+ iter = cso_hash_first_node(hash);
+ while (!cso_hash_iter_is_null(iter)) {
+ void *state = cso_hash_iter_data(iter);
+ if (state) {
+ func(state, user_data);
+ }
+ iter = cso_hash_iter_next(iter);
+ }
+}
+
void cso_cache_delete(struct cso_cache *sc)
{
assert(sc);
+ /* delete driver data */
+ cso_for_each_state(sc, CSO_BLEND, delete_blend_state, 0);
+ cso_for_each_state(sc, CSO_DEPTH_STENCIL_ALPHA, delete_depth_stencil_state, 0);
+ cso_for_each_state(sc, CSO_FRAGMENT_SHADER, delete_fs_state, 0);
+ cso_for_each_state(sc, CSO_VERTEX_SHADER, delete_vs_state, 0);
+ cso_for_each_state(sc, CSO_RASTERIZER, delete_rasterizer_state, 0);
+ cso_for_each_state(sc, CSO_SAMPLER, delete_sampler_state, 0);
+
cso_hash_delete(sc->blend_hash);
cso_hash_delete(sc->sampler_hash);
cso_hash_delete(sc->depth_stencil_hash);
cso_hash_delete(sc->rasterizer_hash);
cso_hash_delete(sc->fs_hash);
cso_hash_delete(sc->vs_hash);
- free(sc);
+ FREE(sc);
}
+
+void cso_set_maximum_cache_size(struct cso_cache *sc, int number)
+{
+ sc->max_size = number;
+
+ sanitize_hash(sc->blend_hash, CSO_BLEND, sc->max_size);
+ sanitize_hash(sc->depth_stencil_hash, CSO_DEPTH_STENCIL_ALPHA,
+ sc->max_size);
+ sanitize_hash(sc->fs_hash, CSO_FRAGMENT_SHADER, sc->max_size);
+ sanitize_hash(sc->vs_hash, CSO_VERTEX_SHADER, sc->max_size);
+ sanitize_hash(sc->rasterizer_hash, CSO_RASTERIZER, sc->max_size);
+ sanitize_hash(sc->sampler_hash, CSO_SAMPLER, sc->max_size);
+}
+
+int cso_maximum_cache_size(const struct cso_cache *sc)
+{
+ return sc->max_size;
+}
+
diff --git a/src/gallium/auxiliary/cso_cache/cso_cache.h b/src/gallium/auxiliary/cso_cache/cso_cache.h
index 116e2eaa2c..3b0fe100b8 100644
--- a/src/gallium/auxiliary/cso_cache/cso_cache.h
+++ b/src/gallium/auxiliary/cso_cache/cso_cache.h
@@ -1,6 +1,6 @@
/**************************************************************************
*
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -25,9 +25,48 @@
*
**************************************************************************/
- /*
- * Authors:
- * Zack Rusin <zack@tungstengraphics.com>
+ /**
+ * @file
+ * Constant State Object (CSO) cache.
+ *
+ * The basic idea is that the states are created via the
+ * create_state/bind_state/delete_state semantics. The driver is expected to
+ * perform as much of the Gallium state translation to whatever its internal
+ * representation is during the create call. Gallium then has a caching
+ * mechanism where it stores the created states. When the pipeline needs an
+ * actual state change, a bind call is issued. In the bind call the driver
+ * gets its already translated representation.
+ *
+ * Those semantics mean that the driver doesn't do the repeated translations
+ * of states on every frame, but only once, when a new state is actually
+ * created.
+ *
+ * Even on hardware that doesn't do any kind of state cache, it makes the
+ * driver look a lot neater, plus it avoids all the redundant state
+ * translations on every frame.
+ *
+ * Currently our constant state objects are:
+ * - alpha test
+ * - blend
+ * - depth stencil
+ * - fragment shader
+ * - rasterizer (old setup)
+ * - sampler
+ * - vertex shader
+ *
+ * Things that are not constant state objects include:
+ * - blend_color
+ * - clip_state
+ * - clear_color_state
+ * - constant_buffer
+ * - feedback_state
+ * - framebuffer_state
+ * - polygon_stipple
+ * - scissor_state
+ * - texture_state
+ * - viewport_state
+ *
+ * @author Zack Rusin <zack@tungstengraphics.com>
*/
#ifndef CSO_CACHE_H
@@ -36,46 +75,57 @@
#include "pipe/p_context.h"
#include "pipe/p_state.h"
+/* cso_hash.h is necessary for cso_hash_iter, as MSVC requires structures
+ * returned by value to be fully defined */
+#include "cso_hash.h"
-struct cso_hash;
-struct cso_cache {
- struct cso_hash *blend_hash;
- struct cso_hash *depth_stencil_hash;
- struct cso_hash *fs_hash;
- struct cso_hash *vs_hash;
- struct cso_hash *rasterizer_hash;
- struct cso_hash *sampler_hash;
-};
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct cso_cache;
struct cso_blend {
struct pipe_blend_state state;
void *data;
+ void (*delete_state)(void *, void *);
+ void *context;
};
struct cso_depth_stencil_alpha {
struct pipe_depth_stencil_alpha_state state;
void *data;
+ void (*delete_state)(void *, void *);
+ void *context;
};
struct cso_rasterizer {
struct pipe_rasterizer_state state;
void *data;
+ void (*delete_state)(void *, void *);
+ void *context;
};
struct cso_fragment_shader {
struct pipe_shader_state state;
void *data;
+ void (*delete_state)(void *, void *);
+ void *context;
};
struct cso_vertex_shader {
struct pipe_shader_state state;
void *data;
+ void (*delete_state)(void *, void *);
+ void *context;
};
struct cso_sampler {
struct pipe_sampler_state state;
void *data;
+ void (*delete_state)(void *, void *);
+ void *context;
};
@@ -88,6 +138,8 @@ enum cso_cache_type {
CSO_VERTEX_SHADER
};
+typedef void (*cso_state_callback)(void *, void *);
+
unsigned cso_construct_key(void *item, int item_size);
struct cso_cache *cso_cache_create(void);
@@ -101,7 +153,16 @@ struct cso_hash_iter cso_find_state(struct cso_cache *sc,
struct cso_hash_iter cso_find_state_template(struct cso_cache *sc,
unsigned hash_key, enum cso_cache_type type,
void *templ);
+void cso_for_each_state(struct cso_cache *sc, enum cso_cache_type type,
+ cso_state_callback func, void *user_data);
void * cso_take_state(struct cso_cache *sc, unsigned hash_key,
enum cso_cache_type type);
+void cso_set_maximum_cache_size(struct cso_cache *sc, int number);
+int cso_maximum_cache_size(const struct cso_cache *sc);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/src/gallium/auxiliary/cso_cache/cso_hash.c b/src/gallium/auxiliary/cso_cache/cso_hash.c
index b40217c524..b3b4d667d2 100644
--- a/src/gallium/auxiliary/cso_cache/cso_hash.c
+++ b/src/gallium/auxiliary/cso_cache/cso_hash.c
@@ -30,12 +30,10 @@
* Zack Rusin <zack@tungstengraphics.com>
*/
-#include "cso_hash.h"
+#include "pipe/p_debug.h"
+#include "pipe/p_util.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
+#include "cso_hash.h"
#define MAX(a, b) ((a > b) ? (a) : (b))
@@ -98,7 +96,7 @@ struct cso_hash {
static void *cso_data_allocate_node(struct cso_hash_data *hash)
{
- return malloc(hash->nodeSize);
+ return MALLOC(hash->nodeSize);
}
static void cso_data_free_node(struct cso_node *node)
@@ -107,10 +105,10 @@ static void cso_data_free_node(struct cso_node *node)
* Need to cast value ptr to original cso type, then free the
* driver-specific data hanging off of it. For example:
struct cso_sampler *csamp = (struct cso_sampler *) node->value;
- free(csamp->data);
+ FREE(csamp->data);
*/
- free(node->value);
- free(node);
+ FREE(node->value);
+ FREE(node);
}
static struct cso_node *
@@ -134,7 +132,7 @@ static void cso_data_rehash(struct cso_hash_data *hash, int hint)
hint = countBits(-hint);
if (hint < MinNumBits)
hint = MinNumBits;
- hash->userNumBits = hint;
+ hash->userNumBits = (short)hint;
while (primeForNumBits(hint) < (hash->size >> 1))
++hint;
} else if (hint < MinNumBits) {
@@ -147,9 +145,9 @@ static void cso_data_rehash(struct cso_hash_data *hash, int hint)
int oldNumBuckets = hash->numBuckets;
int i = 0;
- hash->numBits = hint;
+ hash->numBits = (short)hint;
hash->numBuckets = primeForNumBits(hint);
- hash->buckets = malloc(sizeof(struct cso_node*) * hash->numBuckets);
+ hash->buckets = MALLOC(sizeof(struct cso_node*) * hash->numBuckets);
for (i = 0; i < hash->numBuckets; ++i)
hash->buckets[i] = e;
@@ -173,7 +171,7 @@ static void cso_data_rehash(struct cso_hash_data *hash, int hint)
firstNode = afterLastNode;
}
}
- free(oldBuckets);
+ FREE(oldBuckets);
}
}
@@ -235,13 +233,13 @@ struct cso_hash_iter cso_hash_insert(struct cso_hash *hash,
struct cso_hash * cso_hash_create(void)
{
- struct cso_hash *hash = malloc(sizeof(struct cso_hash));
- hash->data.d = malloc(sizeof(struct cso_hash_data));
+ struct cso_hash *hash = MALLOC_STRUCT(cso_hash);
+ hash->data.d = MALLOC_STRUCT(cso_hash_data);
hash->data.d->fakeNext = 0;
hash->data.d->buckets = 0;
hash->data.d->size = 0;
hash->data.d->nodeSize = sizeof(struct cso_node);
- hash->data.d->userNumBits = MinNumBits;
+ hash->data.d->userNumBits = (short)MinNumBits;
hash->data.d->numBits = 0;
hash->data.d->numBuckets = 0;
@@ -261,9 +259,9 @@ void cso_hash_delete(struct cso_hash *hash)
cur = next;
}
}
- free(hash->data.d->buckets);
- free(hash->data.d);
- free(hash);
+ FREE(hash->data.d->buckets);
+ FREE(hash->data.d);
+ FREE(hash);
}
struct cso_hash_iter cso_hash_find(struct cso_hash *hash,
@@ -301,7 +299,7 @@ static struct cso_node *cso_hash_data_next(struct cso_node *node)
a.next = node->next;
if (!a.next) {
- fprintf(stderr, "iterating beyond the last element\n");
+ debug_printf("iterating beyond the last element\n");
return 0;
}
if (a.next->next)
@@ -352,7 +350,7 @@ static struct cso_node *cso_hash_data_prev(struct cso_node *node)
--bucket;
--start;
}
- fprintf(stderr, "iterating backward beyond first element\n");
+ debug_printf("iterating backward beyond first element\n");
return a.e;
}
@@ -397,3 +395,8 @@ struct cso_hash_iter cso_hash_first_node(struct cso_hash *hash)
struct cso_hash_iter iter = {hash, cso_data_first_node(hash->data.d)};
return iter;
}
+
+int cso_hash_size(struct cso_hash *hash)
+{
+ return hash->data.d->size;
+}
diff --git a/src/gallium/auxiliary/cso_cache/cso_hash.h b/src/gallium/auxiliary/cso_cache/cso_hash.h
index b4aa111860..d5bca9d591 100644
--- a/src/gallium/auxiliary/cso_cache/cso_hash.h
+++ b/src/gallium/auxiliary/cso_cache/cso_hash.h
@@ -33,6 +33,11 @@
#ifndef CSO_HASH_H
#define CSO_HASH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct cso_hash;
struct cso_node;
@@ -42,7 +47,9 @@ struct cso_hash_iter {
};
struct cso_hash *cso_hash_create(void);
-void cso_hash_delete(struct cso_hash *hash);
+void cso_hash_delete(struct cso_hash *hash);
+
+int cso_hash_size(struct cso_hash *hash);
struct cso_hash_iter cso_hash_insert(struct cso_hash *hash, unsigned key,
void *data);
@@ -59,4 +66,17 @@ void *cso_hash_iter_data(struct cso_hash_iter iter);
struct cso_hash_iter cso_hash_iter_next(struct cso_hash_iter iter);
struct cso_hash_iter cso_hash_iter_prev(struct cso_hash_iter iter);
+
+/* KW: a convenience routine:
+ */
+void *cso_hash_find_data_from_template( struct cso_hash *hash,
+ unsigned hash_key,
+ void *templ,
+ int size );
+
+
+#ifdef __cplusplus
+}
+#endif
+
#endif