~elementary-os/elementaryos/os-patch-mutter-bionic

« back to all changes in this revision

Viewing changes to cogl/cogl/deprecated/cogl-program.c

  • Committer: RabbitBot
  • Date: 2018-04-11 14:49:36 UTC
  • Revision ID: rabbitbot@elementary.io-20180411144936-hgymqa9d8d1xfpbh
Initial import, version 3.28.0-2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
31
#ifdef HAVE_CONFIG_H
 
32
#include "cogl-config.h"
 
33
#endif
 
34
 
 
35
 
 
36
#include "cogl-util.h"
 
37
#include "cogl-util-gl-private.h"
 
38
#include "cogl-context-private.h"
 
39
#include "cogl-object-private.h"
 
40
 
 
41
#include "cogl-shader-private.h"
 
42
#include "cogl-program-private.h"
 
43
 
 
44
#include <string.h>
 
45
 
 
46
static void _cogl_program_free (CoglProgram *program);
 
47
 
 
48
COGL_HANDLE_DEFINE (Program, program);
 
49
COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING (program);
 
50
 
 
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
 
56
   it. */
 
57
 
 
58
static void
 
59
_cogl_program_free (CoglProgram *program)
 
60
{
 
61
  int i;
 
62
 
 
63
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
64
 
 
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);
 
69
 
 
70
  for (i = 0; i < program->custom_uniforms->len; i++)
 
71
    {
 
72
      CoglProgramUniform *uniform =
 
73
        &g_array_index (program->custom_uniforms, CoglProgramUniform, i);
 
74
 
 
75
      g_free (uniform->name);
 
76
 
 
77
      if (uniform->value.count > 1)
 
78
        g_free (uniform->value.v.array);
 
79
    }
 
80
 
 
81
  g_array_free (program->custom_uniforms, TRUE);
 
82
 
 
83
  g_slice_free (CoglProgram, program);
 
84
}
 
85
 
 
86
CoglHandle
 
87
cogl_create_program (void)
 
88
{
 
89
  CoglProgram *program;
 
90
 
 
91
  program = g_slice_new0 (CoglProgram);
 
92
 
 
93
  program->custom_uniforms =
 
94
    g_array_new (FALSE, FALSE, sizeof (CoglProgramUniform));
 
95
  program->age = 0;
 
96
 
 
97
  return _cogl_program_handle_new (program);
 
98
}
 
99
 
 
100
void
 
101
cogl_program_attach_shader (CoglHandle program_handle,
 
102
                            CoglHandle shader_handle)
 
103
{
 
104
  CoglProgram *program;
 
105
  CoglShader *shader;
 
106
 
 
107
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
108
 
 
109
  if (!cogl_is_program (program_handle) || !cogl_is_shader (shader_handle))
 
110
    return;
 
111
 
 
112
  program = program_handle;
 
113
  shader = shader_handle;
 
114
 
 
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);
 
121
 
 
122
  program->attached_shaders
 
123
    = g_slist_prepend (program->attached_shaders,
 
124
                       cogl_handle_ref (shader_handle));
 
125
 
 
126
  program->age++;
 
127
}
 
128
 
 
129
void
 
130
cogl_program_link (CoglHandle handle)
 
131
{
 
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 */
 
135
}
 
136
 
 
137
void
 
138
cogl_program_use (CoglHandle handle)
 
139
{
 
140
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
141
 
 
142
  _COGL_RETURN_IF_FAIL (handle == COGL_INVALID_HANDLE ||
 
143
                    cogl_is_program (handle));
 
144
 
 
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--;
 
149
 
 
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;
 
155
}
 
156
 
 
157
int
 
158
cogl_program_get_uniform_location (CoglHandle handle,
 
159
                                   const char *uniform_name)
 
160
{
 
161
  int i;
 
162
  CoglProgram *program;
 
163
  CoglProgramUniform *uniform;
 
164
 
 
165
  if (!cogl_is_program (handle))
 
166
    return -1;
 
167
 
 
168
  program = handle;
 
169
 
 
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++)
 
175
    {
 
176
      uniform = &g_array_index (program->custom_uniforms,
 
177
                                CoglProgramUniform, i);
 
178
 
 
179
      if (!strcmp (uniform->name, uniform_name))
 
180
        return i;
 
181
    }
 
182
 
 
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,
 
187
                            CoglProgramUniform,
 
188
                            program->custom_uniforms->len - 1);
 
189
 
 
190
  uniform->name = g_strdup (uniform_name);
 
191
  memset (&uniform->value, 0, sizeof (CoglBoxedValue));
 
192
  uniform->dirty = TRUE;
 
193
  uniform->location_valid = FALSE;
 
194
 
 
195
  return program->custom_uniforms->len - 1;
 
196
}
 
197
 
 
198
static CoglProgramUniform *
 
199
cogl_program_modify_uniform (CoglProgram *program,
 
200
                             int uniform_no)
 
201
{
 
202
  CoglProgramUniform *uniform;
 
203
 
 
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,
 
207
                            NULL);
 
