From 17731b3af1def4981404db85d244e3c8fbd9d29b Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 15 Jun 2010 16:44:52 +0100 Subject: [PATCH] material: Split the fragment processing backends out 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. --- cogl/Makefile.am | 6 + cogl/cogl-material-arbfp-private.h | 36 + cogl/cogl-material-arbfp.c | 1029 ++++++++++++++++++++++ cogl/cogl-material-fixed-private.h | 36 + cogl/cogl-material-fixed.c | 201 +++++ cogl/cogl-material-glsl-private.h | 36 + cogl/cogl-material-glsl.c | 123 +++ cogl/cogl-material-private.h | 83 +- cogl/cogl-material.c | 1309 +--------------------------- 9 files changed, 1587 insertions(+), 1272 deletions(-) create mode 100644 cogl/cogl-material-arbfp-private.h create mode 100644 cogl/cogl-material-arbfp.c create mode 100644 cogl/cogl-material-fixed-private.h create mode 100644 cogl/cogl-material-fixed.c create mode 100644 cogl/cogl-material-glsl-private.h create mode 100644 cogl/cogl-material-glsl.c 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; }