material: Split the fragment processing backends out
authorRobert Bragg <robert@linux.intel.com>
Tue, 15 Jun 2010 15:44:52 +0000 (16:44 +0100)
committerRobert Bragg <robert@linux.intel.com>
Wed, 30 Jun 2010 14:04:10 +0000 (15:04 +0100)
This splits the fragment processing backends (glsl, arbfp and fixed) out
from cogl-material.c into their own cogl-material-{glsl,arbfp,fixed}.c
files in an effort to help and keep cogl-material.c maintainable.

clutter/cogl/cogl/Makefile.am
clutter/cogl/cogl/cogl-material-arbfp-private.h [new file with mode: 0644]
clutter/cogl/cogl/cogl-material-arbfp.c [new file with mode: 0644]
clutter/cogl/cogl/cogl-material-fixed-private.h [new file with mode: 0644]
clutter/cogl/cogl/cogl-material-fixed.c [new file with mode: 0644]
clutter/cogl/cogl/cogl-material-glsl-private.h [new file with mode: 0644]
clutter/cogl/cogl/cogl-material-glsl.c [new file with mode: 0644]
clutter/cogl/cogl/cogl-material-private.h
clutter/cogl/cogl/cogl-material.c

index b3d5383..070d62c 100644 (file)
@@ -119,6 +119,12 @@ cogl_sources_c = \
        $(srcdir)/cogl-matrix-stack.h                   \
        $(srcdir)/cogl-material.c                       \
        $(srcdir)/cogl-material-private.h               \
+       $(srcdir)/cogl-material-glsl.c                  \
+       $(srcdir)/cogl-material-glsl-private.h          \
+       $(srcdir)/cogl-material-arbfp.c                 \
+       $(srcdir)/cogl-material-arbfp-private.h         \
+       $(srcdir)/cogl-material-fixed.c                 \
+       $(srcdir)/cogl-material-fixed-private.h         \
        $(srcdir)/cogl-blend-string.c                   \
        $(srcdir)/cogl-blend-string.h                   \
        $(srcdir)/cogl-debug.c                          \
