4
* A Low Level GPU Graphics and Utilities API
6
* Copyright (C) 2008,2009,2010 Intel Corporation.
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:
16
* The above copyright notice and this permission notice shall be
17
* included in all copies or substantial portions of the Software.
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
32
#include "cogl-config.h"
36
#include "cogl-util.h"
37
#include "cogl-util-gl-private.h"
38
#include "cogl-context-private.h"
39
#include "cogl-object-private.h"
41
#include "cogl-shader-private.h"
42
#include "cogl-program-private.h"
46
static void _cogl_program_free (CoglProgram *program);
48
COGL_HANDLE_DEFINE (Program, program);
49
COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING (program);
51
/* A CoglProgram is effectively just a list of shaders that will be
52
used together and a set of values for the custom uniforms. No
53
actual GL program is created - instead this is the responsibility
54
of the GLSL material backend. The uniform values are collected in
55
an array and then flushed whenever the material backend requests
59
_cogl_program_free (CoglProgram *program)
63
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
65
/* Unref all of the attached shaders */
66
g_slist_foreach (program->attached_shaders, (GFunc) cogl_handle_unref, NULL);
67
/* Destroy the list */
68
g_slist_free (program->attached_shaders);
70
for (i = 0; i < program->custom_uniforms->len; i++)
72
CoglProgramUniform *uniform =
73
&g_array_index (program->custom_uniforms, CoglProgramUniform, i);
75
g_free (uniform->name);
77
if (uniform->value.count > 1)
78
g_free (uniform->value.v.array);
81
g_array_free (program->custom_uniforms, TRUE);
83
g_slice_free (CoglProgram, program);
87
cogl_create_program (void)
91
program = g_slice_new0 (CoglProgram);
93
program->custom_uniforms =
94
g_array_new (FALSE, FALSE, sizeof (CoglProgramUniform));
97
return _cogl_program_handle_new (program);
101
cogl_program_attach_shader (CoglHandle program_handle,
102
CoglHandle shader_handle)
104
CoglProgram *program;
107
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
109
if (!cogl_is_program (program_handle) || !cogl_is_shader (shader_handle))
112
program = program_handle;
113
shader = shader_handle;
115
/* Only one shader is allowed if the type is ARBfp */
116
if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
117
_COGL_RETURN_IF_FAIL (program->attached_shaders == NULL);
118
else if (shader->language == COGL_SHADER_LANGUAGE_GLSL)
119
_COGL_RETURN_IF_FAIL (_cogl_program_get_language (program) ==
120
COGL_SHADER_LANGUAGE_GLSL);
122
program->attached_shaders
123
= g_slist_prepend (program->attached_shaders,
124
cogl_handle_ref (shader_handle));
130
cogl_program_link (CoglHandle handle)
132
/* There's no point in linking the program here because it will have
133
to be relinked with a different fixed functionality shader
134
whenever the settings change */
138
cogl_program_use (CoglHandle handle)
140
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
142
_COGL_RETURN_IF_FAIL (handle == COGL_INVALID_HANDLE ||
143
cogl_is_program (handle));
145
if (ctx->current_program == 0 && handle != 0)
146
ctx->legacy_state_set++;
147
else if (handle == 0 && ctx->current_program != 0)
148
ctx->legacy_state_set--;
150
if (handle != COGL_INVALID_HANDLE)
151
cogl_handle_ref (handle);
152
if (ctx->current_program != COGL_INVALID_HANDLE)
153
cogl_handle_unref (ctx->current_program);
154
ctx->current_program = handle;
158
cogl_program_get_uniform_location (CoglHandle handle,
159
const char *uniform_name)
162
CoglProgram *program;
163
CoglProgramUniform *uniform;
165
if (!cogl_is_program (handle))
170
/* We can't just ask the GL program object for the uniform location
171
directly because it will change every time the program is linked
172
with a different shader. Instead we make our own mapping of
173
uniform numbers and cache the names */
174
for (i = 0; i < program->custom_uniforms->len; i++)
176
uniform = &g_array_index (program->custom_uniforms,
177
CoglProgramUniform, i);
179
if (!strcmp (uniform->name, uniform_name))
183
/* Create a new uniform with the given name */
184
g_array_set_size (program->custom_uniforms,
185
program->custom_uniforms->len + 1);
186
uniform = &g_array_index (program->custom_uniforms,
188
program->custom_uniforms->len - 1);
190
uniform->name = g_strdup (uniform_name);
191
memset (&uniform->value, 0, sizeof (CoglBoxedValue));
192
uniform->dirty = TRUE;
193
uniform->location_valid = FALSE;
195
return program->custom_uniforms->len - 1;
198
static CoglProgramUniform *
199
cogl_program_modify_uniform (CoglProgram *program,
202
CoglProgramUniform *uniform;
204
_COGL_RETURN_VAL_IF_FAIL (cogl_is_program (program), NULL);
205
_COGL_RETURN_VAL_IF_FAIL (uniform_no >= 0 &&
206
uniform_no < program->custom_uniforms->len,
209
uniform = &g_array_index (program->custom_uniforms,
210
CoglProgramUniform, uniform_no);
211
uniform->dirty = TRUE;
217
cogl_program_uniform_1f (int uniform_no,
220
CoglProgramUniform *uniform;
222
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
224
uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
225
_cogl_boxed_value_set_1f (&uniform->value, value);
229
cogl_program_set_uniform_1f (CoglHandle handle,
230
int uniform_location,
233
CoglProgramUniform *uniform;
235
uniform = cogl_program_modify_uniform (handle, uniform_location);
236
_cogl_boxed_value_set_1f (&uniform->value, value);
240
cogl_program_uniform_1i (int uniform_no,
243
CoglProgramUniform *uniform;
245
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
247
uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
248
_cogl_boxed_value_set_1i (&uniform->value, value);
252
cogl_program_set_uniform_1i (CoglHandle handle,
253
int uniform_location,
256
CoglProgramUniform *uniform;
258
uniform = cogl_program_modify_uniform (handle, uniform_location);
259
_cogl_boxed_value_set_1i (&uniform->value, value);
263
cogl_program_uniform_float (int uniform_no,
268
CoglProgramUniform *uniform;
270
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
272
uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
273
_cogl_boxed_value_set_float (&uniform->value, size, count, value);
277
cogl_program_set_uniform_float (CoglHandle handle,
278
int uniform_location,
283
CoglProgramUniform *uniform;
285
uniform = cogl_program_modify_uniform (handle, uniform_location);
286
_cogl_boxed_value_set_float (&uniform->value, n_components, count, value);
290
cogl_program_uniform_int (int uniform_no,
295
CoglProgramUniform *uniform;
297
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
299
uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
300
_cogl_boxed_value_set_int (&uniform->value, size, count, value);
304
cogl_program_set_uniform_int (CoglHandle handle,
305
int uniform_location,
310
CoglProgramUniform *uniform;
312
uniform = cogl_program_modify_uniform (handle, uniform_location);
313
_cogl_boxed_value_set_int (&uniform->value, n_components, count, value);
317
cogl_program_set_uniform_matrix (CoglHandle handle,
318
int uniform_location,
324
CoglProgramUniform *uniform;
326
uniform = cogl_program_modify_uniform (handle, uniform_location);
327
_cogl_boxed_value_set_matrix (&uniform->value,
335
cogl_program_uniform_matrix (int uniform_no,
341
CoglProgramUniform *uniform;
343
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
345
uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
346
_cogl_boxed_value_set_matrix (&uniform->value, size, count, transpose, value);
349
/* ARBfp local parameters can be referenced like:
352
* ^14char offset (after whitespace is stripped)
355
get_local_param_index (const char *uniform_name)
357
char *input = g_strdup (uniform_name);
363
for (i = 0; input[i] != '\0'; i++)
364
if (input[i] != '_' && input[i] != '\t')
368
_COGL_RETURN_VAL_IF_FAIL (strncmp ("program.local[", input, 14) == 0, -1);
370
_index = g_ascii_strtoull (input + 14, &endptr, 10);
371
_COGL_RETURN_VAL_IF_FAIL (endptr != input + 14, -1);
372
_COGL_RETURN_VAL_IF_FAIL (*endptr == ']', -1);
374
_COGL_RETURN_VAL_IF_FAIL (_index >= 0, -1);
384
_cogl_program_flush_uniform_arbfp (GLint location,
385
CoglBoxedValue *value)
387
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
389
if (value->type != COGL_BOXED_NONE)
391
_COGL_RETURN_IF_FAIL (value->type == COGL_BOXED_FLOAT);
392
_COGL_RETURN_IF_FAIL (value->size == 4);
393
_COGL_RETURN_IF_FAIL (value->count == 1);
395
GE( ctx, glProgramLocalParameter4fv (GL_FRAGMENT_PROGRAM_ARB, location,
396
value->v.float_value) );
400
#endif /* HAVE_COGL_GL */
403
_cogl_program_flush_uniforms (CoglProgram *program,
405
CoglBool gl_program_changed)
407
CoglProgramUniform *uniform;
410
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
412
_COGL_RETURN_IF_FAIL (ctx->driver != COGL_DRIVER_GLES1);
414
for (i = 0; i < program->custom_uniforms->len; i++)
416
uniform = &g_array_index (program->custom_uniforms,
417
CoglProgramUniform, i);
419
if (gl_program_changed || uniform->dirty)
421
if (gl_program_changed || !uniform->location_valid)
423
if (_cogl_program_get_language (program) ==
424
COGL_SHADER_LANGUAGE_GLSL)
426
ctx->glGetUniformLocation (gl_program, uniform->name);
429
get_local_param_index (uniform->name);
431
uniform->location_valid = TRUE;
434
/* If the uniform isn't really in the program then there's
435
no need to actually set it */
436
if (uniform->location != -1)
438
switch (_cogl_program_get_language (program))
440
case COGL_SHADER_LANGUAGE_GLSL:
441
_cogl_boxed_value_set_uniform (ctx,
446
case COGL_SHADER_LANGUAGE_ARBFP:
448
_cogl_program_flush_uniform_arbfp (uniform->location,
455
uniform->dirty = FALSE;
461
_cogl_program_get_language (CoglHandle handle)
463
CoglProgram *program = handle;
465
/* Use the language of the first shader */
467
if (program->attached_shaders)
469
CoglShader *shader = program->attached_shaders->data;
470
return shader->language;
473
return COGL_SHADER_LANGUAGE_GLSL;
477
_cogl_program_has_shader_type (CoglProgram *program,
482
for (l = program->attached_shaders; l; l = l->next)
484
CoglShader *shader = l->data;
486
if (shader->type == type)
494
_cogl_program_has_fragment_shader (CoglHandle handle)
496
return _cogl_program_has_shader_type (handle, COGL_SHADER_TYPE_FRAGMENT);
500
_cogl_program_has_vertex_shader (CoglHandle handle)
502
return _cogl_program_has_shader_type (handle, COGL_SHADER_TYPE_VERTEX);