material-arbfp: don't recompile for constant changes

Instead of lazily incorporating combine constants as arbfp PARAM
constants in the source directly we now use program.local parameters
instead so we can avoid repeating codegen if a material's combine
constant is updated. This should be a big win for applications animating
a constant used for example in an animated interpolation, such as
gnome-shell.

http://bugzilla.clutter-project.org/show_bug.cgi?id=2280
This commit is contained in:
Robert Bragg 2010-09-14 00:33:46 +01:00
parent 2815cf4719
commit 5583d9c12e

View File

@ -76,6 +76,10 @@
typedef struct _UnitState typedef struct _UnitState
{ {
int layer_index; /* only valid when the combine constant is dirty */
int constant_id; /* The program.local[] index */
unsigned int dirty_combine_constant:1;
unsigned int sampled:1; unsigned int sampled:1;
} UnitState; } UnitState;
@ -134,7 +138,6 @@ layers_arbfp_would_differ (CoglMaterialLayer **material0_layers,
/* The layer state that affects arbfp codegen... */ /* The layer state that affects arbfp codegen... */
unsigned long arbfp_codegen_modifiers = unsigned long arbfp_codegen_modifiers =
COGL_MATERIAL_LAYER_STATE_COMBINE | COGL_MATERIAL_LAYER_STATE_COMBINE |
COGL_MATERIAL_LAYER_STATE_COMBINE_CONSTANT |
COGL_MATERIAL_LAYER_STATE_UNIT; COGL_MATERIAL_LAYER_STATE_UNIT;
for (i = 0; i < n_layers; i++) for (i = 0; i < n_layers; i++)
@ -420,8 +423,11 @@ _cogl_material_backend_arbfp_start (CoglMaterial *material,
for (i = 0; i < n_layers; i++) for (i = 0; i < n_layers; i++)
{ {
authority_priv->unit_state[i].layer_index = -1;
authority_priv->unit_state[i].sampled = FALSE; authority_priv->unit_state[i].sampled = FALSE;
authority_priv->unit_state[i].dirty_combine_constant = FALSE;
} }
authority_priv->next_constant_id = 0;
} }
return TRUE; return TRUE;
@ -589,7 +595,7 @@ append_arg (GString *source, const CoglMaterialBackendARBfpArg *arg)
arg->texture_unit, arg->swizzle); arg->texture_unit, arg->swizzle);
break; break;
case COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_CONSTANT: case COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_CONSTANT:
g_string_append_printf (source, "constant%d%s", g_string_append_printf (source, "program.local[%d]%s",
arg->constant_id, arg->swizzle); arg->constant_id, arg->swizzle);
break; break;
case COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE: case COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE:
@ -630,29 +636,16 @@ setup_arg (CoglMaterial *material,
break; break;
case GL_CONSTANT: case GL_CONSTANT:
{ {
unsigned long state = COGL_MATERIAL_LAYER_STATE_COMBINE_CONSTANT; int unit_index = _cogl_material_layer_get_unit_index (layer);
CoglMaterialLayer *authority = UnitState *unit_state = &priv->unit_state[unit_index];
_cogl_material_layer_get_authority (layer, state);
CoglMaterialLayerBigState *big_state = authority->big_state; unit_state->layer_index = layer->index;
char buf[4][G_ASCII_DTOSTR_BUF_SIZE]; unit_state->constant_id = priv->next_constant_id++;
int i; unit_state->dirty_combine_constant = TRUE;
arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_CONSTANT; arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_CONSTANT;
arg->name = "constant%d"; arg->name = "program.local[%d]";
arg->constant_id = priv->next_constant_id++; arg->constant_id = unit_state->constant_id;
for (i = 0; i < 4; i++)
g_ascii_dtostr (buf[i], G_ASCII_DTOSTR_BUF_SIZE,
big_state->texture_combine_constant[i]);
g_string_append_printf (priv->source,
"PARAM constant%d = "
" {%s, %s, %s, %s};\n",
arg->constant_id,
buf[0],
buf[1],
buf[2],
buf[3]);
break; break;
} }
case GL_PRIMARY_COLOR: case GL_PRIMARY_COLOR:
@ -1072,6 +1065,28 @@ _cogl_material_backend_arbfp_end (CoglMaterial *material,
GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, gl_program)); GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, gl_program));
_cogl_use_program (COGL_INVALID_HANDLE, COGL_MATERIAL_PROGRAM_TYPE_ARBFP); _cogl_use_program (COGL_INVALID_HANDLE, COGL_MATERIAL_PROGRAM_TYPE_ARBFP);
if (priv->user_program == COGL_INVALID_HANDLE)
{
int n_layers = cogl_material_get_n_layers (material);
int i;
for (i = 0; i < n_layers; i++)
{
UnitState *unit_state = &priv->unit_state[i];
if (unit_state->dirty_combine_constant)
{
float constant[4];
int layer_index = unit_state->layer_index;
_cogl_material_get_layer_combine_constant (material,
layer_index,
constant);
GE (glProgramLocalParameter4fv (GL_FRAGMENT_PROGRAM_ARB,
unit_state->constant_id,
constant));
unit_state->dirty_combine_constant = FALSE;
}
}
}
return TRUE; return TRUE;
} }
@ -1201,6 +1216,7 @@ _cogl_material_backend_arbfp_layer_pre_change_notify (
{ {
CoglMaterialBackendARBfpPrivate *priv = get_arbfp_authority_priv (owner); CoglMaterialBackendARBfpPrivate *priv = get_arbfp_authority_priv (owner);
static const unsigned long not_fragment_op_changes = static const unsigned long not_fragment_op_changes =
COGL_MATERIAL_LAYER_STATE_COMBINE_CONSTANT |
COGL_MATERIAL_LAYER_STATE_TEXTURE; COGL_MATERIAL_LAYER_STATE_TEXTURE;
priv = get_arbfp_authority_priv (owner); priv = get_arbfp_authority_priv (owner);
@ -1213,6 +1229,12 @@ _cogl_material_backend_arbfp_layer_pre_change_notify (
return; return;
} }
if (change & COGL_MATERIAL_LAYER_STATE_COMBINE_CONSTANT)
{
int unit_index = _cogl_material_layer_get_unit_index (layer);
priv->unit_state[unit_index].dirty_combine_constant = TRUE;
}
/* TODO: we could be saving snippets of texture combine code along /* TODO: we could be saving snippets of texture combine code along
* with each layer and then when a layer changes we would just free * with each layer and then when a layer changes we would just free
* the snippet. */ * the snippet. */