diff --git a/clutter/cogl/cogl/cogl-material-arbfp-private.h b/clutter/cogl/cogl/cogl-material-arbfp-private.h
new file mode 100644 (file)
index 0000000..f3c472f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert@linux.intel.com>
+ */
+
+#ifndef __COGL_MATERIAL_ARBFP_PRIVATE_H
+#define __COGL_MATERIAL_ARBFP_PRIVATE_H
+
+#include "cogl-material-private.h"
+
+const CoglMaterialBackend _cogl_material_arbfp_backend;
+
+#endif /* __COGL_MATERIAL_ARBFP_PRIVATE_H */
+
diff --git a/clutter/cogl/cogl/cogl-material-arbfp.c b/clutter/cogl/cogl/cogl-material-arbfp.c
new file mode 100644 (file)
index 0000000..bbc510e
--- /dev/null
@@ -0,0 +1,1029 @@
+/*
+ * 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.h"
+#include "cogl-internal.h"
+#include "cogl-context.h"
+#include "cogl-handle.h"
+
+#include "cogl-material-private.h"
+#include "cogl-texture-private.h"
+#include "cogl-blend-string.h"
+#include "cogl-journal-private.h"
+#include "cogl-color-private.h"
+#include "cogl-profile.h"
+#ifndef HAVE_COGL_GLES
+#include "cogl-program.h"
+#endif
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <string.h>
+
+/*
+ * GL/GLES compatability defines for material thingies:
+ */
+
+#ifdef HAVE_COGL_GLES2
+#include "../gles/cogl-gles2-wrapper.h"
+#endif
+
+#ifdef HAVE_COGL_GL
+#define glProgramString ctx->drv.pf_glProgramString
+#define glBindProgram ctx->drv.pf_glBindProgram
+#define glDeletePrograms ctx->drv.pf_glDeletePrograms
+#define glGenPrograms ctx->drv.pf_glGenPrograms
+#define glProgramLocalParameter4fv ctx->drv.pf_glProgramLocalParameter4fv
+#define glUseProgram ctx->drv.pf_glUseProgram
+#endif
+
+typedef struct _CoglMaterialBackendARBfpPrivate
+{
+  CoglMaterial *authority_cache;
+  unsigned long authority_cache_age;
+
+  GString *source;
+  GLuint gl_program;
+  gboolean *sampled;
+  int next_constant_id;
+} CoglMaterialBackendARBfpPrivate;
+
+static int
+_cogl_material_backend_arbfp_get_max_texture_units (void)
+{
+  return _cogl_get_max_texture_image_units ();
+}
+
+typedef struct
+{
+  int i;
+  CoglMaterialLayer **layers;
+} AddLayersToArrayState;
+
+static gboolean
+add_layer_to_array_cb (CoglMaterialLayer *layer,
+                       void *user_data)
+{
+  AddLayersToArrayState *state = user_data;
+  state->layers[state->i++] = layer;
+  return TRUE;
+}
+
+static gboolean
+layers_arbfp_would_differ (CoglMaterialLayer **material0_layers,
+                           CoglMaterialLayer **material1_layers,
+                           int n_layers)
+{
+  int i;
+  /* The layer state that affects arbfp codegen... */
+  unsigned long arbfp_codegen_modifiers =
+    COGL_MATERIAL_LAYER_STATE_COMBINE |
+    COGL_MATERIAL_LAYER_STATE_COMBINE_CONSTANT |
+    COGL_MATERIAL_LAYER_STATE_UNIT |
+    COGL_MATERIAL_LAYER_STATE_TEXTURE;
+
+  for (i = 0; i < n_layers; i++)
+    {
+      CoglMaterialLayer *layer0 = material0_layers[i];
+      CoglMaterialLayer *layer1 = material1_layers[i];
+      unsigned long layer_differences;
+
+      if (layer0 == layer1)
+        continue;
+
+      layer_differences =
+        _cogl_material_layer_compare_differences (layer0, layer1);
+
+      if (layer_differences & arbfp_codegen_modifiers)
+        {
+          /* When it comes to texture differences the only thing that
+           * affects the arbfp is the target enum... */
+          if (layer_differences == COGL_MATERIAL_LAYER_STATE_TEXTURE)
+            {
+              CoglHandle tex0 = _cogl_material_layer_get_texture (layer0);
+              CoglHandle tex1 = _cogl_material_layer_get_texture (layer1);
+              GLenum gl_target0;
+              GLenum gl_target1;
+
+              cogl_texture_get_gl_texture (tex0, NULL, &gl_target0);
+              cogl_texture_get_gl_texture (tex1, NULL, &gl_target1);
+              if (gl_target0 == gl_target1)
+                continue;
+            }
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+/* This tries to find the oldest ancestor whos state would generate
+ * the same arbfp program as the current material. This is a simple
+ * mechanism for reducing the number of arbfp programs we have to
+ * generate.
+ */
+static CoglMaterial *
+find_arbfp_authority (CoglMaterial *material)
+{
+  CoglMaterial *authority0;
+  CoglMaterial *authority1;
+  int n_layers;
+  CoglMaterialLayer **authority0_layers;
+  CoglMaterialLayer **authority1_layers;
+
+  /* XXX: we'll need to update this when we add fog support to the
+   * arbfp codegen */
+
+  /* Find the first material that modifies state that affects the
+   * arbfp codegen... */
+  authority0 = _cogl_material_get_authority (material,
+                                             COGL_MATERIAL_STATE_LAYERS);
+
+  /* Find the next ancestor after that, that also modifies state
+   * affecting arbfp codegen... */
+  if (authority0->parent)
+    authority1 = _cogl_material_get_authority (authority0->parent,
+                                               COGL_MATERIAL_STATE_LAYERS);
+  else
+    return authority0;
+
+  n_layers = authority0->n_layers;
+
+  for (;;)
+    {
+      AddLayersToArrayState state;
+
+      if (authority0->n_layers != authority1->n_layers)
+        return authority0;
+
+      authority0_layers =
+        g_alloca (sizeof (CoglMaterialLayer *) * n_layers);
+      state.i = 0;
+      state.layers = authority0_layers;
+      _cogl_material_foreach_layer (authority0,
+                                    add_layer_to_array_cb,
+                                    &state);
+
+      authority1_layers =
+        g_alloca (sizeof (CoglMaterialLayer *) * n_layers);
+      state.i = 0;
+      state.layers = authority1_layers;
+      _cogl_material_foreach_layer (authority1,
+                                    add_layer_to_array_cb,
+                                    &state);
+
+      if (layers_arbfp_would_differ (authority0_layers, authority1_layers,
+                                     n_layers))
+        return authority0;
+
+      /* Find the next ancestor after that, that also modifies state
+       * affecting arbfp codegen... */
+
+      if (!authority1->parent)
+        break;
+
+      authority0 = authority1;
+      authority1 = _cogl_material_get_authority (authority1->parent,
+                                                 COGL_MATERIAL_STATE_LAYERS);
+      if (authority1 == authority0)
+        break;
+    }
+
+  return authority1;
+}
+
+static void
+invalidate_arbfp_authority_cache (CoglMaterial *material)
+{
+  if (material->backend_priv_set_mask  & COGL_MATERIAL_BACKEND_ARBFP_MASK)
+    {
+      CoglMaterialBackendARBfpPrivate *priv =
+        material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
+      priv->authority_cache = NULL;
+      priv->authority_cache_age = 0;
+    }
+}
+
+static gboolean
+_cogl_material_backend_arbfp_start (CoglMaterial *material,
+                                    int n_layers,
+                                    unsigned long materials_difference)
+{
+  CoglMaterial *authority;
+  CoglMaterialBackendARBfpPrivate *priv;
+  CoglMaterialBackendARBfpPrivate *authority_priv;
+
+  _COGL_GET_CONTEXT (ctx, FALSE);
+
+  if (!_cogl_features_available_private (COGL_FEATURE_PRIVATE_ARB_FP))
+    return FALSE;
+
+  /* TODO: support fog */
+  if (ctx->fog_enabled)
+    return FALSE;
+
+  /* Note: we allocate ARBfp private state for both the given material
+   * and the authority. (The oldest ancestor whos state will result in
+   * the same program being generated) The former will simply cache a
+   * pointer to the authority and the later will track the arbfp
+   * program that we will generate.
+   */
+
+  if (!(material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK))
+    {
+      material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP] =
+        g_slice_new0 (CoglMaterialBackendARBfpPrivate);
+      material->backend_priv_set_mask |= COGL_MATERIAL_BACKEND_ARBFP_MASK;
+    }
+  priv = material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
+
+  /* XXX: We are making assumptions that we don't yet support
+   * modification of ancestors to optimize the sharing of state in the
+   * material graph. When we start to support this then the arbfp
+   * backend will somehow need to be notified of graph changes that
+   * may invalidate authority_cache pointers.
+   */
+
+  if (priv->authority_cache &&
+      priv->authority_cache_age != _cogl_material_get_age (material))
+    invalidate_arbfp_authority_cache (material);
+
+  if (!priv->authority_cache)
+    {
+      priv->authority_cache = find_arbfp_authority (material);
+      priv->authority_cache_age = _cogl_material_get_age (material);
+    }
+
+  authority = priv->authority_cache;
+  if (!(authority->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK))
+    {
+      authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP] =
+        g_slice_new0 (CoglMaterialBackendARBfpPrivate);
+      authority->backend_priv_set_mask |= COGL_MATERIAL_BACKEND_ARBFP_MASK;
+    }
+  authority_priv = authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
+
+  if (authority_priv->gl_program == 0)
+    {
+      /* We reuse a single grow-only GString for ARBfp code-gen */
+      g_string_set_size (ctx->arbfp_source_buffer, 0);
+      authority_priv->source = ctx->arbfp_source_buffer;
+      g_string_append (authority_priv->source,
+                       "!!ARBfp1.0\n"
+                       "TEMP output;\n"
+                       "TEMP tmp0, tmp1, tmp2, tmp3, tmp4;\n"
+                       "PARAM half = {.5, .5, .5, .5};\n"
+                       "PARAM one = {1, 1, 1, 1};\n"
+                       "PARAM two = {2, 2, 2, 2};\n"
+                       "PARAM minus_one = {-1, -1, -1, -1};\n");
+      authority_priv->sampled = g_new0 (gboolean, n_layers);
+    }
+
+  return TRUE;
+}
+
+static CoglMaterial *
+get_arbfp_authority (CoglMaterial *material)
+{
+  CoglMaterialBackendARBfpPrivate *priv =
+    material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
+
+  g_return_val_if_fail (priv != NULL, NULL);
+
+  return priv->authority_cache;
+}
+
+/* Determines if we need to handle the RGB and A texture combining
+ * separately or is the same function used for both channel masks and
+ * with the same arguments...
+ */
+static gboolean
+need_texture_combine_separate (CoglMaterialLayer *combine_authority)
+{
+  CoglMaterialLayerBigState *big_state = combine_authority->big_state;
+  int n_args;
+  int i;
+
+  if (big_state->texture_combine_rgb_func !=
+      big_state->texture_combine_alpha_func)
+    return TRUE;
+
+  n_args = _cogl_get_n_args_for_combine_func (big_state->texture_combine_rgb_func);
+
+  for (i = 0; i < n_args; i++)
+    {
+      if (big_state->texture_combine_rgb_src[i] !=
+          big_state->texture_combine_alpha_src[i])
+        return TRUE;
+
+      /*
+       * We can allow some variation of the source operands without
+       * needing a separation...
+       *
+       * "A = REPLACE (CONSTANT[A])" + either of the following...
+       * "RGB = REPLACE (CONSTANT[RGB])"
+       * "RGB = REPLACE (CONSTANT[A])"
+       *
+       * can be combined as:
+       * "RGBA = REPLACE (CONSTANT)" or
+       * "RGBA = REPLACE (CONSTANT[A])" or
+       *
+       * And "A = REPLACE (1-CONSTANT[A])" + either of the following...
+       * "RGB = REPLACE (1-CONSTANT)" or
+       * "RGB = REPLACE (1-CONSTANT[A])"
+       *
+       * can be combined as:
+       * "RGBA = REPLACE (1-CONSTANT)" or
+       * "RGBA = REPLACE (1-CONSTANT[A])"
+       */
+      switch (big_state->texture_combine_alpha_op[i])
+        {
+        case GL_SRC_ALPHA:
+          switch (big_state->texture_combine_rgb_op[i])
+            {
+            case GL_SRC_COLOR:
+            case GL_SRC_ALPHA:
+              break;
+            default:
+              return FALSE;
+            }
+          break;
+        case GL_ONE_MINUS_SRC_ALPHA:
+          switch (big_state->texture_combine_rgb_op[i])
+            {
+            case GL_ONE_MINUS_SRC_COLOR:
+            case GL_ONE_MINUS_SRC_ALPHA:
+              break;
+            default:
+              return FALSE;
+            }
+          break;
+        default:
+          return FALSE;        /* impossible */
+        }
+    }
+
+   return FALSE;
+}
+
+static const char *
+gl_target_to_arbfp_string (GLenum gl_target)
+{
+#ifndef HAVE_COGL_GLES2
+  if (gl_target == GL_TEXTURE_1D)
+    return "1D";
+  else
+#endif
+    if (gl_target == GL_TEXTURE_2D)
+    return "2D";
+#ifdef GL_ARB_texture_rectangle
+  else if (gl_target == GL_TEXTURE_RECTANGLE_ARB)
+    return "RECT";
+#endif
+  else
+    return "2D";
+}
+
+static void
+setup_texture_source (CoglMaterialBackendARBfpPrivate *priv,
+                      int unit_index,
+                      GLenum gl_target)
+{
+  if (!priv->sampled[unit_index])
+    {
+      g_string_append_printf (priv->source,
+                              "TEMP texel%d;\n"
+                              "TEX texel%d,fragment.texcoord[%d],"
+                              "texture[%d],%s;\n",
+                              unit_index,
+                              unit_index,
+                              unit_index,
+                              unit_index,
+                              gl_target_to_arbfp_string (gl_target));
+      priv->sampled[unit_index] = TRUE;
+    }
+}
+
+typedef enum _CoglMaterialBackendARBfpArgType
+{
+  COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE,
+  COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_CONSTANT,
+  COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_TEXTURE
+} CoglMaterialBackendARBfpArgType;
+
+typedef struct _CoglMaterialBackendARBfpArg
+{
+  const char *name;
+
+  CoglMaterialBackendARBfpArgType type;
+
+  /* for type = TEXTURE */
+  int texture_unit;
+  GLenum texture_target;
+
+  /* for type = CONSTANT */
+  int constant_id;
+
+  const char *swizzle;
+
+} CoglMaterialBackendARBfpArg;
+
+static void
+append_arg (GString *source, const CoglMaterialBackendARBfpArg *arg)
+{
+  switch (arg->type)
+    {
+    case COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_TEXTURE:
+      g_string_append_printf (source, "texel%d%s",
+                              arg->texture_unit, arg->swizzle);
+      break;
+    case COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_CONSTANT:
+      g_string_append_printf (source, "constant%d%s",
+                              arg->constant_id, arg->swizzle);
+      break;
+    case COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE:
+      g_string_append_printf (source, "%s%s",
+                              arg->name, arg->swizzle);
+      break;
+    }
+}
+
+/* Note: we are trying to avoid duplicating strings during codegen
+ * which is why we have the slightly awkward
+ * CoglMaterialBackendARBfpArg mechanism. */
+static void
+setup_arg (CoglMaterial *material,
+           CoglMaterialLayer *layer,
+           CoglBlendStringChannelMask mask,
+           int arg_index,
+           GLint src,
+           GLint op,
+           CoglMaterialBackendARBfpArg *arg)
+{
+  CoglMaterial *arbfp_authority = get_arbfp_authority (material);
+  CoglMaterialBackendARBfpPrivate *priv =
+    arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
+  static const char *tmp_name[3] = { "tmp0", "tmp1", "tmp2" };
+  GLenum gl_target;
+  CoglHandle texture;
+
+  switch (src)
+    {
+    case GL_TEXTURE:
+      arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_TEXTURE;
+      arg->name = "texel%d";
+      arg->texture_unit = _cogl_material_layer_get_unit_index (layer);
+      texture = _cogl_material_layer_get_texture (layer);
+      cogl_texture_get_gl_texture (texture, NULL, &gl_target);
+      setup_texture_source (priv, arg->texture_unit, gl_target);
+      break;
+    case GL_CONSTANT:
+      {
+        unsigned long state = COGL_MATERIAL_LAYER_STATE_COMBINE_CONSTANT;
+        CoglMaterialLayer *authority =
+          _cogl_material_layer_get_authority (layer, state);
+        CoglMaterialLayerBigState *big_state = authority->big_state;
+
+        arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_CONSTANT;
+        arg->name = "constant%d";
+        arg->constant_id = priv->next_constant_id++;
+        g_string_append_printf (priv->source,
+                                "PARAM constant%d = "
+                                "  {%f, %f, %f, %f};\n",
+                                arg->constant_id,
+                                big_state->texture_combine_constant[0],
+                                big_state->texture_combine_constant[1],
+                                big_state->texture_combine_constant[2],
+                                big_state->texture_combine_constant[3]);
+        break;
+      }
+    case GL_PRIMARY_COLOR:
+      arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE;
+      arg->name = "fragment.color.primary";
+      break;
+    case GL_PREVIOUS:
+      arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE;
+      if (_cogl_material_layer_get_unit_index (layer) == 0)
+        arg->name = "fragment.color.primary";
+      else
+        arg->name = "output";
+      break;
+    default: /* GL_TEXTURE0..N */
+      arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_TEXTURE;
+      arg->name = "texture[%d]";
+      arg->texture_unit = src - GL_TEXTURE0;
+      texture = _cogl_material_layer_get_texture (layer);
+      cogl_texture_get_gl_texture (texture, NULL, &gl_target);
+      setup_texture_source (priv, arg->texture_unit, gl_target);
+    }
+
+  arg->swizzle = "";
+
+  switch (op)
+    {
+    case GL_SRC_COLOR:
+      break;
+    case GL_ONE_MINUS_SRC_COLOR:
+      g_string_append_printf (priv->source,
+                              "SUB tmp%d, one, ",
+                              arg_index);
+      append_arg (priv->source, arg);
+      g_string_append_printf (priv->source, ";\n");
+      arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE;
+      arg->name = tmp_name[arg_index];
+      arg->swizzle = "";
+      break;
+    case GL_SRC_ALPHA:
+      /* avoid a swizzle if we know RGB are going to be masked
+       * in the end anyway */
+      if (mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
+        arg->swizzle = ".a";
+      break;
+    case GL_ONE_MINUS_SRC_ALPHA:
+      g_string_append_printf (priv->source,
+                              "SUB tmp%d, one, ",
+                              arg_index);
+      append_arg (priv->source, arg);
+      /* avoid a swizzle if we know RGB are going to be masked
+       * in the end anyway */
+      if (mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
+        g_string_append_printf (priv->source, ".a;\n");
+      else
+        g_string_append_printf (priv->source, ";\n");
+      arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE;
+      arg->name = tmp_name[arg_index];
+      break;
+    default:
+      g_error ("Unknown texture combine operator %d", op);
+      break;
+    }
+}
+
+static gboolean
+backend_arbfp_args_equal (CoglMaterialBackendARBfpArg *arg0,
+                          CoglMaterialBackendARBfpArg *arg1)
+{
+  if (arg0->type != arg1->type)
+    return FALSE;
+
+  if (arg0->name != arg1->name &&
+      strcmp (arg0->name, arg1->name) != 0)
+    return FALSE;
+
+  if (arg0->type == COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_TEXTURE &&
+      arg0->texture_unit != arg1->texture_unit)
+    return FALSE;
+  /* Note we don't have to check the target; a texture unit can only
+   * have one target enabled at a time. */
+
+  if (arg0->type == COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_CONSTANT &&
+      arg0->constant_id != arg0->constant_id)
+    return FALSE;
+
+  if (arg0->swizzle != arg1->swizzle &&
+      strcmp (arg0->swizzle, arg1->swizzle) != 0)
+    return FALSE;
+
+  return TRUE;
+}
+
+static void
+append_function (CoglMaterial *material,
+                 CoglBlendStringChannelMask mask,
+                 GLint function,
+                 CoglMaterialBackendARBfpArg *args,
+                 int n_args)
+{
+  CoglMaterial *arbfp_authority = get_arbfp_authority (material);
+  CoglMaterialBackendARBfpPrivate *priv =
+    arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
+  const char *mask_name;
+
+  switch (mask)
+    {
+    case COGL_BLEND_STRING_CHANNEL_MASK_RGB:
+      mask_name = ".rgb";
+      break;
+    case COGL_BLEND_STRING_CHANNEL_MASK_ALPHA:
+      mask_name = ".a";
+      break;
+    case COGL_BLEND_STRING_CHANNEL_MASK_RGBA:
+      mask_name = "";
+      break;
+    default:
+      g_error ("Unknown channel mask %d", mask);
+      mask_name = "";
+    }
+
+  switch (function)
+    {
+    case GL_ADD:
+      g_string_append_printf (priv->source, "ADD_SAT output%s, ",
+                              mask_name);
+      break;
+    case GL_MODULATE:
+      /* Note: no need to saturate since we can assume operands
+       * have values in the range [0,1] */
+      g_string_append_printf (priv->source, "MUL output%s, ",
+                              mask_name);
+      break;
+    case GL_REPLACE:
+      /* Note: no need to saturate since we can assume operand
+       * has a value in the range [0,1] */
+      g_string_append_printf (priv->source, "MOV output%s, ",
+                              mask_name);
+      break;
+    case GL_SUBTRACT:
+      g_string_append_printf (priv->source, "SUB_SAT output%s, ",
+                              mask_name);
+      break;
+    case GL_ADD_SIGNED:
+      g_string_append_printf (priv->source, "ADD tmp3%s, ",
+                              mask_name);
+      append_arg (priv->source, &args[0]);
+      g_string_append (priv->source, ", ");
+      append_arg (priv->source, &args[1]);
+      g_string_append (priv->source, ";\n");
+      g_string_append_printf (priv->source, "SUB_SAT output%s, tmp3, half",
+                              mask_name);
+      n_args = 0;
+      break;
+    case GL_DOT3_RGB:
+    /* These functions are the same except that GL_DOT3_RGB never
+     * updates the alpha channel.
+     *
+     * NB: GL_DOT3_RGBA is a bit special because it effectively forces
+     * an RGBA mask and we end up ignoring any separate alpha channel
+     * function.
+     */
+    case GL_DOT3_RGBA:
+      {
+        const char *tmp4 = "tmp4";
+
+        /* The maths for this was taken from Mesa;
+         * apparently:
+         *
+         * tmp3 = 2*src0 - 1
+         * tmp4 = 2*src1 - 1
+         * output = DP3 (tmp3, tmp4)
+         *
+         * is the same as:
+         *
+         * output = 4 * DP3 (src0 - 0.5, src1 - 0.5)
+         */
+
+        g_string_append (priv->source, "MAD tmp3, two, ");
+        append_arg (priv->source, &args[0]);
+        g_string_append (priv->source, ", minus_one;\n");
+
+        if (!backend_arbfp_args_equal (&args[0], &args[1]))
+          {
+            g_string_append (priv->source, "MAD tmp4, two, ");
+            append_arg (priv->source, &args[1]);
+            g_string_append (priv->source, ", minus_one;\n");
+          }
+        else
+          tmp4 = "tmp3";
+
+        g_string_append_printf (priv->source,
+                                "DP3_SAT output%s, tmp3, %s",
+                                mask_name, tmp4);
+        n_args = 0;
+      }
+      break;
+    case GL_INTERPOLATE:
+      /* Note: no need to saturate since we can assume operands
+       * have values in the range [0,1] */
+
+      /* NB: GL_INTERPOLATE = arg0*arg2 + arg1*(1-arg2)
+       * but LRP dst, a, b, c = b*a + c*(1-a) */
+      g_string_append_printf (priv->source, "LRP output%s, ",
+                              mask_name);
+      append_arg (priv->source, &args[2]);
+      g_string_append (priv->source, ", ");
+      append_arg (priv->source, &args[0]);
+      g_string_append (priv->source, ", ");
+      append_arg (priv->source, &args[1]);
+      n_args = 0;
+      break;
+    default:
+      g_error ("Unknown texture combine function %d", function);
+      g_string_append_printf (priv->source, "MUL_SAT output%s, ",
+                              mask_name);
+      n_args = 2;
+      break;
+    }
+
+  if (n_args > 0)
+    append_arg (priv->source, &args[0]);
+  if (n_args > 1)
+    {
+      g_string_append (priv->source, ", ");
+      append_arg (priv->source, &args[1]);
+    }
+  g_string_append (priv->source, ";\n");
+}
+
+static void
+append_masked_combine (CoglMaterial *arbfp_authority,
+                       CoglMaterialLayer *layer,
+                       CoglBlendStringChannelMask mask,
+                       GLint function,
+                       GLint *src,
+                       GLint *op)
+{
+  int i;
+  int n_args;
+  CoglMaterialBackendARBfpArg args[3];
+
+  n_args = _cogl_get_n_args_for_combine_func (function);
+
+  for (i = 0; i < n_args; i++)
+    {
+      setup_arg (arbfp_authority,
+                 layer,
+                 mask,
+                 i,
+                 src[i],
+                 op[i],
+                 &args[i]);
+    }
+
+  append_function (arbfp_authority,
+                   mask,
+                   function,
+                   args,
+                   n_args);
+}
+
+static gboolean
+_cogl_material_backend_arbfp_add_layer (CoglMaterial *material,
+                                        CoglMaterialLayer *layer,
+                                        unsigned long layers_difference)
+{
+  CoglMaterial *arbfp_authority = get_arbfp_authority (material);
+  CoglMaterialBackendARBfpPrivate *priv =
+    arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
+  CoglMaterialLayer *combine_authority =
+    _cogl_material_layer_get_authority (layer,
+                                        COGL_MATERIAL_LAYER_STATE_COMBINE);
+  CoglMaterialLayerBigState *big_state = combine_authority->big_state;
+
+  /* Notes...
+   *
+   * We are ignoring the issue of texture indirection limits until
+   * someone complains (Ref Section 3.11.6 in the ARB_fragment_program
+   * spec)
+   *
+   * There always five TEMPs named tmp0, tmp1 and tmp2, tmp3 and tmp4
+   * available and these constants: 'one' = {1, 1, 1, 1}, 'half'
+   * {.5, .5, .5, .5}, 'two' = {2, 2, 2, 2}, 'minus_one' = {-1, -1,
+   * -1, -1}
+   *
+   * tmp0-2 are intended for dealing with some of the texture combine
+   * operands (e.g. GL_ONE_MINUS_SRC_COLOR) tmp3/4 are for dealing
+   * with the GL_ADD_SIGNED texture combine and the GL_DOT3_RGB[A]
+   * functions.
+   *
+   * Each layer outputs to the TEMP called "output", and reads from
+   * output if it needs to refer to GL_PREVIOUS. (we detect if we are
+   * layer0 so we will read fragment.color for GL_PREVIOUS in that
+   * case)
+   *
+   * We aim to do all the channels together if the same function is
+   * used for RGB as for A.
+   *
+   * We aim to avoid string duplication / allocations during codegen.
+   *
+   * We are careful to only saturate when writing to output.
+   */
+
+  if (!priv->source)
+    return TRUE;
+
+  if (!need_texture_combine_separate (combine_authority))
+    {
+      append_masked_combine (material,
+                             layer,
+                             COGL_BLEND_STRING_CHANNEL_MASK_RGBA,
+                             big_state->texture_combine_rgb_func,
+                             big_state->texture_combine_rgb_src,
+                             big_state->texture_combine_rgb_op);
+    }
+  else if (big_state->texture_combine_rgb_func == GL_DOT3_RGBA)
+    {
+      /* GL_DOT3_RGBA Is a bit weird as a GL_COMBINE_RGB function
+       * since if you use it, it overrides your ALPHA function...
+       */
+      append_masked_combine (material,
+                             layer,
+                             COGL_BLEND_STRING_CHANNEL_MASK_RGBA,
+                             big_state->texture_combine_rgb_func,
+                             big_state->texture_combine_rgb_src,
+                             big_state->texture_combine_rgb_op);
+    }
+  else
+    {
+      append_masked_combine (material,
+                             layer,
+                             COGL_BLEND_STRING_CHANNEL_MASK_RGB,
+                             big_state->texture_combine_rgb_func,
+                             big_state->texture_combine_rgb_src,
+                             big_state->texture_combine_rgb_op);
+      append_masked_combine (material,
+                             layer,
+                             COGL_BLEND_STRING_CHANNEL_MASK_ALPHA,
+                             big_state->texture_combine_alpha_func,
+                             big_state->texture_combine_alpha_src,
+                             big_state->texture_combine_alpha_op);
+    }
+
+  return TRUE;
+}
+
+gboolean
+_cogl_material_backend_arbfp_passthrough (CoglMaterial *material)
+{
+  CoglMaterial *arbfp_authority = get_arbfp_authority (material);
+  CoglMaterialBackendARBfpPrivate *priv =
+    arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
+
+  if (!priv->source)
+    return TRUE;
+
+  g_string_append (priv->source, "MOV output, fragment.color.primary;\n");
+  return TRUE;
+}
+
+static gboolean
+_cogl_material_backend_arbfp_end (CoglMaterial *material,
+                                  unsigned long materials_difference)
+{
+  CoglMaterial *arbfp_authority = get_arbfp_authority (material);
+  CoglMaterialBackendARBfpPrivate *priv =
+    arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
+
+  _COGL_GET_CONTEXT (ctx, FALSE);
+
+  if (priv->source)
+    {
+      GLenum gl_error;
+      COGL_STATIC_COUNTER (backend_arbfp_compile_counter,
+                           "arbfp compile counter",
+                           "Increments each time a new ARBfp "
+                           "program is compiled",
+                           0 /* no application private data */);
+
+      COGL_COUNTER_INC (_cogl_uprof_context, backend_arbfp_compile_counter);
+
+      g_string_append (priv->source, "MOV result.color,output;\n");
+      g_string_append (priv->source, "END\n");
+
+      if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_SHOW_SOURCE))
+        g_message ("material program:\n%s", priv->source->str);
+
+      GE (glGenPrograms (1, &priv->gl_program));
+
+      GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, priv->gl_program));
+
+      while ((gl_error = glGetError ()) != GL_NO_ERROR)
+        ;
+      glProgramString (GL_FRAGMENT_PROGRAM_ARB,
+                       GL_PROGRAM_FORMAT_ASCII_ARB,
+                       priv->source->len,
+                       priv->source->str);
+      if (glGetError () != GL_NO_ERROR)
+        {
+          g_warning ("\n%s\n%s",
+                     priv->source->str,
+                     glGetString (GL_PROGRAM_ERROR_STRING_ARB));
+        }
+
+      priv->source = NULL;
+
+      g_free (priv->sampled);
+      priv->sampled = NULL;
+    }
+  else
+    GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, priv->gl_program));
+
+  _cogl_use_program (COGL_INVALID_HANDLE, COGL_MATERIAL_PROGRAM_TYPE_ARBFP);
+
+  return TRUE;
+}
+
+static void
+_cogl_material_backend_arbfp_material_pre_change_notify (
+                                                   CoglMaterial *material,
+                                                   CoglMaterialState change,
+                                                   const CoglColor *new_color)
+{
+  CoglMaterialBackendARBfpPrivate *priv =
+    material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
+  static const unsigned long fragment_op_changes =
+    COGL_MATERIAL_STATE_LAYERS;
+    /* TODO: COGL_MATERIAL_STATE_FOG */
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  if (material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK &&
+      priv->gl_program &&
+      change & fragment_op_changes)
+    {
+      GE (glDeletePrograms (1, &priv->gl_program));
+      priv->gl_program = 0;
+    }
+}
+
+static gboolean
+invalidate_arbfp_authority_cache_cb (CoglMaterial *material,
+                                     void *user_data)
+{
+  invalidate_arbfp_authority_cache (material);
+  return TRUE;
+}
+
+static void
+_cogl_material_backend_arbfp_material_set_parent_notify (
+                                                CoglMaterial *material)
+{
+  /* Any arbfp authority cache associated with this material or
+   * any of its descendants will now be invalid. */
+  invalidate_arbfp_authority_cache (material);
+
+  _cogl_material_foreach_child (material,
+                                invalidate_arbfp_authority_cache_cb,
+                                NULL);
+}
+
+static void
+_cogl_material_backend_arbfp_layer_pre_change_notify (
+                                                CoglMaterialLayer *layer,
+                                                CoglMaterialLayerState changes)
+{
+  /* TODO: we could be saving snippets of texture combine code along
+   * with each layer and then when a layer changes we would just free
+   * the snippet. */
+  return;
+}
+
+static void
+_cogl_material_backend_arbfp_free_priv (CoglMaterial *material)
+{
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  if (material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK)
+    {
+      CoglMaterialBackendARBfpPrivate *priv =
+        material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
+
+      glDeletePrograms (1, &priv->gl_program);
+      if (priv->sampled)
+        g_free (priv->sampled);
+      g_slice_free (CoglMaterialBackendARBfpPrivate, priv);
+      material->backend_priv_set_mask &= ~COGL_MATERIAL_BACKEND_ARBFP_MASK;
+    }
+}
+
+const CoglMaterialBackend _cogl_material_arbfp_backend =
+{
+  _cogl_material_backend_arbfp_get_max_texture_units,
+  _cogl_material_backend_arbfp_start,
+  _cogl_material_backend_arbfp_add_layer,
+  _cogl_material_backend_arbfp_passthrough,
+  _cogl_material_backend_arbfp_end,
+  _cogl_material_backend_arbfp_material_pre_change_notify,
+  _cogl_material_backend_arbfp_material_set_parent_notify,
+  _cogl_material_backend_arbfp_layer_pre_change_notify,
+  _cogl_material_backend_arbfp_free_priv,
+  NULL
+};
+
diff --git a/clutter/cogl/cogl/cogl-material-fixed-private.h b/clutter/cogl/cogl/cogl-material-fixed-private.h
new file mode 100644 (file)
index 0000000..1af978c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert@linux.intel.com>
+ */
+
+#ifndef __COGL_MATERIAL_FIXED_PRIVATE_H
+#define __COGL_MATERIAL_FIXED_PRIVATE_H
+
+#include "cogl-material-private.h"
+
+const CoglMaterialBackend _cogl_material_fixed_backend;
+
+#endif /* __COGL_MATERIAL_FIXED_PRIVATE_H */
+
diff --git a/clutter/cogl/cogl/cogl-material-fixed.c b/clutter/cogl/cogl/cogl-material-fixed.c
new file mode 100644 (file)
index 0000000..bc2bea1
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * 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.h"
+#include "cogl-internal.h"
+#include "cogl-context.h"
+#include "cogl-handle.h"
+
+#include "cogl-material-private.h"
+#include "cogl-texture-private.h"
+#include "cogl-blend-string.h"
+#include "cogl-profile.h"
+#ifndef HAVE_COGL_GLES
+#include "cogl-program.h"
+#endif
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <string.h>
+
+#ifdef HAVE_COGL_GLES2
+#include "../gles/cogl-gles2-wrapper.h"
+#endif
+
+static int
+_cogl_material_backend_fixed_get_max_texture_units (void)
+{
+  _COGL_GET_CONTEXT (ctx, 0);
+
+  /* This function is called quite often so we cache the value to
+     avoid too many GL calls */
+  if (ctx->max_texture_units == -1)
+    {
+      ctx->max_texture_units = 1;
+      GE (glGetIntegerv (GL_MAX_TEXTURE_UNITS,
+                         &ctx->max_texture_units));
+    }
+
+  return ctx->max_texture_units;
+}
+
+static gboolean
+_cogl_material_backend_fixed_start (CoglMaterial *material,
+                                    int n_layers,
+                                    unsigned long materials_difference)
+{
+  _cogl_use_program (COGL_INVALID_HANDLE, COGL_MATERIAL_PROGRAM_TYPE_FIXED);
+  return TRUE;
+}
+
+static gboolean
+_cogl_material_backend_fixed_add_layer (CoglMaterial *material,
+                                        CoglMaterialLayer *layer,
+                                        unsigned long layers_difference)
+{
+  CoglTextureUnit *unit =
+    _cogl_get_texture_unit (_cogl_material_layer_get_unit_index (layer));
+  int unit_index = unit->index;
+  int n_rgb_func_args;
+  int n_alpha_func_args;
+
+  _COGL_GET_CONTEXT (ctx, FALSE);
+
+  /* XXX: Beware that since we are changing the active texture unit we
+   * must make sure we don't call into other Cogl components that may
+   * temporarily bind texture objects to query/modify parameters since
+   * they will end up binding texture unit 1. See
+   * _cogl_bind_gl_texture_transient for more details.
+   */
+  _cogl_set_active_texture_unit (unit_index);
+
+  if (layers_difference & COGL_MATERIAL_LAYER_STATE_COMBINE)
+    {
+      CoglMaterialLayer *authority =
+        _cogl_material_layer_get_authority (layer,
+                                            COGL_MATERIAL_LAYER_STATE_COMBINE);
+      CoglMaterialLayerBigState *big_state = authority->big_state;
+
+      GE (glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE));
+
+      /* Set the combiner functions... */
+      GE (glTexEnvi (GL_TEXTURE_ENV,
+                     GL_COMBINE_RGB,
+                     big_state->texture_combine_rgb_func));
+      GE (glTexEnvi (GL_TEXTURE_ENV,
+                     GL_COMBINE_ALPHA,
+                     big_state->texture_combine_alpha_func));
+
+      /*
+       * Setup the function arguments...
+       */
+
+      /* For the RGB components... */
+      n_rgb_func_args =
+        _cogl_get_n_args_for_combine_func (big_state->texture_combine_rgb_func);
+
+      GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB,
+                     big_state->texture_combine_rgb_src[0]));
+      GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB,
+                     big_state->texture_combine_rgb_op[0]));
+      if (n_rgb_func_args > 1)
+        {
+          GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB,
+                         big_state->texture_combine_rgb_src[1]));
+          GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB,
+                         big_state->texture_combine_rgb_op[1]));
+        }
+      if (n_rgb_func_args > 2)
+        {
+          GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_RGB,
+                         big_state->texture_combine_rgb_src[2]));
+          GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_RGB,
+                         big_state->texture_combine_rgb_op[2]));
+        }
+
+      /* For the Alpha component */
+      n_alpha_func_args =
+        _cogl_get_n_args_for_combine_func (big_state->texture_combine_alpha_func);
+
+      GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA,
+                     big_state->texture_combine_alpha_src[0]));
+      GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA,
+                     big_state->texture_combine_alpha_op[0]));
+      if (n_alpha_func_args > 1)
+        {
+          GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA,
+                         big_state->texture_combine_alpha_src[1]));
+          GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA,
+                         big_state->texture_combine_alpha_op[1]));
+        }
+      if (n_alpha_func_args > 2)
+        {
+          GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_ALPHA,
+                         big_state->texture_combine_alpha_src[2]));
+          GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA,
+                         big_state->texture_combine_alpha_op[2]));
+        }
+    }
+
+  if (layers_difference & COGL_MATERIAL_LAYER_STATE_COMBINE)
+    {
+      CoglMaterialLayer *authority =
+        _cogl_material_layer_get_authority (layer,
+                                            COGL_MATERIAL_LAYER_STATE_COMBINE);
+      CoglMaterialLayerBigState *big_state = authority->big_state;
+
+      GE (glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
+                      big_state->texture_combine_constant));
+    }
+
+  return TRUE;
+}
+
+static gboolean
+_cogl_material_backend_fixed_end (CoglMaterial *material,
+                                  unsigned long materials_difference)
+{
+  return TRUE;
+}
+
+const CoglMaterialBackend _cogl_material_fixed_backend =
+{
+  _cogl_material_backend_fixed_get_max_texture_units,
+  _cogl_material_backend_fixed_start,
+  _cogl_material_backend_fixed_add_layer,
+  NULL, /* passthrough */
+  _cogl_material_backend_fixed_end,
+  NULL, /* material_change_notify */
+  NULL, /* material_set_parent_notify */
+  NULL, /* layer_change_notify */
+  NULL /* free_priv */
+};
+
diff --git a/clutter/cogl/cogl/cogl-material-glsl-private.h b/clutter/cogl/cogl/cogl-material-glsl-private.h
new file mode 100644 (file)
index 0000000..64557a0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert@linux.intel.com>
+ */
+
+#ifndef __COGL_MATERIAL_GLSL_PRIVATE_H
+#define __COGL_MATERIAL_GLSL_PRIVATE_H
+
+#include "cogl-material-private.h"
+
+const CoglMaterialBackend _cogl_material_glsl_backend;
+
+#endif /* __COGL_MATERIAL_GLSL_PRIVATE_H */
+
diff --git a/clutter/cogl/cogl/cogl-material-glsl.c b/clutter/cogl/cogl/cogl-material-glsl.c
new file mode 100644 (file)
index 0000000..341e86d
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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.h"
+#include "cogl-internal.h"
+#include "cogl-context.h"
+#include "cogl-handle.h"
+
+#include "cogl-material-private.h"
+#ifndef HAVE_COGL_GLES
+#include "cogl-program.h"
+#endif
+
+#include <glib.h>
+
+/*
+ * GL/GLES compatability defines for material thingies:
+ */
+
+#ifdef HAVE_COGL_GLES2
+#include "../gles/cogl-gles2-wrapper.h"
+#endif
+
+static int
+_cogl_material_backend_glsl_get_max_texture_units (void)
+{
+  return _cogl_get_max_texture_image_units ();
+}
+
+static gboolean
+_cogl_material_backend_glsl_start (CoglMaterial *material,
+                                   int n_layers,
+                                   unsigned long materials_difference)
+{
+  _COGL_GET_CONTEXT (ctx, FALSE);
+
+  if (!cogl_features_available (COGL_FEATURE_SHADERS_GLSL))
+    return FALSE;
+
+  /* FIXME: This will likely conflict with the GLES 2 backends use of
+   * glUseProgram.
+   */
+  if (materials_difference & COGL_MATERIAL_STATE_USER_SHADER)
+    {
+      CoglMaterial *authority =
+        _cogl_material_get_authority (material,
+                                      COGL_MATERIAL_STATE_USER_SHADER);
+      CoglHandle program = authority->big_state->user_program;
+
+      if (program == COGL_INVALID_HANDLE)
+        return FALSE; /* XXX: change me when we support code generation here */
+
+      _cogl_use_program (program, COGL_MATERIAL_PROGRAM_TYPE_GLSL);
+      return TRUE;
+    }
+
+  /* TODO: also support code generation */
+
+  return FALSE;
+}
+
+gboolean
+_cogl_material_backend_glsl_add_layer (CoglMaterial *material,
+                                       CoglMaterialLayer *layer,
+                                       unsigned long layers_difference)
+{
+  return TRUE;
+}
+
+gboolean
+_cogl_material_backend_glsl_passthrough (CoglMaterial *material)
+{
+  return TRUE;
+}
+
+gboolean
+_cogl_material_backend_glsl_end (CoglMaterial *material,
+                                 unsigned long materials_difference)
+{
+  return TRUE;
+}
+
+const CoglMaterialBackend _cogl_material_glsl_backend =
+{
+  _cogl_material_backend_glsl_get_max_texture_units,
+  _cogl_material_backend_glsl_start,
+  _cogl_material_backend_glsl_add_layer,
+  _cogl_material_backend_glsl_passthrough,
+  _cogl_material_backend_glsl_end,
+  NULL, /* material_state_change_notify */
+  NULL, /* material_set_parent_notify */
+  NULL, /* layer_state_change_notify */
+  NULL, /* free_priv */
+};
+
index 78c26b6..f57f8f2 100644 (file)
@@ -143,16 +143,38 @@ _cogl_bind_gl_texture_transient (GLenum gl_target,
                                  gboolean is_foreign);
 
 #if defined (HAVE_COGL_GL)
