1/* GSK - The GTK Scene Kit
2 *
3 * Copyright 2020, Red Hat Inc
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * GskGLShader:
21 *
22 * A `GskGLShader` is a snippet of GLSL that is meant to run in the
23 * fragment shader of the rendering pipeline.
24 *
25 * A fragment shader gets the coordinates being rendered as input and
26 * produces the pixel values for that particular pixel. Additionally,
27 * the shader can declare a set of other input arguments, called
28 * uniforms (as they are uniform over all the calls to your shader in
29 * each instance of use). A shader can also receive up to 4
30 * textures that it can use as input when producing the pixel data.
31 *
32 * `GskGLShader` is usually used with gtk_snapshot_push_gl_shader()
33 * to produce a [class@Gsk.GLShaderNode] in the rendering hierarchy,
34 * and then its input textures are constructed by rendering the child
35 * nodes to textures before rendering the shader node itself. (You can
36 * pass texture nodes as children if you want to directly use a texture
37 * as input).
38 *
39 * The actual shader code is GLSL code that gets combined with
40 * some other code into the fragment shader. Since the exact
41 * capabilities of the GPU driver differs between different OpenGL
42 * drivers and hardware, GTK adds some defines that you can use
43 * to ensure your GLSL code runs on as many drivers as it can.
44 *
45 * If the OpenGL driver is GLES, then the shader language version
46 * is set to 100, and GSK_GLES will be defined in the shader.
47 *
48 * Otherwise, if the OpenGL driver does not support the 3.2 core profile,
49 * then the shader will run with language version 110 for GL2 and 130 for GL3,
50 * and GSK_LEGACY will be defined in the shader.
51 *
52 * If the OpenGL driver supports the 3.2 code profile, it will be used,
53 * the shader language version is set to 150, and GSK_GL3 will be defined
54 * in the shader.
55 *
56 * The main function the shader must implement is:
57 *
58 * ```glsl
59 * void mainImage(out vec4 fragColor,
60 * in vec2 fragCoord,
61 * in vec2 resolution,
62 * in vec2 uv)
63 * ```
64 *
65 * Where the input @fragCoord is the coordinate of the pixel we're
66 * currently rendering, relative to the boundary rectangle that was
67 * specified in the `GskGLShaderNode`, and @resolution is the width and
68 * height of that rectangle. This is in the typical GTK coordinate
69 * system with the origin in the top left. @uv contains the u and v
70 * coordinates that can be used to index a texture at the
71 * corresponding point. These coordinates are in the [0..1]x[0..1]
72 * region, with 0, 0 being in the lower left corder (which is typical
73 * for OpenGL).
74 *
75 * The output @fragColor should be a RGBA color (with
76 * premultiplied alpha) that will be used as the output for the
77 * specified pixel location. Note that this output will be
78 * automatically clipped to the clip region of the glshader node.
79 *
80 * In addition to the function arguments the shader can define
81 * up to 4 uniforms for textures which must be called u_textureN
82 * (i.e. u_texture1 to u_texture4) as well as any custom uniforms
83 * you want of types int, uint, bool, float, vec2, vec3 or vec4.
84 *
85 * All textures sources contain premultiplied alpha colors, but if some
86 * there are outer sources of colors there is a gsk_premultiply() helper
87 * to compute premultiplication when needed.
88 *
89 * Note that GTK parses the uniform declarations, so each uniform has to
90 * be on a line by itself with no other code, like so:
91 *
92 * ```glsl
93 * uniform float u_time;
94 * uniform vec3 u_color;
95 * uniform sampler2D u_texture1;
96 * uniform sampler2D u_texture2;
97 * ```
98 *
99 * GTK uses the "gsk" namespace in the symbols it uses in the
100 * shader, so your code should not use any symbols with the prefix gsk
101 * or GSK. There are some helper functions declared that you can use:
102 *
103 * ```glsl
104 * vec4 GskTexture(sampler2D sampler, vec2 texCoords);
105 * ```
106 *
107 * This samples a texture (e.g. u_texture1) at the specified
108 * coordinates, and containes some helper ifdefs to ensure that
109 * it works on all OpenGL versions.
110 *
111 * You can compile the shader yourself using [method@Gsk.GLShader.compile],
112 * otherwise the GSK renderer will do it when it handling the glshader
113 * node. If errors occurs, the returned @error will include the glsl
114 * sources, so you can see what GSK was passing to the compiler. You
115 * can also set GSK_DEBUG=shaders in the environment to see the sources
116 * and other relevant information about all shaders that GSK is handling.
117 *
118 * # An example shader
119 *
120 * ```glsl
121 * uniform float position;
122 * uniform sampler2D u_texture1;
123 * uniform sampler2D u_texture2;
124 *
125 * void mainImage(out vec4 fragColor,
126 * in vec2 fragCoord,
127 * in vec2 resolution,
128 * in vec2 uv) {
129 * vec4 source1 = GskTexture(u_texture1, uv);
130 * vec4 source2 = GskTexture(u_texture2, uv);
131 *
132 * fragColor = position * source1 + (1.0 - position) * source2;
133 * }
134 * ```
135 */
136
137#include "config.h"
138#include "gskglshader.h"
139#include "gskglshaderprivate.h"
140#include "gskdebugprivate.h"
141
142#include "gl/gskglrendererprivate.h"
143
144static GskGLUniformType
145uniform_type_from_glsl (const char *str)
146{
147 if (strcmp (s1: str, s2: "int") == 0)
148 return GSK_GL_UNIFORM_TYPE_INT;
149 if (strcmp (s1: str, s2: "uint") == 0)
150 return GSK_GL_UNIFORM_TYPE_UINT;
151 if (strcmp (s1: str, s2: "bool") == 0)
152 return GSK_GL_UNIFORM_TYPE_BOOL;
153 if (strcmp (s1: str, s2: "float") == 0)
154 return GSK_GL_UNIFORM_TYPE_FLOAT;
155 if (strcmp (s1: str, s2: "vec2") == 0)
156 return GSK_GL_UNIFORM_TYPE_VEC2;
157 if (strcmp (s1: str, s2: "vec3") == 0)
158 return GSK_GL_UNIFORM_TYPE_VEC3;
159 if (strcmp (s1: str, s2: "vec4") == 0)
160 return GSK_GL_UNIFORM_TYPE_VEC4;
161
162 return GSK_GL_UNIFORM_TYPE_NONE;
163}
164
165static const char *
166uniform_type_name (GskGLUniformType type)
167{
168 switch (type)
169 {
170 case GSK_GL_UNIFORM_TYPE_FLOAT:
171 return "float";
172
173 case GSK_GL_UNIFORM_TYPE_INT:
174 return "int";
175
176 case GSK_GL_UNIFORM_TYPE_UINT:
177 return "uint";
178
179 case GSK_GL_UNIFORM_TYPE_BOOL:
180 return "bool";
181
182 case GSK_GL_UNIFORM_TYPE_VEC2:
183 return "vec2";
184
185 case GSK_GL_UNIFORM_TYPE_VEC3:
186 return "vec3";
187
188 case GSK_GL_UNIFORM_TYPE_VEC4:
189 return "vec4";
190
191 case GSK_GL_UNIFORM_TYPE_NONE:
192 default:
193 g_assert_not_reached ();
194 return NULL;
195 }
196}
197
198static int
199uniform_type_size (GskGLUniformType type)
200{
201 switch (type)
202 {
203 case GSK_GL_UNIFORM_TYPE_FLOAT:
204 return sizeof (float);
205
206 case GSK_GL_UNIFORM_TYPE_INT:
207 return sizeof (gint32);
208
209 case GSK_GL_UNIFORM_TYPE_UINT:
210 case GSK_GL_UNIFORM_TYPE_BOOL:
211 return sizeof (guint32);
212
213 case GSK_GL_UNIFORM_TYPE_VEC2:
214 return sizeof (float) * 2;
215
216 case GSK_GL_UNIFORM_TYPE_VEC3:
217 return sizeof (float) * 3;
218
219 case GSK_GL_UNIFORM_TYPE_VEC4:
220 return sizeof (float) * 4;
221
222 case GSK_GL_UNIFORM_TYPE_NONE:
223 default:
224 g_assert_not_reached ();
225 return 0;
226 }
227}
228
229struct _GskGLShader
230{
231 GObject parent_instance;
232 GBytes *source;
233 char *resource;
234 int n_textures;
235 int uniforms_size;
236 GArray *uniforms;
237};
238
239G_DEFINE_TYPE (GskGLShader, gsk_gl_shader, G_TYPE_OBJECT)
240
241enum {
242 GLSHADER_PROP_0,
243 GLSHADER_PROP_SOURCE,
244 GLSHADER_PROP_RESOURCE,
245 GLSHADER_N_PROPS
246};
247static GParamSpec *gsk_gl_shader_properties[GLSHADER_N_PROPS];
248
249static void
250gsk_gl_shader_get_property (GObject *object,
251 guint prop_id,
252 GValue *value,
253 GParamSpec *pspec)
254{
255 GskGLShader *shader = GSK_GL_SHADER (ptr: object);
256
257 switch (prop_id)
258 {
259 case GLSHADER_PROP_SOURCE:
260 g_value_set_boxed (value, v_boxed: shader->source);
261 break;
262
263 case GLSHADER_PROP_RESOURCE:
264 g_value_set_string (value, v_string: shader->resource);
265 break;
266
267 default:
268 g_assert_not_reached ();
269 }
270}
271
272static void
273gsk_gl_shader_set_property (GObject *object,
274 guint prop_id,
275 const GValue *value,
276 GParamSpec *pspec)
277{
278 GskGLShader *shader = GSK_GL_SHADER (ptr: object);
279
280 switch (prop_id)
281 {
282 case GLSHADER_PROP_SOURCE:
283 g_clear_pointer (&shader->source, g_bytes_unref);
284 shader->source = g_value_dup_boxed (value);
285 break;
286
287 case GLSHADER_PROP_RESOURCE:
288 {
289 GError *error = NULL;
290 GBytes *source;
291 const char *resource;
292
293 resource = g_value_get_string (value);
294 if (resource == NULL)
295 break;
296
297 source = g_resources_lookup_data (path: resource, lookup_flags: 0, error: &error);
298 if (source)
299 {
300 g_clear_pointer (&shader->source, g_bytes_unref);
301 shader->source = source;
302 shader->resource = g_strdup (str: resource);
303 }
304 else
305 {
306 g_critical ("Unable to load resource %s for glshader: %s", resource, error->message);
307 g_error_free (error);
308 if (shader->source == NULL)
309 shader->source = g_bytes_new_static (data: "", size: 1);
310 }
311 }
312 break;
313
314 default:
315 g_assert_not_reached ();
316 }
317}
318
319static void
320gsk_gl_shader_finalize (GObject *object)
321{
322 GskGLShader *shader = GSK_GL_SHADER (ptr: object);
323
324 g_bytes_unref (bytes: shader->source);
325 g_free (mem: shader->resource);
326 for (int i = 0; i < shader->uniforms->len; i ++)
327 g_free (g_array_index (shader->uniforms, GskGLUniform, i).name);
328 g_array_free (array: shader->uniforms, TRUE);
329
330 G_OBJECT_CLASS (gsk_gl_shader_parent_class)->finalize (object);
331}
332
333static GRegex *uniform_regexp = NULL; /* Initialized in class_init */
334
335
336static void
337gsk_gl_shader_add_uniform (GskGLShader *shader,
338 const char *name,
339 GskGLUniformType type)
340{
341 GskGLUniform uniform = {
342 g_strdup (str: name),
343 type,
344 shader->uniforms_size
345 };
346
347 shader->uniforms_size += uniform_type_size (type);
348
349 g_array_append_val (shader->uniforms, uniform);
350}
351
352static void
353gsk_gl_shader_constructed (GObject *object)
354{
355 GskGLShader *shader = GSK_GL_SHADER (ptr: object);
356 gsize string_len;
357 const char *string = g_bytes_get_data (bytes: shader->source, size: &string_len);
358 GMatchInfo *match_info;
359 int max_texture_seen = 0;
360
361 g_regex_match_full (regex: uniform_regexp,
362 string, string_len, start_position: 0, match_options: 0,
363 match_info: &match_info, NULL);
364 while (g_match_info_matches (match_info))
365 {
366 char *type = g_match_info_fetch (match_info, match_num: 1);
367 char *name = g_match_info_fetch (match_info, match_num: 2);
368
369 if (strcmp (s1: type, s2: "sampler2D") == 0)
370 {
371 /* Textures are special cased */
372
373 if (g_str_has_prefix (str: name, prefix: "u_texture") &&
374 strlen (s: name) == strlen (s: "u_texture")+1)
375 {
376 char digit = name[strlen(s: "u_texture")];
377 if (digit >= '1' && digit <= '9')
378 max_texture_seen = MAX(max_texture_seen, digit - '0');
379 }
380 else
381 g_debug ("Unhandled shader texture uniform '%s', use uniforms of name 'u_texture[1..9]'", name);
382 }
383 else
384 {
385 GskGLUniformType utype = uniform_type_from_glsl (str: type);
386 g_assert (utype != GSK_GL_UNIFORM_TYPE_NONE); // Shouldn't have matched the regexp
387 gsk_gl_shader_add_uniform (shader, name, type: utype);
388 }
389
390 g_free (mem: type);
391 g_free (mem: name);
392
393 g_match_info_next (match_info, NULL);
394 }
395
396 g_match_info_free (match_info);
397
398 shader->n_textures = max_texture_seen;
399
400 if (GSK_DEBUG_CHECK(SHADERS))
401 {
402 GString *s;
403
404 s = g_string_new (init: "");
405 for (int i = 0; i < shader->uniforms->len; i++)
406 {
407 GskGLUniform *u = &g_array_index (shader->uniforms, GskGLUniform, i);
408 if (i > 0)
409 g_string_append (string: s, val: ", ");
410 g_string_append_printf (string: s, format: "%s %s", uniform_type_name (type: u->type), u->name);
411 }
412 g_message ("Shader constructed: %d textures, %d uniforms (%s)",
413 shader->n_textures, shader->uniforms->len,
414 s->str);
415 g_string_free (string: s, TRUE);
416 }
417}
418
419#define SPACE_RE "[ \\t]+" // Don't use \s, we don't want to match newlines
420#define OPT_SPACE_RE "[ \\t]*"
421#define UNIFORM_TYPE_RE "(int|uint|bool|float|vec2|vec3|vec4|sampler2D)"
422#define UNIFORM_NAME_RE "([\\w]+)"
423#define OPT_INIT_VALUE_RE "[-\\w(),. ]+" // This is a bit simple, but will match most initializers
424#define OPT_COMMENT_RE "(//.*)?"
425#define OPT_INITIALIZER_RE "(" OPT_SPACE_RE "=" OPT_SPACE_RE OPT_INIT_VALUE_RE ")?"
426#define UNIFORM_MATCHER_RE "^uniform" SPACE_RE UNIFORM_TYPE_RE SPACE_RE UNIFORM_NAME_RE OPT_INITIALIZER_RE OPT_SPACE_RE ";" OPT_SPACE_RE OPT_COMMENT_RE "$"
427
428static void
429gsk_gl_shader_class_init (GskGLShaderClass *klass)
430{
431 GObjectClass *object_class = G_OBJECT_CLASS (klass);
432 uniform_regexp = g_regex_new (UNIFORM_MATCHER_RE,
433 compile_options: G_REGEX_MULTILINE | G_REGEX_RAW | G_REGEX_OPTIMIZE,
434 match_options: 0, NULL);
435
436 object_class->get_property = gsk_gl_shader_get_property;
437 object_class->set_property = gsk_gl_shader_set_property;
438 object_class->finalize = gsk_gl_shader_finalize;
439 object_class->constructed = gsk_gl_shader_constructed;
440
441 /**
442 * GskGLShader:sourcecode: (attributes org.gtk.Property.get=gsk_gl_shader_get_source)
443 *
444 * The source code for the shader, as a `GBytes`.
445 */
446 gsk_gl_shader_properties[GLSHADER_PROP_SOURCE] =
447 g_param_spec_boxed (name: "source",
448 nick: "Source",
449 blurb: "The sourcecode for the shader",
450 G_TYPE_BYTES,
451 flags: G_PARAM_READWRITE |
452 G_PARAM_CONSTRUCT_ONLY |
453 G_PARAM_STATIC_STRINGS);
454
455 /**
456 * GskGLShader:resource: (attributes org.gtk.Property.get=gsk_gl_shader_get_resource)
457 *
458 * Resource containing the source code for the shader.
459 *
460 * If the shader source is not coming from a resource, this
461 * will be %NULL.
462 */
463 gsk_gl_shader_properties[GLSHADER_PROP_RESOURCE] =
464 g_param_spec_string (name: "resource",
465 nick: "Resources",
466 blurb: "Resource path to the source code",
467 NULL,
468 flags: G_PARAM_READWRITE |
469 G_PARAM_CONSTRUCT_ONLY |
470 G_PARAM_STATIC_STRINGS);
471
472 g_object_class_install_properties (oclass: object_class, n_pspecs: GLSHADER_N_PROPS, pspecs: gsk_gl_shader_properties);
473}
474
475static void
476gsk_gl_shader_init (GskGLShader *shader)
477{
478 shader->uniforms = g_array_new (FALSE, FALSE, element_size: sizeof (GskGLUniform));
479}
480
481/**
482 * gsk_gl_shader_new_from_bytes:
483 * @sourcecode: GLSL sourcecode for the shader, as a `GBytes`
484 *
485 * Creates a `GskGLShader` that will render pixels using the specified code.
486 *
487 * Returns: (transfer full): A new `GskGLShader`
488 */
489GskGLShader *
490gsk_gl_shader_new_from_bytes (GBytes *sourcecode)
491{
492 g_return_val_if_fail (sourcecode != NULL, NULL);
493
494 return g_object_new (GSK_TYPE_GL_SHADER,
495 first_property_name: "source", sourcecode,
496 NULL);
497}
498
499/**
500 * gsk_gl_shader_new_from_resource:
501 * @resource_path: path to a resource that contains the GLSL sourcecode for
502 * the shader
503 *
504 * Creates a `GskGLShader` that will render pixels using the specified code.
505 *
506 * Returns: (transfer full): A new `GskGLShader`
507 */
508GskGLShader *
509gsk_gl_shader_new_from_resource (const char *resource_path)
510{
511 g_return_val_if_fail (resource_path != NULL, NULL);
512
513 return g_object_new (GSK_TYPE_GL_SHADER,
514 first_property_name: "resource", resource_path,
515 NULL);
516}
517
518/**
519 * gsk_gl_shader_compile:
520 * @shader: a `GskGLShader`
521 * @renderer: a `GskRenderer`
522 * @error: location to store error in
523 *
524 * Tries to compile the @shader for the given @renderer.
525 *
526 * If there is a problem, this function returns %FALSE and reports
527 * an error. You should use this function before relying on the shader
528 * for rendering and use a fallback with a simpler shader or without
529 * shaders if it fails.
530 *
531 * Note that this will modify the rendering state (for example
532 * change the current GL context) and requires the renderer to be
533 * set up. This means that the widget has to be realized. Commonly you
534 * want to call this from the realize signal of a widget, or during
535 * widget snapshot.
536 *
537 * Returns: %TRUE on success, %FALSE if an error occurred
538 */
539gboolean
540gsk_gl_shader_compile (GskGLShader *shader,
541 GskRenderer *renderer,
542 GError **error)
543{
544 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), FALSE);
545
546 if (GSK_IS_GL_RENDERER (renderer))
547 return gsk_gl_renderer_try_compile_gl_shader (GSK_GL_RENDERER (renderer), shader, error);
548
549 g_set_error (err: error, G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED,
550 format: "The renderer does not support gl shaders");
551 return FALSE;
552}
553
554
555/**
556 * gsk_gl_shader_get_source: (attributes org.gtk.Method.get_property=source)
557 * @shader: a `GskGLShader`
558 *
559 * Gets the GLSL sourcecode being used to render this shader.
560 *
561 * Returns: (transfer none): The source code for the shader
562 */
563GBytes *
564gsk_gl_shader_get_source (GskGLShader *shader)
565{
566 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), NULL);
567
568 return shader->source;
569}
570
571/**
572 * gsk_gl_shader_get_resource: (attributes org.gtk.Method.get_property=resource)
573 * @shader: a `GskGLShader`
574 *
575 * Gets the resource path for the GLSL sourcecode being used
576 * to render this shader.
577 *
578 * Returns: (transfer none) (nullable): The resource path for the shader
579 */
580const char *
581gsk_gl_shader_get_resource (GskGLShader *shader)
582{
583 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), NULL);
584
585 return shader->resource;
586}
587
588/**
589 * gsk_gl_shader_get_n_textures:
590 * @shader: a `GskGLShader`
591 *
592 * Returns the number of textures that the shader requires.
593 *
594 * This can be used to check that the a passed shader works
595 * in your usecase. It is determined by looking at the highest
596 * u_textureN value that the shader defines.
597 *
598 * Returns: The number of texture inputs required by @shader
599 */
600int
601gsk_gl_shader_get_n_textures (GskGLShader *shader)
602{
603 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), 0);
604
605 return shader->n_textures;
606}
607
608/**
609 * gsk_gl_shader_get_n_uniforms:
610 * @shader: a `GskGLShader`
611 *
612 * Get the number of declared uniforms for this shader.
613 *
614 * Returns: The number of declared uniforms
615 */
616int
617gsk_gl_shader_get_n_uniforms (GskGLShader *shader)
618{
619 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), 0);
620
621 return shader->uniforms->len;
622}
623
624/**
625 * gsk_gl_shader_get_uniform_name:
626 * @shader: a `GskGLShader`
627 * @idx: index of the uniform
628 *
629 * Get the name of the declared uniform for this shader at index @idx.
630 *
631 * Returns: (transfer none): The name of the declared uniform
632 */
633const char *
634gsk_gl_shader_get_uniform_name (GskGLShader *shader,
635 int idx)
636{
637 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), NULL);
638
639 return g_array_index (shader->uniforms, GskGLUniform, idx).name;
640}
641
642/**
643 * gsk_gl_shader_find_uniform_by_name:
644 * @shader: a `GskGLShader`
645 * @name: uniform name
646 *
647 * Looks for a uniform by the name @name, and returns the index
648 * of the uniform, or -1 if it was not found.
649 *
650 * Returns: The index of the uniform, or -1
651 */
652int
653gsk_gl_shader_find_uniform_by_name (GskGLShader *shader,
654 const char *name)
655{
656 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), -1);
657
658 for (int i = 0; i < shader->uniforms->len; i++)
659 {
660 const GskGLUniform *u = &g_array_index (shader->uniforms, GskGLUniform, i);
661 if (strcmp (s1: u->name, s2: name) == 0)
662 return i;
663 }
664
665 return -1;
666}
667
668/**
669 * gsk_gl_shader_get_uniform_type:
670 * @shader: a `GskGLShader`
671 * @idx: index of the uniform
672 *
673 * Get the type of the declared uniform for this shader at index @idx.
674 *
675 * Returns: The type of the declared uniform
676 */
677GskGLUniformType
678gsk_gl_shader_get_uniform_type (GskGLShader *shader,
679 int idx)
680{
681 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), 0);
682
683 return g_array_index (shader->uniforms, GskGLUniform, idx).type;
684}
685
686/**
687 * gsk_gl_shader_get_uniform_offset:
688 * @shader: a `GskGLShader`
689 * @idx: index of the uniform
690 *
691 * Get the offset into the data block where data for this uniforms is stored.
692 *
693 * Returns: The data offset
694 */
695int
696gsk_gl_shader_get_uniform_offset (GskGLShader *shader,
697 int idx)
698{
699 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), 0);
700
701 return g_array_index (shader->uniforms, GskGLUniform, idx).offset;
702}
703
704const GskGLUniform *
705gsk_gl_shader_get_uniforms (GskGLShader *shader,
706 int *n_uniforms)
707{
708 *n_uniforms = shader->uniforms->len;
709 return &g_array_index (shader->uniforms, GskGLUniform, 0);
710}
711
712/**
713 * gsk_gl_shader_get_args_size:
714 * @shader: a `GskGLShader`
715 *
716 * Get the size of the data block used to specify arguments for this shader.
717 *
718 * Returns: The size of the data block
719 */
720gsize
721gsk_gl_shader_get_args_size (GskGLShader *shader)
722{
723 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), 0);
724
725 return shader->uniforms_size;
726}
727
728static const GskGLUniform *
729gsk_gl_shader_find_uniform (GskGLShader *shader,
730 const char *name)
731{
732 for (int i = 0; i < shader->uniforms->len; i++)
733 {
734 const GskGLUniform *u = &g_array_index (shader->uniforms, GskGLUniform, i);
735 if (strcmp (s1: u->name, s2: name) == 0)
736 return u;
737 }
738
739 return NULL;
740}
741
742/**
743 * gsk_gl_shader_get_arg_float:
744 * @shader: a `GskGLShader`
745 * @args: uniform arguments
746 * @idx: index of the uniform
747 *
748 * Gets the value of the uniform @idx in the @args block.
749 *
750 * The uniform must be of float type.
751 *
752 * Returns: The value
753 */
754float
755gsk_gl_shader_get_arg_float (GskGLShader *shader,
756 GBytes *args,
757 int idx)
758{
759 const GskGLUniform *u;
760 const guchar *args_src;
761 gsize size;
762 const guchar *data = g_bytes_get_data (bytes: args, size: &size);
763
764 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), 0);
765
766 g_assert (size == shader->uniforms_size);
767 g_assert (idx < shader->uniforms->len);
768 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
769 g_assert (u->type == GSK_GL_UNIFORM_TYPE_FLOAT);
770
771 args_src = data + u->offset;
772 return *(float *)args_src;
773}
774
775/**
776 * gsk_gl_shader_get_arg_int:
777 * @shader: a `GskGLShader`
778 * @args: uniform arguments
779 * @idx: index of the uniform
780 *
781 * Gets the value of the uniform @idx in the @args block.
782 *
783 * The uniform must be of int type.
784 *
785 * Returns: The value
786 */
787gint32
788gsk_gl_shader_get_arg_int (GskGLShader *shader,
789 GBytes *args,
790 int idx)
791{
792 const GskGLUniform *u;
793 const guchar *args_src;
794 gsize size;
795 const guchar *data = g_bytes_get_data (bytes: args, size: &size);
796
797 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), 0);
798
799 g_assert (size == shader->uniforms_size);
800 g_assert (idx < shader->uniforms->len);
801 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
802 g_assert (u->type == GSK_GL_UNIFORM_TYPE_INT);
803
804 args_src = data + u->offset;
805 return *(gint32 *)args_src;
806}
807
808/**
809 * gsk_gl_shader_get_arg_uint:
810 * @shader: a `GskGLShader`
811 * @args: uniform arguments
812 * @idx: index of the uniform
813 *
814 * Gets the value of the uniform @idx in the @args block.
815 *
816 * The uniform must be of uint type.
817 *
818 * Returns: The value
819 */
820guint32
821gsk_gl_shader_get_arg_uint (GskGLShader *shader,
822 GBytes *args,
823 int idx)
824{
825 const GskGLUniform *u;
826 const guchar *args_src;
827 gsize size;
828 const guchar *data = g_bytes_get_data (bytes: args, size: &size);
829
830 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), 0);
831
832 g_assert (size == shader->uniforms_size);
833 g_assert (idx < shader->uniforms->len);
834 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
835 g_assert (u->type == GSK_GL_UNIFORM_TYPE_UINT);
836
837 args_src = data + u->offset;
838 return *(guint32 *)args_src;
839}
840
841/**
842 * gsk_gl_shader_get_arg_bool:
843 * @shader: a `GskGLShader`
844 * @args: uniform arguments
845 * @idx: index of the uniform
846 *
847 * Gets the value of the uniform @idx in the @args block.
848 *
849 * The uniform must be of bool type.
850 *
851 * Returns: The value
852 */
853gboolean
854gsk_gl_shader_get_arg_bool (GskGLShader *shader,
855 GBytes *args,
856 int idx)
857{
858 const GskGLUniform *u;
859 const guchar *args_src;
860 gsize size;
861 const guchar *data = g_bytes_get_data (bytes: args, size: &size);
862
863 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), 0);
864
865 g_assert (size == shader->uniforms_size);
866 g_assert (idx < shader->uniforms->len);
867 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
868 g_assert (u->type == GSK_GL_UNIFORM_TYPE_BOOL);
869
870 args_src = data + u->offset;
871 return *(guint32 *)args_src;
872}
873
874/**
875 * gsk_gl_shader_get_arg_vec2:
876 * @shader: a `GskGLShader`
877 * @args: uniform arguments
878 * @idx: index of the uniform
879 * @out_value: location to store the uniform value in
880 *
881 * Gets the value of the uniform @idx in the @args block.
882 *
883 * The uniform must be of vec2 type.
884 */
885void
886gsk_gl_shader_get_arg_vec2 (GskGLShader *shader,
887 GBytes *args,
888 int idx,
889 graphene_vec2_t *out_value)
890{
891 const GskGLUniform *u;
892 const guchar *args_src;
893 gsize size;
894 const guchar *data = g_bytes_get_data (bytes: args, size: &size);
895
896 g_return_if_fail (GSK_IS_GL_SHADER (shader));
897
898 g_assert (size == shader->uniforms_size);
899 g_assert (idx < shader->uniforms->len);
900 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
901 g_assert (u->type == GSK_GL_UNIFORM_TYPE_VEC2);
902
903 args_src = data + u->offset;
904 graphene_vec2_init_from_float (v: out_value, src: (float *)args_src);
905}
906
907/**
908 * gsk_gl_shader_get_arg_vec3:
909 * @shader: a `GskGLShader`
910 * @args: uniform arguments
911 * @idx: index of the uniform
912 * @out_value: location to store the uniform value in
913 *
914 * Gets the value of the uniform @idx in the @args block.
915 *
916 * The uniform must be of vec3 type.
917 */
918void
919gsk_gl_shader_get_arg_vec3 (GskGLShader *shader,
920 GBytes *args,
921 int idx,
922 graphene_vec3_t *out_value)
923{
924 const GskGLUniform *u;
925 const guchar *args_src;
926 gsize size;
927 const guchar *data = g_bytes_get_data (bytes: args, size: &size);
928
929 g_return_if_fail (GSK_IS_GL_SHADER (shader));
930
931 g_assert (size == shader->uniforms_size);
932 g_assert (idx < shader->uniforms->len);
933 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
934 g_assert (u->type == GSK_GL_UNIFORM_TYPE_VEC3);
935
936 args_src = data + u->offset;
937 graphene_vec3_init_from_float (v: out_value, src: (float *)args_src);
938}
939
940/**
941 * gsk_gl_shader_get_arg_vec4:
942 * @shader: a `GskGLShader`
943 * @args: uniform arguments
944 * @idx: index of the uniform
945 * @out_value: location to store set the uniform value in
946 *
947 * Gets the value of the uniform @idx in the @args block.
948 *
949 * The uniform must be of vec4 type.
950 */
951void
952gsk_gl_shader_get_arg_vec4 (GskGLShader *shader,
953 GBytes *args,
954 int idx,
955 graphene_vec4_t *out_value)
956{
957 const GskGLUniform *u;
958 const guchar *args_src;
959 gsize size;
960 const guchar *data = g_bytes_get_data (bytes: args, size: &size);
961
962 g_return_if_fail (GSK_IS_GL_SHADER (shader));
963
964 g_assert (size == shader->uniforms_size);
965 g_assert (idx < shader->uniforms->len);
966 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
967 g_assert (u->type == GSK_GL_UNIFORM_TYPE_VEC4);
968
969 args_src = data + u->offset;
970 graphene_vec4_init_from_float (v: out_value, src: (float *)args_src);
971}
972
973/**
974 * gsk_gl_shader_format_args_va:
975 * @shader: a `GskGLShader`
976 * @uniforms: name-Value pairs for the uniforms of @shader, ending
977 * with a %NULL name
978 *
979 * Formats the uniform data as needed for feeding the named uniforms
980 * values into the shader.
981 *
982 * The argument list is a list of pairs of names, and values for the
983 * types that match the declared uniforms (i.e. double/int/guint/gboolean
984 * for primitive values and `graphene_vecN_t *` for vecN uniforms).
985 *
986 * It is an error to pass a uniform name that is not declared by the shader.
987 *
988 * Any uniforms of the shader that are not included in the argument list
989 * are zero-initialized.
990 *
991 * Returns: (transfer full): A newly allocated block of data which can be
992 * passed to [ctor@Gsk.GLShaderNode.new].
993 */
994GBytes *
995gsk_gl_shader_format_args_va (GskGLShader *shader,
996 va_list uniforms)
997{
998 guchar *args = g_malloc0 (n_bytes: shader->uniforms_size);
999 const char *name;
1000
1001 g_return_val_if_fail (GSK_IS_GL_SHADER (shader), NULL);
1002
1003 while ((name = va_arg (uniforms, const char *)) != NULL)
1004 {
1005 const GskGLUniform *u;
1006 guchar *args_dest;
1007
1008 u = gsk_gl_shader_find_uniform (shader, name);
1009 if (u == NULL)
1010 {
1011 g_warning ("No uniform named `%s` in shader", name);
1012 break;
1013 }
1014
1015 args_dest = args + u->offset;
1016
1017 switch (u->type)
1018 {
1019 case GSK_GL_UNIFORM_TYPE_FLOAT:
1020 *(float *)args_dest = (float)va_arg (uniforms, double); /* floats are promoted to double in varargs */
1021 break;
1022
1023 case GSK_GL_UNIFORM_TYPE_INT:
1024 *(gint32 *)args_dest = (gint32)va_arg (uniforms, int);
1025 break;
1026
1027 case GSK_GL_UNIFORM_TYPE_UINT:
1028 *(guint32 *)args_dest = (guint32)va_arg (uniforms, guint);
1029 break;
1030
1031 case GSK_GL_UNIFORM_TYPE_BOOL:
1032 *(guint32 *)args_dest = (gboolean)va_arg (uniforms, gboolean);
1033 break;
1034
1035 case GSK_GL_UNIFORM_TYPE_VEC2:
1036 graphene_vec2_to_float (va_arg (uniforms, const graphene_vec2_t *),
1037 dest: (float *)args_dest);
1038 break;
1039
1040 case GSK_GL_UNIFORM_TYPE_VEC3:
1041 graphene_vec3_to_float (va_arg (uniforms, const graphene_vec3_t *),
1042 dest: (float *)args_dest);
1043 break;
1044
1045 case GSK_GL_UNIFORM_TYPE_VEC4:
1046 graphene_vec4_to_float (va_arg (uniforms, const graphene_vec4_t *),
1047 dest: (float *)args_dest);
1048 break;
1049
1050 case GSK_GL_UNIFORM_TYPE_NONE:
1051 default:
1052 g_assert_not_reached ();
1053 }
1054 }
1055
1056 return g_bytes_new_take (data: args, size: shader->uniforms_size);
1057}
1058
1059/**
1060 * gsk_gl_shader_format_args:
1061 * @shader: a `GskGLShader`
1062 * @...: name-Value pairs for the uniforms of @shader, ending with
1063 * a %NULL name
1064 *
1065 * Formats the uniform data as needed for feeding the named uniforms
1066 * values into the shader.
1067 *
1068 * The argument list is a list of pairs of names, and values for the types
1069 * that match the declared uniforms (i.e. double/int/guint/gboolean for
1070 * primitive values and `graphene_vecN_t *` for vecN uniforms).
1071 *
1072 * Any uniforms of the shader that are not included in the argument list
1073 * are zero-initialized.
1074 *
1075 * Returns: (transfer full): A newly allocated block of data which can be
1076 * passed to [ctor@Gsk.GLShaderNode.new].
1077 */
1078GBytes *
1079gsk_gl_shader_format_args (GskGLShader *shader,
1080 ...)
1081{
1082 GBytes *bytes;
1083 va_list args;
1084
1085 va_start (args, shader);
1086 bytes = gsk_gl_shader_format_args_va (shader, uniforms: args);
1087 va_end (args);
1088
1089 return bytes;
1090}
1091
1092struct _GskShaderArgsBuilder {
1093 guint ref_count;
1094 GskGLShader *shader;
1095 guchar *data;
1096};
1097
1098G_DEFINE_BOXED_TYPE (GskShaderArgsBuilder, gsk_shader_args_builder,
1099 gsk_shader_args_builder_ref,
1100 gsk_shader_args_builder_unref);
1101
1102
1103/**
1104 * gsk_shader_args_builder_new:
1105 * @shader: a `GskGLShader`
1106 * @initial_values: (nullable): optional `GBytes` with initial values
1107 *
1108 * Allocates a builder that can be used to construct a new uniform data
1109 * chunk.
1110 *
1111 * Returns: (transfer full): The newly allocated builder, free with
1112 * [method@Gsk.ShaderArgsBuilder.unref]
1113 */
1114GskShaderArgsBuilder *
1115gsk_shader_args_builder_new (GskGLShader *shader,
1116 GBytes *initial_values)
1117{
1118 GskShaderArgsBuilder *builder = g_new0 (GskShaderArgsBuilder, 1);
1119 builder->ref_count = 1;
1120 builder->shader = g_object_ref (shader);
1121 builder->data = g_malloc0 (n_bytes: shader->uniforms_size);
1122
1123 if (initial_values)
1124 {
1125 gsize size;
1126 const guchar *data = g_bytes_get_data (bytes: initial_values, size: &size);
1127
1128 g_assert (size == shader->uniforms_size);
1129 memcpy (dest: builder->data, src: data, n: size);
1130 }
1131
1132 return builder;
1133}
1134
1135/**
1136 * gsk_shader_args_builder_to_args:
1137 * @builder: a `GskShaderArgsBuilder`
1138 *
1139 * Creates a new `GBytes` args from the current state of the
1140 * given @builder.
1141 *
1142 * Any uniforms of the shader that have not been explicitly set on
1143 * the @builder are zero-initialized.
1144 *
1145 * The given `GskShaderArgsBuilder` is reset once this function returns;
1146 * you cannot call this function multiple times on the same @builder instance.
1147 *
1148 * This function is intended primarily for bindings. C code should use
1149 * [method@Gsk.ShaderArgsBuilder.free_to_args].
1150 *
1151 *
1152 * Returns: (transfer full): the newly allocated buffer with
1153 * all the args added to @builder
1154 */
1155GBytes *
1156gsk_shader_args_builder_to_args (GskShaderArgsBuilder *builder)
1157{
1158 return g_bytes_new_take (g_steal_pointer (&builder->data),
1159 size: builder->shader->uniforms_size);
1160}
1161
1162/**
1163 * gsk_shader_args_builder_free_to_args: (skip)
1164 * @builder: a `GskShaderArgsBuilder`
1165 *
1166 * Creates a new `GBytes` args from the current state of the
1167 * given @builder, and frees the @builder instance.
1168 *
1169 * Any uniforms of the shader that have not been explicitly set
1170 * on the @builder are zero-initialized.
1171 *
1172 * Returns: (transfer full): the newly allocated buffer with
1173 * all the args added to @builder
1174 */
1175GBytes *
1176gsk_shader_args_builder_free_to_args (GskShaderArgsBuilder *builder)
1177{
1178 GBytes *res;
1179
1180 g_return_val_if_fail (builder != NULL, NULL);
1181
1182 res = gsk_shader_args_builder_to_args (builder);
1183
1184 gsk_shader_args_builder_unref (builder);
1185
1186 return res;
1187}
1188
1189
1190/**
1191 * gsk_shader_args_builder_unref:
1192 * @builder: a `GskShaderArgsBuilder`
1193 *
1194 * Decreases the reference count of a `GskShaderArgBuilder` by one.
1195 *
1196 * If the resulting reference count is zero, frees the builder.
1197 */
1198void
1199gsk_shader_args_builder_unref (GskShaderArgsBuilder *builder)
1200
1201{
1202 g_return_if_fail (builder != NULL);
1203 g_return_if_fail (builder->ref_count > 0);
1204
1205 builder->ref_count--;
1206 if (builder->ref_count > 0)
1207 return;
1208
1209 g_object_unref (object: builder->shader);
1210 g_free (mem: builder->data);
1211 g_free (mem: builder);
1212}
1213
1214/**
1215 * gsk_shader_args_builder_ref:
1216 * @builder: a `GskShaderArgsBuilder`
1217 *
1218 * Increases the reference count of a `GskShaderArgsBuilder` by one.
1219 *
1220 * Returns: the passed in `GskShaderArgsBuilder`
1221 */
1222GskShaderArgsBuilder *
1223gsk_shader_args_builder_ref (GskShaderArgsBuilder *builder)
1224{
1225 g_return_val_if_fail (builder != NULL, NULL);
1226
1227 builder->ref_count++;
1228 return builder;
1229}
1230
1231/**
1232 * gsk_shader_args_builder_set_float:
1233 * @builder: a `GskShaderArgsBuilder`
1234 * @idx: index of the uniform
1235 * @value: value to set the uniform to
1236 *
1237 * Sets the value of the uniform @idx.
1238 *
1239 * The uniform must be of float type.
1240 */
1241void
1242gsk_shader_args_builder_set_float (GskShaderArgsBuilder *builder,
1243 int idx,
1244 float value)
1245{
1246 GskGLShader *shader = builder->shader;
1247 const GskGLUniform *u;
1248 guchar *args_dest;
1249
1250 g_assert (builder->data != NULL);
1251 g_assert (idx < shader->uniforms->len);
1252 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
1253 g_assert (u->type == GSK_GL_UNIFORM_TYPE_FLOAT);
1254
1255 args_dest = builder->data + u->offset;
1256 *(float *)args_dest = value;
1257}
1258
1259/**
1260 * gsk_shader_args_builder_set_int:
1261 * @builder: a `GskShaderArgsBuilder`
1262 * @idx: index of the uniform
1263 * @value: value to set the uniform to
1264 *
1265 * Sets the value of the uniform @idx.
1266 *
1267 * The uniform must be of int type.
1268 */
1269void
1270gsk_shader_args_builder_set_int (GskShaderArgsBuilder *builder,
1271 int idx,
1272 gint32 value)
1273{
1274 GskGLShader *shader = builder->shader;
1275 const GskGLUniform *u;
1276 guchar *args_dest;
1277
1278 g_assert (builder->data != NULL);
1279 g_assert (idx < shader->uniforms->len);
1280 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
1281 g_assert (u->type == GSK_GL_UNIFORM_TYPE_INT);
1282
1283 args_dest = builder->data + u->offset;
1284 *(gint32 *)args_dest = value;
1285}
1286
1287/**
1288 * gsk_shader_args_builder_set_uint:
1289 * @builder: a `GskShaderArgsBuilder`
1290 * @idx: index of the uniform
1291 * @value: value to set the uniform to
1292 *
1293 * Sets the value of the uniform @idx.
1294 *
1295 * The uniform must be of uint type.
1296 */
1297void
1298gsk_shader_args_builder_set_uint (GskShaderArgsBuilder *builder,
1299 int idx,
1300 guint32 value)
1301{
1302 GskGLShader *shader = builder->shader;
1303 const GskGLUniform *u;
1304 guchar *args_dest;
1305
1306 g_assert (builder->data != NULL);
1307 g_assert (idx < shader->uniforms->len);
1308 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
1309 g_assert (u->type == GSK_GL_UNIFORM_TYPE_UINT);
1310
1311 args_dest = builder->data + u->offset;
1312 *(guint32 *)args_dest = value;
1313}
1314
1315/**
1316 * gsk_shader_args_builder_set_bool:
1317 * @builder: a `GskShaderArgsBuilder`
1318 * @idx: index of the uniform
1319 * @value: value to set the uniform to
1320 *
1321 * Sets the value of the uniform @idx.
1322 *
1323 * The uniform must be of bool type.
1324 */
1325void
1326gsk_shader_args_builder_set_bool (GskShaderArgsBuilder *builder,
1327 int idx,
1328 gboolean value)
1329{
1330 GskGLShader *shader = builder->shader;
1331 const GskGLUniform *u;
1332 guchar *args_dest;
1333
1334 g_assert (builder->data != NULL);
1335 g_assert (idx < shader->uniforms->len);
1336 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
1337 g_assert (u->type == GSK_GL_UNIFORM_TYPE_BOOL);
1338
1339 args_dest = builder->data + u->offset;
1340 *(guint32 *)args_dest = !!value;
1341}
1342
1343/**
1344 * gsk_shader_args_builder_set_vec2:
1345 * @builder: A `GskShaderArgsBuilder`
1346 * @idx: index of the uniform
1347 * @value: value to set the uniform too
1348 *
1349 * Sets the value of the uniform @idx.
1350 *
1351 * The uniform must be of vec2 type.
1352 */
1353void
1354gsk_shader_args_builder_set_vec2 (GskShaderArgsBuilder *builder,
1355 int idx,
1356 const graphene_vec2_t *value)
1357{
1358 GskGLShader *shader = builder->shader;
1359 const GskGLUniform *u;
1360 guchar *args_dest;
1361
1362 g_assert (builder->data != NULL);
1363 g_assert (idx < shader->uniforms->len);
1364 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
1365 g_assert (u->type == GSK_GL_UNIFORM_TYPE_VEC2);
1366
1367 args_dest = builder->data + u->offset;
1368 graphene_vec2_to_float (v: value, dest: (float *)args_dest);
1369}
1370
1371/**
1372 * gsk_shader_args_builder_set_vec3:
1373 * @builder: a `GskShaderArgsBuilder`
1374 * @idx: index of the uniform
1375 * @value: value to set the uniform too
1376 *
1377 * Sets the value of the uniform @idx.
1378 *
1379 * The uniform must be of vec3 type.
1380 */
1381void
1382gsk_shader_args_builder_set_vec3 (GskShaderArgsBuilder *builder,
1383 int idx,
1384 const graphene_vec3_t *value)
1385{
1386 GskGLShader *shader = builder->shader;
1387 const GskGLUniform *u;
1388 guchar *args_dest;
1389
1390 g_assert (builder->data != NULL);
1391 g_assert (idx < shader->uniforms->len);
1392 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
1393 g_assert (u->type == GSK_GL_UNIFORM_TYPE_VEC3);
1394
1395 args_dest = builder->data + u->offset;
1396 graphene_vec3_to_float (v: value, dest: (float *)args_dest);
1397}
1398
1399/**
1400 * gsk_shader_args_builder_set_vec4:
1401 * @builder: a `GskShaderArgsBuilder`
1402 * @idx: index of the uniform
1403 * @value: value to set the uniform too
1404 *
1405 * Sets the value of the uniform @idx.
1406 *
1407 * The uniform must be of vec4 type.
1408 */
1409void
1410gsk_shader_args_builder_set_vec4 (GskShaderArgsBuilder *builder,
1411 int idx,
1412 const graphene_vec4_t *value)
1413{
1414 GskGLShader *shader = builder->shader;
1415 const GskGLUniform *u;
1416 guchar *args_dest;
1417
1418 g_assert (builder->data != NULL);
1419 g_assert (idx < shader->uniforms->len);
1420 u = &g_array_index (shader->uniforms, GskGLUniform, idx);
1421 g_assert (u->type == GSK_GL_UNIFORM_TYPE_VEC4);
1422
1423 args_dest = builder->data + u->offset;
1424 graphene_vec4_to_float (v: value, dest: (float *)args_dest);
1425}
1426

source code of gtk/gsk/gskglshader.c