4 * An object oriented GL/GLES Abstraction/Utility Layer
6 * Copyright (C) 2008,2009,2010 Intel Corporation.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see
20 * <http://www.gnu.org/licenses/>.
25 * Robert Bragg <robert@linux.intel.com>
32 #include "cogl-context-private.h"
33 #include "cogl-pipeline-private.h"
34 #include "cogl-pipeline-state-private.h"
35 #include "cogl-pipeline-opengl-private.h"
37 #ifdef COGL_PIPELINE_FRAGEND_FIXED
39 #include "cogl-internal.h"
40 #include "cogl-context-private.h"
41 #include "cogl-handle.h"
43 #include "cogl-texture-private.h"
44 #include "cogl-blend-string.h"
45 #include "cogl-profile.h"
46 #include "cogl-program-private.h"
49 #include <glib/gprintf.h>
52 #ifndef GL_TEXTURE_RECTANGLE_ARB
53 #define GL_TEXTURE_RECTANGLE_ARB 0x84F5
56 const CoglPipelineFragend _cogl_pipeline_fixed_fragend;
59 _cogl_disable_texture_unit (int unit_index)
61 CoglTextureUnit *unit;
63 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
65 unit = &g_array_index (ctx->texture_units, CoglTextureUnit, unit_index);
67 if (unit->enabled_gl_target)
69 _cogl_set_active_texture_unit (unit_index);
70 GE (ctx, glDisable (unit->enabled_gl_target));
71 unit->enabled_gl_target = 0;
76 get_max_texture_units (void)
78 _COGL_GET_CONTEXT (ctx, 0);
80 /* This function is called quite often so we cache the value to
81 avoid too many GL calls */
82 if (ctx->max_texture_units == -1)
84 ctx->max_texture_units = 1;
85 GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_UNITS,
86 &ctx->max_texture_units));
89 return ctx->max_texture_units;
93 _cogl_pipeline_fragend_fixed_start (CoglPipeline *pipeline,
95 unsigned long pipelines_difference,
96 int n_tex_coord_attribs)
98 CoglHandle user_program;
100 _COGL_GET_CONTEXT (ctx, FALSE);
102 if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
105 if (ctx->driver == COGL_DRIVER_GLES2)
108 /* Fragment snippets are only supported in the GLSL fragend */
109 if (_cogl_pipeline_has_fragment_snippets (pipeline))
112 /* If there is a user program with a fragment shader then the
113 appropriate backend for that language should handle it. We can
114 still use the fixed fragment backend if the program only contains
116 user_program = cogl_pipeline_get_user_program (pipeline);
117 if (user_program != COGL_INVALID_HANDLE &&
118 _cogl_program_has_fragment_shader (user_program))
121 _cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED);
126 translate_sources (CoglPipeline *pipeline,
128 CoglPipelineCombineSource *source_in,
133 /* The texture source numbers specified in the layer combine are the
134 layer numbers so we need to map these to unit indices */
136 for (i = 0; i < n_sources; i++)
137 switch (source_in[i])
139 case COGL_PIPELINE_COMBINE_SOURCE_TEXTURE:
140 source_out[i] = GL_TEXTURE;
143 case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT:
144 source_out[i] = GL_CONSTANT;
147 case COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR:
148 source_out[i] = GL_PRIMARY_COLOR;
151 case COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS:
152 source_out[i] = GL_PREVIOUS;
157 int layer_num = source_in[i] - COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0;
158 CoglPipelineGetLayerFlags flags = COGL_PIPELINE_GET_LAYER_NO_CREATE;
159 CoglPipelineLayer *layer =
160 _cogl_pipeline_get_layer_with_flags (pipeline, layer_num, flags);
164 static gboolean warning_seen = FALSE;
167 g_warning ("The application is trying to use a texture "
168 "combine with a layer number that does not exist");
171 source_out[i] = GL_PREVIOUS;
174 source_out[i] = (_cogl_pipeline_layer_get_unit_index (layer) +
181 _cogl_pipeline_fragend_fixed_add_layer (CoglPipeline *pipeline,
182 CoglPipelineLayer *layer,
183 unsigned long layers_difference)
185 CoglTextureUnit *unit =
186 _cogl_get_texture_unit (_cogl_pipeline_layer_get_unit_index (layer));
187 int unit_index = unit->index;
189 int n_alpha_func_args;
191 _COGL_GET_CONTEXT (ctx, FALSE);
193 /* XXX: Beware that since we are changing the active texture unit we
194 * must make sure we don't call into other Cogl components that may
195 * temporarily bind texture objects to query/modify parameters since
196 * they will end up binding texture unit 1. See
197 * _cogl_bind_gl_texture_transient for more details.
199 _cogl_set_active_texture_unit (unit_index);
201 if (G_UNLIKELY (unit_index >= get_max_texture_units ()))
203 _cogl_disable_texture_unit (unit_index);
204 /* TODO: although this isn't considered an error that
205 * warrants falling back to a different backend we
206 * should print a warning here. */
210 /* Handle enabling or disabling the right texture type */
211 if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE)
213 CoglTextureType texture_type =
214 _cogl_pipeline_layer_get_texture_type (layer);
217 switch (texture_type)
219 case COGL_TEXTURE_TYPE_2D:
220 gl_target = GL_TEXTURE_2D;
223 case COGL_TEXTURE_TYPE_3D:
224 gl_target = GL_TEXTURE_3D;
227 case COGL_TEXTURE_TYPE_RECTANGLE:
228 gl_target = GL_TEXTURE_RECTANGLE_ARB;
232 _cogl_set_active_texture_unit (unit_index);
234 /* The common GL code handles binding the right texture so we
235 just need to handle enabling and disabling it */
237 if (unit->enabled_gl_target != gl_target)
239 /* Disable the previous target if it's still enabled */
240 if (unit->enabled_gl_target)
241 GE (ctx, glDisable (unit->enabled_gl_target));
243 /* Enable the new target */
244 if (!G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)))
246 GE (ctx, glEnable (gl_target));
247 unit->enabled_gl_target = gl_target;
253 /* Even though there may be no difference between the last flushed
254 * texture state and the current layers texture state it may be that the
255 * texture unit has been disabled for some time so we need to assert that
258 if (!G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)) &&
259 unit->enabled_gl_target == 0)
261 _cogl_set_active_texture_unit (unit_index);
262 GE (ctx, glEnable (unit->gl_target));
263 unit->enabled_gl_target = unit->gl_target;
267 if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE)
269 CoglPipelineLayer *authority =
270 _cogl_pipeline_layer_get_authority (layer,
271 COGL_PIPELINE_LAYER_STATE_COMBINE);
272 CoglPipelineLayerBigState *big_state = authority->big_state;
275 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE));
277 /* Set the combiner functions... */
278 GE (ctx, glTexEnvi (GL_TEXTURE_ENV,
280 big_state->texture_combine_rgb_func));
281 GE (ctx, glTexEnvi (GL_TEXTURE_ENV,
283 big_state->texture_combine_alpha_func));
286 * Setup the function arguments...
289 /* For the RGB components... */
291 _cogl_get_n_args_for_combine_func (big_state->texture_combine_rgb_func);
293 translate_sources (pipeline,
295 big_state->texture_combine_rgb_src,
298 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB,
300 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB,
301 big_state->texture_combine_rgb_op[0]));
302 if (n_rgb_func_args > 1)
304 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB,
306 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB,
307 big_state->texture_combine_rgb_op[1]));
309 if (n_rgb_func_args > 2)
311 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_RGB,
313 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_RGB,
314 big_state->texture_combine_rgb_op[2]));
317 /* For the Alpha component */
319 _cogl_get_n_args_for_combine_func (big_state->texture_combine_alpha_func);
321 translate_sources (pipeline,
323 big_state->texture_combine_alpha_src,
326 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA,
328 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA,
329 big_state->texture_combine_alpha_op[0]));
330 if (n_alpha_func_args > 1)
332 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA,
334 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA,
335 big_state->texture_combine_alpha_op[1]));
337 if (n_alpha_func_args > 2)
339 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_ALPHA,
341 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA,
342 big_state->texture_combine_alpha_op[2]));
346 if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT)
348 CoglPipelineLayer *authority =
349 _cogl_pipeline_layer_get_authority
350 (layer, COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT);
351 CoglPipelineLayerBigState *big_state = authority->big_state;
353 GE (ctx, glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
354 big_state->texture_combine_constant));
361 get_highest_unit_index_cb (CoglPipelineLayer *layer,
364 int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
365 int *highest_index = user_data;
367 *highest_index = unit_index;
373 _cogl_pipeline_fragend_fixed_end (CoglPipeline *pipeline,
374 unsigned long pipelines_difference)
376 int highest_unit_index = -1;
379 _COGL_GET_CONTEXT (ctx, FALSE);
381 _cogl_pipeline_foreach_layer_internal (pipeline,
382 get_highest_unit_index_cb,
383 &highest_unit_index);
385 /* Disable additional texture units that may have previously been in use.. */
386 for (i = highest_unit_index + 1; i < ctx->texture_units->len; i++)
387 _cogl_disable_texture_unit (i);
389 if (pipelines_difference & COGL_PIPELINE_STATE_FOG)
391 CoglPipeline *authority =
392 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_FOG);
393 CoglPipelineFogState *fog_state = &authority->big_state->fog_state;
395 if (fog_state->enabled)
398 GLenum gl_mode = GL_LINEAR;
400 fogColor[0] = cogl_color_get_red_float (&fog_state->color);
401 fogColor[1] = cogl_color_get_green_float (&fog_state->color);
402 fogColor[2] = cogl_color_get_blue_float (&fog_state->color);
403 fogColor[3] = cogl_color_get_alpha_float (&fog_state->color);
405 GE (ctx, glEnable (GL_FOG));
407 GE (ctx, glFogfv (GL_FOG_COLOR, fogColor));
409 if (ctx->driver == COGL_DRIVER_GLES1)
410 switch (fog_state->mode)
412 case COGL_FOG_MODE_LINEAR:
415 case COGL_FOG_MODE_EXPONENTIAL:
418 case COGL_FOG_MODE_EXPONENTIAL_SQUARED:
422 /* TODO: support other modes for GLES2 */
424 /* NB: GLES doesn't have glFogi */
425 GE (ctx, glFogf (GL_FOG_MODE, gl_mode));
426 GE (ctx, glHint (GL_FOG_HINT, GL_NICEST));
428 GE (ctx, glFogf (GL_FOG_DENSITY, fog_state->density));
429 GE (ctx, glFogf (GL_FOG_START, fog_state->z_near));
430 GE (ctx, glFogf (GL_FOG_END, fog_state->z_far));
433 GE (ctx, glDisable (GL_FOG));
439 const CoglPipelineFragend _cogl_pipeline_fixed_fragend =
441 _cogl_pipeline_fragend_fixed_start,
442 _cogl_pipeline_fragend_fixed_add_layer,
443 NULL, /* passthrough */
444 _cogl_pipeline_fragend_fixed_end,
445 NULL, /* pipeline_change_notify */
446 NULL, /* pipeline_set_parent_notify */
447 NULL, /* layer_change_notify */
450 #endif /* COGL_PIPELINE_FRAGEND_FIXED */