diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index f11a07d0c..1b5d85854 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -240,6 +240,8 @@ cogl_sources_c = \
$(srcdir)/cogl-pipeline-fragend-arbfp-private.h \
$(srcdir)/cogl-pipeline-fragend-fixed.c \
$(srcdir)/cogl-pipeline-fragend-fixed-private.h \
+ $(srcdir)/cogl-pipeline-vertend-fixed.c \
+ $(srcdir)/cogl-pipeline-vertend-fixed-private.h \
$(srcdir)/cogl-pipeline-progend-glsl.c \
$(srcdir)/cogl-pipeline-progend-glsl-private.h \
$(srcdir)/cogl-material-compat.c \
diff --git a/cogl/cogl-pipeline-opengl.c b/cogl/cogl-pipeline-opengl.c
index 88f9fc1db..f417ba195 100644
--- a/cogl/cogl-pipeline-opengl.c
+++ b/cogl/cogl-pipeline-opengl.c
@@ -421,21 +421,6 @@ _cogl_pipeline_flush_color_blend_alpha_depth_state (
}
}
- if (pipelines_difference & COGL_PIPELINE_STATE_LIGHTING)
- {
- CoglPipeline *authority =
- _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
- CoglPipelineLightingState *lighting_state =
- &authority->big_state->lighting_state;
-
- GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, lighting_state->ambient));
- GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, lighting_state->diffuse));
- GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, lighting_state->specular));
- GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, lighting_state->emission));
- GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS,
- &lighting_state->shininess));
- }
-
if (pipelines_difference & COGL_PIPELINE_STATE_BLEND)
{
CoglPipeline *authority =
@@ -678,18 +663,6 @@ flush_layers_common_gl_state_cb (CoglPipelineLayer *layer, void *user_data)
unit->texture_storage_changed = FALSE;
}
- if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX)
- {
- CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
- CoglPipelineLayer *authority =
- _cogl_pipeline_layer_get_authority (layer, state);
-
- _cogl_matrix_stack_set (unit->matrix_stack,
- &authority->big_state->matrix);
-
- _cogl_matrix_stack_flush_to_gl (unit->matrix_stack, COGL_MATRIX_TEXTURE);
- }
-
/* Under GLES2 the fragment shader will use gl_PointCoord instead of
replacing the texture coordinates */
#ifndef HAVE_COGL_GLES2
@@ -905,6 +878,42 @@ fragend_add_layer_cb (CoglPipelineLayer *layer,
return TRUE;
}
+typedef struct
+{
+ const CoglPipelineVertend *vertend;
+ CoglPipeline *pipeline;
+ unsigned long *layer_differences;
+ gboolean error_adding_layer;
+ gboolean added_layer;
+} CoglPipelineVertendAddLayerState;
+
+
+static gboolean
+vertend_add_layer_cb (CoglPipelineLayer *layer,
+ void *user_data)
+{
+ CoglPipelineVertendAddLayerState *state = user_data;
+ const CoglPipelineVertend *vertend = state->vertend;
+ CoglPipeline *pipeline = state->pipeline;
+ int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
+
+ _COGL_GET_CONTEXT (ctx, FALSE);
+
+ /* Either enerate per layer code snippets or setup the
+ * fixed function matrix uniforms for each layer... */
+ if (G_LIKELY (vertend->add_layer (pipeline,
+ layer,
+ state->layer_differences[unit_index])))
+ state->added_layer = TRUE;
+ else
+ {
+ state->error_adding_layer = TRUE;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/*
* _cogl_pipeline_flush_gl_state:
*
@@ -1094,6 +1103,52 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
if (G_UNLIKELY (i >= G_N_ELEMENTS (_cogl_pipeline_fragends)))
g_warning ("No usable pipeline fragment backend was found!");
+ /* Now flush the vertex processing state according to the current
+ * vertex processing backend.
+ */
+
+ if (pipeline->vertend == COGL_PIPELINE_VERTEND_UNDEFINED)
+ _cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_DEFAULT);
+
+ for (i = pipeline->vertend;
+ i < G_N_ELEMENTS (_cogl_pipeline_vertends);
+ i++, _cogl_pipeline_set_vertend (pipeline, i))
+ {
+ const CoglPipelineVertend *vertend = _cogl_pipeline_vertends[i];
+ CoglPipelineVertendAddLayerState state;
+
+ /* E.g. For vertends generating code they can setup their
+ * scratch buffers here... */
+ if (G_UNLIKELY (!vertend->start (pipeline,
+ n_layers,
+ pipelines_difference)))
+ continue;
+
+ state.vertend = vertend;
+ state.pipeline = pipeline;
+ state.layer_differences = layer_differences;
+ state.error_adding_layer = FALSE;
+ state.added_layer = FALSE;
+ _cogl_pipeline_foreach_layer_internal (pipeline,
+ vertend_add_layer_cb,
+ &state);
+
+ if (G_UNLIKELY (state.error_adding_layer))
+ continue;
+
+ /* For vertends generating code they may compile and link their
+ * programs here, update any uniforms and tell OpenGL to use
+ * that program.
+ */
+ if (G_UNLIKELY (!vertend->end (pipeline, pipelines_difference)))
+ continue;
+
+ break;
+ }
+
+ if (G_UNLIKELY (i >= G_N_ELEMENTS (_cogl_pipeline_vertends)))
+ g_warning ("No usable pipeline vertex backend was found!");
+
for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
if (_cogl_pipeline_progends[i]->end)
_cogl_pipeline_progends[i]->end (pipeline, pipelines_difference,
diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h
index 32644934a..bd7738294 100644
--- a/cogl/cogl-pipeline-private.h
+++ b/cogl/cogl-pipeline-private.h
@@ -71,6 +71,13 @@ typedef struct _CoglPipelineLayer CoglPipelineLayer;
#define COGL_PIPELINE_FRAGEND_DEFAULT 0
#define COGL_PIPELINE_FRAGEND_UNDEFINED 3
+#define COGL_PIPELINE_VERTEND_FIXED 0
+
+#define COGL_PIPELINE_N_VERTENDS 1
+
+#define COGL_PIPELINE_VERTEND_DEFAULT 0
+#define COGL_PIPELINE_VERTEND_UNDEFINED 3
+
/* If we have either of the GLSL backends then we also need a GLSL
progend to combine the shaders generated into a single
program. Currently there is only one progend but if we ever add
@@ -610,7 +617,7 @@ struct _CoglPipeline
* state with the ancestors of other pipelines and those ancestors
* could currently be associated with different backends.
*
- * Each set bit indicates if the correspondong ->backend_privs[]
+ * Each set bit indicates if the corresponding ->fragend_privs[]
* entry is valid.
*/
unsigned int fragend_priv_set_mask:COGL_PIPELINE_N_FRAGENDS;
@@ -648,6 +655,7 @@ struct _CoglPipeline
* the pipeline and any private state the backend has associated
* with the pipeline. */
unsigned int fragend:3;
+ unsigned int vertend:3;
};
typedef struct _CoglPipelineFragend
@@ -674,6 +682,25 @@ typedef struct _CoglPipelineFragend
void (*free_priv) (CoglPipeline *pipeline);
} CoglPipelineFragend;
+typedef struct _CoglPipelineVertend
+{
+ gboolean (*start) (CoglPipeline *pipeline,
+ int n_layers,
+ unsigned long pipelines_difference);
+ gboolean (*add_layer) (CoglPipeline *pipeline,
+ CoglPipelineLayer *layer,
+ unsigned long layers_difference);
+ gboolean (*end) (CoglPipeline *pipeline,
+ unsigned long pipelines_difference);
+
+ void (*pipeline_pre_change_notify) (CoglPipeline *pipeline,
+ CoglPipelineState change,
+ const CoglColor *new_color);
+ void (*layer_pre_change_notify) (CoglPipeline *owner,
+ CoglPipelineLayer *layer,
+ CoglPipelineLayerState change);
+} CoglPipelineVertend;
+
typedef struct
{
void (*end) (CoglPipeline *pipeline,
@@ -696,6 +723,8 @@ typedef enum
extern const CoglPipelineFragend *
_cogl_pipeline_fragends[COGL_PIPELINE_N_FRAGENDS];
+extern const CoglPipelineVertend *
+_cogl_pipeline_vertends[COGL_PIPELINE_N_VERTENDS];
extern const CoglPipelineProgend *
_cogl_pipeline_progends[];
@@ -933,6 +962,9 @@ _cogl_pipeline_weak_copy (CoglPipeline *pipeline,
void
_cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend);
+void
+_cogl_pipeline_set_vertend (CoglPipeline *pipeline, int vertend);
+
CoglPipeline *
_cogl_pipeline_get_parent (CoglPipeline *pipeline);
diff --git a/cogl/cogl-pipeline-vertend-fixed-private.h b/cogl/cogl-pipeline-vertend-fixed-private.h
new file mode 100644
index 000000000..59bce34e9
--- /dev/null
+++ b/cogl/cogl-pipeline-vertend-fixed-private.h
@@ -0,0 +1,36 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ *
+ *
+ *
+ * Authors:
+ * Neil Roberts
+ */
+
+#ifndef __COGL_PIPELINE_VERTEND_FIXED_PRIVATE_H
+#define __COGL_PIPELINE_VERTEND_FIXED_PRIVATE_H
+
+#include "cogl-pipeline-private.h"
+
+extern const CoglPipelineVertend _cogl_pipeline_fixed_vertend;
+
+#endif /* __COGL_PIPELINE_VERTEND_FIXED_PRIVATE_H */
+
diff --git a/cogl/cogl-pipeline-vertend-fixed.c b/cogl/cogl-pipeline-vertend-fixed.c
new file mode 100644
index 000000000..8e5a85b9a
--- /dev/null
+++ b/cogl/cogl-pipeline-vertend-fixed.c
@@ -0,0 +1,114 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2008,2009,2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ *
+ *
+ *
+ * Authors:
+ * Neil Roberts
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-pipeline-private.h"
+#include "cogl-pipeline-opengl-private.h"
+
+#ifdef COGL_PIPELINE_VERTEND_FIXED
+
+#include "cogl.h"
+#include "cogl-internal.h"
+#include "cogl-context.h"
+#include "cogl-handle.h"
+
+const CoglPipelineVertend _cogl_pipeline_fixed_vertend;
+
+static gboolean
+_cogl_pipeline_vertend_fixed_start (CoglPipeline *pipeline,
+ int n_layers,
+ unsigned long pipelines_difference)
+{
+ if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_FIXED))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+_cogl_pipeline_vertend_fixed_add_layer (CoglPipeline *pipeline,
+ CoglPipelineLayer *layer,
+ unsigned long layers_difference)
+{
+ int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
+ CoglTextureUnit *unit = _cogl_get_texture_unit (unit_index);
+
+ if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX)
+ {
+ CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
+ CoglPipelineLayer *authority =
+ _cogl_pipeline_layer_get_authority (layer, state);
+
+ _cogl_matrix_stack_set (unit->matrix_stack,
+ &authority->big_state->matrix);
+
+ _cogl_matrix_stack_flush_to_gl (unit->matrix_stack, COGL_MATRIX_TEXTURE);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+_cogl_pipeline_vertend_fixed_end (CoglPipeline *pipeline,
+ unsigned long pipelines_difference)
+{
+ if (pipelines_difference & COGL_PIPELINE_STATE_LIGHTING)
+ {
+ CoglPipeline *authority =
+ _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
+ CoglPipelineLightingState *lighting_state =
+ &authority->big_state->lighting_state;
+
+ GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT,
+ lighting_state->ambient));
+ GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE,
+ lighting_state->diffuse));
+ GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,
+ lighting_state->specular));
+ GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION,
+ lighting_state->emission));
+ GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS,
+ &lighting_state->shininess));
+ }
+
+ return TRUE;
+}
+
+const CoglPipelineVertend _cogl_pipeline_fixed_vertend =
+{
+ _cogl_pipeline_vertend_fixed_start,
+ _cogl_pipeline_vertend_fixed_add_layer,
+ _cogl_pipeline_vertend_fixed_end,
+ NULL, /* pipeline_change_notify */
+ NULL /* layer_change_notify */
+};
+
+#endif /* COGL_PIPELINE_VERTEND_FIXED */
+
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c
index 75208d7e2..c2e490251 100644
--- a/cogl/cogl-pipeline.c
+++ b/cogl/cogl-pipeline.c
@@ -64,6 +64,7 @@ static void recursively_free_layer_caches (CoglPipeline *pipeline);
static gboolean _cogl_pipeline_is_weak (CoglPipeline *pipeline);
const CoglPipelineFragend *_cogl_pipeline_fragends[COGL_PIPELINE_N_FRAGENDS];
+const CoglPipelineVertend *_cogl_pipeline_vertends[COGL_PIPELINE_N_VERTENDS];
/* The 'MAX' here is so that we don't define an empty array when there
are no progends */
const CoglPipelineProgend *
@@ -82,6 +83,10 @@ _cogl_pipeline_progends[MAX (COGL_PIPELINE_N_PROGENDS, 1)];
#include "cogl-pipeline-progend-glsl-private.h"
#endif
+#ifdef COGL_PIPELINE_VERTEND_FIXED
+#include "cogl-pipeline-vertend-fixed-private.h"
+#endif
+
COGL_OBJECT_DEFINE (Pipeline, pipeline);
/* This type was made deprecated before the cogl_is_pipeline_layer
function was ever exposed in the public headers so there's no need
@@ -224,11 +229,17 @@ _cogl_pipeline_init_default_pipeline (void)
&_cogl_pipeline_glsl_progend;
#endif
+#ifdef COGL_PIPELINE_VERTEND_FIXED
+ _cogl_pipeline_vertends[COGL_PIPELINE_VERTEND_FIXED] =
+ &_cogl_pipeline_fixed_vertend;
+#endif
+
_cogl_pipeline_node_init (COGL_PIPELINE_NODE (pipeline));
pipeline->is_weak = FALSE;
pipeline->journal_ref_count = 0;
pipeline->fragend = COGL_PIPELINE_FRAGEND_UNDEFINED;
+ pipeline->vertend = COGL_PIPELINE_VERTEND_UNDEFINED;
pipeline->differences = COGL_PIPELINE_STATE_ALL_SPARSE;
pipeline->real_blend_enable = FALSE;
@@ -356,9 +367,9 @@ _cogl_pipeline_set_parent (CoglPipeline *pipeline,
if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS)
recursively_free_layer_caches (pipeline);
- /* If the fragment processing backend is also caching state along
- * with the pipeline that depends on the pipeline's ancestry then it
- * may be notified here...
+ /* If the backends are also caching state along with the pipeline
+ * that depends on the pipeline's ancestry then it may be notified
+ * here...
*/
if (pipeline->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
_cogl_pipeline_fragends[pipeline->fragend]->pipeline_set_parent_notify)
@@ -443,6 +454,8 @@ _cogl_pipeline_copy (CoglPipeline *src, gboolean is_weak)
pipeline->fragend = src->fragend;
pipeline->fragend_priv_set_mask = 0;
+ pipeline->vertend = src->vertend;
+
pipeline->has_static_breadcrumb = FALSE;
pipeline->age = 0;
@@ -953,6 +966,12 @@ _cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend)
pipeline->fragend = fragend;
}
+void
+_cogl_pipeline_set_vertend (CoglPipeline *pipeline, int vertend)
+{
+ pipeline->vertend = vertend;
+}
+
static void
_cogl_pipeline_copy_differences (CoglPipeline *dest,
CoglPipeline *src,
@@ -1184,13 +1203,45 @@ _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline,
if (pipeline->fragend == COGL_PIPELINE_FRAGEND_FIXED)
_cogl_pipeline_set_fragend (pipeline, COGL_PIPELINE_FRAGEND_UNDEFINED);
#endif
+#ifdef COGL_PIPELINE_VERTEND_FIXED
+ if (pipeline->vertend == COGL_PIPELINE_VERTEND_FIXED)
+ _cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_UNDEFINED);
+#endif
+ /* To simplify things for the backends we are careful about how
+ * we report STATE_LAYERS changes.
+ *
+ * All STATE_LAYERS changes with the exception of ->n_layers
+ * will also result in layer_pre_change_notifications. For
+ * backends that perform code generation for fragment processing
+ * they typically need to understand the details of how layers
+ * get changed to determine if they need to repeat codegen. It
+ * doesn't help them to report a pipeline STATE_LAYERS change
+ * for all layer changes since it's so broad, they really need
+ * to wait for the layer change to be notified. What does help
+ * though is to report a STATE_LAYERS change for a change in
+ * ->n_layers because they typically do need to repeat codegen
+ * in that case.
+ *
+ * This just ensures backends only get a single pipeline or
+ * layer pre-change notification for any particular change.
+ */
if (pipeline->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
_cogl_pipeline_fragends[pipeline->fragend]->pipeline_pre_change_notify)
{
const CoglPipelineFragend *fragend =
_cogl_pipeline_fragends[pipeline->fragend];
+ if (!from_layer_change)
+ fragend->pipeline_pre_change_notify (pipeline, change, new_color);
+ }
+
+ if (pipeline->vertend != COGL_PIPELINE_VERTEND_UNDEFINED &&
+ _cogl_pipeline_vertends[pipeline->vertend]->pipeline_pre_change_notify)
+ {
+ const CoglPipelineVertend *vertend =
+ _cogl_pipeline_vertends[pipeline->vertend];
+
/* To simplify things for the backends we are careful about how
* we report STATE_LAYERS changes.
*
@@ -1210,7 +1261,7 @@ _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline,
* layer pre-change notification for any particular change.
*/
if (!from_layer_change)
- fragend->pipeline_pre_change_notify (pipeline, change, new_color);
+ vertend->pipeline_pre_change_notify (pipeline, change, new_color);
}
/* Notify all of the progends */
@@ -1524,6 +1575,21 @@ _cogl_pipeline_fragend_layer_change_notify (CoglPipeline *owner,
}
}
+static void
+_cogl_pipeline_vertend_layer_change_notify (CoglPipeline *owner,
+ CoglPipelineLayer *layer,
+ CoglPipelineLayerState change)
+{
+ /* NB: The comment in fragend_layer_change_notify applies here too */
+ if (owner->vertend != COGL_PIPELINE_VERTEND_UNDEFINED &&
+ _cogl_pipeline_vertends[owner->vertend]->layer_pre_change_notify)
+ {
+ const CoglPipelineVertend *vertend =
+ _cogl_pipeline_vertends[owner->vertend];
+ vertend->layer_pre_change_notify (owner, layer, change);
+ }
+}
+
static void
_cogl_pipeline_progend_layer_change_notify (CoglPipeline *owner,
CoglPipelineLayer *layer,
@@ -1697,6 +1763,7 @@ _cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner,
* dependant on this layer so it's ok to modify it. */
_cogl_pipeline_fragend_layer_change_notify (required_owner, layer, change);
+ _cogl_pipeline_vertend_layer_change_notify (required_owner, layer, change);
_cogl_pipeline_progend_layer_change_notify (required_owner, layer, change);
/* If the layer being changed is the same as the last layer we
@@ -4356,7 +4423,10 @@ cogl_pipeline_set_user_program (CoglPipeline *pipeline,
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
if (program != COGL_INVALID_HANDLE)
- _cogl_pipeline_set_fragend (pipeline, COGL_PIPELINE_FRAGEND_DEFAULT);
+ {
+ _cogl_pipeline_set_fragend (pipeline, COGL_PIPELINE_FRAGEND_DEFAULT);
+ _cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_DEFAULT);
+ }
/* If we are the current authority see if we can revert to one of our
* ancestors being the authority */