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 | |
144 | static GskGLUniformType |
145 | uniform_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 | |
165 | static const char * |
166 | uniform_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 | |
198 | static int |
199 | uniform_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 | |
229 | struct _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 | |
239 | G_DEFINE_TYPE (GskGLShader, gsk_gl_shader, G_TYPE_OBJECT) |
240 | |
241 | enum { |
242 | GLSHADER_PROP_0, |
243 | GLSHADER_PROP_SOURCE, |
244 | GLSHADER_PROP_RESOURCE, |
245 | GLSHADER_N_PROPS |
246 | }; |
247 | static GParamSpec *gsk_gl_shader_properties[GLSHADER_N_PROPS]; |
248 | |
249 | static void |
250 | gsk_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 | |
272 | static void |
273 | gsk_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 | |
319 | static void |
320 | gsk_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 | |
333 | static GRegex *uniform_regexp = NULL; /* Initialized in class_init */ |
334 | |
335 | |
336 | static void |
337 | gsk_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 | |
352 | static void |
353 | gsk_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 "(//.*)?" |
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 | |
428 | static void |
429 | gsk_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 | |
475 | static void |
476 | gsk_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 | */ |
489 | GskGLShader * |
490 | gsk_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 | */ |
508 | GskGLShader * |
509 | gsk_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 | */ |
539 | gboolean |
540 | gsk_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 | */ |
563 | GBytes * |
564 | gsk_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 | */ |
580 | const char * |
581 | gsk_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 | */ |
600 | int |
601 | gsk_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 | */ |
616 | int |
617 | gsk_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 | */ |
633 | const char * |
634 | gsk_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 | */ |
652 | int |
653 | gsk_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 | */ |
677 | GskGLUniformType |
678 | gsk_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 | */ |
695 | int |
696 | gsk_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 | |
704 | const GskGLUniform * |
705 | gsk_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 | */ |
720 | gsize |
721 | gsk_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 | |
728 | static const GskGLUniform * |
729 | gsk_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 | */ |
754 | float |
755 | gsk_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 | */ |
787 | gint32 |
788 | gsk_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 | */ |
820 | guint32 |
821 | gsk_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 | */ |
853 | gboolean |
854 | gsk_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 | */ |
885 | void |
886 | gsk_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 | */ |
918 | void |
919 | gsk_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 | */ |
951 | void |
952 | gsk_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 | */ |
994 | GBytes * |
995 | gsk_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 | */ |
1078 | GBytes * |
1079 | gsk_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 | |
1092 | struct _GskShaderArgsBuilder { |
1093 | guint ref_count; |
1094 | GskGLShader *shader; |
1095 | guchar *data; |
1096 | }; |
1097 | |
1098 | G_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 | */ |
1114 | GskShaderArgsBuilder * |
1115 | gsk_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 | */ |
1155 | GBytes * |
1156 | gsk_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 | */ |
1175 | GBytes * |
1176 | gsk_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 | */ |
1198 | void |
1199 | gsk_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 | */ |
1222 | GskShaderArgsBuilder * |
1223 | gsk_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 | */ |
1241 | void |
1242 | gsk_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 | */ |
1269 | void |
1270 | gsk_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 | */ |
1297 | void |
1298 | gsk_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 | */ |
1325 | void |
1326 | gsk_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 | */ |
1353 | void |
1354 | gsk_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 | */ |
1381 | void |
1382 | gsk_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 | */ |
1409 | void |
1410 | gsk_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 | |