-/* glsl, arbfp, fixed */
+
+/* NB: material->backend is currently a 3bit unsigned int bitfield */
+#define COGL_MATERIAL_BACKEND_GLSL       0
+#define COGL_MATERIAL_BACKEND_GLSL_MASK  (1L<<0)
+#define COGL_MATERIAL_BACKEND_ARBFP      1
+#define COGL_MATERIAL_BACKEND_ARBFP_MASK (1L<<1)
+#define COGL_MATERIAL_BACKEND_FIXED      2
+#define COGL_MATERIAL_BACKEND_FIXED_MASK (1L<<2)
+
 #define COGL_MATERIAL_N_BACKENDS         3
+
 #elif defined (HAVE_COGL_GLES2)
-/* glsl, fixed */
+
+#define COGL_MATERIAL_BACKEND_GLSL       0
+#define COGL_MATERIAL_BACKEND_GLSL_MASK  (1L<<0)
+#define COGL_MATERIAL_BACKEND_FIXED      1
+#define COGL_MATERIAL_BACKEND_FIXED_MASK (1L<<1)
+
 #define COGL_MATERIAL_N_BACKENDS         2
+
 #else /* HAVE_COGL_GLES */
-/* fixed */
+
+#define COGL_MATERIAL_BACKEND_FIXED      0
+#define COGL_MATERIAL_BACKEND_FIXED_MASK (1L<<0)
+
 #define COGL_MATERIAL_N_BACKENDS         1
