1 /*
2 * Cogl
3 *
4 * A Low Level GPU Graphics and Utilities API
5 *
6 * Copyright (C) 2008,2009,2010 Intel Corporation.
7 *
8 * Permission is hereby granted, free of charge, to any person
9 * obtaining a copy of this software and associated documentation
10 * files (the "Software"), to deal in the Software without
11 * restriction, including without limitation the rights to use, copy,
12 * modify, merge, publish, distribute, sublicense, and/or sell copies
13 * of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 *
28 *
29 *
30 * Authors:
31 * Robert Bragg <robert@linux.intel.com>
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include "cogl-config.h"
36 #endif
37
38 #include "cogl-context-private.h"
39 #include "cogl-util-gl-private.h"
40 #include "cogl-pipeline-private.h"
41 #include "cogl-pipeline-state-private.h"
42 #include "cogl-pipeline-opengl-private.h"
43
44 #ifdef COGL_PIPELINE_FRAGEND_FIXED
45
46 #include "cogl-context-private.h"
47 #include "cogl-object-private.h"
48
49 #include "cogl-texture-private.h"
50 #include "cogl-blend-string.h"
51 #include "cogl-profile.h"
52 #include "cogl-program-private.h"
53
54 #include <glib.h>
55 #include <glib/gprintf.h>
56 #include <string.h>
57
58 #ifndef GL_TEXTURE_RECTANGLE_ARB
59 #define GL_TEXTURE_RECTANGLE_ARB 0x84F5
60 #endif
61
62 const CoglPipelineFragend _cogl_pipeline_fixed_fragend;
63
64 static void
_cogl_disable_texture_unit(int unit_index)65 _cogl_disable_texture_unit (int unit_index)
66 {
67 CoglTextureUnit *unit;
68
69 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
70
71 unit = &g_array_index (ctx->texture_units, CoglTextureUnit, unit_index);
72
73 if (unit->enabled_gl_target)
74 {
75 _cogl_set_active_texture_unit (unit_index);
76 GE (ctx, glDisable (unit->enabled_gl_target));
77 unit->enabled_gl_target = 0;
78 }
79 }
80
81 static int
get_max_texture_units(void)82 get_max_texture_units (void)
83 {
84 _COGL_GET_CONTEXT (ctx, 0);
85
86 /* This function is called quite often so we cache the value to
87 avoid too many GL calls */
88 if (ctx->max_texture_units == -1)
89 {
90 ctx->max_texture_units = 1;
91 GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_UNITS,
92 &ctx->max_texture_units));
93 }
94
95 return ctx->max_texture_units;
96 }
97
98 static void
_cogl_pipeline_fragend_fixed_start(CoglPipeline * pipeline,int n_layers,unsigned long pipelines_difference)99 _cogl_pipeline_fragend_fixed_start (CoglPipeline *pipeline,
100 int n_layers,
101 unsigned long pipelines_difference)
102 {
103 _cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED);
104 }
105
106 static void
translate_sources(CoglPipeline * pipeline,int n_sources,CoglPipelineCombineSource * source_in,GLenum * source_out)107 translate_sources (CoglPipeline *pipeline,
108 int n_sources,
109 CoglPipelineCombineSource *source_in,
110 GLenum *source_out)
111 {
112 int i;
113
114 /* The texture source numbers specified in the layer combine are the
115 layer numbers so we need to map these to unit indices */
116
117 for (i = 0; i < n_sources; i++)
118 switch (source_in[i])
119 {
120 case COGL_PIPELINE_COMBINE_SOURCE_TEXTURE:
121 source_out[i] = GL_TEXTURE;
122 break;
123
124 case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT:
125 source_out[i] = GL_CONSTANT;
126 break;
127
128 case COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR:
129 source_out[i] = GL_PRIMARY_COLOR;
130 break;
131
132 case COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS:
133 source_out[i] = GL_PREVIOUS;
134 break;
135
136 default:
137 {
138 int layer_num = source_in[i] - COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0;
139 CoglPipelineGetLayerFlags flags = COGL_PIPELINE_GET_LAYER_NO_CREATE;
140 CoglPipelineLayer *layer =
141 _cogl_pipeline_get_layer_with_flags (pipeline, layer_num, flags);
142
143 if (layer == NULL)
144 {
145 static CoglBool warning_seen = FALSE;
146 if (!warning_seen)
147 {
148 g_warning ("The application is trying to use a texture "
149 "combine with a layer number that does not exist");
150 warning_seen = TRUE;
151 }
152 source_out[i] = GL_PREVIOUS;
153 }
154 else
155 source_out[i] = (_cogl_pipeline_layer_get_unit_index (layer) +
156 GL_TEXTURE0);
157 }
158 }
159 }
160
161 static CoglBool
_cogl_pipeline_fragend_fixed_add_layer(CoglPipeline * pipeline,CoglPipelineLayer * layer,unsigned long layers_difference)162 _cogl_pipeline_fragend_fixed_add_layer (CoglPipeline *pipeline,
163 CoglPipelineLayer *layer,
164 unsigned long layers_difference)
165 {
166 CoglTextureUnit *unit =
167 _cogl_get_texture_unit (_cogl_pipeline_layer_get_unit_index (layer));
168 int unit_index = unit->index;
169 int n_rgb_func_args;
170 int n_alpha_func_args;
171
172 _COGL_GET_CONTEXT (ctx, FALSE);
173
174 /* XXX: Beware that since we are changing the active texture unit we
175 * must make sure we don't call into other Cogl components that may
176 * temporarily bind texture objects to query/modify parameters since
177 * they will end up binding texture unit 1. See
178 * _cogl_bind_gl_texture_transient for more details.
179 */
180 _cogl_set_active_texture_unit (unit_index);
181
182 if (G_UNLIKELY (unit_index >= get_max_texture_units ()))
183 {
184 _cogl_disable_texture_unit (unit_index);
185 /* TODO: although this isn't considered an error that
186 * warrants falling back to a different backend we
187 * should print a warning here. */
188 return TRUE;
189 }
190
191 /* Handle enabling or disabling the right texture type */
192 if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE)
193 {
194 CoglTextureType texture_type =
195 _cogl_pipeline_layer_get_texture_type (layer);
196 GLenum gl_target;
197
198 switch (texture_type)
199 {
200 case COGL_TEXTURE_TYPE_2D:
201 gl_target = GL_TEXTURE_2D;
202 break;
203
204 case COGL_TEXTURE_TYPE_3D:
205 gl_target = GL_TEXTURE_3D;
206 break;
207
208 case COGL_TEXTURE_TYPE_RECTANGLE:
209 gl_target = GL_TEXTURE_RECTANGLE_ARB;
210 break;
211
212 default:
213 g_assert_not_reached ();
214 }
215
216 _cogl_set_active_texture_unit (unit_index);
217
218 /* The common GL code handles binding the right texture so we
219 just need to handle enabling and disabling it */
220
221 if (unit->enabled_gl_target != gl_target)
222 {
223 /* Disable the previous target if it's still enabled */
224 if (unit->enabled_gl_target)
225 GE (ctx, glDisable (unit->enabled_gl_target));
226
227 /* Enable the new target */
228 if (!G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)))
229 {
230 GE (ctx, glEnable (gl_target));
231 unit->enabled_gl_target = gl_target;
232 }
233 }
234 }
235 else
236 {
237 /* Even though there may be no difference between the last flushed
238 * texture state and the current layers texture state it may be that the
239 * texture unit has been disabled for some time so we need to assert that
240 * it's enabled now.
241 */
242 if (!G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)) &&
243 unit->enabled_gl_target == 0)
244 {
245 _cogl_set_active_texture_unit (unit_index);
246 GE (ctx, glEnable (unit->gl_target));
247 unit->enabled_gl_target = unit->gl_target;
248 }
249 }
250
251 if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE)
252 {
253 CoglPipelineLayer *authority =
254 _cogl_pipeline_layer_get_authority (layer,
255 COGL_PIPELINE_LAYER_STATE_COMBINE);
256 CoglPipelineLayerBigState *big_state = authority->big_state;
257 GLenum sources[3];
258
259 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE));
260
261 /* Set the combiner functions... */
262 GE (ctx, glTexEnvi (GL_TEXTURE_ENV,
263 GL_COMBINE_RGB,
264 big_state->texture_combine_rgb_func));
265 GE (ctx, glTexEnvi (GL_TEXTURE_ENV,
266 GL_COMBINE_ALPHA,
267 big_state->texture_combine_alpha_func));
268
269 /*
270 * Setup the function arguments...
271 */
272
273 /* For the RGB components... */
274 n_rgb_func_args =
275 _cogl_get_n_args_for_combine_func (big_state->texture_combine_rgb_func);
276
277 translate_sources (pipeline,
278 n_rgb_func_args,
279 big_state->texture_combine_rgb_src,
280 sources);
281
282 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB,
283 sources[0]));
284 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB,
285 big_state->texture_combine_rgb_op[0]));
286 if (n_rgb_func_args > 1)
287 {
288 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB,
289 sources[1]));
290 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB,
291 big_state->texture_combine_rgb_op[1]));
292 }
293 if (n_rgb_func_args > 2)
294 {
295 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_RGB,
296 sources[2]));
297 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_RGB,
298 big_state->texture_combine_rgb_op[2]));
299 }
300
301 /* For the Alpha component */
302 n_alpha_func_args =
303 _cogl_get_n_args_for_combine_func (big_state->texture_combine_alpha_func);
304
305 translate_sources (pipeline,
306 n_alpha_func_args,
307 big_state->texture_combine_alpha_src,
308 sources);
309
310 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA,
311 sources[0]));
312 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA,
313 big_state->texture_combine_alpha_op[0]));
314 if (n_alpha_func_args > 1)
315 {
316 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA,
317 sources[1]));
318 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA,
319 big_state->texture_combine_alpha_op[1]));
320 }
321 if (n_alpha_func_args > 2)
322 {
323 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_ALPHA,
324 sources[2]));
325 GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA,
326 big_state->texture_combine_alpha_op[2]));
327 }
328 }
329
330 if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT)
331 {
332 CoglPipelineLayer *authority =
333 _cogl_pipeline_layer_get_authority
334 (layer, COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT);
335 CoglPipelineLayerBigState *big_state = authority->big_state;
336
337 GE (ctx, glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
338 big_state->texture_combine_constant));
339 }
340
341 return TRUE;
342 }
343
344 static CoglBool
get_highest_unit_index_cb(CoglPipelineLayer * layer,void * user_data)345 get_highest_unit_index_cb (CoglPipelineLayer *layer,
346 void *user_data)
347 {
348 int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
349 int *highest_index = user_data;
350
351 *highest_index = unit_index;
352
353 return TRUE;
354 }
355
356 static CoglBool
_cogl_pipeline_fragend_fixed_end(CoglPipeline * pipeline,unsigned long pipelines_difference)357 _cogl_pipeline_fragend_fixed_end (CoglPipeline *pipeline,
358 unsigned long pipelines_difference)
359 {
360 int highest_unit_index = -1;
361 int i;
362
363 _COGL_GET_CONTEXT (ctx, FALSE);
364
365 _cogl_pipeline_foreach_layer_internal (pipeline,
366 get_highest_unit_index_cb,
367 &highest_unit_index);
368
369 /* Disable additional texture units that may have previously been in use.. */
370 for (i = highest_unit_index + 1; i < ctx->texture_units->len; i++)
371 _cogl_disable_texture_unit (i);
372
373 if (pipelines_difference & COGL_PIPELINE_STATE_FOG)
374 {
375 CoglPipeline *authority =
376 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_FOG);
377 CoglPipelineFogState *fog_state = &authority->big_state->fog_state;
378
379 if (fog_state->enabled)
380 {
381 GLfloat fogColor[4];
382 GLenum gl_mode = GL_LINEAR;
383
384 fogColor[0] = cogl_color_get_red_float (&fog_state->color);
385 fogColor[1] = cogl_color_get_green_float (&fog_state->color);
386 fogColor[2] = cogl_color_get_blue_float (&fog_state->color);
387 fogColor[3] = cogl_color_get_alpha_float (&fog_state->color);
388
389 GE (ctx, glEnable (GL_FOG));
390
391 GE (ctx, glFogfv (GL_FOG_COLOR, fogColor));
392
393 if (ctx->driver == COGL_DRIVER_GLES1)
394 switch (fog_state->mode)
395 {
396 case COGL_FOG_MODE_LINEAR:
397 gl_mode = GL_LINEAR;
398 break;
399 case COGL_FOG_MODE_EXPONENTIAL:
400 gl_mode = GL_EXP;
401 break;
402 case COGL_FOG_MODE_EXPONENTIAL_SQUARED:
403 gl_mode = GL_EXP2;
404 break;
405 }
406 /* TODO: support other modes for GLES2 */
407
408 /* NB: GLES doesn't have glFogi */
409 GE (ctx, glFogf (GL_FOG_MODE, gl_mode));
410 GE (ctx, glHint (GL_FOG_HINT, GL_NICEST));
411
412 GE (ctx, glFogf (GL_FOG_DENSITY, fog_state->density));
413 GE (ctx, glFogf (GL_FOG_START, fog_state->z_near));
414 GE (ctx, glFogf (GL_FOG_END, fog_state->z_far));
415 }
416 else
417 GE (ctx, glDisable (GL_FOG));
418 }
419
420 return TRUE;
421 }
422
423 const CoglPipelineFragend _cogl_pipeline_fixed_fragend =
424 {
425 _cogl_pipeline_fragend_fixed_start,
426 _cogl_pipeline_fragend_fixed_add_layer,
427 NULL, /* passthrough */
428 _cogl_pipeline_fragend_fixed_end,
429 NULL, /* pipeline_change_notify */
430 NULL, /* pipeline_set_parent_notify */
431 NULL, /* layer_change_notify */
432 };
433
434 #endif /* COGL_PIPELINE_FRAGEND_FIXED */
435
436