diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index b3d53831d..070d62cbe 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -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/cogl/cogl-material-arbfp-private.h b/cogl/cogl-material-arbfp-private.h
new file mode 100644
index 000000000..f3c472f86
--- /dev/null
+++ b/cogl/cogl-material-arbfp-private.h
@@ -0,0 +1,36 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ *
+ *
+ *
+ * Authors:
+ * Robert Bragg
+ */
+
+#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/cogl/cogl-material-arbfp.c b/cogl/cogl-material-arbfp.c
new file mode 100644
index 000000000..bbc510e4a
--- /dev/null
+++ b/cogl/cogl-material-arbfp.c
@@ -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
+ * .
+ *
+ *
+ *
+ * Authors:
+ * Robert Bragg
+ */
+
+#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
+#include
+#include
+
+/*
+ * 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/cogl/cogl-material-fixed-private.h b/cogl/cogl-material-fixed-private.h
new file mode 100644
index 000000000..1af978cde
--- /dev/null
+++ b/cogl/cogl-material-fixed-private.h
@@ -0,0 +1,36 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ *
+ *
+ *
+ * Authors:
+ * Robert Bragg
+ */
+
+#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/cogl/cogl-material-fixed.c b/cogl/cogl-material-fixed.c
new file mode 100644
index 000000000..bc2bea1ec
--- /dev/null
+++ b/cogl/cogl-material-fixed.c
@@ -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
+ * .
+ *
+ *
+ *
+ * Authors:
+ * Robert Bragg
+ */
+
+#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
+#include
+#include
+
+#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/cogl/cogl-material-glsl-private.h b/cogl/cogl-material-glsl-private.h
new file mode 100644
index 000000000..64557a022
--- /dev/null
+++ b/cogl/cogl-material-glsl-private.h
@@ -0,0 +1,36 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ *
+ *
+ *
+ * Authors:
+ * Robert Bragg
+ */
+
+#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/cogl/cogl-material-glsl.c b/cogl/cogl-material-glsl.c
new file mode 100644
index 000000000..341e86d4a
--- /dev/null
+++ b/cogl/cogl-material-glsl.c
@@ -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
+ * .
+ *
+ *
+ *
+ * Authors:
+ * Robert Bragg
+ */
+
+#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
+
+/*
+ * 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 */
+};
+
diff --git a/cogl/cogl-material-private.h b/cogl/cogl-material-private.h
index 78c26b68c..f57f8f263 100644
--- a/cogl/cogl-material-private.h
+++ b/cogl/cogl-material-private.h
@@ -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);
@@ -757,9 +797,6 @@ void
_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);
@@ -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 */
diff --git a/cogl/cogl-material.c b/cogl/cogl-material.c
index a600e9284..256fa93eb 100644
--- a/cogl/cogl-material.c
+++ b/cogl/cogl-material.c
@@ -80,17 +80,6 @@
#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;
}