208
 
 
209
  uniform = &g_array_index (program->custom_uniforms,
 
210
                            CoglProgramUniform, uniform_no);
 
211
  uniform->dirty = TRUE;
 
212
 
 
213
  return uniform;
 
214
}
 
215
 
 
216
void
 
217
cogl_program_uniform_1f (int uniform_no,
 
218
                         float  value)
 
219
{
 
220
  CoglProgramUniform *uniform;
 
221
 
 
222
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
223
 
 
224
  uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
 
225
  _cogl_boxed_value_set_1f (&uniform->value, value);
 
226
}
 
227
 
 
228
void
 
229
cogl_program_set_uniform_1f (CoglHandle handle,
 
230
                             int uniform_location,
 
231
                             float value)
 
232
{
 
233
  CoglProgramUniform *uniform;
 
234
 
 
235
  uniform = cogl_program_modify_uniform (handle, uniform_location);
 
236
  _cogl_boxed_value_set_1f (&uniform->value, value);
 
237
}
 
238
 
 
239
void
 
240
cogl_program_uniform_1i (int uniform_no,
 
241
                         int value)
 
242
{
 
243
  CoglProgramUniform *uniform;
 
244
 
 
245
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
246
 
 
247
  uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
 
248
  _cogl_boxed_value_set_1i (&uniform->value, value);
 
249
}
 
250
 
 
251
void
 
252
cogl_program_set_uniform_1i (CoglHandle handle,
 
253
                             int uniform_location,
 
254
                             int value)
 
255
{
 
256
  CoglProgramUniform *uniform;
 
257
 
 
258
  uniform = cogl_program_modify_uniform (handle, uniform_location);
 
259
  _cogl_boxed_value_set_1i (&uniform->value, value);
 
260
}
 
261
 
 
262
void
 
263
cogl_program_uniform_float (int uniform_no,
 
264
                            int size,
 
265
                            int count,
 
266
                            const float *value)
 
267
{
 
268
  CoglProgramUniform *uniform;
 
269
 
 
270
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
271
 
 
272
  uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
 
273
  _cogl_boxed_value_set_float (&uniform->value, size, count, value);
 
274
}
 
275
 
 
276
void
 
277
cogl_program_set_uniform_float (CoglHandle handle,
 
278
                                int uniform_location,
 
279
                                int n_components,
 
280
                                int count,
 
281
                                const float *value)
 
282
{
 
283
  CoglProgramUniform *uniform;
 
284
 
 
285
  uniform = cogl_program_modify_uniform (handle, uniform_location);
 
286
  _cogl_boxed_value_set_float (&uniform->value, n_components, count, value);
 
287
}
 
288
 
 
289
void
 
290
cogl_program_uniform_int (int uniform_no,
 
291
                          int size,
 
292
                          int count,
 
293
                          const int *value)
 
294
{
 
295
  CoglProgramUniform *uniform;
 
296
 
 
297
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
298
 
 
299
  uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
 
300
  _cogl_boxed_value_set_int (&uniform->value, size, count, value);
 
301
}
 
302
 
 
303
void
 
304
cogl_program_set_uniform_int (CoglHandle handle,
 
305
                              int uniform_location,
 
306
                              int n_components,
 
307
                              int count,
 
308
                              const int *value)
 
309
{
 
310
  CoglProgramUniform *uniform;
 
311
 
 
312
  uniform = cogl_program_modify_uniform (handle, uniform_location);
 
313
  _cogl_boxed_value_set_int (&uniform->value, n_components, count, value);
 
314
}
 
315
 
 
316
void
 
317
cogl_program_set_uniform_matrix (CoglHandle handle,
 
318
                                 int uniform_location,
 
319
                                 int dimensions,
 
320
                                 int count,
 
321
                                 CoglBool transpose,
 
322
                                 const float *value)
 
323
{
 
324
  CoglProgramUniform *uniform;
 
325
 
 
326
  uniform = cogl_program_modify_uniform (handle, uniform_location);
 
327
  _cogl_boxed_value_set_matrix (&uniform->value,
 
328
                                dimensions,
 
329
                                count,
 
330
                                transpose,
 
331
                                value);
 
332
}
 
333
 
 
334
void
 
335
cogl_program_uniform_matrix (int uniform_no,
 
336
                             int size,
 
337
                             int count,
 
338
                             CoglBool transpose,
 
339
                             const float *value)
 
340
{
 
341
  CoglProgramUniform *uniform;
 
342
 
 
343
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
344
 
 
345
  uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no);
 
346
  _cogl_boxed_value_set_matrix (&uniform->value, size, count, transpose, value);
 
347
}
 
348
 
 
349
/* ARBfp local parameters can be referenced like:
 
350
 *
 
351
 * "program.local[5]"
 
352
 *                ^14char offset (after whitespace is stripped)
 
353
 */
 
354
static int
 
355
get_local_param_index (const char *uniform_name)
 
