summaryrefslogtreecommitdiff
path: root/cogl
diff options
context:
space:
mode:
Diffstat (limited to 'cogl')
-rw-r--r--cogl/cogl-color-private.h5
-rw-r--r--cogl/cogl-context.c2
-rw-r--r--cogl/cogl-pipeline-private.h18
-rw-r--r--cogl/cogl-pipeline.c520
-rw-r--r--cogl/cogl-util.c9
-rw-r--r--cogl/cogl-util.h27
6 files changed, 580 insertions, 1 deletions
diff --git a/cogl/cogl-color-private.h b/cogl/cogl-color-private.h
index 2ce2bf76..78bfcf94 100644
--- a/cogl/cogl-color-private.h
+++ b/cogl/cogl-color-private.h
@@ -32,6 +32,11 @@
#include <glib.h>
+/* cogl-pipeline.c wants to be able to hash CoglColor data so it needs
+ * the exact data size to be able to avoid reading the padding bytes.
+ */
+#define _COGL_COLOR_DATA_SIZE 4
+
void
_cogl_color_get_rgba_4ubv (const CoglColor *color,
guint8 *dest);
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index 4b5b15e3..a366b8bf 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -127,6 +127,8 @@ cogl_create_context (void)
_cogl_pipeline_init_default_pipeline ();
_cogl_pipeline_init_default_layers ();
+ _cogl_pipeline_init_state_hash_functions ();
+ _cogl_pipeline_init_layer_state_hash_functions ();
_context->enable_flags = 0;
diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h
index 4cc8489e..ec7366ae 100644
--- a/cogl/cogl-pipeline-private.h
+++ b/cogl/cogl-pipeline-private.h
@@ -390,7 +390,7 @@ typedef struct
{
/* Determines what fragments are discarded based on their alpha */
CoglPipelineAlphaFunc alpha_func;
- GLfloat alpha_func_reference;
+ float alpha_func_reference;
} CoglPipelineAlphaFuncState;
typedef enum _CoglPipelineBlendEnable
@@ -886,6 +886,10 @@ void
_cogl_pipeline_get_colorubv (CoglPipeline *pipeline,
guint8 *color);
+/* XXX: At some point it could be good for this to accept a mask of
+ * the state groups we are interested in comparing since we can
+ * probably use that information in a number situations to reduce
+ * the work we do. */
unsigned long
_cogl_pipeline_compare_differences (CoglPipeline *pipeline0,
CoglPipeline *pipeline1);
@@ -908,6 +912,12 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0,
unsigned long layer_differences,
CoglPipelineEvalFlags flags);
+unsigned int
+_cogl_pipeline_hash (CoglPipeline *pipeline,
+ unsigned long differences,
+ unsigned long layer_differences,
+ CoglPipelineEvalFlags flags);
+
CoglPipeline *
_cogl_pipeline_journal_ref (CoglPipeline *pipeline);
@@ -1042,5 +1052,11 @@ CoglPipeline *
_cogl_pipeline_find_codegen_authority (CoglPipeline *pipeline,
CoglHandle user_program);
+void
+_cogl_pipeline_init_state_hash_functions (void);
+
+void
+_cogl_pipeline_init_layer_state_hash_functions (void);
+
#endif /* __COGL_PIPELINE_PRIVATE_H */
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c
index 6a0de48d..b3a56231 100644
--- a/cogl/cogl-pipeline.c
+++ b/cogl/cogl-pipeline.c
@@ -41,6 +41,7 @@
#include "cogl-blend-string.h"
#include "cogl-journal-private.h"
#include "cogl-color-private.h"
+#include "cogl-util.h"
#include "cogl-profile.h"
#include <glib.h>
@@ -188,6 +189,8 @@ _cogl_pipeline_init_default_pipeline (void)
{
/* Create new - blank - pipeline */
CoglPipeline *pipeline = g_slice_new0 (CoglPipeline);
+ /* XXX: NB: It's important that we zero this to avoid polluting
+ * pipeline hash values with un-initialized data */
CoglPipelineBigState *big_state = g_slice_new0 (CoglPipelineBigState);
CoglPipelineLightingState *lighting_state = &big_state->lighting_state;
CoglPipelineAlphaFuncState *alpha_state = &big_state->alpha_state;
@@ -5508,6 +5511,523 @@ _cogl_pipeline_set_static_breadcrumb (CoglPipeline *pipeline,
pipeline->static_breadcrumb = breadcrumb;
}
+typedef struct _HashState
+{
+ unsigned long pipeline_differences;
+ unsigned long layer_differences;
+ CoglPipelineEvalFlags flags;
+ unsigned int hash;
+} HashState;
+
+static void
+_cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ HashState *state)
+{
+ int unit = authority->unit_index;
+ state->hash =
+ _cogl_util_one_at_a_time_hash (state->hash, &unit, sizeof (unit));
+}
+
+static void
+_cogl_pipeline_layer_hash_texture_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ HashState *state)
+{
+ GLuint gl_handle;
+ GLenum gl_target;
+ unsigned long hash = state->hash;
+
+ cogl_texture_get_gl_texture (authority->texture, &gl_handle, &gl_target);
+
+ hash = _cogl_util_one_at_a_time_hash (hash, &gl_target, sizeof (gl_target));
+
+ if (!(state->flags & COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA))
+ hash = _cogl_util_one_at_a_time_hash (hash, &gl_handle, sizeof (gl_handle));
+
+ state->hash = hash;
+}
+
+static void
+_cogl_pipeline_layer_hash_filters_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ HashState *state)
+{
+ unsigned int hash = state->hash;
+ hash = _cogl_util_one_at_a_time_hash (hash, &authority->mag_filter,
+ sizeof (authority->mag_filter));
+ hash = _cogl_util_one_at_a_time_hash (hash, &authority->min_filter,
+ sizeof (authority->min_filter));
+ state->hash = hash;
+}
+
+static void
+_cogl_pipeline_layer_hash_wrap_modes_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ HashState *state)
+{
+ unsigned int hash = state->hash;
+ hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_s,
+ sizeof (authority->wrap_mode_s));
+ hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_t,
+ sizeof (authority->wrap_mode_t));
+ hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_p,
+ sizeof (authority->wrap_mode_p));
+ state->hash = hash;
+}
+
+static void
+_cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ HashState *state)
+{
+ unsigned int hash = state->hash;
+ CoglPipelineLayerBigState *b = authority->big_state;
+ int n_args;
+ int i;
+
+ hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_func,
+ sizeof (b->texture_combine_rgb_func));
+ n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func);
+ for (i = 0; i < n_args; i++)
+ {
+ hash =
+ _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_src[i],
+ sizeof (b->texture_combine_rgb_src[i]));
+ hash =
+ _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_op[i],
+ sizeof (b->texture_combine_rgb_op[i]));
+ }
+
+ hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_func,
+ sizeof (b->texture_combine_alpha_func));
+ n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func);
+ for (i = 0; i < n_args; i++)
+ {
+ hash =
+ _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_src[i],
+ sizeof (b->texture_combine_alpha_src[i]));
+ hash =
+ _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_op[i],
+ sizeof (b->texture_combine_alpha_op[i]));
+ }
+
+ state->hash = hash;
+}
+
+static void
+_cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ HashState *state)
+{
+ CoglPipelineLayerBigState *b = authority->big_state;
+ gboolean need_hash = FALSE;
+ int n_args;
+ int i;
+
+ /* XXX: If the user also asked to hash the ALPHA_FUNC_STATE then it
+ * would be nice if we could combine the n_args loops in this
+ * function and _cogl_pipeline_layer_hash_combine_state.
+ */
+
+ n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func);
+ for (i = 0; i < n_args; i++)
+ {
+ if (b->texture_combine_rgb_src[i] == GL_CONSTANT_COLOR ||
+ b->texture_combine_rgb_src[i] == GL_CONSTANT_ALPHA)
+ {
+ /* XXX: should we be careful to only hash the alpha
+ * component in the GL_CONSTANT_ALPHA case? */
+ need_hash = TRUE;
+ goto done;
+ }
+ }
+
+ n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func);
+ for (i = 0; i < n_args; i++)
+ {
+ if (b->texture_combine_alpha_src[i] == GL_CONSTANT_COLOR ||
+ b->texture_combine_alpha_src[i] == GL_CONSTANT_ALPHA)
+ {
+ /* XXX: should we be careful to only hash the alpha
+ * component in the GL_CONSTANT_ALPHA case? */
+ need_hash = TRUE;
+ goto done;
+ }
+ }
+
+done:
+ if (need_hash)
+ {
+ float *constant = b->texture_combine_constant;
+ state->hash = _cogl_util_one_at_a_time_hash (state->hash, constant,
+ sizeof (float) * 4);
+ }
+}
+
+static void
+_cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ HashState *state)
+{
+ CoglPipelineLayerBigState *big_state = authority->big_state;
+ state->hash = _cogl_util_one_at_a_time_hash (state->hash, &big_state->matrix,
+ sizeof (float) * 16);
+}
+
+static void
+_cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ HashState *state)
+{
+ CoglPipelineLayerBigState *big_state = authority->big_state;
+ state->hash =
+ _cogl_util_one_at_a_time_hash (state->hash, &big_state->point_sprite_coords,
+ sizeof (big_state->point_sprite_coords));
+}
+
+typedef void (*LayerStateHashFunction) (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ HashState *state);
+
+static LayerStateHashFunction
+layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT];
+
+/* XXX: We don't statically initialize the array of hash functions, so
+ * we won't get caught out by later re-indexing the groups for some
+ * reason. */
+void
+_cogl_pipeline_init_layer_state_hash_functions (void)
+{
+ CoglPipelineLayerStateIndex _index;
+ layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_UNIT_INDEX] =
+ _cogl_pipeline_layer_hash_unit_state;
+ layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_TEXTURE_INDEX] =
+ _cogl_pipeline_layer_hash_texture_state;
+ layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX] =
+ _cogl_pipeline_layer_hash_filters_state;
+ layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX] =
+ _cogl_pipeline_layer_hash_wrap_modes_state;
+ layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX] =
+ _cogl_pipeline_layer_hash_combine_state;
+ layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX] =
+ _cogl_pipeline_layer_hash_combine_constant_state;
+ layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX] =
+ _cogl_pipeline_layer_hash_user_matrix_state;
+ _index = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX;
+ layer_state_hash_functions[_index] =
+ _cogl_pipeline_layer_hash_point_sprite_state;
+
+ /* So we get a big error if we forget to update this code! */
+ g_assert (COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT == 8);
+}
+
+static gboolean
+_cogl_pipeline_hash_layer_cb (CoglPipelineLayer *layer,
+ void *user_data)
+{
+ HashState *state = user_data;
+ unsigned long differences = state->layer_differences;
+ CoglPipelineLayer *authorities[COGL_PIPELINE_LAYER_STATE_COUNT];
+ unsigned long mask;
+ int i;
+
+ /* Theoretically we would hash non-sparse layer state here but
+ * currently layers don't have any. */
+
+ /* XXX: we resolve all the authorities here - not just those
+ * corresponding to hash_state->layer_differences - because
+ * the hashing of some state groups actually depends on the values
+ * in other groups. For example we don't hash layer combine
+ * constants if they are aren't referenced by the current layer
+ * combine function.
+ */
+ mask = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE;
+ _cogl_pipeline_layer_resolve_authorities (layer,
+ mask,
+ authorities);
+
+ /* So we go right ahead and hash the sparse state... */
+ for (i = 0; i < COGL_PIPELINE_LAYER_STATE_COUNT; i++)
+ {
+ unsigned long current_state = (1L<<i);
+
+ /* XXX: we are hashing the un-mixed hash values of all the
+ * individual state groups; we should provide a means to test
+ * the quality of the final hash values we are getting with this
+ * approach... */
+ if (differences & current_state)
+ {
+ CoglPipelineLayer *authority = authorities[i];
+ layer_state_hash_functions[i] (authority, authorities, state);
+ }
+
+ if (current_state > differences)
+ break;
+ }
+
+ return TRUE;
+}
+
+static void
+_cogl_pipeline_hash_color_state (CoglPipeline *authority,
+ HashState *state)
+{
+ state->hash = _cogl_util_one_at_a_time_hash (state->hash, &authority->color,
+ _COGL_COLOR_DATA_SIZE);
+}
+
+static void
+_cogl_pipeline_hash_blend_enable_state (CoglPipeline *authority,
+ HashState *state)
+{
+ guint8 blend_enable = authority->blend_enable;
+ state->hash = _cogl_util_one_at_a_time_hash (state->hash, &blend_enable, 1);
+}
+
+static void
+_cogl_pipeline_hash_layers_state (CoglPipeline *authority,
+ HashState *state)
+{
+ state->hash =
+ _cogl_util_one_at_a_time_hash (state->hash, &authority->n_layers,
+ sizeof (authority->n_layers));
+ _cogl_pipeline_foreach_layer_internal (authority,
+ _cogl_pipeline_hash_layer_cb,
+ state);
+}
+
+static void
+_cogl_pipeline_hash_lighting_state (CoglPipeline *authority,
+ HashState *state)
+{
+ CoglPipelineLightingState *lighting_state =
+ &authority->big_state->lighting_state;
+ state->hash =
+ _cogl_util_one_at_a_time_hash (state->hash, lighting_state,
+ sizeof (CoglPipelineLightingState));
+}
+
+static void
+_cogl_pipeline_hash_alpha_func_state (CoglPipeline *authority,
+ HashState *state)
+{
+ CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state;
+ state->hash =
+ _cogl_util_one_at_a_time_hash (state->hash, &alpha_state->alpha_func,
+ sizeof (alpha_state->alpha_func));
+}
+
+static void
+_cogl_pipeline_hash_alpha_func_reference_state (CoglPipeline *authority,
+ HashState *state)
+{
+ CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state;
+ float ref = alpha_state->alpha_func_reference;
+ state->hash =
+ _cogl_util_one_at_a_time_hash (state->hash, &ref, sizeof (float));
+}
+
+static void
+_cogl_pipeline_hash_blend_state (CoglPipeline *authority,
+ HashState *state)
+{
+ CoglPipelineBlendState *blend_state = &authority->big_state->blend_state;
+ unsigned int hash;
+
+ if (!authority->real_blend_enable)
+ return;
+
+ hash = state->hash;
+
+#ifndef HAVE_COGL_GLES
+ hash =
+ _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_equation_rgb,
+ sizeof (blend_state->blend_equation_rgb));
+ hash =
+ _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_equation_alpha,
+ sizeof (blend_state->blend_equation_alpha));
+ hash =
+ _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_src_factor_alpha,
+ sizeof (blend_state->blend_src_factor_alpha));
+ hash =
+ _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_dst_factor_alpha,
+ sizeof (blend_state->blend_dst_factor_alpha));
+
+ if (blend_state->blend_src_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR ||
+ blend_state->blend_src_factor_rgb == GL_CONSTANT_COLOR ||
+ blend_state->blend_dst_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR ||
+ blend_state->blend_dst_factor_rgb == GL_CONSTANT_COLOR)
+ {
+ hash =
+ _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_constant,
+ sizeof (blend_state->blend_constant));
+ }
+#endif
+
+ hash =
+ _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_src_factor_rgb,
+ sizeof (blend_state->blend_src_factor_rgb));
+ hash =
+ _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_dst_factor_rgb,
+ sizeof (blend_state->blend_dst_factor_rgb));
+
+ state->hash = hash;
+}
+
+static void
+_cogl_pipeline_hash_user_shader_state (CoglPipeline *authority,
+ HashState *state)
+{
+ CoglHandle user_program = authority->big_state->user_program;
+ state->hash = _cogl_util_one_at_a_time_hash (state->hash, &user_program,
+ sizeof (user_program));
+}
+
+static void
+_cogl_pipeline_hash_depth_state (CoglPipeline *authority,
+ HashState *state)
+{
+ CoglPipelineDepthState *depth_state = &authority->big_state->depth_state;
+ unsigned int hash = state->hash;
+
+ if (depth_state->depth_test_enabled)
+ {
+ guint8 enabled = depth_state->depth_test_enabled;
+ CoglDepthTestFunction function = depth_state->depth_test_function;
+ hash = _cogl_util_one_at_a_time_hash (hash, &enabled, sizeof (enabled));
+ hash = _cogl_util_one_at_a_time_hash (hash, &function, sizeof (function));
+ }
+
+ if (depth_state->depth_writing_enabled)
+ {
+ guint8 enabled = depth_state->depth_writing_enabled;
+ float near = depth_state->depth_range_near;
+ float far = depth_state->depth_range_far;
+ hash = _cogl_util_one_at_a_time_hash (hash, &enabled, sizeof (enabled));
+ hash = _cogl_util_one_at_a_time_hash (hash, &near, sizeof (near));
+ hash = _cogl_util_one_at_a_time_hash (hash, &far, sizeof (far));
+ }
+
+ state->hash = hash;
+}
+
+static void
+_cogl_pipeline_hash_fog_state (CoglPipeline *authority,
+ HashState *state)
+{
+ CoglPipelineFogState *fog_state = &authority->big_state->fog_state;
+ unsigned long hash = state->hash;
+
+ if (!fog_state->enabled)
+ hash = _cogl_util_one_at_a_time_hash (hash, &fog_state->enabled,
+ sizeof (fog_state->enabled));
+ else
+ hash = _cogl_util_one_at_a_time_hash (hash, &fog_state,
+ sizeof (CoglPipelineFogState));
+
+ state->hash = hash;
+}
+
+static void
+_cogl_pipeline_hash_point_size_state (CoglPipeline *authority,
+ HashState *state)
+{
+ float point_size = authority->big_state->point_size;
+ state->hash = _cogl_util_one_at_a_time_hash (state->hash, &point_size,
+ sizeof (point_size));
+}
+
+typedef void (*StateHashFunction) (CoglPipeline *authority, HashState *state);
+
+static StateHashFunction
+state_hash_functions[COGL_PIPELINE_STATE_SPARSE_COUNT];
+
+/* We don't statically initialize the array of hash functions
+ * so we won't get caught out by later re-indexing the groups for
+ * some reason. */
+void
+_cogl_pipeline_init_state_hash_functions (void)
+{
+ state_hash_functions[COGL_PIPELINE_STATE_COLOR_INDEX] =
+ _cogl_pipeline_hash_color_state;
+ state_hash_functions[COGL_PIPELINE_STATE_BLEND_ENABLE_INDEX] =
+ _cogl_pipeline_hash_blend_enable_state;
+ state_hash_functions[COGL_PIPELINE_STATE_LAYERS_INDEX] =
+ _cogl_pipeline_hash_layers_state;
+ state_hash_functions[COGL_PIPELINE_STATE_LIGHTING_INDEX] =
+ _cogl_pipeline_hash_lighting_state;
+ state_hash_functions[COGL_PIPELINE_STATE_ALPHA_FUNC_INDEX] =
+ _cogl_pipeline_hash_alpha_func_state;
+ state_hash_functions[COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE_INDEX] =
+ _cogl_pipeline_hash_alpha_func_reference_state;
+ state_hash_functions[COGL_PIPELINE_STATE_BLEND_INDEX] =
+ _cogl_pipeline_hash_blend_state;
+ state_hash_functions[COGL_PIPELINE_STATE_USER_SHADER_INDEX] =
+ _cogl_pipeline_hash_user_shader_state;
+ state_hash_functions[COGL_PIPELINE_STATE_DEPTH_INDEX] =
+ _cogl_pipeline_hash_depth_state;
+ state_hash_functions[COGL_PIPELINE_STATE_FOG_INDEX] =
+ _cogl_pipeline_hash_fog_state;
+ state_hash_functions[COGL_PIPELINE_STATE_POINT_SIZE_INDEX] =
+ _cogl_pipeline_hash_point_size_state;
+
+ /* So we get a big error if we forget to update this code! */
+ g_assert (COGL_PIPELINE_STATE_SPARSE_COUNT == 11);
+}
+
+unsigned int
+_cogl_pipeline_hash (CoglPipeline *pipeline,
+ unsigned long differences,
+ unsigned long layer_differences,
+ CoglPipelineEvalFlags flags)
+{
+ CoglPipeline *authorities[COGL_PIPELINE_STATE_SPARSE_COUNT];
+ unsigned long mask;
+ int i;
+ HashState state;
+ unsigned int final_hash = 0;
+
+ state.hash = 0;
+ state.layer_differences = layer_differences;
+
+ /* hash non-sparse state */
+
+ if (differences & COGL_PIPELINE_STATE_REAL_BLEND_ENABLE)
+ {
+ gboolean enable = pipeline->real_blend_enable;
+ state.hash =
+ _cogl_util_one_at_a_time_hash (state.hash, &enable, sizeof (enable));
+ }
+
+ /* hash sparse state */
+
+ mask = differences & COGL_PIPELINE_STATE_ALL_SPARSE;
+ _cogl_pipeline_resolve_authorities (pipeline, mask, authorities);
+
+ for (i = 0; i < COGL_PIPELINE_STATE_SPARSE_COUNT; i++)
+ {
+ unsigned long current_state = (1L<<i);
+
+ /* XXX: we are hashing the un-mixed hash values of all the
+ * individual state groups; we should provide a means to test
+ * the quality of the final hash values we are getting with this
+ * approach... */
+ if (differences & current_state)
+ {
+ CoglPipeline *authority = authorities[i];
+ state_hash_functions[i] (authority, &state);
+ final_hash = _cogl_util_one_at_a_time_hash (final_hash, &state.hash,
+ sizeof (state.hash));
+ }
+
+ if (current_state > differences)
+ break;
+ }
+
+ return _cogl_util_one_at_a_time_mix (final_hash);
+}
+
typedef struct
{
int parent_id;
diff --git a/cogl/cogl-util.c b/cogl/cogl-util.c
index 7c8c5479..29165872 100644
--- a/cogl/cogl-util.c
+++ b/cogl/cogl-util.c
@@ -208,4 +208,13 @@ cogl_fixed_get_type (void)
return _cogl_fixed_type;
}
+unsigned int
+_cogl_util_one_at_a_time_mix (unsigned int hash)
+{
+ hash += ( hash << 3 );
+ hash ^= ( hash >> 11 );
+ hash += ( hash << 15 );
+
+ return hash;
+}
diff --git a/cogl/cogl-util.h b/cogl/cogl-util.h
index 64ba8ffc..0ac56c9d 100644
--- a/cogl/cogl-util.h
+++ b/cogl/cogl-util.h
@@ -68,4 +68,31 @@ _cogl_util_is_pot (unsigned int num)
return (num & (num - 1)) == 0;
}
+/* Split Bob Jenkins' One-at-a-Time hash
+ *
+ * This uses the One-at-a-Time hash algorithm designed by Bob Jenkins
+ * but the mixing step is split out so the function can be used in a
+ * more incremental fashion.
+ */
+static inline unsigned int
+_cogl_util_one_at_a_time_hash (unsigned int hash,
+ void *key,
+ size_t bytes)
+{
+ unsigned char *p = key;
+ int i;
+
+ for (i = 0; i < bytes; i++)
+ {
+ hash += p[i];
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+
+ return hash;
+}
+
+unsigned int
+_cogl_util_one_at_a_time_mix (unsigned int hash);
+
#endif /* __COGL_UTIL_H */