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 <http://www.gnu.org/licenses/>.
29 #include "cogl-util.h"
30 #include "cogl-internal.h"
31 #include "cogl-context-private.h"
32 #include "cogl-handle.h"
34 #include "cogl-shader-private.h"
35 #include "cogl-program-private.h"
39 static void _cogl_program_free (CoglProgram *program);
41 COGL_HANDLE_DEFINE (Program, program);
42 COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING (program);
44 /* A CoglProgram is effectively just a list of shaders that will be
45 used together and a set of values for the custom uniforms. No
46 actual GL program is created - instead this is the responsibility
47 of the GLSL material backend. The uniform values are collected in
48 an array and then flushed whenever the material backend requests
52 _cogl_program_free (CoglProgram *program)
56 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
58 /* Unref all of the attached shaders */
59 g_slist_foreach (program->attached_shaders, (GFunc) cogl_handle_unref, NULL);
60 /* Destroy the list */
61 g_slist_free (program->attached_shaders);
63 for (i = 0; i < program->custom_uniforms->len; i++)
65 CoglProgramUniform *uniform =
66 &g_array_index (program->custom_uniforms, CoglProgramUniform, i);
68 g_free (uniform->name);
70 if (uniform->value.count > 1)
71 g_free (uniform->value.v.array);
74 g_array_free (program->custom_uniforms, TRUE);
76 g_slice_free (CoglProgram, program);
80 cogl_create_program (void)
84 program = g_slice_new0 (CoglProgram);
86 program->custom_uniforms =
87 g_array_new (FALSE, FALSE, sizeof (CoglProgramUniform));
90 return _cogl_program_handle_new (program);
94 cogl_program_attach_shader (CoglHandle program_handle,
95 CoglHandle shader_handle)
100 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
102 if (!cogl_is_program (program_handle) || !cogl_is_shader (shader_handle))
105 program = program_handle;
106 shader = shader_handle;
108 /* Only one shader is allowed if the type is ARBfp */
109 if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
110 _COGL_RETURN_IF_FAIL (program->attached_shaders == NULL);
111 else if (shader->language == COGL_SHADER_LANGUAGE_GLSL)
112 _COGL_RETURN_IF_FAIL (_cogl_program_get_language (program) ==
113 COGL_SHADER_LANGUAGE_GLSL);
115 program->attached_shaders
116 = g_slist_prepend (program->attached_shaders,
117 cogl_handle_ref (shader_handle));
123 cogl_program_link (CoglHandle handle)
125 /* There's no point in linking the program here because it will have
126 to be relinked with a different fixed functionality shader
127 whenever the settings change */
131 cogl_program_use (CoglHandle handle)
133 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
135 _COGL_RETURN_IF_FAIL (handle == COGL_INVALID_HANDLE ||
136 cogl_is_program (handle));
138 if (ctx->current_program == 0 && handle != 0)
139 ctx->legacy_state_set++;
140 else if (handle == 0 && ctx->current_program != 0)
141 ctx->legacy_state_set--;
143 if (handle != COGL_INVALID_HANDLE)
144 cogl_handle_ref (handle);
145 if (ctx->current_program != COGL_INVALID_HANDLE)
146 cogl_handle_unref (ctx->current_program);
147 ctx->current_program = handle;
151 cogl_program_get_uniform_location (CoglHandle handle,
152 const char *uniform_name)
155 CoglProgram *program;
156 CoglProgramUniform *uniform;
158 if (!cogl_is_program (handle))
163 /* We can't just ask the GL program object for the uniform location
164 directly because it will change every time the program is linked
165 with a different shader. Instead we make our own mapping of
166 uniform numbers and cache the names */
167 for (i = 0; i < program->custom_uniforms->len; i++)
169 uniform = &g_array_index (program->custom_uniforms,
170 CoglProgramUniform, i);
172 if (!strcmp (uniform->name, uniform_name))
176 /* Create a new uniform with the given name */
177 g_array_set_size (program->custom_uniforms,
178 program->custom_uniforms->len + 1);
179 uniform = &g_array_index (program->custom_uniforms,
181 program->custom_uniforms->len - 1);
183 uniform->name = g_strdup (uniform_name);
184 memset (&uniform->value, 0, sizeof (CoglBoxedValue));
185 uniform->dirty = TRUE;
186 uniform->location_valid = FALSE;
188 return program->custom_uniforms->len - 1;
191 static CoglProgramUniform *
192 cogl_program_modify_uniform (CoglProgram *program,
195 CoglProgramUniform *uniform;
197 _COGL_RETURN_VAL_IF_FAIL (cogl_is_program (program), NULL);
198 _COGL_RETURN_VAL_IF_FAIL (uniform_no >= 0 &&
199 uniform_no < program->custom_uniforms->len,
202 uniform = &g_array_index (program->custom_uniforms,
203 CoglProgramUniform, uniform_no);
204 uniform->dirty = TRUE;
210 cogl_program_uniform_1f (int uniform_no,
213 CoglProgramUniform *uniform;
215 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
217 uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
218 _cogl_boxed_value_set_1f (&uniform->value, value);
222 cogl_program_set_uniform_1f (CoglHandle handle,
223 int uniform_location,
226 CoglProgramUniform *uniform;
228 uniform = cogl_program_modify_uniform (handle, uniform_location);
229 _cogl_boxed_value_set_1f (&uniform->value, value);
233 cogl_program_uniform_1i (int uniform_no,
236 CoglProgramUniform *uniform;
238 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
240 uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
241 _cogl_boxed_value_set_1i (&uniform->value, value);
245 cogl_program_set_uniform_1i (CoglHandle handle,
246 int uniform_location,
249 CoglProgramUniform *uniform;
251 uniform = cogl_program_modify_uniform (handle, uniform_location);
252 _cogl_boxed_value_set_1i (&uniform->value, value);
256 cogl_program_uniform_float (int uniform_no,
261 CoglProgramUniform *uniform;
263 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
265 uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
266 _cogl_boxed_value_set_float (&uniform->value, size, count, value);
270 cogl_program_set_uniform_float (CoglHandle handle,
271 int uniform_location,
276 CoglProgramUniform *uniform;
278 uniform = cogl_program_modify_uniform (handle, uniform_location);
279 _cogl_boxed_value_set_float (&uniform->value, n_components, count, value);
283 cogl_program_uniform_int (int uniform_no,
288 CoglProgramUniform *uniform;
290 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
292 uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
293 _cogl_boxed_value_set_int (&uniform->value, size, count, value);
297 cogl_program_set_uniform_int (CoglHandle handle,
298 int uniform_location,
303 CoglProgramUniform *uniform;
305 uniform = cogl_program_modify_uniform (handle, uniform_location);
306 _cogl_boxed_value_set_int (&uniform->value, n_components, count, value);
310 cogl_program_set_uniform_matrix (CoglHandle handle,
311 int uniform_location,
317 CoglProgramUniform *uniform;
319 uniform = cogl_program_modify_uniform (handle, uniform_location);
320 _cogl_boxed_value_set_matrix (&uniform->value,
328 cogl_program_uniform_matrix (int uniform_no,
334 CoglProgramUniform *uniform;
336 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
338 uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
339 _cogl_boxed_value_set_matrix (&uniform->value, size, count, transpose, value);
342 /* ARBfp local parameters can be referenced like:
345 * ^14char offset (after whitespace is stripped)
348 get_local_param_index (const char *uniform_name)
350 char *input = g_strdup (uniform_name);
356 for (i = 0; input[i] != '\0'; i++)
357 if (input[i] != '_' && input[i] != '\t')
361 _COGL_RETURN_VAL_IF_FAIL (strncmp ("program.local[", input, 14) == 0, -1);
363 _index = g_ascii_strtoull (input + 14, &endptr, 10);
364 _COGL_RETURN_VAL_IF_FAIL (endptr != input + 14, -1);
365 _COGL_RETURN_VAL_IF_FAIL (*endptr == ']', -1);
367 _COGL_RETURN_VAL_IF_FAIL (_index >= 0, -1);
377 _cogl_program_flush_uniform_arbfp (GLint location,
378 CoglBoxedValue *value)
380 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
382 if (value->type != COGL_BOXED_NONE)
384 _COGL_RETURN_IF_FAIL (value->type == COGL_BOXED_FLOAT);
385 _COGL_RETURN_IF_FAIL (value->size == 4);
386 _COGL_RETURN_IF_FAIL (value->count == 1);
388 GE( ctx, glProgramLocalParameter4fv (GL_FRAGMENT_PROGRAM_ARB, location,
389 value->v.float_value) );
393 #endif /* HAVE_COGL_GL */
396 _cogl_program_flush_uniforms (CoglProgram *program,
398 gboolean gl_program_changed)
400 CoglProgramUniform *uniform;
403 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
405 _COGL_RETURN_IF_FAIL (ctx->driver != COGL_DRIVER_GLES1);
407 for (i = 0; i < program->custom_uniforms->len; i++)
409 uniform = &g_array_index (program->custom_uniforms,
410 CoglProgramUniform, i);
412 if (gl_program_changed || uniform->dirty)
414 if (gl_program_changed || !uniform->location_valid)
416 if (_cogl_program_get_language (program) ==
417 COGL_SHADER_LANGUAGE_GLSL)
419 ctx->glGetUniformLocation (gl_program, uniform->name);
422 get_local_param_index (uniform->name);
424 uniform->location_valid = TRUE;
427 /* If the uniform isn't really in the program then there's
428 no need to actually set it */
429 if (uniform->location != -1)
431 switch (_cogl_program_get_language (program))
433 case COGL_SHADER_LANGUAGE_GLSL:
434 _cogl_boxed_value_set_uniform (ctx,
439 case COGL_SHADER_LANGUAGE_ARBFP:
441 _cogl_program_flush_uniform_arbfp (uniform->location,
448 uniform->dirty = FALSE;
454 _cogl_program_get_language (CoglHandle handle)
456 CoglProgram *program = handle;
458 /* Use the language of the first shader */
460 if (program->attached_shaders)
462 CoglShader *shader = program->attached_shaders->data;
463 return shader->language;
466 return COGL_SHADER_LANGUAGE_GLSL;
470 _cogl_program_has_shader_type (CoglProgram *program,
475 for (l = program->attached_shaders; l; l = l->next)
477 CoglShader *shader = l->data;
479 if (shader->type == type)
487 _cogl_program_has_fragment_shader (CoglHandle handle)
489 return _cogl_program_has_shader_type (handle, COGL_SHADER_TYPE_FRAGMENT);
493 _cogl_program_has_vertex_shader (CoglHandle handle)
495 return _cogl_program_has_shader_type (handle, COGL_SHADER_TYPE_VERTEX);