356
{
 
357
  char *input = g_strdup (uniform_name);
 
358
  int i;
 
359
  char *p = input;
 
360
  char *endptr;
 
361
  int _index;
 
362
 
 
363
  for (i = 0; input[i] != '\0'; i++)
 
364
    if (input[i] != '_' && input[i] != '\t')
 
365
      *p++ = input[i];
 
366
  input[i] = '\0';
 
367
 
 
368
  _COGL_RETURN_VAL_IF_FAIL (strncmp ("program.local[", input, 14) == 0, -1);
 
369
 
 
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);
 
373
 
 
374
  _COGL_RETURN_VAL_IF_FAIL (_index >= 0, -1);
 
375
 
 
376
  g_free (input);
 
377
 
 
378
  return _index;
 
379
}
 
380
 
 
381
#ifdef HAVE_COGL_GL
 
382
 
 
383
static void
 
384
_cogl_program_flush_uniform_arbfp (GLint location,
 
385
                                   CoglBoxedValue *value)
 
386
{
 
387
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
388
 
 
389
  if (value->type != COGL_BOXED_NONE)
 
390
    {
 
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);
 
394
 
 
395
      GE( ctx, glProgramLocalParameter4fv (GL_FRAGMENT_PROGRAM_ARB, location,
 
396
                                           value->v.float_value) );
 
397
    }
 
398
}
 
399
 
 
400
#endif /* HAVE_COGL_GL */
 
401
 
 
402
void
 
403
_cogl_program_flush_uniforms (CoglProgram *program,
 
404
                              GLuint gl_program,
 
405
                              CoglBool gl_program_changed)
 
406
{
 
407
  CoglProgramUniform *uniform;
 
408
  int i;
 
409
 
 
410
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
411
 
 
412
  _COGL_RETURN_IF_FAIL (ctx->driver != COGL_DRIVER_GLES1);
 
413
 
 
414
  for (i = 0; i < program->custom_uniforms->len; i++)
 
415
    {
 
416
      uniform = &g_array_index (program->custom_uniforms,
 
417
                                CoglProgramUniform, i);
 
418
 
 
419
      if (gl_program_changed || uniform->dirty)
 
420
        {
 
421
          if (gl_program_changed || !uniform->location_valid)
 
422
            {
 
423
              if (_cogl_program_get_language (program) ==
 
424
                  COGL_SHADER_LANGUAGE_GLSL)
 
425
                uniform->location =
 
426
                  ctx->glGetUniformLocation (gl_program, uniform->name);
 
427
              else
 
428
                uniform->location =
 
429
                  get_local_param_index (uniform->name);
 
430
 
 
431
              uniform->location_valid = TRUE;
 
432
            }
 
433
 
 
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)
 
437
            {
 
438
              switch (_cogl_program_get_language (program))
 
439
                {
 
440
                case COGL_SHADER_LANGUAGE_GLSL:
 
441
                  _cogl_boxed_value_set_uniform (ctx,
 
442
                                                 uniform->location,
 
443
                                                 &uniform->value);
 
444
                  break;
 
445
 
 
446
                case COGL_SHADER_LANGUAGE_ARBFP:
 
447
#ifdef HAVE_COGL_GL
 
448
                  _cogl_program_flush_uniform_arbfp (uniform->location,
 
449
                                                     &uniform->value);
 
450
#endif
 
451
                  break;
 
452
                }
 
453
            }
 
454
 
 
455
          uniform->dirty = FALSE;
 
456
        }
 
457
    }
 
458
}
 
459
 
 
460
CoglShaderLanguage
 
461
_cogl_program_get_language (CoglHandle handle)
 
462
{
 
463
  CoglProgram *program = handle;
 
464
 
 
465
  /* Use the language of the first shader */
 
466
 
 
467
  if (program->attached_shaders)
 
468
    {
 
469
      CoglShader *shader = program->attached_shaders->data;
 
470
      return shader->language;
 
471
    }
 
472
  else
 
473
    return COGL_SHADER_LANGUAGE_GLSL;
 
474
}
 
475
 
 
476
static CoglBool
 
477
_cogl_program_has_shader_type (CoglProgram *program,
 
478
                               CoglShaderType type)
 
479
{
 
480
  GSList *l;
 
481
 
 
482
  for (l = program->attached_shaders; l; l = l->next)
 
483
    {
 
484
      CoglShader *shader = l->data;
 
485
 
 
486
      if (shader->type == type)
 
487
        return TRUE;
 
488
    }
 
489
 
 
490
  return FALSE;
 
491
}
 
492
 
 
493
CoglBool
 
494
_cogl_program_has_fragment_shader (CoglHandle handle)
 
495
{
 
496
  return _cogl_program_has_shader_type (handle, COGL_SHADER_TYPE_FRAGMENT);
 
497
}
 
498
 
 
499
CoglBool
 
500
_cogl_program_has_vertex_shader (CoglHandle handle)
 
501
{
 
502
  return _cogl_program_has_shader_type (handle, COGL_SHADER_TYPE_VERTEX);
 
503
}