[cogl/wip/rib/master-next: 9/10] pipeline: split out all layer state apis
- From: Robert Bragg <rbragg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [cogl/wip/rib/master-next: 9/10] pipeline: split out all layer state apis
- Date: Thu, 8 Sep 2011 12:06:21 +0000 (UTC)
commit 515be7bc80bab859cd05e089a7d8bad45d43c387
Author: Robert Bragg <robert linux intel com>
Date: Thu Sep 8 00:42:22 2011 +0100
pipeline: split out all layer state apis
As part of an on-going effort to get cogl-pipeline.c into a more
maintainable state this splits out all the apis relating just to
layer state. This just leaves code relating to the core CoglPipeline
and CoglPipelineLayer design left in cogl-pipeline.c.
This splits out around 2k more lines from cogl-pipeline.c although we
are still left with nearly 4k lines so we still have some way to go!
cogl/Makefile.am | 2 +
cogl/cogl-pipeline-layer-state-private.h | 115 ++
cogl/cogl-pipeline-layer-state.c | 1664 +++++++++++++++++++
cogl/cogl-pipeline-layer-state.h | 473 ++++++
cogl/cogl-pipeline-private.h | 31 +
cogl/cogl-pipeline.c | 1969 ++---------------------
cogl/cogl-pipeline.h | 433 -----
cogl/cogl.h | 1 +
doc/reference/cogl-2.0-experimental/Makefile.am | 1 +
doc/reference/cogl/Makefile.am | 1 +
10 files changed, 2456 insertions(+), 2234 deletions(-)
---
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 43da82a..2caf098 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -244,6 +244,8 @@ cogl_sources_c = \
$(srcdir)/cogl-pipeline.c \
$(srcdir)/cogl-pipeline-private.h \
$(srcdir)/cogl-pipeline-state.c \
+ $(srcdir)/cogl-pipeline-layer-state-private.h \
+ $(srcdir)/cogl-pipeline-layer-state.c \
$(srcdir)/cogl-pipeline-state-private.h \
$(srcdir)/cogl-pipeline-opengl.c \
$(srcdir)/cogl-pipeline-opengl-private.h \
diff --git a/cogl/cogl-pipeline-layer-state-private.h b/cogl/cogl-pipeline-layer-state-private.h
new file mode 100644
index 0000000..5c0aa64
--- /dev/null
+++ b/cogl/cogl-pipeline-layer-state-private.h
@@ -0,0 +1,115 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ * Robert Bragg <robert linux intel com>
+ */
+
+#ifndef __COGL_PIPELINE_LAYER_STATE_PRIVATE_H
+#define __COGL_PIPELINE_LAYER_STATE_PRIVATE_H
+
+CoglPipelineLayer *
+_cogl_pipeline_set_layer_unit (CoglPipeline *required_owner,
+ CoglPipelineLayer *layer,
+ int unit_index);
+
+gboolean
+_cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1,
+ CoglPipelineEvalFlags flags);
+
+gboolean
+_cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1,
+ CoglPipelineEvalFlags flags);
+
+gboolean
+_cogl_pipeline_layer_combine_state_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1);
+
+gboolean
+_cogl_pipeline_layer_combine_constant_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1);
+
+gboolean
+_cogl_pipeline_layer_filters_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1);
+
+gboolean
+_cogl_pipeline_layer_wrap_modes_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1);
+
+gboolean
+_cogl_pipeline_layer_user_matrix_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1);
+
+gboolean
+_cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1);
+
+void
+_cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state);
+
+void
+_cogl_pipeline_layer_hash_texture_target_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state);
+
+void
+_cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state);
+
+void
+_cogl_pipeline_layer_hash_filters_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state);
+
+void
+_cogl_pipeline_layer_hash_wrap_modes_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state);
+
+void
+_cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state);
+
+void
+_cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state);
+
+void
+_cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state);
+
+void
+_cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state);
+
+#endif /* __COGL_PIPELINE_LAYER_STATE_PRIVATE_H */
diff --git a/cogl/cogl-pipeline-layer-state.c b/cogl/cogl-pipeline-layer-state.c
new file mode 100644
index 0000000..a7a25bc
--- /dev/null
+++ b/cogl/cogl-pipeline-layer-state.c
@@ -0,0 +1,1664 @@
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ * Robert Bragg <robert linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-pipeline-private.h"
+#include "cogl-blend-string.h"
+#include "cogl-util.h"
+#include "cogl-matrix.h"
+
+#include "string.h"
+#if 0
+#include "cogl-context-private.h"
+#include "cogl-color-private.h"
+
+#endif
+
+/*
+ * XXX: consider special casing layer->unit_index so it's not a sparse
+ * property so instead we can assume it's valid for all layer
+ * instances.
+ * - We would need to initialize ->unit_index in
+ * _cogl_pipeline_layer_copy ().
+ *
+ * XXX: If you use this API you should consider that the given layer
+ * might not be writeable and so a new derived layer will be allocated
+ * and modified instead. The layer modified will be returned so you
+ * can identify when this happens.
+ */
+CoglPipelineLayer *
+_cogl_pipeline_set_layer_unit (CoglPipeline *required_owner,
+ CoglPipelineLayer *layer,
+ int unit_index)
+{
+ CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_UNIT;
+ CoglPipelineLayer *authority =
+ _cogl_pipeline_layer_get_authority (layer, change);
+ CoglPipelineLayer *new;
+
+ if (authority->unit_index == unit_index)
+ return layer;
+
+ new =
+ _cogl_pipeline_layer_pre_change_notify (required_owner,
+ layer,
+ change);
+ if (new != layer)
+ layer = new;
+ else
+ {
+ /* If the layer we found is currently the authority on the state
+ * we are changing see if we can revert to one of our ancestors
+ * being the authority. */
+ if (layer == authority &&
+ _cogl_pipeline_layer_get_parent (authority) != NULL)
+ {
+ CoglPipelineLayer *parent =
+ _cogl_pipeline_layer_get_parent (authority);
+ CoglPipelineLayer *old_authority =
+ _cogl_pipeline_layer_get_authority (parent, change);
+
+ if (old_authority->unit_index == unit_index)
+ {
+ layer->differences &= ~change;
+ return layer;
+ }
+ }
+ }
+
+ layer->unit_index = unit_index;
+
+ /* If we weren't previously the authority on this state then we need
+ * to extended our differences mask and so it's possible that some
+ * of our ancestry will now become redundant, so we aim to reparent
+ * ourselves if that's true... */
+ if (layer != authority)
+ {
+ layer->differences |= change;
+ _cogl_pipeline_layer_prune_redundant_ancestry (layer);
+ }
+
+ return layer;
+}
+
+CoglTexture *
+_cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer)
+{
+ CoglPipelineLayer *authority =
+ _cogl_pipeline_layer_get_authority (layer,
+ COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
+
+ return authority->texture;
+}
+
+CoglTexture *
+_cogl_pipeline_get_layer_texture (CoglPipeline *pipeline,
+ int layer_index)
+{
+ CoglPipelineLayer *layer =
+ _cogl_pipeline_get_layer (pipeline, layer_index);
+ return _cogl_pipeline_layer_get_texture (layer);
+}
+
+static void
+_cogl_pipeline_set_layer_texture_target (CoglPipeline *pipeline,
+ int layer_index,
+ GLenum target)
+{
+ CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+ CoglPipelineLayer *new;
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, change);
+
+ if (target == authority->target)
+ return;
+
+ new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
+ if (new != layer)
+ layer = new;
+ else
+ {
+ /* If the original layer we found is currently the authority on
+ * the state we are changing see if we can revert to one of our
+ * ancestors being the authority. */
+ if (layer == authority &&
+ _cogl_pipeline_layer_get_parent (authority) != NULL)
+ {
+ CoglPipelineLayer *parent =
+ _cogl_pipeline_layer_get_parent (authority);
+ CoglPipelineLayer *old_authority =
+ _cogl_pipeline_layer_get_authority (parent, change);
+
+ if (old_authority->target == target)
+ {
+ layer->differences &= ~change;
+
+ g_assert (layer->owner == pipeline);
+ if (layer->differences == 0)
+ _cogl_pipeline_prune_empty_layer_difference (pipeline,
+ layer);
+ goto changed;
+ }
+ }
+ }
+
+ layer->target = target;
+
+ /* If we weren't previously the authority on this state then we need
+ * to extended our differences mask and so it's possible that some
+ * of our ancestry will now become redundant, so we aim to reparent
+ * ourselves if that's true... */
+ if (layer != authority)
+ {
+ layer->differences |= change;
+ _cogl_pipeline_layer_prune_redundant_ancestry (layer);
+ }
+
+changed:
+
+ _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
+}
+
+static void
+_cogl_pipeline_set_layer_texture_data (CoglPipeline *pipeline,
+ int layer_index,
+ CoglTexture *texture)
+{
+ CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+ CoglPipelineLayer *new;
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, change);
+
+ if (authority->texture == texture)
+ return;
+
+ new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
+ if (new != layer)
+ layer = new;
+ else
+ {
+ /* If the original layer we found is currently the authority on
+ * the state we are changing see if we can revert to one of our
+ * ancestors being the authority. */
+ if (layer == authority &&
+ _cogl_pipeline_layer_get_parent (authority) != NULL)
+ {
+ CoglPipelineLayer *parent =
+ _cogl_pipeline_layer_get_parent (authority);
+ CoglPipelineLayer *old_authority =
+ _cogl_pipeline_layer_get_authority (parent, change);
+
+ if (old_authority->texture == texture)
+ {
+ layer->differences &= ~change;
+
+ if (layer->texture != NULL)
+ cogl_object_unref (layer->texture);
+
+ g_assert (layer->owner == pipeline);
+ if (layer->differences == 0)
+ _cogl_pipeline_prune_empty_layer_difference (pipeline,
+ layer);
+ goto changed;
+ }
+ }
+ }
+
+ if (texture != NULL)
+ cogl_object_ref (texture);
+ if (layer == authority &&
+ layer->texture != NULL)
+ cogl_object_unref (layer->texture);
+ layer->texture = texture;
+
+ /* If we weren't previously the authority on this state then we need
+ * to extended our differences mask and so it's possible that some
+ * of our ancestry will now become redundant, so we aim to reparent
+ * ourselves if that's true... */
+ if (layer != authority)
+ {
+ layer->differences |= change;
+ _cogl_pipeline_layer_prune_redundant_ancestry (layer);
+ }
+
+changed:
+
+ _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
+}
+
+/* A convenience for querying the target of a given texture that
+ * notably returns 0 for NULL textures - so we can say that a layer
+ * with no associated CoglTexture will have a texture target of 0.
+ */
+static GLenum
+get_texture_target (CoglHandle texture)
+{
+ GLuint ignore_handle;
+ GLenum gl_target;
+
+ g_return_val_if_fail (texture, 0);
+
+ cogl_texture_get_gl_texture (texture, &ignore_handle, &gl_target);
+
+ return gl_target;
+}
+
+void
+cogl_pipeline_set_layer_texture (CoglPipeline *pipeline,
+ int layer_index,
+ CoglTexture *texture)
+{
+ /* For the convenience of fragend code we separate texture state
+ * into the "target" and the "data", and setting a layer texture
+ * updates both of these properties.
+ *
+ * One example for why this is helpful is that the fragends may
+ * cache programs they generate and want to re-use those programs
+ * with all pipelines having equivalent fragment processing state.
+ * For the sake of determining if pipelines have equivalent fragment
+ * processing state we don't need to compare that the same
+ * underlying texture objects are referenced by the pipelines but we
+ * do need to see if they use the same texture targets. Making this
+ * distinction is much simpler if they are in different state
+ * groups.
+ *
+ * Note: if a NULL texture is set then we leave the target unchanged
+ * so we can avoid needlessly invalidating any associated fragment
+ * program.
+ */
+ if (texture)
+ _cogl_pipeline_set_layer_texture_target (pipeline, layer_index,
+ get_texture_target (texture));
+ _cogl_pipeline_set_layer_texture_data (pipeline, layer_index, texture);
+}
+
+void
+_cogl_pipeline_set_layer_wrap_modes (CoglPipeline *pipeline,
+ CoglPipelineLayer *layer,
+ CoglPipelineLayer *authority,
+ CoglPipelineWrapModeInternal wrap_mode_s,
+ CoglPipelineWrapModeInternal wrap_mode_t,
+ CoglPipelineWrapModeInternal wrap_mode_p)
+{
+ CoglPipelineLayer *new;
+ CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
+
+ if (authority->wrap_mode_s == wrap_mode_s &&
+ authority->wrap_mode_t == wrap_mode_t &&
+ authority->wrap_mode_p == wrap_mode_p)
+ return;
+
+ new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
+ if (new != layer)
+ layer = new;
+ else
+ {
+ /* If the original layer we found is currently the authority on
+ * the state we are changing see if we can revert to one of our
+ * ancestors being the authority. */
+ if (layer == authority &&
+ _cogl_pipeline_layer_get_parent (authority) != NULL)
+ {
+ CoglPipelineLayer *parent =
+ _cogl_pipeline_layer_get_parent (authority);
+ CoglPipelineLayer *old_authority =
+ _cogl_pipeline_layer_get_authority (parent, change);
+
+ if (old_authority->wrap_mode_s == wrap_mode_s &&
+ old_authority->wrap_mode_t == wrap_mode_t &&
+ old_authority->wrap_mode_p == wrap_mode_p)
+ {
+ layer->differences &= ~change;
+
+ g_assert (layer->owner == pipeline);
+ if (layer->differences == 0)
+ _cogl_pipeline_prune_empty_layer_difference (pipeline,
+ layer);
+ return;
+ }
+ }
+ }
+
+ layer->wrap_mode_s = wrap_mode_s;
+ layer->wrap_mode_t = wrap_mode_t;
+ layer->wrap_mode_p = wrap_mode_p;
+
+ /* If we weren't previously the authority on this state then we need
+ * to extended our differences mask and so it's possible that some
+ * of our ancestry will now become redundant, so we aim to reparent
+ * ourselves if that's true... */
+ if (layer != authority)
+ {
+ layer->differences |= change;
+ _cogl_pipeline_layer_prune_redundant_ancestry (layer);
+ }
+}
+
+static CoglPipelineWrapModeInternal
+public_to_internal_wrap_mode (CoglPipelineWrapMode mode)
+{
+ return (CoglPipelineWrapModeInternal)mode;
+}
+
+static CoglPipelineWrapMode
+internal_to_public_wrap_mode (CoglPipelineWrapModeInternal internal_mode)
+{
+ g_return_val_if_fail (internal_mode !=
+ COGL_PIPELINE_WRAP_MODE_INTERNAL_CLAMP_TO_BORDER,
+ COGL_PIPELINE_WRAP_MODE_AUTOMATIC);
+ return (CoglPipelineWrapMode)internal_mode;
+}
+
+void
+cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline,
+ int layer_index,
+ CoglPipelineWrapMode mode)
+{
+ CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+ CoglPipelineWrapModeInternal internal_mode =
+ public_to_internal_wrap_mode (mode);
+
+ g_return_if_fail (cogl_is_pipeline (pipeline));
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, change);
+
+ _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority,
+ internal_mode,
+ authority->wrap_mode_t,
+ authority->wrap_mode_p);
+}
+
+void
+cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline,
+ int layer_index,
+ CoglPipelineWrapMode mode)
+{
+ CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+ CoglPipelineWrapModeInternal internal_mode =
+ public_to_internal_wrap_mode (mode);
+
+ g_return_if_fail (cogl_is_pipeline (pipeline));
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, change);
+
+ _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority,
+ authority->wrap_mode_s,
+ internal_mode,
+ authority->wrap_mode_p);
+}
+
+/* The rationale for naming the third texture coordinate 'p' instead
+ of OpenGL's usual 'r' is that 'r' conflicts with the usual naming
+ of the 'red' component when treating a vector as a color. Under
+ GLSL this is awkward because the texture swizzling for a vector
+ uses a single letter for each component and the names for colors,
+ textures and positions are synonymous. GLSL works around this by
+ naming the components of the texture s, t, p and q. Cogl already
+ effectively already exposes this naming because it exposes GLSL so
+ it makes sense to use that naming consistently. Another alternative
+ could be u, v and w. This is what Blender and Direct3D use. However
+ the w component conflicts with the w component of a position
+ vertex. */
+void
+cogl_pipeline_set_layer_wrap_mode_p (CoglPipeline *pipeline,
+ int layer_index,
+ CoglPipelineWrapMode mode)
+{
+ CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+ CoglPipelineWrapModeInternal internal_mode =
+ public_to_internal_wrap_mode (mode);
+
+ g_return_if_fail (cogl_is_pipeline (pipeline));
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, change);
+
+ _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority,
+ authority->wrap_mode_s,
+ authority->wrap_mode_t,
+ internal_mode);
+}
+
+void
+cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline,
+ int layer_index,
+ CoglPipelineWrapMode mode)
+{
+ CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+ CoglPipelineWrapModeInternal internal_mode =
+ public_to_internal_wrap_mode (mode);
+
+ g_return_if_fail (cogl_is_pipeline (pipeline));
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, change);
+
+ _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority,
+ internal_mode,
+ internal_mode,
+ internal_mode);
+ /* XXX: I wonder if we should really be duplicating the mode into
+ * the 'r' wrap mode too? */
+}
+
+/* FIXME: deprecate this API */
+CoglPipelineWrapMode
+_cogl_pipeline_layer_get_wrap_mode_s (CoglPipelineLayer *layer)
+{
+ CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
+ CoglPipelineLayer *authority;
+
+ g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, change);
+
+ return internal_to_public_wrap_mode (authority->wrap_mode_s);
+}
+
+CoglPipelineWrapMode
+cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline, int layer_index)
+{
+ CoglPipelineLayer *layer;
+
+ g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+ /* FIXME: we shouldn't ever construct a layer in a getter function */
+
+ return _cogl_pipeline_layer_get_wrap_mode_s (layer);
+}
+
+/* FIXME: deprecate this API */
+CoglPipelineWrapMode
+_cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer)
+{
+ CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
+ CoglPipelineLayer *authority;
+
+ g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, change);
+
+ return internal_to_public_wrap_mode (authority->wrap_mode_t);
+}
+
+CoglPipelineWrapMode
+cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline, int layer_index)
+{
+ CoglPipelineLayer *layer;
+
+ g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+ /* FIXME: we shouldn't ever construct a layer in a getter function */
+
+ return _cogl_pipeline_layer_get_wrap_mode_t (layer);
+}
+
+CoglPipelineWrapMode
+_cogl_pipeline_layer_get_wrap_mode_p (CoglPipelineLayer *layer)
+{
+ CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
+ CoglPipelineLayer *authority =
+ _cogl_pipeline_layer_get_authority (layer, change);
+
+ return internal_to_public_wrap_mode (authority->wrap_mode_p);
+}
+
+CoglPipelineWrapMode
+cogl_pipeline_get_layer_wrap_mode_p (CoglPipeline *pipeline, int layer_index)
+{
+ CoglPipelineLayer *layer;
+
+ g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ return _cogl_pipeline_layer_get_wrap_mode_p (layer);
+}
+
+void
+_cogl_pipeline_layer_get_wrap_modes (CoglPipelineLayer *layer,
+ CoglPipelineWrapModeInternal *wrap_mode_s,
+ CoglPipelineWrapModeInternal *wrap_mode_t,
+ CoglPipelineWrapModeInternal *wrap_mode_p)
+{
+ CoglPipelineLayer *authority =
+ _cogl_pipeline_layer_get_authority (layer,
+ COGL_PIPELINE_LAYER_STATE_WRAP_MODES);
+
+ *wrap_mode_s = authority->wrap_mode_s;
+ *wrap_mode_t = authority->wrap_mode_t;
+ *wrap_mode_p = authority->wrap_mode_p;
+}
+
+gboolean
+cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
+ int layer_index,
+ gboolean enable,
+ GError **error)
+{
+ CoglPipelineLayerState change =
+ COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *new;
+ CoglPipelineLayer *authority;
+
+ g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
+
+ /* Don't allow point sprite coordinates to be enabled if the driver
+ doesn't support it */
+ if (enable && !cogl_features_available (COGL_FEATURE_POINT_SPRITE))
+ {
+ if (error)
+ {
+ g_set_error (error, COGL_ERROR, COGL_ERROR_UNSUPPORTED,
+ "Point sprite texture coordinates are enabled "
+ "for a layer but the GL driver does not support it.");
+ }
+ else
+ {
+ static gboolean warning_seen = FALSE;
+ if (!warning_seen)
+ g_warning ("Point sprite texture coordinates are enabled "
+ "for a layer but the GL driver does not support it.");
+ warning_seen = TRUE;
+ }
+
+ return FALSE;
+ }
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, change);
+
+ if (authority->big_state->point_sprite_coords == enable)
+ return TRUE;
+
+ new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
+ if (new != layer)
+ layer = new;
+ else
+ {
+ /* If the original layer we found is currently the authority on
+ * the state we are changing see if we can revert to one of our
+ * ancestors being the authority. */
+ if (layer == authority &&
+ _cogl_pipeline_layer_get_parent (authority) != NULL)
+ {
+ CoglPipelineLayer *parent =
+ _cogl_pipeline_layer_get_parent (authority);
+ CoglPipelineLayer *old_authority =
+ _cogl_pipeline_layer_get_authority (parent, change);
+
+ if (old_authority->big_state->point_sprite_coords == enable)
+ {
+ layer->differences &= ~change;
+
+ g_assert (layer->owner == pipeline);
+ if (layer->differences == 0)
+ _cogl_pipeline_prune_empty_layer_difference (pipeline,
+ layer);
+ return TRUE;
+ }
+ }
+ }
+
+ layer->big_state->point_sprite_coords = enable;
+
+ /* If we weren't previously the authority on this state then we need
+ * to extended our differences mask and so it's possible that some
+ * of our ancestry will now become redundant, so we aim to reparent
+ * ourselves if that's true... */
+ if (layer != authority)
+ {
+ layer->differences |= change;
+ _cogl_pipeline_layer_prune_redundant_ancestry (layer);
+ }
+
+ return TRUE;
+}
+
+gboolean
+cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
+ int layer_index)
+{
+ CoglPipelineLayerState change =
+ COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+
+ g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+ /* FIXME: we shouldn't ever construct a layer in a getter function */
+
+ authority = _cogl_pipeline_layer_get_authority (layer, change);
+
+ return authority->big_state->point_sprite_coords;
+}
+
+gboolean
+_cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1,
+ CoglPipelineEvalFlags flags)
+{
+ return authority0->target == authority1->target;
+}
+
+gboolean
+_cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1,
+ CoglPipelineEvalFlags flags)
+{
+ GLuint gl_handle0, gl_handle1;
+
+ cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, NULL);
+ cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, NULL);
+
+ return gl_handle0 == gl_handle1;
+}
+
+gboolean
+_cogl_pipeline_layer_combine_state_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1)
+{
+ CoglPipelineLayerBigState *big_state0 = authority0->big_state;
+ CoglPipelineLayerBigState *big_state1 = authority1->big_state;
+ int n_args;
+ int i;
+
+ if (big_state0->texture_combine_rgb_func !=
+ big_state1->texture_combine_rgb_func)
+ return FALSE;
+
+ if (big_state0->texture_combine_alpha_func !=
+ big_state1->texture_combine_alpha_func)
+ return FALSE;
+
+ n_args =
+ _cogl_get_n_args_for_combine_func (big_state0->texture_combine_rgb_func);
+ for (i = 0; i < n_args; i++)
+ {
+ if ((big_state0->texture_combine_rgb_src[i] !=
+ big_state1->texture_combine_rgb_src[i]) ||
+ (big_state0->texture_combine_rgb_op[i] !=
+ big_state1->texture_combine_rgb_op[i]))
+ return FALSE;
+ }
+
+ n_args =
+ _cogl_get_n_args_for_combine_func (big_state0->texture_combine_alpha_func);
+ for (i = 0; i < n_args; i++)
+ {
+ if ((big_state0->texture_combine_alpha_src[i] !=
+ big_state1->texture_combine_alpha_src[i]) ||
+ (big_state0->texture_combine_alpha_op[i] !=
+ big_state1->texture_combine_alpha_op[i]))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+_cogl_pipeline_layer_combine_constant_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1)
+{
+ return memcmp (authority0->big_state->texture_combine_constant,
+ authority1->big_state->texture_combine_constant,
+ sizeof (float) * 4) == 0 ? TRUE : FALSE;
+}
+
+gboolean
+_cogl_pipeline_layer_filters_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1)
+{
+ if (authority0->mag_filter != authority1->mag_filter)
+ return FALSE;
+ if (authority0->min_filter != authority1->min_filter)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+compare_wrap_mode_equal (CoglPipelineWrapMode wrap_mode0,
+ CoglPipelineWrapMode wrap_mode1)
+{
+ /* We consider AUTOMATIC to be equivalent to CLAMP_TO_EDGE because
+ the primitives code is expected to override this to something
+ else if it wants it to be behave any other way */
+ if (wrap_mode0 == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
+ wrap_mode0 = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
+ if (wrap_mode1 == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
+ wrap_mode1 = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
+
+ return wrap_mode0 == wrap_mode1;
+}
+
+gboolean
+_cogl_pipeline_layer_wrap_modes_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1)
+{
+ if (!compare_wrap_mode_equal (authority0->wrap_mode_s,
+ authority1->wrap_mode_s) ||
+ !compare_wrap_mode_equal (authority0->wrap_mode_t,
+ authority1->wrap_mode_t) ||
+ !compare_wrap_mode_equal (authority0->wrap_mode_p,
+ authority1->wrap_mode_p))
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
+_cogl_pipeline_layer_user_matrix_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1)
+{
+ CoglPipelineLayerBigState *big_state0 = authority0->big_state;
+ CoglPipelineLayerBigState *big_state1 = authority1->big_state;
+
+ if (!cogl_matrix_equal (&big_state0->matrix, &big_state1->matrix))
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
+_cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1)
+{
+ CoglPipelineLayerBigState *big_state0 = authority0->big_state;
+ CoglPipelineLayerBigState *big_state1 = authority1->big_state;
+
+ return big_state0->point_sprite_coords == big_state1->point_sprite_coords;
+}
+
+static void
+setup_texture_combine_state (CoglBlendStringStatement *statement,
+ CoglPipelineCombineFunc *texture_combine_func,
+ CoglPipelineCombineSource *texture_combine_src,
+ CoglPipelineCombineOp *texture_combine_op)
+{
+ int i;
+
+ switch (statement->function->type)
+ {
+ case COGL_BLEND_STRING_FUNCTION_REPLACE:
+ *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_REPLACE;
+ break;
+ case COGL_BLEND_STRING_FUNCTION_MODULATE:
+ *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_MODULATE;
+ break;
+ case COGL_BLEND_STRING_FUNCTION_ADD:
+ *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD;
+ break;
+ case COGL_BLEND_STRING_FUNCTION_ADD_SIGNED:
+ *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED;
+ break;
+ case COGL_BLEND_STRING_FUNCTION_INTERPOLATE:
+ *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE;
+ break;
+ case COGL_BLEND_STRING_FUNCTION_SUBTRACT:
+ *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_SUBTRACT;
+ break;
+ case COGL_BLEND_STRING_FUNCTION_DOT3_RGB:
+ *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB;
+ break;
+ case COGL_BLEND_STRING_FUNCTION_DOT3_RGBA:
+ *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA;
+ break;
+ }
+
+ for (i = 0; i < statement->function->argc; i++)
+ {
+ CoglBlendStringArgument *arg = &statement->args[i];
+
+ switch (arg->source.info->type)
+ {
+ case COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT:
+ texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_CONSTANT;
+ break;
+ case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE:
+ texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
+ break;
+ case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N:
+ texture_combine_src[i] =
+ COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0 + arg->source.texture;
+ break;
+ case COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY:
+ texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR;
+ break;
+ case COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS:
+ texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
+ break;
+ default:
+ g_warning ("Unexpected texture combine source");
+ texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
+ }
+
+ if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB)
+ {
+ if (statement->args[i].source.one_minus)
+ texture_combine_op[i] =
+ COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR;
+ else
+ texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
+ }
+ else
+ {
+ if (statement->args[i].source.one_minus)
+ texture_combine_op[i] =
+ COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA;
+ else
+ texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
+ }
+ }
+}
+
+gboolean
+cogl_pipeline_set_layer_combine (CoglPipeline *pipeline,
+ int layer_index,
+ const char *combine_description,
+ GError **error)
+{
+ CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE;
+ CoglPipelineLayer *authority;
+ CoglPipelineLayer *layer;
+ CoglBlendStringStatement statements[2];
+ CoglBlendStringStatement split[2];
+ CoglBlendStringStatement *rgb;
+ CoglBlendStringStatement *a;
+ GError *internal_error = NULL;
+ int count;
+
+ g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, state);
+
+ count =
+ _cogl_blend_string_compile (combine_description,
+ COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE,
+ statements,
+ &internal_error);
+ if (!count)
+ {
+ if (error)
+ g_propagate_error (error, internal_error);
+ else
+ {
+ g_warning ("Cannot compile combine description: %s\n",
+ internal_error->message);
+ g_error_free (internal_error);
+ }
+ return FALSE;
+ }
+
+ if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA)
+ {
+ _cogl_blend_string_split_rgba_statement (statements,
+ &split[0], &split[1]);
+ rgb = &split[0];
+ a = &split[1];
+ }
+ else
+ {
+ rgb = &statements[0];
+ a = &statements[1];
+ }
+
+ /* FIXME: compare the new state with the current state! */
+
+ /* possibly flush primitives referencing the current state... */
+ layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
+
+ setup_texture_combine_state (rgb,
+ &layer->big_state->texture_combine_rgb_func,
+ layer->big_state->texture_combine_rgb_src,
+ layer->big_state->texture_combine_rgb_op);
+
+ setup_texture_combine_state (a,
+ &layer->big_state->texture_combine_alpha_func,
+ layer->big_state->texture_combine_alpha_src,
+ layer->big_state->texture_combine_alpha_op);
+
+ /* If the original layer we found is currently the authority on
+ * the state we are changing see if we can revert to one of our
+ * ancestors being the authority. */
+ if (layer == authority &&
+ _cogl_pipeline_layer_get_parent (authority) != NULL)
+ {
+ CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority);
+ CoglPipelineLayer *old_authority =
+ _cogl_pipeline_layer_get_authority (parent, state);
+
+ if (_cogl_pipeline_layer_combine_state_equal (authority,
+ old_authority))
+ {
+ layer->differences &= ~state;
+
+ g_assert (layer->owner == pipeline);
+ if (layer->differences == 0)
+ _cogl_pipeline_prune_empty_layer_difference (pipeline,
+ layer);
+ goto changed;
+ }
+ }
+
+ /* If we weren't previously the authority on this state then we need
+ * to extended our differences mask and so it's possible that some
+ * of our ancestry will now become redundant, so we aim to reparent
+ * ourselves if that's true... */
+ if (layer != authority)
+ {
+ layer->differences |= state;
+ _cogl_pipeline_layer_prune_redundant_ancestry (layer);
+ }
+
+changed:
+
+ _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
+ return TRUE;
+}
+
+void
+cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline,
+ int layer_index,
+ const CoglColor *constant_color)
+{
+ CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+ CoglPipelineLayer *new;
+ float color_as_floats[4];
+
+ g_return_if_fail (cogl_is_pipeline (pipeline));
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, state);
+
+ color_as_floats[0] = cogl_color_get_red_float (constant_color);
+ color_as_floats[1] = cogl_color_get_green_float (constant_color);
+ color_as_floats[2] = cogl_color_get_blue_float (constant_color);
+ color_as_floats[3] = cogl_color_get_alpha_float (constant_color);
+
+ if (memcmp (authority->big_state->texture_combine_constant,
+ color_as_floats, sizeof (float) * 4) == 0)
+ return;
+
+ new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
+ if (new != layer)
+ layer = new;
+ else
+ {
+ /* If the original layer we found is currently the authority on
+ * the state we are changing see if we can revert to one of our
+ * ancestors being the authority. */
+ if (layer == authority &&
+ _cogl_pipeline_layer_get_parent (authority) != NULL)
+ {
+ CoglPipelineLayer *parent =
+ _cogl_pipeline_layer_get_parent (authority);
+ CoglPipelineLayer *old_authority =
+ _cogl_pipeline_layer_get_authority (parent, state);
+ CoglPipelineLayerBigState *old_big_state = old_authority->big_state;
+
+ if (memcmp (old_big_state->texture_combine_constant,
+ color_as_floats, sizeof (float) * 4) == 0)
+ {
+ layer->differences &= ~state;
+
+ g_assert (layer->owner == pipeline);
+ if (layer->differences == 0)
+ _cogl_pipeline_prune_empty_layer_difference (pipeline,
+ layer);
+ goto changed;
+ }
+ }
+ }
+
+ memcpy (layer->big_state->texture_combine_constant,
+ color_as_floats,
+ sizeof (color_as_floats));
+
+ /* If we weren't previously the authority on this state then we need
+ * to extended our differences mask and so it's possible that some
+ * of our ancestry will now become redundant, so we aim to reparent
+ * ourselves if that's true... */
+ if (layer != authority)
+ {
+ layer->differences |= state;
+ _cogl_pipeline_layer_prune_redundant_ancestry (layer);
+ }
+
+changed:
+
+ _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
+}
+
+void
+_cogl_pipeline_get_layer_combine_constant (CoglPipeline *pipeline,
+ int layer_index,
+ float *constant)
+{
+ CoglPipelineLayerState change =
+ COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+
+ g_return_if_fail (cogl_is_pipeline (pipeline));
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+ /* FIXME: we shouldn't ever construct a layer in a getter function */
+
+ authority = _cogl_pipeline_layer_get_authority (layer, change);
+ memcpy (constant, authority->big_state->texture_combine_constant,
+ sizeof (float) * 4);
+}
+
+/* We should probably make a public API version of this that has a
+ matrix out-param. For an internal API it's good to be able to avoid
+ copying the matrix */
+const CoglMatrix *
+_cogl_pipeline_get_layer_matrix (CoglPipeline *pipeline, int layer_index)
+{
+ CoglPipelineLayerState change =
+ COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+
+ g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL);
+
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ authority = _cogl_pipeline_layer_get_authority (layer, change);
+ return &authority->big_state->matrix;
+}
+
+void
+cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline,
+ int layer_index,
+ const CoglMatrix *matrix)
+{
+ CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+ CoglPipelineLayer *new;
+
+ g_return_if_fail (cogl_is_pipeline (pipeline));
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, state);
+
+ if (cogl_matrix_equal (matrix, &authority->big_state->matrix))
+ return;
+
+ new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
+ if (new != layer)
+ layer = new;
+ else
+ {
+ /* If the original layer we found is currently the authority on
+ * the state we are changing see if we can revert to one of our
+ * ancestors being the authority. */
+ if (layer == authority &&
+ _cogl_pipeline_layer_get_parent (authority) != NULL)
+ {
+ CoglPipelineLayer *parent =
+ _cogl_pipeline_layer_get_parent (authority);
+ CoglPipelineLayer *old_authority =
+ _cogl_pipeline_layer_get_authority (parent, state);
+
+ if (cogl_matrix_equal (matrix, &old_authority->big_state->matrix))
+ {
+ layer->differences &= ~state;
+
+ g_assert (layer->owner == pipeline);
+ if (layer->differences == 0)
+ _cogl_pipeline_prune_empty_layer_difference (pipeline,
+ layer);
+ return;
+ }
+ }
+ }
+
+ layer->big_state->matrix = *matrix;
+
+ /* If we weren't previously the authority on this state then we need
+ * to extended our differences mask and so it's possible that some
+ * of our ancestry will now become redundant, so we aim to reparent
+ * ourselves if that's true... */
+ if (layer != authority)
+ {
+ layer->differences |= state;
+ _cogl_pipeline_layer_prune_redundant_ancestry (layer);
+ }
+}
+
+/* FIXME: deprecate and replace with
+ * cogl_pipeline_get_layer_texture() instead. */
+CoglTexture *
+_cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer)
+{
+ g_return_val_if_fail (_cogl_is_pipeline_layer (layer), NULL);
+
+ return _cogl_pipeline_layer_get_texture_real (layer);
+}
+
+gboolean
+_cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline,
+ int layer_index)
+{
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ authority =
+ _cogl_pipeline_layer_get_authority (layer,
+ COGL_PIPELINE_LAYER_STATE_USER_MATRIX);
+
+ /* If the authority is the default pipeline then no, otherwise yes */
+ return _cogl_pipeline_layer_get_parent (authority) ? TRUE : FALSE;
+}
+
+void
+_cogl_pipeline_layer_get_filters (CoglPipelineLayer *layer,
+ CoglPipelineFilter *min_filter,
+ CoglPipelineFilter *mag_filter)
+{
+ CoglPipelineLayer *authority =
+ _cogl_pipeline_layer_get_authority (layer,
+ COGL_PIPELINE_LAYER_STATE_FILTERS);
+
+ *min_filter = authority->min_filter;
+ *mag_filter = authority->mag_filter;
+}
+
+void
+_cogl_pipeline_get_layer_filters (CoglPipeline *pipeline,
+ int layer_index,
+ CoglPipelineFilter *min_filter,
+ CoglPipelineFilter *mag_filter)
+{
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+
+ g_return_if_fail (cogl_is_pipeline (pipeline));
+
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ authority =
+ _cogl_pipeline_layer_get_authority (layer,
+ COGL_PIPELINE_LAYER_STATE_FILTERS);
+
+ *min_filter = authority->min_filter;
+ *mag_filter = authority->mag_filter;
+}
+
+CoglPipelineFilter
+_cogl_pipeline_get_layer_min_filter (CoglPipeline *pipeline,
+ int layer_index)
+{
+ CoglPipelineFilter min_filter;
+ CoglPipelineFilter mag_filter;
+
+ _cogl_pipeline_get_layer_filters (pipeline, layer_index,
+ &min_filter, &mag_filter);
+ return min_filter;
+}
+
+CoglPipelineFilter
+_cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline,
+ int layer_index)
+{
+ CoglPipelineFilter min_filter;
+ CoglPipelineFilter mag_filter;
+
+ _cogl_pipeline_get_layer_filters (pipeline, layer_index,
+ &min_filter, &mag_filter);
+ return mag_filter;
+}
+
+CoglPipelineFilter
+_cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer)
+{
+ CoglPipelineLayer *authority;
+
+ g_return_val_if_fail (_cogl_is_pipeline_layer (layer), 0);
+
+ authority =
+ _cogl_pipeline_layer_get_authority (layer,
+ COGL_PIPELINE_LAYER_STATE_FILTERS);
+
+ return authority->min_filter;
+}
+
+CoglPipelineFilter
+_cogl_pipeline_layer_get_mag_filter (CoglPipelineLayer *layer)
+{
+ CoglPipelineLayer *authority;
+
+ g_return_val_if_fail (_cogl_is_pipeline_layer (layer), 0);
+
+ authority =
+ _cogl_pipeline_layer_get_authority (layer,
+ COGL_PIPELINE_LAYER_STATE_FILTERS);
+
+ return authority->mag_filter;
+}
+
+void
+cogl_pipeline_set_layer_filters (CoglPipeline *pipeline,
+ int layer_index,
+ CoglPipelineFilter min_filter,
+ CoglPipelineFilter mag_filter)
+{
+ CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_FILTERS;
+ CoglPipelineLayer *layer;
+ CoglPipelineLayer *authority;
+ CoglPipelineLayer *new;
+
+ g_return_if_fail (cogl_is_pipeline (pipeline));
+
+ /* Note: this will ensure that the layer exists, creating one if it
+ * doesn't already.
+ *
+ * Note: If the layer already existed it's possibly owned by another
+ * pipeline. If the layer is created then it will be owned by
+ * pipeline. */
+ layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+ /* Now find the ancestor of the layer that is the authority for the
+ * state we want to change */
+ authority = _cogl_pipeline_layer_get_authority (layer, state);
+
+ if (authority->min_filter == min_filter &&
+ authority->mag_filter == mag_filter)
+ return;
+
+ new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
+ if (new != layer)
+ layer = new;
+ else
+ {
+ /* If the original layer we found is currently the authority on
+ * the state we are changing see if we can revert to one of our
+ * ancestors being the authority. */
+ if (layer == authority &&
+ _cogl_pipeline_layer_get_parent (authority) != NULL)
+ {
+ CoglPipelineLayer *parent =
+ _cogl_pipeline_layer_get_parent (authority);
+ CoglPipelineLayer *old_authority =
+ _cogl_pipeline_layer_get_authority (parent, state);
+
+ if (old_authority->min_filter == min_filter &&
+ old_authority->mag_filter == mag_filter)
+ {
+ layer->differences &= ~state;
+
+ g_assert (layer->owner == pipeline);
+ if (layer->differences == 0)
+ _cogl_pipeline_prune_empty_layer_difference (pipeline,
+ layer);
+ return;
+ }
+ }
+ }
+
+ layer->min_filter = min_filter;
+ layer->mag_filter = mag_filter;
+
+ /* If we weren't previously the authority on this state then we need
+ * to extended our differences mask and so it's possible that some
+ * of our ancestry will now become redundant, so we aim to reparent
+ * ourselves if that's true... */
+ if (layer != authority)
+ {
+ layer->differences |= state;
+ _cogl_pipeline_layer_prune_redundant_ancestry (layer);
+ }
+}
+
+void
+_cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state)
+{
+ int unit = authority->unit_index;
+ state->hash =
+ _cogl_util_one_at_a_time_hash (state->hash, &unit, sizeof (unit));
+}
+
+void
+_cogl_pipeline_layer_hash_texture_target_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state)
+{
+ GLenum gl_target = authority->target;
+
+ state->hash =
+ _cogl_util_one_at_a_time_hash (state->hash, &gl_target, sizeof (gl_target));
+}
+
+void
+_cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state)
+{
+ GLuint gl_handle;
+
+ cogl_texture_get_gl_texture (authority->texture, &gl_handle, NULL);
+
+ state->hash =
+ _cogl_util_one_at_a_time_hash (state->hash, &gl_handle, sizeof (gl_handle));
+}
+
+void
+_cogl_pipeline_layer_hash_filters_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *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;
+}
+
+void
+_cogl_pipeline_layer_hash_wrap_modes_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *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;
+}
+
+void
+_cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *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;
+}
+
+void
+_cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *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] ==
+ COGL_PIPELINE_COMBINE_SOURCE_CONSTANT)
+ {
+ /* XXX: should we be careful to only hash the alpha
+ * component in the COGL_PIPELINE_COMBINE_OP_SRC_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] ==
+ COGL_PIPELINE_COMBINE_SOURCE_CONSTANT)
+ {
+ /* XXX: should we be careful to only hash the alpha
+ * component in the COGL_PIPELINE_COMBINE_OP_SRC_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);
+ }
+}
+
+void
+_cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *state)
+{
+ CoglPipelineLayerBigState *big_state = authority->big_state;
+ state->hash = _cogl_util_one_at_a_time_hash (state->hash, &big_state->matrix,
+ sizeof (float) * 16);
+}
+
+void
+_cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority,
+ CoglPipelineLayer **authorities,
+ CoglPipelineHashState *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));
+}
+
+
diff --git a/cogl/cogl-pipeline-layer-state.h b/cogl/cogl-pipeline-layer-state.h
new file mode 100644
index 0000000..c629815
--- /dev/null
+++ b/cogl/cogl-pipeline-layer-state.h
@@ -0,0 +1,473 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2007,2008,2009 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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only <cogl/cogl.h> can be included directly."
+#endif
+
+#ifndef __COGL_PIPELINE_LAYER_STATE_H__
+#define __COGL_PIPELINE_LAYER_STATE_H__
+
+#include <cogl/cogl-pipeline.h>
+#include <cogl/cogl-color.h>
+#include <cogl/cogl-matrix.h>
+#include <cogl/cogl-texture.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/**
+ * CoglPipelineFilter:
+ * @COGL_PIPELINE_FILTER_NEAREST: Measuring in manhatten distance from the,
+ * current pixel center, use the nearest texture texel
+ * @COGL_PIPELINE_FILTER_LINEAR: Use the weighted average of the 4 texels
+ * nearest the current pixel center
+ * @COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose
+ * texel size most closely matches the current pixel, and use the
+ * %COGL_PIPELINE_FILTER_NEAREST criterion
+ * @COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose
+ * texel size most closely matches the current pixel, and use the
+ * %COGL_PIPELINE_FILTER_LINEAR criterion
+ * @COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels
+ * whose texel size most closely matches the current pixel, use
+ * the %COGL_PIPELINE_FILTER_NEAREST criterion on each one and take
+ * their weighted average
+ * @COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels
+ * whose texel size most closely matches the current pixel, use
+ * the %COGL_PIPELINE_FILTER_LINEAR criterion on each one and take
+ * their weighted average
+ *
+ * Texture filtering is used whenever the current pixel maps either to more
+ * than one texture element (texel) or less than one. These filter enums
+ * correspond to different strategies used to come up with a pixel color, by
+ * possibly referring to multiple neighbouring texels and taking a weighted
+ * average or simply using the nearest texel.
+ */
+typedef enum {
+ COGL_PIPELINE_FILTER_NEAREST = 0x2600,
+ COGL_PIPELINE_FILTER_LINEAR = 0x2601,
+ COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST = 0x2700,
+ COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST = 0x2701,
+ COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR = 0x2702,
+ COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR = 0x2703
+} CoglPipelineFilter;
+/* NB: these values come from the equivalents in gl.h */
+
+/**
+ * CoglPipelineWrapMode:
+ * @COGL_PIPELINE_WRAP_MODE_REPEAT: The texture will be repeated. This
+ * is useful for example to draw a tiled background.
+ * @COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE: The coordinates outside the
+ * range 0â1 will sample copies of the edge pixels of the
+ * texture. This is useful to avoid artifacts if only one copy of
+ * the texture is being rendered.
+ * @COGL_PIPELINE_WRAP_MODE_AUTOMATIC: Cogl will try to automatically
+ * decide which of the above two to use. For cogl_rectangle(), it
+ * will use repeat mode if any of the texture coordinates are
+ * outside the range 0â1, otherwise it will use clamp to edge. For
+ * cogl_polygon() it will always use repeat mode. For
+ * cogl_vertex_buffer_draw() it will use repeat mode except for
+ * layers that have point sprite coordinate generation enabled. This
+ * is the default value.
+ *
+ * The wrap mode specifies what happens when texture coordinates
+ * outside the range 0â1 are used. Note that if the filter mode is
+ * anything but %COGL_PIPELINE_FILTER_NEAREST then texels outside the
+ * range 0â1 might be used even when the coordinate is exactly 0 or 1
+ * because OpenGL will try to sample neighbouring pixels. For example
+ * if you are trying to render the full texture then you may get
+ * artifacts around the edges when the pixels from the other side are
+ * merged in if the wrap mode is set to repeat.
+ *
+ * Since: 2.0
+ */
+/* GL_ALWAYS is just used here as a value that is known not to clash
+ * with any valid GL wrap modes
+ *
+ * XXX: keep the values in sync with the CoglPipelineWrapModeInternal
+ * enum so no conversion is actually needed.
+ */
+typedef enum {
+ COGL_PIPELINE_WRAP_MODE_REPEAT = 0x2901,
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE = 0x812F,
+ COGL_PIPELINE_WRAP_MODE_AUTOMATIC = 0x0207
+} CoglPipelineWrapMode;
+/* NB: these values come from the equivalents in gl.h */
+
+/**
+ * cogl_pipeline_set_layer:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: the index of the layer
+ * @texture: a #CoglHandle for the layer object
+ *
+ * In addition to the standard OpenGL lighting model a Cogl pipeline may have
+ * one or more layers comprised of textures that can be blended together in
+ * order, with a number of different texture combine modes. This function
+ * defines a new texture layer.
+ *
+ * The index values of multiple layers do not have to be consecutive; it is
+ * only their relative order that is important.
+ *
+ * <note>In the future, we may define other types of pipeline layers, such
+ * as purely GLSL based layers.</note>
+ *
+ * Since: 2.0
+ */
+void
+cogl_pipeline_set_layer_texture (CoglPipeline *pipeline,
+ int layer_index,
+ CoglTexture *texture);
+
+/**
+ * cogl_pipeline_remove_layer:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: Specifies the layer you want to remove
+ *
+ * This function removes a layer from your pipeline
+ */
+void
+cogl_pipeline_remove_layer (CoglPipeline *pipeline,
+ int layer_index);
+
+/**
+ * cogl_pipeline_set_layer_combine:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: Specifies the layer you want define a combine function for
+ * @blend_string: A <link linkend="cogl-Blend-Strings">Cogl blend string</link>
+ * describing the desired texture combine function.
+ * @error: A #GError that may report parse errors or lack of GPU/driver
+ * support. May be %NULL, in which case a warning will be printed out if an
+ * error is encountered.
+ *
+ * If not already familiar; you can refer
+ * <link linkend="cogl-Blend-Strings">here</link> for an overview of what blend
+ * strings are and there syntax.
+ *
+ * These are all the functions available for texture combining:
+ * <itemizedlist>
+ * <listitem>REPLACE(arg0) = arg0</listitem>
+ * <listitem>MODULATE(arg0, arg1) = arg0 x arg1</listitem>
+ * <listitem>ADD(arg0, arg1) = arg0 + arg1</listitem>
+ * <listitem>ADD_SIGNED(arg0, arg1) = arg0 + arg1 - 0.5</listitem>
+ * <listitem>INTERPOLATE(arg0, arg1, arg2) = arg0 x arg2 + arg1 x (1 - arg2)</listitem>
+ * <listitem>SUBTRACT(arg0, arg1) = arg0 - arg1</listitem>
+ * <listitem>
+ * <programlisting>
+ * DOT3_RGB(arg0, arg1) = 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) +
+ * (arg0[G] - 0.5)) * (arg1[G] - 0.5) +
+ * (arg0[B] - 0.5)) * (arg1[B] - 0.5))
+ * </programlisting>
+ * </listitem>
+ * <listitem>
+ * <programlisting>
+ * DOT3_RGBA(arg0, arg1) = 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) +
+ * (arg0[G] - 0.5)) * (arg1[G] - 0.5) +
+ * (arg0[B] - 0.5)) * (arg1[B] - 0.5))
+ * </programlisting>
+ * </listitem>
+ * </itemizedlist>
+ *
+ * Refer to the
+ * <link linkend="cogl-Blend-String-syntax">color-source syntax</link> for
+ * describing the arguments. The valid source names for texture combining
+ * are:
+ * <variablelist>
+ * <varlistentry>
+ * <term>TEXTURE</term>
+ * <listitem>Use the color from the current texture layer</listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>TEXTURE_0, TEXTURE_1, etc</term>
+ * <listitem>Use the color from the specified texture layer</listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>CONSTANT</term>
+ * <listitem>Use the color from the constant given with
+ * cogl_pipeline_set_layer_constant()</listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>PRIMARY</term>
+ * <listitem>Use the color of the pipeline as set with
+ * cogl_pipeline_set_color()</listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>PREVIOUS</term>
+ * <listitem>Either use the texture color from the previous layer, or
+ * if this is layer 0, use the color of the pipeline as set with
+ * cogl_pipeline_set_color()</listitem>
+ * </varlistentry>
+ * </variablelist>
+ *
+ * <refsect2 id="cogl-Layer-Combine-Examples">
+ * <title>Layer Combine Examples</title>
+ * <para>This is effectively what the default blending is:</para>
+ * <informalexample><programlisting>
+ * RGBA = MODULATE (PREVIOUS, TEXTURE)
+ * </programlisting></informalexample>
+ * <para>This could be used to cross-fade between two images, using
+ * the alpha component of a constant as the interpolator. The constant
+ * color is given by calling cogl_pipeline_set_layer_constant.</para>
+ * <informalexample><programlisting>
+ * RGBA = INTERPOLATE (PREVIOUS, TEXTURE, CONSTANT[A])
+ * </programlisting></informalexample>
+ * </refsect2>
+ *
+ * <note>You can't give a multiplication factor for arguments as you can
+ * with blending.</note>
+ *
+ * Return value: %TRUE if the blend string was successfully parsed, and the
+ * described texture combining is supported by the underlying driver and
+ * or hardware. On failure, %FALSE is returned and @error is set
+ *
+ * Since: 2.0
+ */
+gboolean
+cogl_pipeline_set_layer_combine (CoglPipeline *pipeline,
+ int layer_index,
+ const char *blend_string,
+ GError **error);
+
+/**
+ * cogl_pipeline_set_layer_combine_constant:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: Specifies the layer you want to specify a constant used
+ * for texture combining
+ * @constant: The constant color you want
+ *
+ * When you are using the 'CONSTANT' color source in a layer combine
+ * description then you can use this function to define its value.
+ *
+ * Since: 2.0
+ */
+void
+cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline,
+ int layer_index,
+ const CoglColor *constant);
+
+/**
+ * cogl_pipeline_set_layer_matrix:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: the index for the layer inside @pipeline
+ * @matrix: the transformation matrix for the layer
+ *
+ * This function lets you set a matrix that can be used to e.g. translate
+ * and rotate a single layer of a pipeline used to fill your geometry.
+ */
+void
+cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline,
+ int layer_index,
+ const CoglMatrix *matrix);
+
+/**
+ * cogl_pipeline_get_n_layers:
+ * @pipeline: A #CoglPipeline object
+ *
+ * Retrieves the number of layers defined for the given @pipeline
+ *
+ * Return value: the number of layers
+ *
+ * Since: 2.0
+ */
+int
+cogl_pipeline_get_n_layers (CoglPipeline *pipeline);
+
+/**
+ * cogl_pipeline_set_layer_filters:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: the layer number to change.
+ * @min_filter: the filter used when scaling a texture down.
+ * @mag_filter: the filter used when magnifying a texture.
+ *
+ * Changes the decimation and interpolation filters used when a texture is
+ * drawn at other scales than 100%.
+ */
+void
+cogl_pipeline_set_layer_filters (CoglPipeline *pipeline,
+ int layer_index,
+ CoglPipelineFilter min_filter,
+ CoglPipelineFilter mag_filter);
+
+/**
+ * cogl_pipeline_set_layer_point_sprite_coords_enabled:
+ * @pipeline: a #CoglHandle to a pipeline.
+ * @layer_index: the layer number to change.
+ * @enable: whether to enable point sprite coord generation.
+ * @error: A return location for a GError, or NULL to ignore errors.
+ *
+ * When rendering points, if @enable is %TRUE then the texture
+ * coordinates for this layer will be replaced with coordinates that
+ * vary from 0.0 to 1.0 across the primitive. The top left of the
+ * point will have the coordinates 0.0,0.0 and the bottom right will
+ * have 1.0,1.0. If @enable is %FALSE then the coordinates will be
+ * fixed for the entire point.
+ *
+ * This function will only work if %COGL_FEATURE_POINT_SPRITE is
+ * available. If the feature is not available then the function will
+ * return %FALSE and set @error.
+ *
+ * Return value: %TRUE if the function succeeds, %FALSE otherwise.
+ * Since: 2.0
+ */
+gboolean
+cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
+ int layer_index,
+ gboolean enable,
+ GError **error);
+
+/**
+ * cogl_pipeline_get_layer_point_sprite_coords_enabled:
+ * @pipeline: a #CoglHandle to a pipeline.
+ * @layer_index: the layer number to check.
+ *
+ * Gets whether point sprite coordinate generation is enabled for this
+ * texture layer.
+ *
+ * Return value: whether the texture coordinates will be replaced with
+ * point sprite coordinates.
+ *
+ * Since: 2.0
+ */
+gboolean
+cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
+ int layer_index);
+
+/**
+ * cogl_pipeline_get_layer_wrap_mode_s:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: the layer number to change.
+ *
+ * Returns the wrap mode for the 's' coordinate of texture lookups on this
+ * layer.
+ *
+ * Return value: the wrap mode for the 's' coordinate of texture lookups on
+ * this layer.
+ *
+ * Since: 1.6
+ */
+CoglPipelineWrapMode
+cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline,
+ int layer_index);
+
+/**
+ * cogl_pipeline_set_layer_wrap_mode_s:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: the layer number to change.
+ * @mode: the new wrap mode
+ *
+ * Sets the wrap mode for the 's' coordinate of texture lookups on this layer.
+ *
+ * Since: 2.0
+ */
+void
+cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline,
+ int layer_index,
+ CoglPipelineWrapMode mode);
+
+/**
+ * cogl_pipeline_get_layer_wrap_mode_t:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: the layer number to change.
+ *
+ * Returns the wrap mode for the 't' coordinate of texture lookups on this
+ * layer.
+ *
+ * Return value: the wrap mode for the 't' coordinate of texture lookups on
+ * this layer.
+ *
+ * Since: 1.6
+ */
+CoglPipelineWrapMode
+cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline,
+ int layer_index);
+
+
+/**
+ * cogl_pipeline_set_layer_wrap_mode_t:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: the layer number to change.
+ * @mode: the new wrap mode
+ *
+ * Sets the wrap mode for the 't' coordinate of texture lookups on this layer.
+ *
+ * Since: 2.0
+ */
+void
+cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline,
+ int layer_index,
+ CoglPipelineWrapMode mode);
+
+/**
+ * cogl_pipeline_get_layer_wrap_mode_p:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: the layer number to change.
+ *
+ * Returns the wrap mode for the 'p' coordinate of texture lookups on this
+ * layer.
+ *
+ * Return value: the wrap mode for the 'p' coordinate of texture lookups on
+ * this layer.
+ *
+ * Since: 1.6
+ */
+CoglPipelineWrapMode
+cogl_pipeline_get_layer_wrap_mode_p (CoglPipeline *pipeline,
+ int layer_index);
+
+/**
+ * cogl_pipeline_set_layer_wrap_mode_p:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: the layer number to change.
+ * @mode: the new wrap mode
+ *
+ * Sets the wrap mode for the 'p' coordinate of texture lookups on
+ * this layer. 'p' is the third coordinate.
+ *
+ * Since: 2.0
+ */
+void
+cogl_pipeline_set_layer_wrap_mode_p (CoglPipeline *pipeline,
+ int layer_index,
+ CoglPipelineWrapMode mode);
+
+/**
+ * cogl_pipeline_set_layer_wrap_mode:
+ * @pipeline: A #CoglPipeline object
+ * @layer_index: the layer number to change.
+ * @mode: the new wrap mode
+ *
+ * Sets the wrap mode for all three coordinates of texture lookups on
+ * this layer. This is equivalent to calling
+ * cogl_pipeline_set_layer_wrap_mode_s(),
+ * cogl_pipeline_set_layer_wrap_mode_t() and
+ * cogl_pipeline_set_layer_wrap_mode_p() separately.
+ *
+ * Since: 2.0
+ */
+void
+cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline,
+ int layer_index,
+ CoglPipelineWrapMode mode);
+
+G_END_DECLS
+
+#endif /* __COGL_PIPELINE_LAYER_STATE_H__ */
diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h
index 760f132..52ca0f0 100644
--- a/cogl/cogl-pipeline-private.h
+++ b/cogl/cogl-pipeline-private.h
@@ -860,6 +860,11 @@ _cogl_pipeline_get_authority (CoglPipeline *pipeline,
typedef gboolean (*CoglPipelineStateComparitor) (CoglPipeline *authority0,
CoglPipeline *authority1);
+typedef gboolean
+(*CoglPipelineLayerStateComparitor) (CoglPipelineLayer *authority0,
+ CoglPipelineLayer *authority1);
+
+
void
_cogl_pipeline_update_authority (CoglPipeline *pipeline,
CoglPipeline *authority,
@@ -878,6 +883,32 @@ _cogl_pipeline_prune_redundant_ancestry (CoglPipeline *pipeline);
void _cogl_pipeline_update_blend_enable (CoglPipeline *pipeline,
CoglPipelineState changes);
+CoglPipelineLayer *
+_cogl_pipeline_get_layer (CoglPipeline *pipeline,
+ int layer_index);
+
+gboolean
+_cogl_is_pipeline_layer (void *object);
+
+static inline CoglPipelineLayer *
+_cogl_pipeline_layer_get_parent (CoglPipelineLayer *layer)
+{
+ CoglPipelineNode *parent_node = COGL_PIPELINE_NODE (layer)->parent;
+ return COGL_PIPELINE_LAYER (parent_node);
+}
+
+CoglPipelineLayer *
+_cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner,
+ CoglPipelineLayer *layer,
+ CoglPipelineLayerState change);
+
+void
+_cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer);
+
+void
+_cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority,
+ CoglPipelineLayer *layer);
+
/*
* SECTION:cogl-pipeline-internals
* @short_description: Functions for creating custom primitives that make use
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c
index c439ee2..3de266d 100644
--- a/cogl/cogl-pipeline.c
+++ b/cogl/cogl-pipeline.c
@@ -38,6 +38,7 @@
#include "cogl-pipeline-private.h"
#include "cogl-pipeline-opengl-private.h"
#include "cogl-pipeline-state-private.h"
+#include "cogl-pipeline-layer-state-private.h"
#include "cogl-texture-private.h"
#include "cogl-blend-string.h"
#include "cogl-journal-private.h"
@@ -560,16 +561,6 @@ _cogl_pipeline_get_real_blend_enabled (CoglPipeline *pipeline)
return pipeline->real_blend_enable;
}
-/* XXX: Think twice before making this non static since it is used
- * heavily and we expect the compiler to inline it...
- */
-static CoglPipelineLayer *
-_cogl_pipeline_layer_get_parent (CoglPipelineLayer *layer)
-{
- CoglPipelineNode *parent_node = COGL_PIPELINE_NODE (layer)->parent;
- return COGL_PIPELINE_LAYER (parent_node);
-}
-
CoglPipelineLayer *
_cogl_pipeline_layer_get_authority (CoglPipelineLayer *layer,
unsigned long difference)
@@ -1734,7 +1725,7 @@ _cogl_pipeline_layer_init_multi_property_sparse_state (
* required_owner can only by NULL for new, currently unowned layers
* with no dependants.
*/
-static CoglPipelineLayer *
+CoglPipelineLayer *
_cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner,
CoglPipelineLayer *layer,
CoglPipelineLayerState change)
@@ -1851,7 +1842,7 @@ _cogl_pipeline_layer_set_parent (CoglPipelineLayer *layer,
/* XXX: This is duplicated logic; the same as for
* _cogl_pipeline_prune_redundant_ancestry it would be nice to find a
* way to consolidate these functions! */
-static void
+void
_cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer)
{
CoglPipelineLayer *new_parent = _cogl_pipeline_layer_get_parent (layer);
@@ -1866,73 +1857,6 @@ _cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer)
_cogl_pipeline_layer_set_parent (layer, new_parent);
}
-/*
- * XXX: consider special casing layer->unit_index so it's not a sparse
- * property so instead we can assume it's valid for all layer
- * instances.
- * - We would need to initialize ->unit_index in
- * _cogl_pipeline_layer_copy ().
- *
- * XXX: If you use this API you should consider that the given layer
- * might not be writeable and so a new derived layer will be allocated
- * and modified instead. The layer modified will be returned so you
- * can identify when this happens.
- */
-static CoglPipelineLayer *
-_cogl_pipeline_set_layer_unit (CoglPipeline *required_owner,
- CoglPipelineLayer *layer,
- int unit_index)
-{
- CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_UNIT;
- CoglPipelineLayer *authority =
- _cogl_pipeline_layer_get_authority (layer, change);
- CoglPipelineLayer *new;
-
- if (authority->unit_index == unit_index)
- return layer;
-
- new =
- _cogl_pipeline_layer_pre_change_notify (required_owner,
- layer,
- change);
- if (new != layer)
- layer = new;
- else
- {
- /* If the layer we found is currently the authority on the state
- * we are changing see if we can revert to one of our ancestors
- * being the authority. */
- if (layer == authority &&
- _cogl_pipeline_layer_get_parent (authority) != NULL)
- {
- CoglPipelineLayer *parent =
- _cogl_pipeline_layer_get_parent (authority);
- CoglPipelineLayer *old_authority =
- _cogl_pipeline_layer_get_authority (parent, change);
-
- if (old_authority->unit_index == unit_index)
- {
- layer->differences &= ~change;
- return layer;
- }
- }
- }
-
- layer->unit_index = unit_index;
-
- /* If we weren't previously the authority on this state then we need
- * to extended our differences mask and so it's possible that some
- * of our ancestry will now become redundant, so we aim to reparent
- * ourselves if that's true... */
- if (layer != authority)
- {
- layer->differences |= change;
- _cogl_pipeline_layer_prune_redundant_ancestry (layer);
- }
-
- return layer;
-}
-
typedef struct
{
/* The layer we are trying to find */
@@ -2033,7 +1957,7 @@ _cogl_pipeline_get_layer_info (CoglPipeline *pipeline,
}
}
-static CoglPipelineLayer *
+CoglPipelineLayer *
_cogl_pipeline_get_layer (CoglPipeline *pipeline,
int layer_index)
{
@@ -2106,26 +2030,7 @@ _cogl_pipeline_get_layer (CoglPipeline *pipeline,
return layer;
}
-CoglTexture *
-_cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer)
-{
- CoglPipelineLayer *authority =
- _cogl_pipeline_layer_get_authority (layer,
- COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
-
- return authority->texture;
-}
-
-CoglTexture *
-_cogl_pipeline_get_layer_texture (CoglPipeline *pipeline,
- int layer_index)
-{
- CoglPipelineLayer *layer =
- _cogl_pipeline_get_layer (pipeline, layer_index);
- return _cogl_pipeline_layer_get_texture (layer);
-}
-
-static void
+void
_cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority,
CoglPipelineLayer *layer)
{
@@ -2203,202 +2108,6 @@ _cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority,
}
}
-static void
-_cogl_pipeline_set_layer_texture_target (CoglPipeline *pipeline,
- int layer_index,
- GLenum target)
-{
- CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
- CoglPipelineLayer *new;
-
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
-
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, change);
-
- if (target == authority->target)
- return;
-
- new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
- if (new != layer)
- layer = new;
- else
- {
- /* If the original layer we found is currently the authority on
- * the state we are changing see if we can revert to one of our
- * ancestors being the authority. */
- if (layer == authority &&
- _cogl_pipeline_layer_get_parent (authority) != NULL)
- {
- CoglPipelineLayer *parent =
- _cogl_pipeline_layer_get_parent (authority);
- CoglPipelineLayer *old_authority =
- _cogl_pipeline_layer_get_authority (parent, change);
-
- if (old_authority->target == target)
- {
- layer->differences &= ~change;
-
- g_assert (layer->owner == pipeline);
- if (layer->differences == 0)
- _cogl_pipeline_prune_empty_layer_difference (pipeline,
- layer);
- goto changed;
- }
- }
- }
-
- layer->target = target;
-
- /* If we weren't previously the authority on this state then we need
- * to extended our differences mask and so it's possible that some
- * of our ancestry will now become redundant, so we aim to reparent
- * ourselves if that's true... */
- if (layer != authority)
- {
- layer->differences |= change;
- _cogl_pipeline_layer_prune_redundant_ancestry (layer);
- }
-
-changed:
-
- _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
-}
-
-static void
-_cogl_pipeline_set_layer_texture_data (CoglPipeline *pipeline,
- int layer_index,
- CoglTexture *texture)
-{
- CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
- CoglPipelineLayer *new;
-
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
-
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, change);
-
- if (authority->texture == texture)
- return;
-
- new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
- if (new != layer)
- layer = new;
- else
- {
- /* If the original layer we found is currently the authority on
- * the state we are changing see if we can revert to one of our
- * ancestors being the authority. */
- if (layer == authority &&
- _cogl_pipeline_layer_get_parent (authority) != NULL)
- {
- CoglPipelineLayer *parent =
- _cogl_pipeline_layer_get_parent (authority);
- CoglPipelineLayer *old_authority =
- _cogl_pipeline_layer_get_authority (parent, change);
-
- if (old_authority->texture == texture)
- {
- layer->differences &= ~change;
-
- if (layer->texture != NULL)
- cogl_object_unref (layer->texture);
-
- g_assert (layer->owner == pipeline);
- if (layer->differences == 0)
- _cogl_pipeline_prune_empty_layer_difference (pipeline,
- layer);
- goto changed;
- }
- }
- }
-
- if (texture != NULL)
- cogl_object_ref (texture);
- if (layer == authority &&
- layer->texture != NULL)
- cogl_object_unref (layer->texture);
- layer->texture = texture;
-
- /* If we weren't previously the authority on this state then we need
- * to extended our differences mask and so it's possible that some
- * of our ancestry will now become redundant, so we aim to reparent
- * ourselves if that's true... */
- if (layer != authority)
- {
- layer->differences |= change;
- _cogl_pipeline_layer_prune_redundant_ancestry (layer);
- }
-
-changed:
-
- _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
-}
-
-/* A convenience for querying the target of a given texture that
- * notably returns 0 for NULL textures - so we can say that a layer
- * with no associated CoglTexture will have a texture target of 0.
- */
-static GLenum
-get_texture_target (CoglHandle texture)
-{
- GLuint ignore_handle;
- GLenum gl_target;
-
- g_return_val_if_fail (texture, 0);
-
- cogl_texture_get_gl_texture (texture, &ignore_handle, &gl_target);
-
- return gl_target;
-}
-
-void
-cogl_pipeline_set_layer_texture (CoglPipeline *pipeline,
- int layer_index,
- CoglTexture *texture)
-{
- /* For the convenience of fragend code we separate texture state
- * into the "target" and the "data", and setting a layer texture
- * updates both of these properties.
- *
- * One example for why this is helpful is that the fragends may
- * cache programs they generate and want to re-use those programs
- * with all pipelines having equivalent fragment processing state.
- * For the sake of determining if pipelines have equivalent fragment
- * processing state we don't need to compare that the same
- * underlying texture objects are referenced by the pipelines but we
- * do need to see if they use the same texture targets. Making this
- * distinction is much simpler if they are in different state
- * groups.
- *
- * Note: if a NULL texture is set then we leave the target unchanged
- * so we can avoid needlessly invalidating any associated fragment
- * program.
- */
- if (texture)
- _cogl_pipeline_set_layer_texture_target (pipeline, layer_index,
- get_texture_target (texture));
- _cogl_pipeline_set_layer_texture_data (pipeline, layer_index, texture);
-}
-
typedef struct
{
int i;
@@ -2453,584 +2162,115 @@ fallback_layer_cb (CoglPipelineLayer *layer, void *user_data)
return TRUE;
}
-void
-_cogl_pipeline_set_layer_wrap_modes (CoglPipeline *pipeline,
- CoglPipelineLayer *layer,
- CoglPipelineLayer *authority,
- CoglPipelineWrapModeInternal wrap_mode_s,
- CoglPipelineWrapModeInternal wrap_mode_t,
- CoglPipelineWrapModeInternal wrap_mode_p)
-{
- CoglPipelineLayer *new;
- CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
-
- if (authority->wrap_mode_s == wrap_mode_s &&
- authority->wrap_mode_t == wrap_mode_t &&
- authority->wrap_mode_p == wrap_mode_p)
- return;
-
- new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
- if (new != layer)
- layer = new;
- else
- {
- /* If the original layer we found is currently the authority on
- * the state we are changing see if we can revert to one of our
- * ancestors being the authority. */
- if (layer == authority &&
- _cogl_pipeline_layer_get_parent (authority) != NULL)
- {
- CoglPipelineLayer *parent =
- _cogl_pipeline_layer_get_parent (authority);
- CoglPipelineLayer *old_authority =
- _cogl_pipeline_layer_get_authority (parent, change);
-
- if (old_authority->wrap_mode_s == wrap_mode_s &&
- old_authority->wrap_mode_t == wrap_mode_t &&
- old_authority->wrap_mode_p == wrap_mode_p)
- {
- layer->differences &= ~change;
-
- g_assert (layer->owner == pipeline);
- if (layer->differences == 0)
- _cogl_pipeline_prune_empty_layer_difference (pipeline,
- layer);
- return;
- }
- }
- }
-
- layer->wrap_mode_s = wrap_mode_s;
- layer->wrap_mode_t = wrap_mode_t;
- layer->wrap_mode_p = wrap_mode_p;
-
- /* If we weren't previously the authority on this state then we need
- * to extended our differences mask and so it's possible that some
- * of our ancestry will now become redundant, so we aim to reparent
- * ourselves if that's true... */
- if (layer != authority)
- {
- layer->differences |= change;
- _cogl_pipeline_layer_prune_redundant_ancestry (layer);
- }
-}
-
-static CoglPipelineWrapModeInternal
-public_to_internal_wrap_mode (CoglPipelineWrapMode mode)
-{
- return (CoglPipelineWrapModeInternal)mode;
-}
-
-static CoglPipelineWrapMode
-internal_to_public_wrap_mode (CoglPipelineWrapModeInternal internal_mode)
+typedef struct
{
- g_return_val_if_fail (internal_mode !=
- COGL_PIPELINE_WRAP_MODE_INTERNAL_CLAMP_TO_BORDER,
- COGL_PIPELINE_WRAP_MODE_AUTOMATIC);
- return (CoglPipelineWrapMode)internal_mode;
-}
+ CoglPipeline *pipeline;
+ CoglHandle texture;
+} CoglPipelineOverrideLayerState;
-void
-cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline,
- int layer_index,
- CoglPipelineWrapMode mode)
+static gboolean
+override_layer_texture_cb (CoglPipelineLayer *layer, void *user_data)
{
- CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
- CoglPipelineWrapModeInternal internal_mode =
- public_to_internal_wrap_mode (mode);
-
- g_return_if_fail (cogl_is_pipeline (pipeline));
-
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+ CoglPipelineOverrideLayerState *state = user_data;
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, change);
+ cogl_pipeline_set_layer_texture (state->pipeline,
+ layer->index,
+ state->texture);
- _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority,
- internal_mode,
- authority->wrap_mode_t,
- authority->wrap_mode_p);
+ return TRUE;
}
void
-cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline,
- int layer_index,
- CoglPipelineWrapMode mode)
+_cogl_pipeline_apply_overrides (CoglPipeline *pipeline,
+ CoglPipelineFlushOptions *options)
{
- CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
- CoglPipelineWrapModeInternal internal_mode =
- public_to_internal_wrap_mode (mode);
+ COGL_STATIC_COUNTER (apply_overrides_counter,
+ "pipeline overrides counter",
+ "Increments each time we have to apply "
+ "override options to a pipeline",
+ 0 /* no application private data */);
- g_return_if_fail (cogl_is_pipeline (pipeline));
+ COGL_COUNTER_INC (_cogl_uprof_context, apply_overrides_counter);
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+ if (options->flags & COGL_PIPELINE_FLUSH_DISABLE_MASK)
+ {
+ int i;
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, change);
+ /* NB: we can assume that once we see one bit to disable
+ * a layer, all subsequent layers are also disabled. */
+ for (i = 0; i < 32 && options->disable_layers & (1<<i); i++)
+ ;
- _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority,
- authority->wrap_mode_s,
- internal_mode,
- authority->wrap_mode_p);
-}
+ _cogl_pipeline_prune_to_n_layers (pipeline, i);
+ }
-/* The rationale for naming the third texture coordinate 'p' instead
- of OpenGL's usual 'r' is that 'r' conflicts with the usual naming
- of the 'red' component when treating a vector as a color. Under
- GLSL this is awkward because the texture swizzling for a vector
- uses a single letter for each component and the names for colors,
- textures and positions are synonymous. GLSL works around this by
- naming the components of the texture s, t, p and q. Cogl already
- effectively already exposes this naming because it exposes GLSL so
- it makes sense to use that naming consistently. Another alternative
- could be u, v and w. This is what Blender and Direct3D use. However
- the w component conflicts with the w component of a position
- vertex. */
-void
-cogl_pipeline_set_layer_wrap_mode_p (CoglPipeline *pipeline,
- int layer_index,
- CoglPipelineWrapMode mode)
-{
- CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
- CoglPipelineWrapModeInternal internal_mode =
- public_to_internal_wrap_mode (mode);
+ if (options->flags & COGL_PIPELINE_FLUSH_FALLBACK_MASK)
+ {
+ CoglPipelineFallbackState state;
- g_return_if_fail (cogl_is_pipeline (pipeline));
+ state.i = 0;
+ state.pipeline = pipeline;
+ state.fallback_layers = options->fallback_layers;
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+ _cogl_pipeline_foreach_layer_internal (pipeline,
+ fallback_layer_cb,
+ &state);
+ }
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, change);
+ if (options->flags & COGL_PIPELINE_FLUSH_LAYER0_OVERRIDE)
+ {
+ CoglPipelineOverrideLayerState state;
+
+ _cogl_pipeline_prune_to_n_layers (pipeline, 1);
- _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority,
- authority->wrap_mode_s,
- authority->wrap_mode_t,
- internal_mode);
+ /* NB: we are overriding the first layer, but we don't know
+ * the user's given layer_index, which is why we use
+ * _cogl_pipeline_foreach_layer_internal() here even though we know
+ * there's only one layer. */
+ state.pipeline = pipeline;
+ state.texture = options->layer0_override_texture;
+ _cogl_pipeline_foreach_layer_internal (pipeline,
+ override_layer_texture_cb,
+ &state);
+ }
}
-void
-cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline,
- int layer_index,
- CoglPipelineWrapMode mode)
+/* Determine the mask of differences between two layers.
+ *
+ * XXX: If layers and pipelines could both be cast to a common Tree
+ * type of some kind then we could have a unified
+ * compare_differences() function.
+ */
+unsigned long
+_cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0,
+ CoglPipelineLayer *layer1)
{
- CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
- CoglPipelineWrapModeInternal internal_mode =
- public_to_internal_wrap_mode (mode);
+ CoglPipelineLayer *node0;
+ CoglPipelineLayer *node1;
+ int len0;
+ int len1;
+ int len0_index;
+ int len1_index;
+ int count;
+ int i;
+ CoglPipelineLayer *common_ancestor = NULL;
+ unsigned long layers_difference = 0;
- g_return_if_fail (cogl_is_pipeline (pipeline));
+ _COGL_GET_CONTEXT (ctx, 0);
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
+ /* Algorithm:
+ *
+ * 1) Walk the ancestors of each layer to the root node, adding a
+ * pointer to each ancester node to two GArrays:
+ * ctx->pipeline0_nodes, and ctx->pipeline1_nodes.
*
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
-
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, change);
-
- _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority,
- internal_mode,
- internal_mode,
- internal_mode);
- /* XXX: I wonder if we should really be duplicating the mode into
- * the 'r' wrap mode too? */
-}
-
-/* FIXME: deprecate this API */
-CoglPipelineWrapMode
-_cogl_pipeline_layer_get_wrap_mode_s (CoglPipelineLayer *layer)
-{
- CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
- CoglPipelineLayer *authority;
-
- g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE);
-
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, change);
-
- return internal_to_public_wrap_mode (authority->wrap_mode_s);
-}
-
-CoglPipelineWrapMode
-cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline, int layer_index)
-{
- CoglPipelineLayer *layer;
-
- g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
-
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
- /* FIXME: we shouldn't ever construct a layer in a getter function */
-
- return _cogl_pipeline_layer_get_wrap_mode_s (layer);
-}
-
-/* FIXME: deprecate this API */
-CoglPipelineWrapMode
-_cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer)
-{
- CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
- CoglPipelineLayer *authority;
-
- g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE);
-
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, change);
-
- return internal_to_public_wrap_mode (authority->wrap_mode_t);
-}
-
-CoglPipelineWrapMode
-cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline, int layer_index)
-{
- CoglPipelineLayer *layer;
-
- g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
-
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
- /* FIXME: we shouldn't ever construct a layer in a getter function */
-
- return _cogl_pipeline_layer_get_wrap_mode_t (layer);
-}
-
-CoglPipelineWrapMode
-_cogl_pipeline_layer_get_wrap_mode_p (CoglPipelineLayer *layer)
-{
- CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES;
- CoglPipelineLayer *authority =
- _cogl_pipeline_layer_get_authority (layer, change);
-
- return internal_to_public_wrap_mode (authority->wrap_mode_p);
-}
-
-CoglPipelineWrapMode
-cogl_pipeline_get_layer_wrap_mode_p (CoglPipeline *pipeline, int layer_index)
-{
- CoglPipelineLayer *layer;
-
- g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
-
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
-
- return _cogl_pipeline_layer_get_wrap_mode_p (layer);
-}
-
-void
-_cogl_pipeline_layer_get_wrap_modes (CoglPipelineLayer *layer,
- CoglPipelineWrapModeInternal *wrap_mode_s,
- CoglPipelineWrapModeInternal *wrap_mode_t,
- CoglPipelineWrapModeInternal *wrap_mode_p)
-{
- CoglPipelineLayer *authority =
- _cogl_pipeline_layer_get_authority (layer,
- COGL_PIPELINE_LAYER_STATE_WRAP_MODES);
-
- *wrap_mode_s = authority->wrap_mode_s;
- *wrap_mode_t = authority->wrap_mode_t;
- *wrap_mode_p = authority->wrap_mode_p;
-}
-
-gboolean
-cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
- int layer_index,
- gboolean enable,
- GError **error)
-{
- CoglPipelineLayerState change =
- COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *new;
- CoglPipelineLayer *authority;
-
- g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
-
- /* Don't allow point sprite coordinates to be enabled if the driver
- doesn't support it */
- if (enable && !cogl_features_available (COGL_FEATURE_POINT_SPRITE))
- {
- if (error)
- {
- g_set_error (error, COGL_ERROR, COGL_ERROR_UNSUPPORTED,
- "Point sprite texture coordinates are enabled "
- "for a layer but the GL driver does not support it.");
- }
- else
- {
- static gboolean warning_seen = FALSE;
- if (!warning_seen)
- g_warning ("Point sprite texture coordinates are enabled "
- "for a layer but the GL driver does not support it.");
- warning_seen = TRUE;
- }
-
- return FALSE;
- }
-
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
-
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, change);
-
- if (authority->big_state->point_sprite_coords == enable)
- return TRUE;
-
- new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
- if (new != layer)
- layer = new;
- else
- {
- /* If the original layer we found is currently the authority on
- * the state we are changing see if we can revert to one of our
- * ancestors being the authority. */
- if (layer == authority &&
- _cogl_pipeline_layer_get_parent (authority) != NULL)
- {
- CoglPipelineLayer *parent =
- _cogl_pipeline_layer_get_parent (authority);
- CoglPipelineLayer *old_authority =
- _cogl_pipeline_layer_get_authority (parent, change);
-
- if (old_authority->big_state->point_sprite_coords == enable)
- {
- layer->differences &= ~change;
-
- g_assert (layer->owner == pipeline);
- if (layer->differences == 0)
- _cogl_pipeline_prune_empty_layer_difference (pipeline,
- layer);
- return TRUE;
- }
- }
- }
-
- layer->big_state->point_sprite_coords = enable;
-
- /* If we weren't previously the authority on this state then we need
- * to extended our differences mask and so it's possible that some
- * of our ancestry will now become redundant, so we aim to reparent
- * ourselves if that's true... */
- if (layer != authority)
- {
- layer->differences |= change;
- _cogl_pipeline_layer_prune_redundant_ancestry (layer);
- }
-
- return TRUE;
-}
-
-gboolean
-cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
- int layer_index)
-{
- CoglPipelineLayerState change =
- COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
-
- g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
-
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
- /* FIXME: we shouldn't ever construct a layer in a getter function */
-
- authority = _cogl_pipeline_layer_get_authority (layer, change);
-
- return authority->big_state->point_sprite_coords;
-}
-
-typedef struct
-{
- CoglPipeline *pipeline;
- CoglHandle texture;
-} CoglPipelineOverrideLayerState;
-
-static gboolean
-override_layer_texture_cb (CoglPipelineLayer *layer, void *user_data)
-{
- CoglPipelineOverrideLayerState *state = user_data;
-
- cogl_pipeline_set_layer_texture (state->pipeline,
- layer->index,
- state->texture);
-
- return TRUE;
-}
-
-void
-_cogl_pipeline_apply_overrides (CoglPipeline *pipeline,
- CoglPipelineFlushOptions *options)
-{
- COGL_STATIC_COUNTER (apply_overrides_counter,
- "pipeline overrides counter",
- "Increments each time we have to apply "
- "override options to a pipeline",
- 0 /* no application private data */);
-
- COGL_COUNTER_INC (_cogl_uprof_context, apply_overrides_counter);
-
- if (options->flags & COGL_PIPELINE_FLUSH_DISABLE_MASK)
- {
- int i;
-
- /* NB: we can assume that once we see one bit to disable
- * a layer, all subsequent layers are also disabled. */
- for (i = 0; i < 32 && options->disable_layers & (1<<i); i++)
- ;
-
- _cogl_pipeline_prune_to_n_layers (pipeline, i);
- }
-
- if (options->flags & COGL_PIPELINE_FLUSH_FALLBACK_MASK)
- {
- CoglPipelineFallbackState state;
-
- state.i = 0;
- state.pipeline = pipeline;
- state.fallback_layers = options->fallback_layers;
-
- _cogl_pipeline_foreach_layer_internal (pipeline,
- fallback_layer_cb,
- &state);
- }
-
- if (options->flags & COGL_PIPELINE_FLUSH_LAYER0_OVERRIDE)
- {
- CoglPipelineOverrideLayerState state;
-
- _cogl_pipeline_prune_to_n_layers (pipeline, 1);
-
- /* NB: we are overriding the first layer, but we don't know
- * the user's given layer_index, which is why we use
- * _cogl_pipeline_foreach_layer_internal() here even though we know
- * there's only one layer. */
- state.pipeline = pipeline;
- state.texture = options->layer0_override_texture;
- _cogl_pipeline_foreach_layer_internal (pipeline,
- override_layer_texture_cb,
- &state);
- }
-}
-
-static gboolean
-_cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0,
- CoglPipelineLayer *authority1,
- CoglPipelineEvalFlags flags)
-{
- return authority0->target == authority1->target;
-}
-
-static gboolean
-_cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0,
- CoglPipelineLayer *authority1,
- CoglPipelineEvalFlags flags)
-{
- GLuint gl_handle0, gl_handle1;
-
- cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, NULL);
- cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, NULL);
-
- return gl_handle0 == gl_handle1;
-}
-
-/* Determine the mask of differences between two layers.
- *
- * XXX: If layers and pipelines could both be cast to a common Tree
- * type of some kind then we could have a unified
- * compare_differences() function.
- */
-unsigned long
-_cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0,
- CoglPipelineLayer *layer1)
-{
- CoglPipelineLayer *node0;
- CoglPipelineLayer *node1;
- int len0;
- int len1;
- int len0_index;
- int len1_index;
- int count;
- int i;
- CoglPipelineLayer *common_ancestor = NULL;
- unsigned long layers_difference = 0;
-
- _COGL_GET_CONTEXT (ctx, 0);
-
- /* Algorithm:
- *
- * 1) Walk the ancestors of each layer to the root node, adding a
- * pointer to each ancester node to two GArrays:
- * ctx->pipeline0_nodes, and ctx->pipeline1_nodes.
- *
- * 2) Compare the arrays to find the nodes where they stop to
- * differ.
- *
- * 3) For each array now iterate from index 0 to the first node of
- * difference ORing that nodes ->difference mask into the final
- * pipeline_differences mask.
- */
+ * 2) Compare the arrays to find the nodes where they stop to
+ * differ.
+ *
+ * 3) For each array now iterate from index 0 to the first node of
+ * difference ORing that nodes ->difference mask into the final
+ * pipeline_differences mask.
+ */
g_array_set_size (ctx->pipeline0_nodes, 0);
g_array_set_size (ctx->pipeline1_nodes, 0);
@@ -3088,126 +2328,6 @@ _cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0,
}
static gboolean
-_cogl_pipeline_layer_combine_state_equal (CoglPipelineLayer *authority0,
- CoglPipelineLayer *authority1)
-{
- CoglPipelineLayerBigState *big_state0 = authority0->big_state;
- CoglPipelineLayerBigState *big_state1 = authority1->big_state;
- int n_args;
- int i;
-
- if (big_state0->texture_combine_rgb_func !=
- big_state1->texture_combine_rgb_func)
- return FALSE;
-
- if (big_state0->texture_combine_alpha_func !=
- big_state1->texture_combine_alpha_func)
- return FALSE;
-
- n_args =
- _cogl_get_n_args_for_combine_func (big_state0->texture_combine_rgb_func);
- for (i = 0; i < n_args; i++)
- {
- if ((big_state0->texture_combine_rgb_src[i] !=
- big_state1->texture_combine_rgb_src[i]) ||
- (big_state0->texture_combine_rgb_op[i] !=
- big_state1->texture_combine_rgb_op[i]))
- return FALSE;
- }
-
- n_args =
- _cogl_get_n_args_for_combine_func (big_state0->texture_combine_alpha_func);
- for (i = 0; i < n_args; i++)
- {
- if ((big_state0->texture_combine_alpha_src[i] !=
- big_state1->texture_combine_alpha_src[i]) ||
- (big_state0->texture_combine_alpha_op[i] !=
- big_state1->texture_combine_alpha_op[i]))
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-_cogl_pipeline_layer_combine_constant_equal (CoglPipelineLayer *authority0,
- CoglPipelineLayer *authority1)
-{
- return memcmp (authority0->big_state->texture_combine_constant,
- authority1->big_state->texture_combine_constant,
- sizeof (float) * 4) == 0 ? TRUE : FALSE;
-}
-
-static gboolean
-_cogl_pipeline_layer_filters_equal (CoglPipelineLayer *authority0,
- CoglPipelineLayer *authority1)
-{
- if (authority0->mag_filter != authority1->mag_filter)
- return FALSE;
- if (authority0->min_filter != authority1->min_filter)
- return FALSE;
-
- return TRUE;
-}
-
-static gboolean
-compare_wrap_mode_equal (CoglPipelineWrapMode wrap_mode0,
- CoglPipelineWrapMode wrap_mode1)
-{
- /* We consider AUTOMATIC to be equivalent to CLAMP_TO_EDGE because
- the primitives code is expected to override this to something
- else if it wants it to be behave any other way */
- if (wrap_mode0 == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
- wrap_mode0 = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
- if (wrap_mode1 == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
- wrap_mode1 = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE;
-
- return wrap_mode0 == wrap_mode1;
-}
-
-static gboolean
-_cogl_pipeline_layer_wrap_modes_equal (CoglPipelineLayer *authority0,
- CoglPipelineLayer *authority1)
-{
- if (!compare_wrap_mode_equal (authority0->wrap_mode_s,
- authority1->wrap_mode_s) ||
- !compare_wrap_mode_equal (authority0->wrap_mode_t,
- authority1->wrap_mode_t) ||
- !compare_wrap_mode_equal (authority0->wrap_mode_p,
- authority1->wrap_mode_p))
- return FALSE;
-
- return TRUE;
-}
-
-static gboolean
-_cogl_pipeline_layer_user_matrix_equal (CoglPipelineLayer *authority0,
- CoglPipelineLayer *authority1)
-{
- CoglPipelineLayerBigState *big_state0 = authority0->big_state;
- CoglPipelineLayerBigState *big_state1 = authority1->big_state;
-
- if (!cogl_matrix_equal (&big_state0->matrix, &big_state1->matrix))
- return FALSE;
-
- return TRUE;
-}
-
-static gboolean
-_cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0,
- CoglPipelineLayer *authority1)
-{
- CoglPipelineLayerBigState *big_state0 = authority0->big_state;
- CoglPipelineLayerBigState *big_state1 = authority1->big_state;
-
- return big_state0->point_sprite_coords == big_state1->point_sprite_coords;
-}
-
-typedef gboolean
-(*CoglPipelineLayerStateComparitor) (CoglPipelineLayer *authority0,
- CoglPipelineLayer *authority1);
-
-static gboolean
layer_state_equal (CoglPipelineLayerStateIndex state_index,
CoglPipelineLayer **authorities0,
CoglPipelineLayer **authorities1,
@@ -3805,493 +2925,98 @@ _cogl_pipeline_layer_free (CoglPipelineLayer *layer)
*
* Alternatively we could leave it to the caller to check
* ...?
- */
-
-void
-_cogl_pipeline_init_default_layers (void)
-{
- CoglPipelineLayer *layer = g_slice_new0 (CoglPipelineLayer);
- CoglPipelineLayerBigState *big_state =
- g_slice_new0 (CoglPipelineLayerBigState);
- CoglPipelineLayer *new;
-
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- _cogl_pipeline_node_init (COGL_PIPELINE_NODE (layer));
-
- layer->index = 0;
-
- layer->differences = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE;
-
- layer->unit_index = 0;
-
- layer->texture = NULL;
- layer->target = 0;
-
- layer->mag_filter = COGL_PIPELINE_FILTER_LINEAR;
- layer->min_filter = COGL_PIPELINE_FILTER_LINEAR;
-
- layer->wrap_mode_s = COGL_PIPELINE_WRAP_MODE_AUTOMATIC;
- layer->wrap_mode_t = COGL_PIPELINE_WRAP_MODE_AUTOMATIC;
- layer->wrap_mode_p = COGL_PIPELINE_WRAP_MODE_AUTOMATIC;
-
- layer->big_state = big_state;
- layer->has_big_state = TRUE;
-
- /* Choose the same default combine mode as OpenGL:
- * RGBA = MODULATE(PREVIOUS[RGBA],TEXTURE[RGBA]) */
- big_state->texture_combine_rgb_func =
- COGL_PIPELINE_COMBINE_FUNC_MODULATE;
- big_state->texture_combine_rgb_src[0] =
- COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
- big_state->texture_combine_rgb_src[1] =
- COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
- big_state->texture_combine_rgb_op[0] =
- COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
- big_state->texture_combine_rgb_op[1] =
- COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
- big_state->texture_combine_alpha_func =
- COGL_PIPELINE_COMBINE_FUNC_MODULATE;
- big_state->texture_combine_alpha_src[0] =
- COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
- big_state->texture_combine_alpha_src[1] =
- COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
- big_state->texture_combine_alpha_op[0] =
- COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
- big_state->texture_combine_alpha_op[1] =
- COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
-
- big_state->point_sprite_coords = FALSE;
-
- cogl_matrix_init_identity (&big_state->matrix);
-
- ctx->default_layer_0 = _cogl_pipeline_layer_object_new (layer);
-
- /* TODO: we should make default_layer_n comprise of two
- * descendants of default_layer_0:
- * - the first descendant should change the texture combine
- * to what we expect is most commonly used for multitexturing
- * - the second should revert the above change.
- *
- * why? the documentation for how a new layer is initialized
- * doesn't say that layers > 0 have different defaults so unless
- * we change the documentation we can't use different defaults,
- * but if the user does what we expect and changes the
- * texture combine then we can revert the authority to the
- * first descendant which means we can maximize the number
- * of layers with a common ancestor.
- *
- * The main problem will be that we'll need to disable the
- * optimizations for flattening the ancestry when we make
- * the second descendant which reverts the state.
- */
- ctx->default_layer_n = _cogl_pipeline_layer_copy (layer);
- new = _cogl_pipeline_set_layer_unit (NULL, ctx->default_layer_n, 1);
- g_assert (new == ctx->default_layer_n);
- /* Since we passed a newly allocated layer we don't expect that
- * _set_layer_unit() will have to allocate *another* layer. */
-
- /* Finally we create a dummy dependant for ->default_layer_n which
- * effectively ensures that ->default_layer_n and ->default_layer_0
- * remain immutable.
- */
- ctx->dummy_layer_dependant =
- _cogl_pipeline_layer_copy (ctx->default_layer_n);
-}
-
-static void
-setup_texture_combine_state (CoglBlendStringStatement *statement,
- CoglPipelineCombineFunc *texture_combine_func,
- CoglPipelineCombineSource *texture_combine_src,
- CoglPipelineCombineOp *texture_combine_op)
-{
- int i;
-
- switch (statement->function->type)
- {
- case COGL_BLEND_STRING_FUNCTION_REPLACE:
- *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_REPLACE;
- break;
- case COGL_BLEND_STRING_FUNCTION_MODULATE:
- *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_MODULATE;
- break;
- case COGL_BLEND_STRING_FUNCTION_ADD:
- *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD;
- break;
- case COGL_BLEND_STRING_FUNCTION_ADD_SIGNED:
- *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED;
- break;
- case COGL_BLEND_STRING_FUNCTION_INTERPOLATE:
- *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE;
- break;
- case COGL_BLEND_STRING_FUNCTION_SUBTRACT:
- *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_SUBTRACT;
- break;
- case COGL_BLEND_STRING_FUNCTION_DOT3_RGB:
- *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB;
- break;
- case COGL_BLEND_STRING_FUNCTION_DOT3_RGBA:
- *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA;
- break;
- }
-
- for (i = 0; i < statement->function->argc; i++)
- {
- CoglBlendStringArgument *arg = &statement->args[i];
-
- switch (arg->source.info->type)
- {
- case COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT:
- texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_CONSTANT;
- break;
- case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE:
- texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
- break;
- case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N:
- texture_combine_src[i] =
- COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0 + arg->source.texture;
- break;
- case COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY:
- texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR;
- break;
- case COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS:
- texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
- break;
- default:
- g_warning ("Unexpected texture combine source");
- texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
- }
-
- if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB)
- {
- if (statement->args[i].source.one_minus)
- texture_combine_op[i] =
- COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR;
- else
- texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
- }
- else
- {
- if (statement->args[i].source.one_minus)
- texture_combine_op[i] =
- COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA;
- else
- texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
- }
- }
-}
-
-gboolean
-cogl_pipeline_set_layer_combine (CoglPipeline *pipeline,
- int layer_index,
- const char *combine_description,
- GError **error)
-{
- CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE;
- CoglPipelineLayer *authority;
- CoglPipelineLayer *layer;
- CoglBlendStringStatement statements[2];
- CoglBlendStringStatement split[2];
- CoglBlendStringStatement *rgb;
- CoglBlendStringStatement *a;
- GError *internal_error = NULL;
- int count;
-
- g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
-
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
-
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, state);
-
- count =
- _cogl_blend_string_compile (combine_description,
- COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE,
- statements,
- &internal_error);
- if (!count)
- {
- if (error)
- g_propagate_error (error, internal_error);
- else
- {
- g_warning ("Cannot compile combine description: %s\n",
- internal_error->message);
- g_error_free (internal_error);
- }
- return FALSE;
- }
-
- if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA)
- {
- _cogl_blend_string_split_rgba_statement (statements,
- &split[0], &split[1]);
- rgb = &split[0];
- a = &split[1];
- }
- else
- {
- rgb = &statements[0];
- a = &statements[1];
- }
-
- /* FIXME: compare the new state with the current state! */
-
- /* possibly flush primitives referencing the current state... */
- layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
-
- setup_texture_combine_state (rgb,
- &layer->big_state->texture_combine_rgb_func,
- layer->big_state->texture_combine_rgb_src,
- layer->big_state->texture_combine_rgb_op);
-
- setup_texture_combine_state (a,
- &layer->big_state->texture_combine_alpha_func,
- layer->big_state->texture_combine_alpha_src,
- layer->big_state->texture_combine_alpha_op);
-
- /* If the original layer we found is currently the authority on
- * the state we are changing see if we can revert to one of our
- * ancestors being the authority. */
- if (layer == authority &&
- _cogl_pipeline_layer_get_parent (authority) != NULL)
- {
- CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority);
- CoglPipelineLayer *old_authority =
- _cogl_pipeline_layer_get_authority (parent, state);
-
- if (_cogl_pipeline_layer_combine_state_equal (authority,
- old_authority))
- {
- layer->differences &= ~state;
-
- g_assert (layer->owner == pipeline);
- if (layer->differences == 0)
- _cogl_pipeline_prune_empty_layer_difference (pipeline,
- layer);
- goto changed;
- }
- }
-
- /* If we weren't previously the authority on this state then we need
- * to extended our differences mask and so it's possible that some
- * of our ancestry will now become redundant, so we aim to reparent
- * ourselves if that's true... */
- if (layer != authority)
- {
- layer->differences |= state;
- _cogl_pipeline_layer_prune_redundant_ancestry (layer);
- }
-
-changed:
-
- _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
- return TRUE;
-}
-
-void
-cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline,
- int layer_index,
- const CoglColor *constant_color)
-{
- CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
- CoglPipelineLayer *new;
- float color_as_floats[4];
-
- g_return_if_fail (cogl_is_pipeline (pipeline));
-
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
-
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, state);
-
- color_as_floats[0] = cogl_color_get_red_float (constant_color);
- color_as_floats[1] = cogl_color_get_green_float (constant_color);
- color_as_floats[2] = cogl_color_get_blue_float (constant_color);
- color_as_floats[3] = cogl_color_get_alpha_float (constant_color);
-
- if (memcmp (authority->big_state->texture_combine_constant,
- color_as_floats, sizeof (float) * 4) == 0)
- return;
-
- new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
- if (new != layer)
- layer = new;
- else
- {
- /* If the original layer we found is currently the authority on
- * the state we are changing see if we can revert to one of our
- * ancestors being the authority. */
- if (layer == authority &&
- _cogl_pipeline_layer_get_parent (authority) != NULL)
- {
- CoglPipelineLayer *parent =
- _cogl_pipeline_layer_get_parent (authority);
- CoglPipelineLayer *old_authority =
- _cogl_pipeline_layer_get_authority (parent, state);
- CoglPipelineLayerBigState *old_big_state = old_authority->big_state;
-
- if (memcmp (old_big_state->texture_combine_constant,
- color_as_floats, sizeof (float) * 4) == 0)
- {
- layer->differences &= ~state;
-
- g_assert (layer->owner == pipeline);
- if (layer->differences == 0)
- _cogl_pipeline_prune_empty_layer_difference (pipeline,
- layer);
- goto changed;
- }
- }
- }
-
- memcpy (layer->big_state->texture_combine_constant,
- color_as_floats,
- sizeof (color_as_floats));
-
- /* If we weren't previously the authority on this state then we need
- * to extended our differences mask and so it's possible that some
- * of our ancestry will now become redundant, so we aim to reparent
- * ourselves if that's true... */
- if (layer != authority)
- {
- layer->differences |= state;
- _cogl_pipeline_layer_prune_redundant_ancestry (layer);
- }
-
-changed:
-
- _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
-}
-
-void
-_cogl_pipeline_get_layer_combine_constant (CoglPipeline *pipeline,
- int layer_index,
- float *constant)
-{
- CoglPipelineLayerState change =
- COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
-
- g_return_if_fail (cogl_is_pipeline (pipeline));
-
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
- /* FIXME: we shouldn't ever construct a layer in a getter function */
-
- authority = _cogl_pipeline_layer_get_authority (layer, change);
- memcpy (constant, authority->big_state->texture_combine_constant,
- sizeof (float) * 4);
-}
+ */
-/* We should probably make a public API version of this that has a
- matrix out-param. For an internal API it's good to be able to avoid
- copying the matrix */
-const CoglMatrix *
-_cogl_pipeline_get_layer_matrix (CoglPipeline *pipeline, int layer_index)
+void
+_cogl_pipeline_init_default_layers (void)
{
- CoglPipelineLayerState change =
- COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
+ CoglPipelineLayer *layer = g_slice_new0 (CoglPipelineLayer);
+ CoglPipelineLayerBigState *big_state =
+ g_slice_new0 (CoglPipelineLayerBigState);
+ CoglPipelineLayer *new;
- g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL);
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+ _cogl_pipeline_node_init (COGL_PIPELINE_NODE (layer));
- authority = _cogl_pipeline_layer_get_authority (layer, change);
- return &authority->big_state->matrix;
-}
+ layer->index = 0;
-void
-cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline,
- int layer_index,
- const CoglMatrix *matrix)
-{
- CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
- CoglPipelineLayer *new;
+ layer->differences = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE;
- g_return_if_fail (cogl_is_pipeline (pipeline));
+ layer->unit_index = 0;
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+ layer->texture = NULL;
+ layer->target = 0;
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, state);
+ layer->mag_filter = COGL_PIPELINE_FILTER_LINEAR;
+ layer->min_filter = COGL_PIPELINE_FILTER_LINEAR;
- if (cogl_matrix_equal (matrix, &authority->big_state->matrix))
- return;
+ layer->wrap_mode_s = COGL_PIPELINE_WRAP_MODE_AUTOMATIC;
+ layer->wrap_mode_t = COGL_PIPELINE_WRAP_MODE_AUTOMATIC;
+ layer->wrap_mode_p = COGL_PIPELINE_WRAP_MODE_AUTOMATIC;
- new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
- if (new != layer)
- layer = new;
- else
- {
- /* If the original layer we found is currently the authority on
- * the state we are changing see if we can revert to one of our
- * ancestors being the authority. */
- if (layer == authority &&
- _cogl_pipeline_layer_get_parent (authority) != NULL)
- {
- CoglPipelineLayer *parent =
- _cogl_pipeline_layer_get_parent (authority);
- CoglPipelineLayer *old_authority =
- _cogl_pipeline_layer_get_authority (parent, state);
+ layer->big_state = big_state;
+ layer->has_big_state = TRUE;
- if (cogl_matrix_equal (matrix, &old_authority->big_state->matrix))
- {
- layer->differences &= ~state;
+ /* Choose the same default combine mode as OpenGL:
+ * RGBA = MODULATE(PREVIOUS[RGBA],TEXTURE[RGBA]) */
+ big_state->texture_combine_rgb_func =
+ COGL_PIPELINE_COMBINE_FUNC_MODULATE;
+ big_state->texture_combine_rgb_src[0] =
+ COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
+ big_state->texture_combine_rgb_src[1] =
+ COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
+ big_state->texture_combine_rgb_op[0] =
+ COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
+ big_state->texture_combine_rgb_op[1] =
+ COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
+ big_state->texture_combine_alpha_func =
+ COGL_PIPELINE_COMBINE_FUNC_MODULATE;
+ big_state->texture_combine_alpha_src[0] =
+ COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
+ big_state->texture_combine_alpha_src[1] =
+ COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
+ big_state->texture_combine_alpha_op[0] =
+ COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
+ big_state->texture_combine_alpha_op[1] =
+ COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
- g_assert (layer->owner == pipeline);
- if (layer->differences == 0)
- _cogl_pipeline_prune_empty_layer_difference (pipeline,
- layer);
- return;
- }
- }
- }
+ big_state->point_sprite_coords = FALSE;
- layer->big_state->matrix = *matrix;
+ cogl_matrix_init_identity (&big_state->matrix);
- /* If we weren't previously the authority on this state then we need
- * to extended our differences mask and so it's possible that some
- * of our ancestry will now become redundant, so we aim to reparent
- * ourselves if that's true... */
- if (layer != authority)
- {
- layer->differences |= state;
- _cogl_pipeline_layer_prune_redundant_ancestry (layer);
- }
+ ctx->default_layer_0 = _cogl_pipeline_layer_object_new (layer);
+
+ /* TODO: we should make default_layer_n comprise of two
+ * descendants of default_layer_0:
+ * - the first descendant should change the texture combine
+ * to what we expect is most commonly used for multitexturing
+ * - the second should revert the above change.
+ *
+ * why? the documentation for how a new layer is initialized
+ * doesn't say that layers > 0 have different defaults so unless
+ * we change the documentation we can't use different defaults,
+ * but if the user does what we expect and changes the
+ * texture combine then we can revert the authority to the
+ * first descendant which means we can maximize the number
+ * of layers with a common ancestor.
+ *
+ * The main problem will be that we'll need to disable the
+ * optimizations for flattening the ancestry when we make
+ * the second descendant which reverts the state.
+ */
+ ctx->default_layer_n = _cogl_pipeline_layer_copy (layer);
+ new = _cogl_pipeline_set_layer_unit (NULL, ctx->default_layer_n, 1);
+ g_assert (new == ctx->default_layer_n);
+ /* Since we passed a newly allocated layer we don't expect that
+ * _set_layer_unit() will have to allocate *another* layer. */
+
+ /* Finally we create a dummy dependant for ->default_layer_n which
+ * effectively ensures that ->default_layer_n and ->default_layer_0
+ * remain immutable.
+ */
+ ctx->dummy_layer_dependant =
+ _cogl_pipeline_layer_copy (ctx->default_layer_n);
}
void
@@ -4395,91 +3120,6 @@ cogl_pipeline_get_n_layers (CoglPipeline *pipeline)
return authority->n_layers;
}
-/* FIXME: deprecate and replace with
- * cogl_pipeline_get_layer_texture() instead. */
-CoglTexture *
-_cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer)
-{
- g_return_val_if_fail (_cogl_is_pipeline_layer (layer), NULL);
-
- return _cogl_pipeline_layer_get_texture_real (layer);
-}
-
-gboolean
-_cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline,
- int layer_index)
-{
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
-
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
-
- authority =
- _cogl_pipeline_layer_get_authority (layer,
- COGL_PIPELINE_LAYER_STATE_USER_MATRIX);
-
- /* If the authority is the default pipeline then no, otherwise yes */
- return _cogl_pipeline_layer_get_parent (authority) ? TRUE : FALSE;
-}
-
-void
-_cogl_pipeline_layer_get_filters (CoglPipelineLayer *layer,
- CoglPipelineFilter *min_filter,
- CoglPipelineFilter *mag_filter)
-{
- CoglPipelineLayer *authority =
- _cogl_pipeline_layer_get_authority (layer,
- COGL_PIPELINE_LAYER_STATE_FILTERS);
-
- *min_filter = authority->min_filter;
- *mag_filter = authority->mag_filter;
-}
-
-void
-_cogl_pipeline_get_layer_filters (CoglPipeline *pipeline,
- int layer_index,
- CoglPipelineFilter *min_filter,
- CoglPipelineFilter *mag_filter)
-{
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
-
- g_return_if_fail (cogl_is_pipeline (pipeline));
-
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
-
- authority =
- _cogl_pipeline_layer_get_authority (layer,
- COGL_PIPELINE_LAYER_STATE_FILTERS);
-
- *min_filter = authority->min_filter;
- *mag_filter = authority->mag_filter;
-}
-
-CoglPipelineFilter
-_cogl_pipeline_get_layer_min_filter (CoglPipeline *pipeline,
- int layer_index)
-{
- CoglPipelineFilter min_filter;
- CoglPipelineFilter mag_filter;
-
- _cogl_pipeline_get_layer_filters (pipeline, layer_index,
- &min_filter, &mag_filter);
- return min_filter;
-}
-
-CoglPipelineFilter
-_cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline,
- int layer_index)
-{
- CoglPipelineFilter min_filter;
- CoglPipelineFilter mag_filter;
-
- _cogl_pipeline_get_layer_filters (pipeline, layer_index,
- &min_filter, &mag_filter);
- return mag_filter;
-}
-
void
_cogl_pipeline_layer_pre_paint (CoglPipelineLayer *layer)
{
@@ -4515,107 +3155,6 @@ _cogl_pipeline_pre_paint_for_layer (CoglPipeline *pipeline,
_cogl_pipeline_layer_pre_paint (layer);
}
-CoglPipelineFilter
-_cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer)
-{
- CoglPipelineLayer *authority;
-
- g_return_val_if_fail (_cogl_is_pipeline_layer (layer), 0);
-
- authority =
- _cogl_pipeline_layer_get_authority (layer,
- COGL_PIPELINE_LAYER_STATE_FILTERS);
-
- return authority->min_filter;
-}
-
-CoglPipelineFilter
-_cogl_pipeline_layer_get_mag_filter (CoglPipelineLayer *layer)
-{
- CoglPipelineLayer *authority;
-
- g_return_val_if_fail (_cogl_is_pipeline_layer (layer), 0);
-
- authority =
- _cogl_pipeline_layer_get_authority (layer,
- COGL_PIPELINE_LAYER_STATE_FILTERS);
-
- return authority->mag_filter;
-}
-
-void
-cogl_pipeline_set_layer_filters (CoglPipeline *pipeline,
- int layer_index,
- CoglPipelineFilter min_filter,
- CoglPipelineFilter mag_filter)
-{
- CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_FILTERS;
- CoglPipelineLayer *layer;
- CoglPipelineLayer *authority;
- CoglPipelineLayer *new;
-
- g_return_if_fail (cogl_is_pipeline (pipeline));
-
- /* Note: this will ensure that the layer exists, creating one if it
- * doesn't already.
- *
- * Note: If the layer already existed it's possibly owned by another
- * pipeline. If the layer is created then it will be owned by
- * pipeline. */
- layer = _cogl_pipeline_get_layer (pipeline, layer_index);
-
- /* Now find the ancestor of the layer that is the authority for the
- * state we want to change */
- authority = _cogl_pipeline_layer_get_authority (layer, state);
-
- if (authority->min_filter == min_filter &&
- authority->mag_filter == mag_filter)
- return;
-
- new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
- if (new != layer)
- layer = new;
- else
- {
- /* If the original layer we found is currently the authority on
- * the state we are changing see if we can revert to one of our
- * ancestors being the authority. */
- if (layer == authority &&
- _cogl_pipeline_layer_get_parent (authority) != NULL)
- {
- CoglPipelineLayer *parent =
- _cogl_pipeline_layer_get_parent (authority);
- CoglPipelineLayer *old_authority =
- _cogl_pipeline_layer_get_authority (parent, state);
-
- if (old_authority->min_filter == min_filter &&
- old_authority->mag_filter == mag_filter)
- {
- layer->differences &= ~state;
-
- g_assert (layer->owner == pipeline);
- if (layer->differences == 0)
- _cogl_pipeline_prune_empty_layer_difference (pipeline,
- layer);
- return;
- }
- }
- }
-
- layer->min_filter = min_filter;
- layer->mag_filter = mag_filter;
-
- /* If we weren't previously the authority on this state then we need
- * to extended our differences mask and so it's possible that some
- * of our ancestry will now become redundant, so we aim to reparent
- * ourselves if that's true... */
- if (layer != authority)
- {
- layer->differences |= state;
- _cogl_pipeline_layer_prune_redundant_ancestry (layer);
- }
-}
-
/* While a pipeline is referenced by the Cogl journal we can not allow
* modifications, so this gives us a mechanism to track journal
* references separately */
@@ -4671,178 +3210,6 @@ _cogl_pipeline_set_static_breadcrumb (CoglPipeline *pipeline,
pipeline->static_breadcrumb = breadcrumb;
}
-static void
-_cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority,
- CoglPipelineLayer **authorities,
- CoglPipelineHashState *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_target_state (CoglPipelineLayer *authority,
- CoglPipelineLayer **authorities,
- CoglPipelineHashState *state)
-{
- GLenum gl_target = authority->target;
-
- state->hash =
- _cogl_util_one_at_a_time_hash (state->hash, &gl_target, sizeof (gl_target));
-}
-
-static void
-_cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority,
- CoglPipelineLayer **authorities,
- CoglPipelineHashState *state)
-{
- GLuint gl_handle;
-
- cogl_texture_get_gl_texture (authority->texture, &gl_handle, NULL);
-
- state->hash =
- _cogl_util_one_at_a_time_hash (state->hash, &gl_handle, sizeof (gl_handle));
-}
-
-static void
-_cogl_pipeline_layer_hash_filters_state (CoglPipelineLayer *authority,
- CoglPipelineLayer **authorities,
- CoglPipelineHashState *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,
- CoglPipelineHashState *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,
- CoglPipelineHashState *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,
- CoglPipelineHashState *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] ==
- COGL_PIPELINE_COMBINE_SOURCE_CONSTANT)
- {
- /* XXX: should we be careful to only hash the alpha
- * component in the COGL_PIPELINE_COMBINE_OP_SRC_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] ==
- COGL_PIPELINE_COMBINE_SOURCE_CONSTANT)
- {
- /* XXX: should we be careful to only hash the alpha
- * component in the COGL_PIPELINE_COMBINE_OP_SRC_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,
- CoglPipelineHashState *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,
- CoglPipelineHashState *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,
CoglPipelineHashState *state);
diff --git a/cogl/cogl-pipeline.h b/cogl/cogl-pipeline.h
index 331a82d..0ea79e9 100644
--- a/cogl/cogl-pipeline.h
+++ b/cogl/cogl-pipeline.h
@@ -31,7 +31,6 @@
G_BEGIN_DECLS
#include <cogl/cogl-types.h>
-#include <cogl/cogl-matrix.h>
/**
* SECTION:cogl-pipeline
@@ -52,84 +51,6 @@ typedef struct _CoglPipeline CoglPipeline;
#define COGL_PIPELINE(OBJECT) ((CoglPipeline *)OBJECT)
/**
- * CoglPipelineFilter:
- * @COGL_PIPELINE_FILTER_NEAREST: Measuring in manhatten distance from the,
- * current pixel center, use the nearest texture texel
- * @COGL_PIPELINE_FILTER_LINEAR: Use the weighted average of the 4 texels
- * nearest the current pixel center
- * @COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose
- * texel size most closely matches the current pixel, and use the
- * %COGL_PIPELINE_FILTER_NEAREST criterion
- * @COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose
- * texel size most closely matches the current pixel, and use the
- * %COGL_PIPELINE_FILTER_LINEAR criterion
- * @COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels
- * whose texel size most closely matches the current pixel, use
- * the %COGL_PIPELINE_FILTER_NEAREST criterion on each one and take
- * their weighted average
- * @COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels
- * whose texel size most closely matches the current pixel, use
- * the %COGL_PIPELINE_FILTER_LINEAR criterion on each one and take
- * their weighted average
- *
- * Texture filtering is used whenever the current pixel maps either to more
- * than one texture element (texel) or less than one. These filter enums
- * correspond to different strategies used to come up with a pixel color, by
- * possibly referring to multiple neighbouring texels and taking a weighted
- * average or simply using the nearest texel.
- */
-typedef enum {
- COGL_PIPELINE_FILTER_NEAREST = 0x2600,
- COGL_PIPELINE_FILTER_LINEAR = 0x2601,
- COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST = 0x2700,
- COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST = 0x2701,
- COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR = 0x2702,
- COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR = 0x2703
-} CoglPipelineFilter;
-/* NB: these values come from the equivalents in gl.h */
-
-/**
- * CoglPipelineWrapMode:
- * @COGL_PIPELINE_WRAP_MODE_REPEAT: The texture will be repeated. This
- * is useful for example to draw a tiled background.
- * @COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE: The coordinates outside the
- * range 0â1 will sample copies of the edge pixels of the
- * texture. This is useful to avoid artifacts if only one copy of
- * the texture is being rendered.
- * @COGL_PIPELINE_WRAP_MODE_AUTOMATIC: Cogl will try to automatically
- * decide which of the above two to use. For cogl_rectangle(), it
- * will use repeat mode if any of the texture coordinates are
- * outside the range 0â1, otherwise it will use clamp to edge. For
- * cogl_polygon() it will always use repeat mode. For
- * cogl_vertex_buffer_draw() it will use repeat mode except for
- * layers that have point sprite coordinate generation enabled. This
- * is the default value.
- *
- * The wrap mode specifies what happens when texture coordinates
- * outside the range 0â1 are used. Note that if the filter mode is
- * anything but %COGL_PIPELINE_FILTER_NEAREST then texels outside the
- * range 0â1 might be used even when the coordinate is exactly 0 or 1
- * because OpenGL will try to sample neighbouring pixels. For example
- * if you are trying to render the full texture then you may get
- * artifacts around the edges when the pixels from the other side are
- * merged in if the wrap mode is set to repeat.
- *
- * Since: 2.0
- */
-/* GL_ALWAYS is just used here as a value that is known not to clash
- * with any valid GL wrap modes
- *
- * XXX: keep the values in sync with the CoglPipelineWrapModeInternal
- * enum so no conversion is actually needed.
- */
-typedef enum {
- COGL_PIPELINE_WRAP_MODE_REPEAT = 0x2901,
- COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE = 0x812F,
- COGL_PIPELINE_WRAP_MODE_AUTOMATIC = 0x0207
-} CoglPipelineWrapMode;
-/* NB: these values come from the equivalents in gl.h */
-
-/**
* cogl_pipeline_new:
*
* Allocates and initializes a default simple pipeline that will color
@@ -172,360 +93,6 @@ cogl_pipeline_copy (CoglPipeline *source);
gboolean
cogl_is_pipeline (CoglHandle handle);
-/**
- * cogl_pipeline_set_layer:
- * @pipeline: A #CoglPipeline object
- * @layer_index: the index of the layer
- * @texture: a #CoglHandle for the layer object
- *
- * In addition to the standard OpenGL lighting model a Cogl pipeline may have
- * one or more layers comprised of textures that can be blended together in
- * order, with a number of different texture combine modes. This function
- * defines a new texture layer.
- *
- * The index values of multiple layers do not have to be consecutive; it is
- * only their relative order that is important.
- *
- * <note>In the future, we may define other types of pipeline layers, such
- * as purely GLSL based layers.</note>
- *
- * Since: 2.0
- */
-void
-cogl_pipeline_set_layer_texture (CoglPipeline *pipeline,
- int layer_index,
- CoglTexture *texture);
-
-/**
- * cogl_pipeline_remove_layer:
- * @pipeline: A #CoglPipeline object
- * @layer_index: Specifies the layer you want to remove
- *
- * This function removes a layer from your pipeline
- */
-void
-cogl_pipeline_remove_layer (CoglPipeline *pipeline,
- int layer_index);
-
-/**
- * cogl_pipeline_set_layer_combine:
- * @pipeline: A #CoglPipeline object
- * @layer_index: Specifies the layer you want define a combine function for
- * @blend_string: A <link linkend="cogl-Blend-Strings">Cogl blend string</link>
- * describing the desired texture combine function.
- * @error: A #GError that may report parse errors or lack of GPU/driver
- * support. May be %NULL, in which case a warning will be printed out if an
- * error is encountered.
- *
- * If not already familiar; you can refer
- * <link linkend="cogl-Blend-Strings">here</link> for an overview of what blend
- * strings are and there syntax.
- *
- * These are all the functions available for texture combining:
- * <itemizedlist>
- * <listitem>REPLACE(arg0) = arg0</listitem>
- * <listitem>MODULATE(arg0, arg1) = arg0 x arg1</listitem>
- * <listitem>ADD(arg0, arg1) = arg0 + arg1</listitem>
- * <listitem>ADD_SIGNED(arg0, arg1) = arg0 + arg1 - 0.5</listitem>
- * <listitem>INTERPOLATE(arg0, arg1, arg2) = arg0 x arg2 + arg1 x (1 - arg2)</listitem>
- * <listitem>SUBTRACT(arg0, arg1) = arg0 - arg1</listitem>
- * <listitem>
- * <programlisting>
- * DOT3_RGB(arg0, arg1) = 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) +
- * (arg0[G] - 0.5)) * (arg1[G] - 0.5) +
- * (arg0[B] - 0.5)) * (arg1[B] - 0.5))
- * </programlisting>
- * </listitem>
- * <listitem>
- * <programlisting>
- * DOT3_RGBA(arg0, arg1) = 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) +
- * (arg0[G] - 0.5)) * (arg1[G] - 0.5) +
- * (arg0[B] - 0.5)) * (arg1[B] - 0.5))
- * </programlisting>
- * </listitem>
- * </itemizedlist>
- *
- * Refer to the
- * <link linkend="cogl-Blend-String-syntax">color-source syntax</link> for
- * describing the arguments. The valid source names for texture combining
- * are:
- * <variablelist>
- * <varlistentry>
- * <term>TEXTURE</term>
- * <listitem>Use the color from the current texture layer</listitem>
- * </varlistentry>
- * <varlistentry>
- * <term>TEXTURE_0, TEXTURE_1, etc</term>
- * <listitem>Use the color from the specified texture layer</listitem>
- * </varlistentry>
- * <varlistentry>
- * <term>CONSTANT</term>
- * <listitem>Use the color from the constant given with
- * cogl_pipeline_set_layer_constant()</listitem>
- * </varlistentry>
- * <varlistentry>
- * <term>PRIMARY</term>
- * <listitem>Use the color of the pipeline as set with
- * cogl_pipeline_set_color()</listitem>
- * </varlistentry>
- * <varlistentry>
- * <term>PREVIOUS</term>
- * <listitem>Either use the texture color from the previous layer, or
- * if this is layer 0, use the color of the pipeline as set with
- * cogl_pipeline_set_color()</listitem>
- * </varlistentry>
- * </variablelist>
- *
- * <refsect2 id="cogl-Layer-Combine-Examples">
- * <title>Layer Combine Examples</title>
- * <para>This is effectively what the default blending is:</para>
- * <informalexample><programlisting>
- * RGBA = MODULATE (PREVIOUS, TEXTURE)
- * </programlisting></informalexample>
- * <para>This could be used to cross-fade between two images, using
- * the alpha component of a constant as the interpolator. The constant
- * color is given by calling cogl_pipeline_set_layer_constant.</para>
- * <informalexample><programlisting>
- * RGBA = INTERPOLATE (PREVIOUS, TEXTURE, CONSTANT[A])
- * </programlisting></informalexample>
- * </refsect2>
- *
- * <note>You can't give a multiplication factor for arguments as you can
- * with blending.</note>
- *
- * Return value: %TRUE if the blend string was successfully parsed, and the
- * described texture combining is supported by the underlying driver and
- * or hardware. On failure, %FALSE is returned and @error is set
- *
- * Since: 2.0
- */
-gboolean
-cogl_pipeline_set_layer_combine (CoglPipeline *pipeline,
- int layer_index,
- const char *blend_string,
- GError **error);
-
-/**
- * cogl_pipeline_set_layer_combine_constant:
- * @pipeline: A #CoglPipeline object
- * @layer_index: Specifies the layer you want to specify a constant used
- * for texture combining
- * @constant: The constant color you want
- *
- * When you are using the 'CONSTANT' color source in a layer combine
- * description then you can use this function to define its value.
- *
- * Since: 2.0
- */
-void
-cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline,
- int layer_index,
- const CoglColor *constant);
-
-/**
- * cogl_pipeline_set_layer_matrix:
- * @pipeline: A #CoglPipeline object
- * @layer_index: the index for the layer inside @pipeline
- * @matrix: the transformation matrix for the layer
- *
- * This function lets you set a matrix that can be used to e.g. translate
- * and rotate a single layer of a pipeline used to fill your geometry.
- */
-void
-cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline,
- int layer_index,
- const CoglMatrix *matrix);
-
-/**
- * cogl_pipeline_get_n_layers:
- * @pipeline: A #CoglPipeline object
- *
- * Retrieves the number of layers defined for the given @pipeline
- *
- * Return value: the number of layers
- *
- * Since: 2.0
- */
-int
-cogl_pipeline_get_n_layers (CoglPipeline *pipeline);
-
-/**
- * cogl_pipeline_set_layer_filters:
- * @pipeline: A #CoglPipeline object
- * @layer_index: the layer number to change.
- * @min_filter: the filter used when scaling a texture down.
- * @mag_filter: the filter used when magnifying a texture.
- *
- * Changes the decimation and interpolation filters used when a texture is
- * drawn at other scales than 100%.
- */
-void
-cogl_pipeline_set_layer_filters (CoglPipeline *pipeline,
- int layer_index,
- CoglPipelineFilter min_filter,
- CoglPipelineFilter mag_filter);
-
-/**
- * cogl_pipeline_set_layer_point_sprite_coords_enabled:
- * @pipeline: a #CoglHandle to a pipeline.
- * @layer_index: the layer number to change.
- * @enable: whether to enable point sprite coord generation.
- * @error: A return location for a GError, or NULL to ignore errors.
- *
- * When rendering points, if @enable is %TRUE then the texture
- * coordinates for this layer will be replaced with coordinates that
- * vary from 0.0 to 1.0 across the primitive. The top left of the
- * point will have the coordinates 0.0,0.0 and the bottom right will
- * have 1.0,1.0. If @enable is %FALSE then the coordinates will be
- * fixed for the entire point.
- *
- * This function will only work if %COGL_FEATURE_POINT_SPRITE is
- * available. If the feature is not available then the function will
- * return %FALSE and set @error.
- *
- * Return value: %TRUE if the function succeeds, %FALSE otherwise.
- * Since: 2.0
- */
-gboolean
-cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
- int layer_index,
- gboolean enable,
- GError **error);
-
-/**
- * cogl_pipeline_get_layer_point_sprite_coords_enabled:
- * @pipeline: a #CoglHandle to a pipeline.
- * @layer_index: the layer number to check.
- *
- * Gets whether point sprite coordinate generation is enabled for this
- * texture layer.
- *
- * Return value: whether the texture coordinates will be replaced with
- * point sprite coordinates.
- *
- * Since: 2.0
- */
-gboolean
-cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
- int layer_index);
-
-/**
- * cogl_pipeline_get_layer_wrap_mode_s:
- * @pipeline: A #CoglPipeline object
- * @layer_index: the layer number to change.
- *
- * Returns the wrap mode for the 's' coordinate of texture lookups on this
- * layer.
- *
- * Return value: the wrap mode for the 's' coordinate of texture lookups on
- * this layer.
- *
- * Since: 1.6
- */
-CoglPipelineWrapMode
-cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline,
- int layer_index);
-
-/**
- * cogl_pipeline_set_layer_wrap_mode_s:
- * @pipeline: A #CoglPipeline object
- * @layer_index: the layer number to change.
- * @mode: the new wrap mode
- *
- * Sets the wrap mode for the 's' coordinate of texture lookups on this layer.
- *
- * Since: 2.0
- */
-void
-cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline,
- int layer_index,
- CoglPipelineWrapMode mode);
-
-/**
- * cogl_pipeline_get_layer_wrap_mode_t:
- * @pipeline: A #CoglPipeline object
- * @layer_index: the layer number to change.
- *
- * Returns the wrap mode for the 't' coordinate of texture lookups on this
- * layer.
- *
- * Return value: the wrap mode for the 't' coordinate of texture lookups on
- * this layer.
- *
- * Since: 1.6
- */
-CoglPipelineWrapMode
-cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline,
- int layer_index);
-
-
-/**
- * cogl_pipeline_set_layer_wrap_mode_t:
- * @pipeline: A #CoglPipeline object
- * @layer_index: the layer number to change.
- * @mode: the new wrap mode
- *
- * Sets the wrap mode for the 't' coordinate of texture lookups on this layer.
- *
- * Since: 2.0
- */
-void
-cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline,
- int layer_index,
- CoglPipelineWrapMode mode);
-
-/**
- * cogl_pipeline_get_layer_wrap_mode_p:
- * @pipeline: A #CoglPipeline object
- * @layer_index: the layer number to change.
- *
- * Returns the wrap mode for the 'p' coordinate of texture lookups on this
- * layer.
- *
- * Return value: the wrap mode for the 'p' coordinate of texture lookups on
- * this layer.
- *
- * Since: 1.6
- */
-CoglPipelineWrapMode
-cogl_pipeline_get_layer_wrap_mode_p (CoglPipeline *pipeline,
- int layer_index);
-
-/**
- * cogl_pipeline_set_layer_wrap_mode_p:
- * @pipeline: A #CoglPipeline object
- * @layer_index: the layer number to change.
- * @mode: the new wrap mode
- *
- * Sets the wrap mode for the 'p' coordinate of texture lookups on
- * this layer. 'p' is the third coordinate.
- *
- * Since: 2.0
- */
-void
-cogl_pipeline_set_layer_wrap_mode_p (CoglPipeline *pipeline,
- int layer_index,
- CoglPipelineWrapMode mode);
-
-/**
- * cogl_pipeline_set_layer_wrap_mode:
- * @pipeline: A #CoglPipeline object
- * @layer_index: the layer number to change.
- * @mode: the new wrap mode
- *
- * Sets the wrap mode for all three coordinates of texture lookups on
- * this layer. This is equivalent to calling
- * cogl_pipeline_set_layer_wrap_mode_s(),
- * cogl_pipeline_set_layer_wrap_mode_t() and
- * cogl_pipeline_set_layer_wrap_mode_p() separately.
- *
- * Since: 2.0
- */
-void
-cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline,
- int layer_index,
- CoglPipelineWrapMode mode);
-
#ifdef COGL_ENABLE_EXPERIMENTAL_API
/**
diff --git a/cogl/cogl.h b/cogl/cogl.h
index b486d81..240fa2a 100644
--- a/cogl/cogl.h
+++ b/cogl/cogl.h
@@ -89,6 +89,7 @@ typedef struct _CoglFramebuffer CoglFramebuffer;
#include <cogl/cogl-depth-state.h>
#include <cogl/cogl-pipeline.h>
#include <cogl/cogl-pipeline-state.h>
+#include <cogl/cogl-pipeline-layer-state.h>
#include <cogl/cogl-framebuffer.h>
#ifdef COGL_HAS_XLIB
#include <cogl/cogl-xlib.h>
diff --git a/doc/reference/cogl-2.0-experimental/Makefile.am b/doc/reference/cogl-2.0-experimental/Makefile.am
index b2b9b2f..e34e89b 100644
--- a/doc/reference/cogl-2.0-experimental/Makefile.am
+++ b/doc/reference/cogl-2.0-experimental/Makefile.am
@@ -75,6 +75,7 @@ IGNORE_HFILES=\
cogl-pipeline-opengl-private.h \
cogl-pipeline-private.h \
cogl-pipeline-state-private.h \
+ cogl-pipeline-layer-state-private.h \
cogl-pipeline-progend-glsl-private.h \
cogl-pipeline-vertend-fixed-private.h \
cogl-pipeline-vertend-glsl-private.h \
diff --git a/doc/reference/cogl/Makefile.am b/doc/reference/cogl/Makefile.am
index e4cd24b..fb5dd3f 100644
--- a/doc/reference/cogl/Makefile.am
+++ b/doc/reference/cogl/Makefile.am
@@ -73,6 +73,7 @@ IGNORE_HFILES=\
cogl-pipeline-opengl-private.h \
cogl-pipeline-private.h \
cogl-pipeline-state-private.h \
+ cogl-pipeline-layer-state-private.h \
cogl-pipeline-progend-glsl-private.h \
cogl-pipeline-vertend-fixed-private.h \
cogl-pipeline-vertend-glsl-private.h \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]