mirror of
https://github.com/brl/mutter.git
synced 2024-12-25 20:32:16 +00:00
pipeline: Implements _cogl_pipeline_hash function
This allows us to get a hash for a set of state groups for a given pipeline. This can be used for example to get a hash of the fragment processing state of a pipeline so we can implement a cache for compiled arbfp/glsl programs.
This commit is contained in:
parent
cc36e49ec5
commit
e87c3820ee
@ -32,6 +32,11 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#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
|
void
|
||||||
_cogl_color_get_rgba_4ubv (const CoglColor *color,
|
_cogl_color_get_rgba_4ubv (const CoglColor *color,
|
||||||
guint8 *dest);
|
guint8 *dest);
|
||||||
|
@ -127,6 +127,8 @@ cogl_create_context (void)
|
|||||||
|
|
||||||
_cogl_pipeline_init_default_pipeline ();
|
_cogl_pipeline_init_default_pipeline ();
|
||||||
_cogl_pipeline_init_default_layers ();
|
_cogl_pipeline_init_default_layers ();
|
||||||
|
_cogl_pipeline_init_state_hash_functions ();
|
||||||
|
_cogl_pipeline_init_layer_state_hash_functions ();
|
||||||
|
|
||||||
_context->enable_flags = 0;
|
_context->enable_flags = 0;
|
||||||
|
|
||||||
|
@ -390,7 +390,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
/* Determines what fragments are discarded based on their alpha */
|
/* Determines what fragments are discarded based on their alpha */
|
||||||
CoglPipelineAlphaFunc alpha_func;
|
CoglPipelineAlphaFunc alpha_func;
|
||||||
GLfloat alpha_func_reference;
|
float alpha_func_reference;
|
||||||
} CoglPipelineAlphaFuncState;
|
} CoglPipelineAlphaFuncState;
|
||||||
|
|
||||||
typedef enum _CoglPipelineBlendEnable
|
typedef enum _CoglPipelineBlendEnable
|
||||||
@ -886,6 +886,10 @@ void
|
|||||||
_cogl_pipeline_get_colorubv (CoglPipeline *pipeline,
|
_cogl_pipeline_get_colorubv (CoglPipeline *pipeline,
|
||||||
guint8 *color);
|
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
|
unsigned long
|
||||||
_cogl_pipeline_compare_differences (CoglPipeline *pipeline0,
|
_cogl_pipeline_compare_differences (CoglPipeline *pipeline0,
|
||||||
CoglPipeline *pipeline1);
|
CoglPipeline *pipeline1);
|
||||||
@ -908,6 +912,12 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0,
|
|||||||
unsigned long layer_differences,
|
unsigned long layer_differences,
|
||||||
CoglPipelineEvalFlags flags);
|
CoglPipelineEvalFlags flags);
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
_cogl_pipeline_hash (CoglPipeline *pipeline,
|
||||||
|
unsigned long differences,
|
||||||
|
unsigned long layer_differences,
|
||||||
|
CoglPipelineEvalFlags flags);
|
||||||
|
|
||||||
CoglPipeline *
|
CoglPipeline *
|
||||||
_cogl_pipeline_journal_ref (CoglPipeline *pipeline);
|
_cogl_pipeline_journal_ref (CoglPipeline *pipeline);
|
||||||
|
|
||||||
@ -1042,5 +1052,11 @@ CoglPipeline *
|
|||||||
_cogl_pipeline_find_codegen_authority (CoglPipeline *pipeline,
|
_cogl_pipeline_find_codegen_authority (CoglPipeline *pipeline,
|
||||||
CoglHandle user_program);
|
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 */
|
#endif /* __COGL_PIPELINE_PRIVATE_H */
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "cogl-blend-string.h"
|
#include "cogl-blend-string.h"
|
||||||
#include "cogl-journal-private.h"
|
#include "cogl-journal-private.h"
|
||||||
#include "cogl-color-private.h"
|
#include "cogl-color-private.h"
|
||||||
|
#include "cogl-util.h"
|
||||||
#include "cogl-profile.h"
|
#include "cogl-profile.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
@ -188,6 +189,8 @@ _cogl_pipeline_init_default_pipeline (void)
|
|||||||
{
|
{
|
||||||
/* Create new - blank - pipeline */
|
/* Create new - blank - pipeline */
|
||||||
CoglPipeline *pipeline = g_slice_new0 (CoglPipeline);
|
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);
|
CoglPipelineBigState *big_state = g_slice_new0 (CoglPipelineBigState);
|
||||||
CoglPipelineLightingState *lighting_state = &big_state->lighting_state;
|
CoglPipelineLightingState *lighting_state = &big_state->lighting_state;
|
||||||
CoglPipelineAlphaFuncState *alpha_state = &big_state->alpha_state;
|
CoglPipelineAlphaFuncState *alpha_state = &big_state->alpha_state;
|
||||||
@ -5508,6 +5511,523 @@ _cogl_pipeline_set_static_breadcrumb (CoglPipeline *pipeline,
|
|||||||
pipeline->static_breadcrumb = breadcrumb;
|
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
|
typedef struct
|
||||||
{
|
{
|
||||||
int parent_id;
|
int parent_id;
|
||||||
|
@ -208,4 +208,13 @@ cogl_fixed_get_type (void)
|
|||||||
return _cogl_fixed_type;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -68,4 +68,31 @@ _cogl_util_is_pot (unsigned int num)
|
|||||||
return (num & (num - 1)) == 0;
|
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 */
|
#endif /* __COGL_UTIL_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user