+
 #endif
 
+#define COGL_MATERIAL_BACKEND_DEFAULT    0
+#define COGL_MATERIAL_BACKEND_UNDEFINED  3
+
 typedef enum
 {
   COGL_MATERIAL_LAYER_STATE_UNIT             = 1L<<0,
@@ -724,6 +746,24 @@ typedef struct _CoglMaterialFlushOptions
   CoglMaterialWrapModeOverrides wrap_mode_overrides;
 } CoglMaterialFlushOptions;
 
+
+void
+_cogl_set_active_texture_unit (int unit_index);
+
+void
+_cogl_delete_gl_texture (GLuint gl_texture);
+
+int
+_cogl_get_max_texture_image_units (void);
+
+
+void
+_cogl_use_program (CoglHandle program_handle, CoglMaterialProgramType type);
+
+unsigned int
+_cogl_get_n_args_for_combine_func (GLint func);
+
+
 void
 _cogl_material_get_colorubv (CoglHandle  handle,
                              guint8     *color);
@@ -758,9 +798,6 @@ _cogl_material_set_user_program (CoglHandle handle,
                                  CoglHandle program);
 
 void
-_cogl_delete_gl_texture (GLuint gl_texture);
-
-void
 _cogl_material_texture_storage_change_notify (CoglHandle texture);
 
 void
@@ -787,5 +824,39 @@ _cogl_material_set_static_breadcrumb (CoglHandle handle,
 unsigned long
 _cogl_material_get_age (CoglHandle handle);
 
+CoglMaterial *
+_cogl_material_get_authority (CoglMaterial *material,
+                              unsigned long difference);
+
+typedef gboolean (*CoglMaterialChildCallback) (CoglMaterial *child,
+                                               void *user_data);
+
+void
+_cogl_material_foreach_child (CoglMaterial *material,
+                              CoglMaterialChildCallback callback,
+                              void *user_data);
+
+unsigned long
+_cogl_material_layer_compare_differences (CoglMaterialLayer *layer0,
+                                          CoglMaterialLayer *layer1);
+
+CoglMaterialLayer *
+_cogl_material_layer_get_authority (CoglMaterialLayer *layer,
+                                    unsigned long difference);
+
+CoglHandle
+_cogl_material_layer_get_texture (CoglMaterialLayer *layer);
+
+typedef gboolean (*CoglMaterialLayerCallback) (CoglMaterialLayer *layer,
+                                               void *user_data);
+
+void
+_cogl_material_foreach_layer (CoglMaterial *material,
+                              CoglMaterialLayerCallback callback,
+                              void *user_data);
+
+int
+_cogl_material_layer_get_unit_index (CoglMaterialLayer *layer);
+
 #endif /* __COGL_MATERIAL_PRIVATE_H */
 
index a600e92..256fa93 100644 (file)
 #define COGL_MATERIAL(X) ((CoglMaterial *)(X))
 #define COGL_MATERIAL_LAYER(X) ((CoglMaterialLayer *)(X))
 
-typedef struct _CoglMaterialBackendARBfpPrivate
-{
-  CoglMaterial *authority_cache;
-  unsigned long authority_cache_age;
-
-  GString *source;
-  GLuint gl_program;
-  gboolean *sampled;
-  int next_constant_id;
-} CoglMaterialBackendARBfpPrivate;
-
 typedef gboolean (*CoglMaterialStateComparitor) (CoglMaterial *authority0,
                                                  CoglMaterial *authority1);
 
@@ -104,54 +93,17 @@ static void _cogl_material_add_layer_difference (CoglMaterial *material,
 static void handle_automatic_blend_enable (CoglMaterial *material,
                                            CoglMaterialState changes);
 
-#if defined (HAVE_COGL_GL)
-
-static const CoglMaterialBackend _cogl_material_glsl_backend;
-static const CoglMaterialBackend _cogl_material_arbfp_backend;
-static const CoglMaterialBackend _cogl_material_fixed_backend;
-static const CoglMaterialBackend *backends[] =
-{
-  /* The fragment processing backends in order of precedence... */
-  &_cogl_material_glsl_backend,
-  &_cogl_material_arbfp_backend,
-  &_cogl_material_fixed_backend
-};
-/* NB: material->backend is currently a 3bit unsigned int bitfield */
-#define COGL_MATERIAL_BACKEND_GLSL       0
-#define COGL_MATERIAL_BACKEND_GLSL_MASK  (1L<<0)
-#define COGL_MATERIAL_BACKEND_ARBFP      1
-#define COGL_MATERIAL_BACKEND_ARBFP_MASK (1L<<1)
-#define COGL_MATERIAL_BACKEND_FIXED      2
-#define COGL_MATERIAL_BACKEND_FIXED_MASK (1L<<2)
-
-#elif defined (HAVE_COGL_GLES2)
-
-static const CoglMaterialBackend _cogl_material_glsl_backend;
-static const CoglMaterialBackend _cogl_material_fixed_backend;
-static const CoglMaterialBackend *backends[] =
-{
-  /* The fragment processing backends in order of precedence... */
-  &_cogl_material_glsl_backend,
-  &_cogl_material_fixed_backend
-};
-#define COGL_MATERIAL_BACKEND_GLSL       0
-#define COGL_MATERIAL_BACKEND_FIXED      1
-
-#else /* HAVE_COGL_GLES */
-
-static const CoglMaterialBackend _cogl_material_fixed_backend;
-static const CoglMaterialBackend *backends[] =
-{
-  /* The fragment processing backends in order of precedence... */
-  &_cogl_material_fixed_backend
-};
-
-#define COGL_MATERIAL_BACKEND_FIXED      0
+static const CoglMaterialBackend *backends[COGL_MATERIAL_N_BACKENDS];
 
+#ifdef COGL_MATERIAL_BACKEND_GLSL
+#include "cogl-material-glsl-private.h"
+#endif
+#ifdef COGL_MATERIAL_BACKEND_ARBFP
+#include "cogl-material-arbfp-private.h"
+#endif
+#ifdef COGL_MATERIAL_BACKEND_FIXED
+#include "cogl-material-fixed-private.h"
 #endif
-
-#define COGL_MATERIAL_BACKEND_DEFAULT    0
-#define COGL_MATERIAL_BACKEND_UNDEFINED  3
 
 COGL_HANDLE_DEFINE (Material, material);
 COGL_HANDLE_DEFINE (MaterialLayer, material_layer);
@@ -218,8 +170,8 @@ _cogl_destroy_texture_units (void)
   g_array_free (ctx->texture_units, TRUE);
 }
 
-static void
-set_active_texture_unit (int unit_index)
+void
+_cogl_set_active_texture_unit (int unit_index)
 {
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
@@ -266,7 +218,7 @@ _cogl_bind_gl_texture_transient (GLenum gl_target,
    * in case the driver doesn't have a sparse data structure for
    * texture units.
    */
-  set_active_texture_unit (1);
+  _cogl_set_active_texture_unit (1);
   unit = _cogl_get_texture_unit (1);
 
   /* NB: If we have previously bound a foreign texture to this texture
@@ -357,6 +309,17 @@ _cogl_material_init_default_material (void)
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  /* Take this opportunity to setup the fragment processing backends... */
+#ifdef COGL_MATERIAL_BACKEND_GLSL
+  backends[COGL_MATERIAL_BACKEND_GLSL] = &_cogl_material_glsl_backend;
+#endif
+#ifdef COGL_MATERIAL_BACKEND_ARBFP
+  backends[COGL_MATERIAL_BACKEND_ARBFP] = &_cogl_material_arbfp_backend;
+#endif
+#ifdef COGL_MATERIAL_BACKEND_FIXED
+  backends[COGL_MATERIAL_BACKEND_FIXED] = &_cogl_material_fixed_backend;
+#endif
+
   material->is_weak = FALSE;
   material->journal_ref_count = 0;
   material->parent = NULL;
@@ -645,7 +608,7 @@ _cogl_material_get_real_blend_enabled (CoglHandle handle)
   return material->real_blend_enable;
 }
 
-static CoglMaterial *
+CoglMaterial *
 _cogl_material_get_authority (CoglMaterial *material,
                               unsigned long difference)
 {
@@ -655,7 +618,7 @@ _cogl_material_get_authority (CoglMaterial *material,
   return authority;
 }
 
-static CoglMaterialLayer *
+CoglMaterialLayer *
 _cogl_material_layer_get_authority (CoglMaterialLayer *layer,
                                     unsigned long difference)
 {
@@ -665,7 +628,7 @@ _cogl_material_layer_get_authority (CoglMaterialLayer *layer,
   return authority;
 }
 
-static int
+int
 _cogl_material_layer_get_unit_index (CoglMaterialLayer *layer)
 {
   CoglMaterialLayer *authority =
@@ -750,14 +713,11 @@ _cogl_material_update_layers_cache (CoglMaterial *material)
   g_warn_if_reached ();
 }
 
-typedef gboolean (*CoglMaterialLayerCallback) (CoglMaterialLayer *layer,
-                                               void *user_data);
-
 /* TODO: add public cogl_material_foreach_layer but instead of passing
  * a CoglMaterialLayer pointer to the callback we should pass a
  * layer_index instead. */
 
-static void
+void
 _cogl_material_foreach_layer (CoglHandle handle,
                               CoglMaterialLayerCallback callback,
                               void *user_data)
@@ -1096,10 +1056,7 @@ _cogl_material_initialize_state (CoglMaterial *dest,
     }
 }
 
-typedef gboolean (*CoglMaterialChildCallback) (CoglMaterial *child,
-                                               void *user_data);
-
-static void
+void
 _cogl_material_foreach_child (CoglMaterial *material,
                               CoglMaterialChildCallback callback,
                               void *user_data)
@@ -1483,8 +1440,8 @@ _cogl_material_backend_layer_change_notify (CoglMaterialLayer *layer,
     }
 }
 
-static unsigned int
-get_n_args_for_combine_func (GLint func)
+unsigned int
+_cogl_get_n_args_for_combine_func (GLint func)
 {
   switch (func)
     {
@@ -1549,7 +1506,7 @@ _cogl_material_layer_initialize_state (CoglMaterialLayer *dest,
       int i;
       GLint func = src->big_state->texture_combine_rgb_func;
       big_state->texture_combine_rgb_func = func;
-      n_args = get_n_args_for_combine_func (func);
+      n_args = _cogl_get_n_args_for_combine_func (func);
       for (i = 0; i < n_args; i++)
         {
           big_state->texture_combine_rgb_src[i] =
@@ -1560,7 +1517,7 @@ _cogl_material_layer_initialize_state (CoglMaterialLayer *dest,
 
       func = src->big_state->texture_combine_alpha_func;
       big_state->texture_combine_alpha_func = func;
-      n_args = get_n_args_for_combine_func (func);
+      n_args = _cogl_get_n_args_for_combine_func (func);
       for (i = 0; i < n_args; i++)
         {
           big_state->texture_combine_alpha_src[i] =
@@ -1911,7 +1868,7 @@ _cogl_material_get_layer (CoglMaterial *material,
   return layer;
 }
 
-static CoglHandle
+CoglHandle
 _cogl_material_layer_get_texture (CoglMaterialLayer *layer)
 {
   CoglMaterialLayer *authority =
@@ -2661,7 +2618,7 @@ _cogl_material_layer_texture_equal (CoglMaterialLayer *authority0,
  * type of some kind then we could have a unified
  * compare_differences() function.
  */
-static unsigned long
+unsigned long
 _cogl_material_layer_compare_differences (CoglMaterialLayer *layer0,
                                           CoglMaterialLayer *layer1)
 {
@@ -2765,7 +2722,7 @@ _cogl_material_layer_combine_state_equal (CoglMaterialLayer *authority0,
     return FALSE;
 
   n_args =
-    get_n_args_for_combine_func (big_state0->texture_combine_rgb_func);
+    _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] !=
@@ -2776,7 +2733,7 @@ _cogl_material_layer_combine_state_equal (CoglMaterialLayer *authority0,
     }
 
   n_args =
-    get_n_args_for_combine_func (big_state0->texture_combine_alpha_func);
+    _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] !=
@@ -5030,7 +4987,7 @@ disable_texture_unit (int unit_index)
 
   if (unit->enabled)
     {
-      set_active_texture_unit (unit_index);
+      _cogl_set_active_texture_unit (unit_index);
       GE (glDisable (unit->current_gl_target));
       unit->enabled = FALSE;
     }
@@ -5088,8 +5045,8 @@ disable_arbfp (void)
 #endif
 }
 
-static void
-use_program (CoglHandle program_handle, CoglMaterialProgramType type)
+void
+_cogl_use_program (CoglHandle program_handle, CoglMaterialProgramType type)
 {
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
@@ -5157,8 +5114,8 @@ use_program (CoglHandle program_handle, CoglMaterialProgramType type)
 
 #if defined (COGL_MATERIAL_BACKEND_GLSL) || \
     defined (COGL_MATERIAL_BACKEND_ARBFP)
-static int
-get_max_texture_image_units (void)
+int
+_cogl_get_max_texture_image_units (void)
 {
   _COGL_GET_CONTEXT (ctx, 0);
 
@@ -5175,1186 +5132,6 @@ get_max_texture_image_units (void)
 }
 #endif
 
-#ifdef COGL_MATERIAL_BACKEND_GLSL
-
-static int
-_cogl_material_backend_glsl_get_max_texture_units (void)
-{
-  return get_max_texture_image_units ();
-}
-
-static gboolean
-_cogl_material_backend_glsl_start (CoglMaterial *material,
-                                   int n_layers,
-                                   unsigned long materials_difference)
-{
-  _COGL_GET_CONTEXT (ctx, FALSE);
-
-  if (!cogl_features_available (COGL_FEATURE_SHADERS_GLSL))
-    return FALSE;
-
-  /* FIXME: This will likely conflict with the GLES 2 backends use of
-   * glUseProgram.
-   */
-  if (materials_difference & COGL_MATERIAL_STATE_USER_SHADER)
-    {
-      CoglMaterial *authority =
-        _cogl_material_get_authority (material,
-                                      COGL_MATERIAL_STATE_USER_SHADER);
-      CoglHandle program = authority->big_state->user_program;
-
-      if (program == COGL_INVALID_HANDLE)
-        return FALSE; /* XXX: change me when we support code generation here */
-
-      use_program (program, COGL_MATERIAL_PROGRAM_TYPE_GLSL);
-      return TRUE;
-    }
-
-  /* TODO: also support code generation */
-
-  return FALSE;
-}
-
-gboolean
-_cogl_material_backend_glsl_add_layer (CoglMaterial *material,
-                                       CoglMaterialLayer *layer,
-                                       unsigned long layers_difference)
-{
-  return TRUE;
-}
-
-gboolean
-_cogl_material_backend_glsl_passthrough (CoglMaterial *material)
-{
-  return TRUE;
-}
-
-gboolean
-_cogl_material_backend_glsl_end (CoglMaterial *material,
-                                 unsigned long materials_difference)
-{
-  return TRUE;
-}
-
-static const CoglMaterialBackend _cogl_material_glsl_backend =
-{
-  _cogl_material_backend_glsl_get_max_texture_units,
-  _cogl_material_backend_glsl_start,
-  _cogl_material_backend_glsl_add_layer,
-  _cogl_material_backend_glsl_passthrough,
-  _cogl_material_backend_glsl_end,
-  NULL, /* material_state_change_notify */
-  NULL, /* material_set_parent_notify */
-  NULL, /* layer_state_change_notify */
-  NULL, /* free_priv */
-};
-
-#endif /* COGL_MATERIAL_BACKEND_GLSL */
-
-#ifdef COGL_MATERIAL_BACKEND_ARBFP
-
-static int
-_cogl_material_backend_arbfp_get_max_texture_units (void)
-{
-  return get_max_texture_image_units ();
-}
-
-typedef struct
-{
-  int i;
-  CoglMaterialLayer **layers;
-} AddLayersToArrayState;
-
-static gboolean
-add_layer_to_array_cb (CoglMaterialLayer *layer,
-                       void *user_data)
-{
-  AddLayersToArrayState *state = user_data;
-  state->layers[state->i++] = layer;
-  return TRUE;
-}
-
-static gboolean
-layers_arbfp_would_differ (CoglMaterialLayer **material0_layers,
-                           CoglMaterialLayer **material1_layers,
-                           int n_layers)
-{
-  int i;
-  /* The layer state that affects arbfp codegen... */
-  unsigned long arbfp_codegen_modifiers =
-    COGL_MATERIAL_LAYER_STATE_COMBINE |
-    COGL_MATERIAL_LAYER_STATE_COMBINE_CONSTANT |
-    COGL_MATERIAL_LAYER_STATE_UNIT |
-    COGL_MATERIAL_LAYER_STATE_TEXTURE;
-
-  for (i = 0; i < n_layers; i++)
-    {
-      CoglMaterialLayer *layer0 = material0_layers[i];
-      CoglMaterialLayer *layer1 = material1_layers[i];
-      unsigned long layer_differences;
-
-      if (layer0 == layer1)
-        continue;
-
-      layer_differences =
-        _cogl_material_layer_compare_differences (layer0, layer1);
-
-      if (layer_differences & arbfp_codegen_modifiers)
-        {
-          /* When it comes to texture differences the only thing that
-           * affects the arbfp is the target enum... */
-          if (layer_differences == COGL_MATERIAL_LAYER_STATE_TEXTURE)
-            {
-              CoglHandle tex0 = _cogl_material_layer_get_texture (layer0);
-              CoglHandle tex1 = _cogl_material_layer_get_texture (layer1);
-              GLenum gl_target0;
-              GLenum gl_target1;
-
-              cogl_texture_get_gl_texture (tex0, NULL, &gl_target0);
-              cogl_texture_get_gl_texture (tex1, NULL, &gl_target1);
-              if (gl_target0 == gl_target1)
-                continue;
-            }
-          return TRUE;
-        }
-    }
-
-  return FALSE;
-}
-
-/* This tries to find the oldest ancestor whos state would generate
- * the same arbfp program as the current material. This is a simple
- * mechanism for reducing the number of arbfp programs we have to
- * generate.
- */
-static CoglMaterial *
-find_arbfp_authority (CoglMaterial *material)
-{
-  CoglMaterial *authority0;
-  CoglMaterial *authority1;
-  int n_layers;
-  CoglMaterialLayer **authority0_layers;
-  CoglMaterialLayer **authority1_layers;
-
-  /* XXX: we'll need to update this when we add fog support to the
-   * arbfp codegen */
-
-  /* Find the first material that modifies state that affects the
-   * arbfp codegen... */
-  authority0 = _cogl_material_get_authority (material,
-                                             COGL_MATERIAL_STATE_LAYERS);
-
-  /* Find the next ancestor after that, that also modifies state
-   * affecting arbfp codegen... */
-  if (authority0->parent)
-    authority1 = _cogl_material_get_authority (authority0->parent,
-                                               COGL_MATERIAL_STATE_LAYERS);
-  else
-    return authority0;
-
-  n_layers = authority0->n_layers;
-
-  for (;;)
-    {
-      AddLayersToArrayState state;
-
-      if (authority0->n_layers != authority1->n_layers)
-        return authority0;
-
-      authority0_layers =
-        g_alloca (sizeof (CoglMaterialLayer *) * n_layers);
-      state.i = 0;
-      state.layers = authority0_layers;
-      _cogl_material_foreach_layer (authority0,
-                                    add_layer_to_array_cb,
-                                    &state);
-
-      authority1_layers =
-        g_alloca (sizeof (CoglMaterialLayer *) * n_layers);
-      state.i = 0;
-      state.layers = authority1_layers;
-      _cogl_material_foreach_layer (authority1,
-                                    add_layer_to_array_cb,
-                                    &state);
-
-      if (layers_arbfp_would_differ (authority0_layers, authority1_layers,
-                                     n_layers))
-        return authority0;
-
-      /* Find the next ancestor after that, that also modifies state
-       * affecting arbfp codegen... */
-
-      if (!authority1->parent)
-        break;
-
-      authority0 = authority1;
-      authority1 = _cogl_material_get_authority (authority1->parent,
-                                                 COGL_MATERIAL_STATE_LAYERS);
-      if (authority1 == authority0)
-        break;
-    }
-
-  return authority1;
-}
-
-static void
-invalidate_arbfp_authority_cache (CoglMaterial *material)
-{
-  if (material->backend_priv_set_mask  & COGL_MATERIAL_BACKEND_ARBFP_MASK)
-    {
-      CoglMaterialBackendARBfpPrivate *priv =
-        material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
-      priv->authority_cache = NULL;
-      priv->authority_cache_age = 0;
-    }
-}
-
-static gboolean
-_cogl_material_backend_arbfp_start (CoglMaterial *material,
-                                    int n_layers,
-                                    unsigned long materials_difference)
-{
-  CoglMaterial *authority;
-  CoglMaterialBackendARBfpPrivate *priv;
-  CoglMaterialBackendARBfpPrivate *authority_priv;
-
-  _COGL_GET_CONTEXT (ctx, FALSE);
-
-  if (!_cogl_features_available_private (COGL_FEATURE_PRIVATE_ARB_FP))
-    return FALSE;
-
-  /* TODO: support fog */
-  if (ctx->fog_enabled)
-    return FALSE;
-
-  /* Note: we allocate ARBfp private state for both the given material
-   * and the authority. (The oldest ancestor whos state will result in
-   * the same program being generated) The former will simply cache a
-   * pointer to the authority and the later will track the arbfp
-   * program that we will generate.
-   */
-
-  if (!(material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK))
-    {
-      material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP] =
-        g_slice_new0 (CoglMaterialBackendARBfpPrivate);
-      material->backend_priv_set_mask |= COGL_MATERIAL_BACKEND_ARBFP_MASK;
-    }
-  priv = material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
-
-  /* XXX: We are making assumptions that we don't yet support
-   * modification of ancestors to optimize the sharing of state in the
-   * material graph. When we start to support this then the arbfp
-   * backend will somehow need to be notified of graph changes that
-   * may invalidate authority_cache pointers.
-   */
-
-  if (priv->authority_cache &&
-      priv->authority_cache_age != _cogl_material_get_age (material))
-    invalidate_arbfp_authority_cache (material);
-
-  if (!priv->authority_cache)
-    {
-      priv->authority_cache = find_arbfp_authority (material);
-      priv->authority_cache_age = _cogl_material_get_age (material);
-    }
-
-  authority = priv->authority_cache;
-  if (!(authority->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK))
-    {
-      authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP] =
-        g_slice_new0 (CoglMaterialBackendARBfpPrivate);
-      authority->backend_priv_set_mask |= COGL_MATERIAL_BACKEND_ARBFP_MASK;
-    }
-  authority_priv = authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
-
-  if (authority_priv->gl_program == 0)
-    {
-      /* We reuse a single grow-only GString for ARBfp code-gen */
-      g_string_set_size (ctx->arbfp_source_buffer, 0);
-      authority_priv->source = ctx->arbfp_source_buffer;
-      g_string_append (authority_priv->source,
-                       "!!ARBfp1.0\n"
-                       "TEMP output;\n"
-                       "TEMP tmp0, tmp1, tmp2, tmp3, tmp4;\n"
-                       "PARAM half = {.5, .5, .5, .5};\n"
-                       "PARAM one = {1, 1, 1, 1};\n"
-                       "PARAM two = {2, 2, 2, 2};\n"
-                       "PARAM minus_one = {-1, -1, -1, -1};\n");
-      authority_priv->sampled = g_new0 (gboolean, n_layers);
-    }
-
-  return TRUE;
-}
-
-static CoglMaterial *
-get_arbfp_authority (CoglMaterial *material)
-{
-  CoglMaterialBackendARBfpPrivate *priv =
-    material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
-
-  g_return_val_if_fail (priv != NULL, NULL);
-
-  return priv->authority_cache;
-}
-
-/* Determines if we need to handle the RGB and A texture combining
- * separately or is the same function used for both channel masks and
- * with the same arguments...
- */
-static gboolean
-need_texture_combine_separate (CoglMaterialLayer *combine_authority)
-{
-  CoglMaterialLayerBigState *big_state = combine_authority->big_state;
-  int n_args;
-  int i;
-
-  if (big_state->texture_combine_rgb_func !=
-      big_state->texture_combine_alpha_func)
-    return TRUE;
-
-  n_args = get_n_args_for_combine_func (big_state->texture_combine_rgb_func);
-
-  for (i = 0; i < n_args; i++)
-    {
-      if (big_state->texture_combine_rgb_src[i] !=
-          big_state->texture_combine_alpha_src[i])
-        return TRUE;
-
-      /*
-       * We can allow some variation of the source operands without
-       * needing a separation...
-       *
-       * "A = REPLACE (CONSTANT[A])" + either of the following...
-       * "RGB = REPLACE (CONSTANT[RGB])"
-       * "RGB = REPLACE (CONSTANT[A])"
-       *
-       * can be combined as:
-       * "RGBA = REPLACE (CONSTANT)" or
-       * "RGBA = REPLACE (CONSTANT[A])" or
-       *
-       * And "A = REPLACE (1-CONSTANT[A])" + either of the following...
-       * "RGB = REPLACE (1-CONSTANT)" or
-       * "RGB = REPLACE (1-CONSTANT[A])"
-       *
-       * can be combined as:
-       * "RGBA = REPLACE (1-CONSTANT)" or
-       * "RGBA = REPLACE (1-CONSTANT[A])"
-       */
-      switch (big_state->texture_combine_alpha_op[i])
-        {
-        case GL_SRC_ALPHA:
-          switch (big_state->texture_combine_rgb_op[i])
-            {
-            case GL_SRC_COLOR:
-            case GL_SRC_ALPHA:
-              break;
-            default:
-              return FALSE;
-            }
-          break;
-        case GL_ONE_MINUS_SRC_ALPHA:
-          switch (big_state->texture_combine_rgb_op[i])
-            {
-            case GL_ONE_MINUS_SRC_COLOR:
-            case GL_ONE_MINUS_SRC_ALPHA:
-              break;
-            default:
-              return FALSE;
-            }
-          break;
-        default:
-          return FALSE;        /* impossible */
-        }
-    }
-
-   return FALSE;
-}
-
-static const char *
-gl_target_to_arbfp_string (GLenum gl_target)
-{
-#ifndef HAVE_COGL_GLES2
-  if (gl_target == GL_TEXTURE_1D)
-    return "1D";
-  else
-#endif
-    if (gl_target == GL_TEXTURE_2D)
-    return "2D";
-#ifdef GL_ARB_texture_rectangle
-  else if (gl_target == GL_TEXTURE_RECTANGLE_ARB)
-    return "RECT";
-#endif
-  else
-    return "2D";
-}
-
-static void
-setup_texture_source (CoglMaterialBackendARBfpPrivate *priv,
-                      int unit_index,
-                      GLenum gl_target)
-{
-  if (!priv->sampled[unit_index])
-    {
-      g_string_append_printf (priv->source,
-                              "TEMP texel%d;\n"
-                              "TEX texel%d,fragment.texcoord[%d],"
-                              "texture[%d],%s;\n",
-                              unit_index,
-                              unit_index,
-                              unit_index,
-                              unit_index,
-                              gl_target_to_arbfp_string (gl_target));
-      priv->sampled[unit_index] = TRUE;
-    }
-}
-
-typedef enum _CoglMaterialBackendARBfpArgType
-{
-  COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE,
-  COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_CONSTANT,
-  COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_TEXTURE
-} CoglMaterialBackendARBfpArgType;
-
-typedef struct _CoglMaterialBackendARBfpArg
-{
-  const char *name;
-
-  CoglMaterialBackendARBfpArgType type;
-
-  /* for type = TEXTURE */
-  int texture_unit;
-  GLenum texture_target;
-
-  /* for type = CONSTANT */
-  int constant_id;
-
-  const char *swizzle;
-
-} CoglMaterialBackendARBfpArg;
-
-static void
-append_arg (GString *source, const CoglMaterialBackendARBfpArg *arg)
-{
-  switch (arg->type)
-    {
-    case COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_TEXTURE:
-      g_string_append_printf (source, "texel%d%s",
-                              arg->texture_unit, arg->swizzle);
-      break;
-    case COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_CONSTANT:
-      g_string_append_printf (source, "constant%d%s",
-                              arg->constant_id, arg->swizzle);
-      break;
-    case COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE:
-      g_string_append_printf (source, "%s%s",
-                              arg->name, arg->swizzle);
-      break;
-    }
-}
-
-/* Note: we are trying to avoid duplicating strings during codegen
- * which is why we have the slightly awkward
- * CoglMaterialBackendARBfpArg mechanism. */
-static void
-setup_arg (CoglMaterial *material,
-           CoglMaterialLayer *layer,
-           CoglBlendStringChannelMask mask,
-           int arg_index,
-           GLint src,
-           GLint op,
-           CoglMaterialBackendARBfpArg *arg)
-{
-  CoglMaterial *arbfp_authority = get_arbfp_authority (material);
-  CoglMaterialBackendARBfpPrivate *priv =
-    arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
-  static const char *tmp_name[3] = { "tmp0", "tmp1", "tmp2" };
-  GLenum gl_target;
-  CoglHandle texture;
-
-  switch (src)
-    {
-    case GL_TEXTURE:
-      arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_TEXTURE;
-      arg->name = "texel%d";
-      arg->texture_unit = _cogl_material_layer_get_unit_index (layer);
-      texture = _cogl_material_layer_get_texture (layer);
-      cogl_texture_get_gl_texture (texture, NULL, &gl_target);
-      setup_texture_source (priv, arg->texture_unit, gl_target);
-      break;
-    case GL_CONSTANT:
-      {
-        unsigned long state = COGL_MATERIAL_LAYER_STATE_COMBINE_CONSTANT;
-        CoglMaterialLayer *authority =
-          _cogl_material_layer_get_authority (layer, state);
-        CoglMaterialLayerBigState *big_state = authority->big_state;
-
-        arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_CONSTANT;
-        arg->name = "constant%d";
-        arg->constant_id = priv->next_constant_id++;
-        g_string_append_printf (priv->source,
-                                "PARAM constant%d = "
-                                "  {%f, %f, %f, %f};\n",
-                                arg->constant_id,
-                                big_state->texture_combine_constant[0],
-                                big_state->texture_combine_constant[1],
-                                big_state->texture_combine_constant[2],
-                                big_state->texture_combine_constant[3]);
-        break;
-      }
-    case GL_PRIMARY_COLOR:
-      arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE;
-      arg->name = "fragment.color.primary";
-      break;
-    case GL_PREVIOUS:
-      arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE;
-      if (_cogl_material_layer_get_unit_index (layer) == 0)
-        arg->name = "fragment.color.primary";
-      else
-        arg->name = "output";
-      break;
-    default: /* GL_TEXTURE0..N */
-      arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_TEXTURE;
-      arg->name = "texture[%d]";
-      arg->texture_unit = src - GL_TEXTURE0;
-      texture = _cogl_material_layer_get_texture (layer);
-      cogl_texture_get_gl_texture (texture, NULL, &gl_target);
-      setup_texture_source (priv, arg->texture_unit, gl_target);
-    }
-
-  arg->swizzle = "";
-
-  switch (op)
-    {
-    case GL_SRC_COLOR:
-      break;
-    case GL_ONE_MINUS_SRC_COLOR:
-      g_string_append_printf (priv->source,
-                              "SUB tmp%d, one, ",
-                              arg_index);
-      append_arg (priv->source, arg);
-      g_string_append_printf (priv->source, ";\n");
-      arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE;
-      arg->name = tmp_name[arg_index];
-      arg->swizzle = "";
-      break;
-    case GL_SRC_ALPHA:
-      /* avoid a swizzle if we know RGB are going to be masked
-       * in the end anyway */
-      if (mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
-        arg->swizzle = ".a";
-      break;
-    case GL_ONE_MINUS_SRC_ALPHA:
-      g_string_append_printf (priv->source,
-                              "SUB tmp%d, one, ",
-                              arg_index);
-      append_arg (priv->source, arg);
-      /* avoid a swizzle if we know RGB are going to be masked
-       * in the end anyway */
-      if (mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
-        g_string_append_printf (priv->source, ".a;\n");
-      else
-        g_string_append_printf (priv->source, ";\n");
-      arg->type = COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_SIMPLE;
-      arg->name = tmp_name[arg_index];
-      break;
-    default:
-      g_error ("Unknown texture combine operator %d", op);
-      break;
-    }
-}
-
-static gboolean
-backend_arbfp_args_equal (CoglMaterialBackendARBfpArg *arg0,
-                          CoglMaterialBackendARBfpArg *arg1)
-{
-  if (arg0->type != arg1->type)
-    return FALSE;
-
-  if (arg0->name != arg1->name &&
-      strcmp (arg0->name, arg1->name) != 0)
-    return FALSE;
-
-  if (arg0->type == COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_TEXTURE &&
-      arg0->texture_unit != arg1->texture_unit)
-    return FALSE;
-  /* Note we don't have to check the target; a texture unit can only
-   * have one target enabled at a time. */
-
-  if (arg0->type == COGL_MATERIAL_BACKEND_ARBFP_ARG_TYPE_CONSTANT &&
-      arg0->constant_id != arg0->constant_id)
-    return FALSE;
-
-  if (arg0->swizzle != arg1->swizzle &&
-      strcmp (arg0->swizzle, arg1->swizzle) != 0)
-    return FALSE;
-
-  return TRUE;
-}
-
-static void
-append_function (CoglMaterial *material,
-                 CoglBlendStringChannelMask mask,
-                 GLint function,
-                 CoglMaterialBackendARBfpArg *args,
-                 int n_args)
-{
-  CoglMaterial *arbfp_authority = get_arbfp_authority (material);
-  CoglMaterialBackendARBfpPrivate *priv =
-    arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
-  const char *mask_name;
-
-  switch (mask)
-    {
-    case COGL_BLEND_STRING_CHANNEL_MASK_RGB:
-      mask_name = ".rgb";
-      break;
-    case COGL_BLEND_STRING_CHANNEL_MASK_ALPHA:
-      mask_name = ".a";
-      break;
-    case COGL_BLEND_STRING_CHANNEL_MASK_RGBA:
-      mask_name = "";
-      break;
-    default:
-      g_error ("Unknown channel mask %d", mask);
-      mask_name = "";
-    }
-
-  switch (function)
-    {
-    case GL_ADD:
-      g_string_append_printf (priv->source, "ADD_SAT output%s, ",
-                              mask_name);
-      break;
-    case GL_MODULATE:
-      /* Note: no need to saturate since we can assume operands
-       * have values in the range [0,1] */
-      g_string_append_printf (priv->source, "MUL output%s, ",
-                              mask_name);
-      break;
-    case GL_REPLACE:
-      /* Note: no need to saturate since we can assume operand
-       * has a value in the range [0,1] */
-      g_string_append_printf (priv->source, "MOV output%s, ",
-                              mask_name);
-      break;
-    case GL_SUBTRACT:
-      g_string_append_printf (priv->source, "SUB_SAT output%s, ",
-                              mask_name);
-      break;
-    case GL_ADD_SIGNED:
-      g_string_append_printf (priv->source, "ADD tmp3%s, ",
-                              mask_name);
-      append_arg (priv->source, &args[0]);
-      g_string_append (priv->source, ", ");
-      append_arg (priv->source, &args[1]);
-      g_string_append (priv->source, ";\n");
-      g_string_append_printf (priv->source, "SUB_SAT output%s, tmp3, half",
-                              mask_name);
-      n_args = 0;
-      break;
-    case GL_DOT3_RGB:
-    /* These functions are the same except that GL_DOT3_RGB never
-     * updates the alpha channel.
-     *
-     * NB: GL_DOT3_RGBA is a bit special because it effectively forces
-     * an RGBA mask and we end up ignoring any separate alpha channel
-     * function.
-     */
-    case GL_DOT3_RGBA:
-      {
-        const char *tmp4 = "tmp4";
-
-        /* The maths for this was taken from Mesa;
-         * apparently:
-         *
-         * tmp3 = 2*src0 - 1
-         * tmp4 = 2*src1 - 1
-         * output = DP3 (tmp3, tmp4)
-         *
-         * is the same as:
-         *
-         * output = 4 * DP3 (src0 - 0.5, src1 - 0.5)
-         */
-
-        g_string_append (priv->source, "MAD tmp3, two, ");
-        append_arg (priv->source, &args[0]);
-        g_string_append (priv->source, ", minus_one;\n");
-
-        if (!backend_arbfp_args_equal (&args[0], &args[1]))
-          {
-            g_string_append (priv->source, "MAD tmp4, two, ");
-            append_arg (priv->source, &args[1]);
-            g_string_append (priv->source, ", minus_one;\n");
-          }
-        else
-          tmp4 = "tmp3";
-
-        g_string_append_printf (priv->source,
-                                "DP3_SAT output%s, tmp3, %s",
-                                mask_name, tmp4);
-        n_args = 0;
-      }
-      break;
-    case GL_INTERPOLATE:
-      /* Note: no need to saturate since we can assume operands
-       * have values in the range [0,1] */
-
-      /* NB: GL_INTERPOLATE = arg0*arg2 + arg1*(1-arg2)
-       * but LRP dst, a, b, c = b*a + c*(1-a) */
-      g_string_append_printf (priv->source, "LRP output%s, ",
-                              mask_name);
-      append_arg (priv->source, &args[2]);
-      g_string_append (priv->source, ", ");
-      append_arg (priv->source, &args[0]);
-      g_string_append (priv->source, ", ");
-      append_arg (priv->source, &args[1]);
-      n_args = 0;
-      break;
-    default:
-      g_error ("Unknown texture combine function %d", function);
-      g_string_append_printf (priv->source, "MUL_SAT output%s, ",
-                              mask_name);
-      n_args = 2;
-      break;
-    }
-
-  if (n_args > 0)
-    append_arg (priv->source, &args[0]);
-  if (n_args > 1)
-    {
-      g_string_append (priv->source, ", ");
-      append_arg (priv->source, &args[1]);
-    }
-  g_string_append (priv->source, ";\n");
-}
-
-static void
-append_masked_combine (CoglMaterial *arbfp_authority,
-                       CoglMaterialLayer *layer,
-                       CoglBlendStringChannelMask mask,
-                       GLint function,
-                       GLint *src,
-                       GLint *op)
-{
-  int i;
-  int n_args;
-  CoglMaterialBackendARBfpArg args[3];
-
-  n_args = get_n_args_for_combine_func (function);
-
-  for (i = 0; i < n_args; i++)
-    {
-      setup_arg (arbfp_authority,
-                 layer,
-                 mask,
-                 i,
-                 src[i],
-                 op[i],
-                 &args[i]);
-    }
-
-  append_function (arbfp_authority,
-                   mask,
-                   function,
-                   args,
-                   n_args);
-}
-
-static gboolean
-_cogl_material_backend_arbfp_add_layer (CoglMaterial *material,
-                                        CoglMaterialLayer *layer,
-                                        unsigned long layers_difference)
-{
-  CoglMaterial *arbfp_authority = get_arbfp_authority (material);
-  CoglMaterialBackendARBfpPrivate *priv =
-    arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
-  CoglMaterialLayer *combine_authority =
-    _cogl_material_layer_get_authority (layer,
-                                        COGL_MATERIAL_LAYER_STATE_COMBINE);
-  CoglMaterialLayerBigState *big_state = combine_authority->big_state;
-
-  /* Notes...
-   *
-   * We are ignoring the issue of texture indirection limits until
-   * someone complains (Ref Section 3.11.6 in the ARB_fragment_program
-   * spec)
-   *
-   * There always five TEMPs named tmp0, tmp1 and tmp2, tmp3 and tmp4
-   * available and these constants: 'one' = {1, 1, 1, 1}, 'half'
-   * {.5, .5, .5, .5}, 'two' = {2, 2, 2, 2}, 'minus_one' = {-1, -1,
-   * -1, -1}
-   *
-   * tmp0-2 are intended for dealing with some of the texture combine
-   * operands (e.g. GL_ONE_MINUS_SRC_COLOR) tmp3/4 are for dealing
-   * with the GL_ADD_SIGNED texture combine and the GL_DOT3_RGB[A]
-   * functions.
-   *
-   * Each layer outputs to the TEMP called "output", and reads from
-   * output if it needs to refer to GL_PREVIOUS. (we detect if we are
-   * layer0 so we will read fragment.color for GL_PREVIOUS in that
-   * case)
-   *
-   * We aim to do all the channels together if the same function is
-   * used for RGB as for A.
-   *
-   * We aim to avoid string duplication / allocations during codegen.
-   *
-   * We are careful to only saturate when writing to output.
-   */
-
-  if (!priv->source)
-    return TRUE;
-
-  if (!need_texture_combine_separate (combine_authority))
-    {
-      append_masked_combine (material,
-                             layer,
-                             COGL_BLEND_STRING_CHANNEL_MASK_RGBA,
-                             big_state->texture_combine_rgb_func,
-                             big_state->texture_combine_rgb_src,
-                             big_state->texture_combine_rgb_op);
-    }
-  else if (big_state->texture_combine_rgb_func == GL_DOT3_RGBA)
-    {
-      /* GL_DOT3_RGBA Is a bit weird as a GL_COMBINE_RGB function
-       * since if you use it, it overrides your ALPHA function...
-       */
-      append_masked_combine (material,
-                             layer,
-                             COGL_BLEND_STRING_CHANNEL_MASK_RGBA,
-                             big_state->texture_combine_rgb_func,
-                             big_state->texture_combine_rgb_src,
-                             big_state->texture_combine_rgb_op);
-    }
-  else
-    {
-      append_masked_combine (material,
-                             layer,
-                             COGL_BLEND_STRING_CHANNEL_MASK_RGB,
-                             big_state->texture_combine_rgb_func,
-                             big_state->texture_combine_rgb_src,
-                             big_state->texture_combine_rgb_op);
-      append_masked_combine (material,
-                             layer,
-                             COGL_BLEND_STRING_CHANNEL_MASK_ALPHA,
-                             big_state->texture_combine_alpha_func,
-                             big_state->texture_combine_alpha_src,
-                             big_state->texture_combine_alpha_op);
-    }
-
-  return TRUE;
-}
-
-gboolean
-_cogl_material_backend_arbfp_passthrough (CoglMaterial *material)
-{
-  CoglMaterial *arbfp_authority = get_arbfp_authority (material);
-  CoglMaterialBackendARBfpPrivate *priv =
-    arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
-
-  if (!priv->source)
-    return TRUE;
-
-  g_string_append (priv->source, "MOV output, fragment.color.primary;\n");
-  return TRUE;
-}
-
-static gboolean
-_cogl_material_backend_arbfp_end (CoglMaterial *material,
-                                  unsigned long materials_difference)
-{
-  CoglMaterial *arbfp_authority = get_arbfp_authority (material);
-  CoglMaterialBackendARBfpPrivate *priv =
-    arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
-
-  _COGL_GET_CONTEXT (ctx, FALSE);
-
-  if (priv->source)
-    {
-      GLenum gl_error;
-      COGL_STATIC_COUNTER (backend_arbfp_compile_counter,
-                           "arbfp compile counter",
-                           "Increments each time a new ARBfp "
-                           "program is compiled",
-                           0 /* no application private data */);
-
-      COGL_COUNTER_INC (_cogl_uprof_context, backend_arbfp_compile_counter);
-
-      g_string_append (priv->source, "MOV result.color,output;\n");
-      g_string_append (priv->source, "END\n");
-
-      if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_SHOW_SOURCE))
-        g_message ("material program:\n%s", priv->source->str);
-
-      GE (glGenPrograms (1, &priv->gl_program));
-
-      GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, priv->gl_program));
-
-      while ((gl_error = glGetError ()) != GL_NO_ERROR)
-        ;
-      glProgramString (GL_FRAGMENT_PROGRAM_ARB,
-                       GL_PROGRAM_FORMAT_ASCII_ARB,
-                       priv->source->len,
-                       priv->source->str);
-      if (glGetError () != GL_NO_ERROR)
-        {
-          g_warning ("\n%s\n%s",
-                     priv->source->str,
-                     glGetString (GL_PROGRAM_ERROR_STRING_ARB));
-        }
-
-      priv->source = NULL;
-
-      g_free (priv->sampled);
-      priv->sampled = NULL;
-    }
-  else
-    GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, priv->gl_program));
-
-  use_program (COGL_INVALID_HANDLE, COGL_MATERIAL_PROGRAM_TYPE_ARBFP);
-
-  return TRUE;
-}
-
-static void
-_cogl_material_backend_arbfp_material_pre_change_notify (
-                                                   CoglMaterial *material,
-                                                   CoglMaterialState change,
-                                                   const CoglColor *new_color)
-{
-  CoglMaterialBackendARBfpPrivate *priv =
-    material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
-  static const unsigned long fragment_op_changes =
-    COGL_MATERIAL_STATE_LAYERS;
-    /* TODO: COGL_MATERIAL_STATE_FOG */
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  if (material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK &&
-      priv->gl_program &&
-      change & fragment_op_changes)
-    {
-      GE (glDeletePrograms (1, &priv->gl_program));
-      priv->gl_program = 0;
-    }
-}
-
-static gboolean
-invalidate_arbfp_authority_cache_cb (CoglMaterial *material,
-                                     void *user_data)
-{
-  invalidate_arbfp_authority_cache (material);
-  return TRUE;
-}
-
-static void
-_cogl_material_backend_arbfp_material_set_parent_notify (
-                                                CoglMaterial *material)
-{
-  /* Any arbfp authority cache associated with this material or
-   * any of its descendants will now be invalid. */
-  invalidate_arbfp_authority_cache (material);
-
-  _cogl_material_foreach_child (material,
-                                invalidate_arbfp_authority_cache_cb,
-                                NULL);
-}
-
-static void
-_cogl_material_backend_arbfp_layer_pre_change_notify (
-                                                CoglMaterialLayer *layer,
-                                                CoglMaterialLayerState changes)
-{
-  /* TODO: we could be saving snippets of texture combine code along
-   * with each layer and then when a layer changes we would just free
-   * the snippet. */
-  return;
-}
-
-static void
-_cogl_material_backend_arbfp_free_priv (CoglMaterial *material)
-{
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  if (material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK)
-    {
-      CoglMaterialBackendARBfpPrivate *priv =
-        material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
-
-      glDeletePrograms (1, &priv->gl_program);
-      if (priv->sampled)
-        g_free (priv->sampled);
-      g_slice_free (CoglMaterialBackendARBfpPrivate, priv);
-      material->backend_priv_set_mask &= ~COGL_MATERIAL_BACKEND_ARBFP_MASK;
-    }
-}
-
-static const CoglMaterialBackend _cogl_material_arbfp_backend =
-{
-  _cogl_material_backend_arbfp_get_max_texture_units,
-  _cogl_material_backend_arbfp_start,
-  _cogl_material_backend_arbfp_add_layer,
-  _cogl_material_backend_arbfp_passthrough,
-  _cogl_material_backend_arbfp_end,
-  _cogl_material_backend_arbfp_material_pre_change_notify,
-  _cogl_material_backend_arbfp_material_set_parent_notify,
-  _cogl_material_backend_arbfp_layer_pre_change_notify,
-  _cogl_material_backend_arbfp_free_priv,
-  NULL
-};
-
-#endif /* COGL_MATERIAL_BACKEND_ARBFP */
-
-static int
-_cogl_material_backend_fixed_get_max_texture_units (void)
-{
-  _COGL_GET_CONTEXT (ctx, 0);
-
-  /* This function is called quite often so we cache the value to
-     avoid too many GL calls */
-  if (ctx->max_texture_units == -1)
-    {
-      ctx->max_texture_units = 1;
-      GE (glGetIntegerv (GL_MAX_TEXTURE_UNITS,
-                         &ctx->max_texture_units));
-    }
-
-  return ctx->max_texture_units;
-}
-
-static gboolean
-_cogl_material_backend_fixed_start (CoglMaterial *material,
-                                    int n_layers,
-                                    unsigned long materials_difference)
-{
-  use_program (COGL_INVALID_HANDLE, COGL_MATERIAL_PROGRAM_TYPE_FIXED);
-  return TRUE;
-}
-
-static gboolean
-_cogl_material_backend_fixed_add_layer (CoglMaterial *material,
-                                        CoglMaterialLayer *layer,
-                                        unsigned long layers_difference)
-{
-  CoglTextureUnit *unit =
-    _cogl_get_texture_unit (_cogl_material_layer_get_unit_index (layer));
-  int unit_index = unit->index;
-  int n_rgb_func_args;
-  int n_alpha_func_args;
-
-  _COGL_GET_CONTEXT (ctx, FALSE);
-
-  /* XXX: Beware that since we are changing the active texture unit we
-   * must make sure we don't call into other Cogl components that may
-   * temporarily bind texture objects to query/modify parameters since
-   * they will end up binding texture unit 1. See
-   * _cogl_bind_gl_texture_transient for more details.
-   */
-  set_active_texture_unit (unit_index);
-
-  if (layers_difference & COGL_MATERIAL_LAYER_STATE_COMBINE)
-    {
-      CoglMaterialLayer *authority =
-        _cogl_material_layer_get_authority (layer,
-                                            COGL_MATERIAL_LAYER_STATE_COMBINE);
-      CoglMaterialLayerBigState *big_state = authority->big_state;
-
-      GE (glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE));
-
-      /* Set the combiner functions... */
-      GE (glTexEnvi (GL_TEXTURE_ENV,
-                     GL_COMBINE_RGB,
-                     big_state->texture_combine_rgb_func));
-      GE (glTexEnvi (GL_TEXTURE_ENV,
-                     GL_COMBINE_ALPHA,
-                     big_state->texture_combine_alpha_func));
-
-      /*
-       * Setup the function arguments...
-       */
-
-      /* For the RGB components... */
-      n_rgb_func_args =
-        get_n_args_for_combine_func (big_state->texture_combine_rgb_func);
-
-      GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB,
-                     big_state->texture_combine_rgb_src[0]));
-      GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB,
-                     big_state->texture_combine_rgb_op[0]));
-      if (n_rgb_func_args > 1)
-        {
-          GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB,
-                         big_state->texture_combine_rgb_src[1]));
-          GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB,
-                         big_state->texture_combine_rgb_op[1]));
-        }
-      if (n_rgb_func_args > 2)
-        {
-          GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_RGB,
-                         big_state->texture_combine_rgb_src[2]));
-          GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_RGB,
-                         big_state->texture_combine_rgb_op[2]));
-        }
-
-      /* For the Alpha component */
-      n_alpha_func_args =
-        get_n_args_for_combine_func (big_state->texture_combine_alpha_func);
-
-      GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA,
-                     big_state->texture_combine_alpha_src[0]));
-      GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA,
-                     big_state->texture_combine_alpha_op[0]));
-      if (n_alpha_func_args > 1)
-        {
-          GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA,
-                         big_state->texture_combine_alpha_src[1]));
-          GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA,
-                         big_state->texture_combine_alpha_op[1]));
-        }
-      if (n_alpha_func_args > 2)
-        {
-          GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_ALPHA,
-                         big_state->texture_combine_alpha_src[2]));
-          GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA,
-                         big_state->texture_combine_alpha_op[2]));
-        }
-    }
-
-  if (layers_difference & COGL_MATERIAL_LAYER_STATE_COMBINE)
-    {
-      CoglMaterialLayer *authority =
-        _cogl_material_layer_get_authority (layer,
-                                            COGL_MATERIAL_LAYER_STATE_COMBINE);
-      CoglMaterialLayerBigState *big_state = authority->big_state;
-
-      GE (glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
-                      big_state->texture_combine_constant));
-    }
-
-  return TRUE;
-}
-
-static gboolean
-_cogl_material_backend_fixed_end (CoglMaterial *material,
-                                  unsigned long materials_difference)
-{
-  return TRUE;
-}
-
-static const CoglMaterialBackend _cogl_material_fixed_backend =
-{
-  _cogl_material_backend_fixed_get_max_texture_units,
-  _cogl_material_backend_fixed_start,
-  _cogl_material_backend_fixed_add_layer,
-  NULL, /* passthrough */
-  _cogl_material_backend_fixed_end,
-  NULL, /* material_change_notify */
-  NULL, /* material_set_parent_notify */
-  NULL, /* layer_change_notify */
-  NULL /* free_priv */
-};
-
 static void
 _cogl_material_layer_get_texture_info (CoglMaterialLayer *layer,
                                        CoglHandle *texture,
@@ -6633,7 +5410,7 @@ flush_layers_common_gl_state_cb (CoglMaterialLayer *layer, void *user_data)
                                              &gl_texture,
                                              &gl_target);
 
-      set_active_texture_unit (unit_index);
+      _cogl_set_active_texture_unit (unit_index);
 
       /* NB: There are several Cogl components and some code in
        * Clutter that will temporarily bind arbitrary GL textures to
@@ -7140,7 +5917,7 @@ _cogl_material_flush_gl_state (CoglHandle handle,
   unit1 = _cogl_get_texture_unit (1);
   if (unit1->enabled && unit1->dirty_gl_texture)
     {
-      set_active_texture_unit (1);
+      _cogl_set_active_texture_unit (1);
       GE (glBindTexture (unit1->current_gl_target, unit1->gl_texture));
       unit1->dirty_gl_texture = FALSE;
     }