1/* gskgluniformstateprivate.h
2 *
3 * Copyright 2020 Christian Hergert <chergert@redhat.com>
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.1 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 program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: LGPL-2.1-or-later
19 */
20
21#ifndef GSK_GL_UNIFORM_STATE_PRIVATE_H
22#define GSK_GL_UNIFORM_STATE_PRIVATE_H
23
24#include "gskgltypesprivate.h"
25
26G_BEGIN_DECLS
27
28typedef struct { float v0; } Uniform1f;
29typedef struct { float v0; float v1; } Uniform2f;
30typedef struct { float v0; float v1; float v2; } Uniform3f;
31typedef struct { float v0; float v1; float v2; float v3; } Uniform4f;
32
33typedef struct { int v0; } Uniform1i;
34typedef struct { int v0; int v1; } Uniform2i;
35typedef struct { int v0; int v1; int v2; } Uniform3i;
36typedef struct { int v0; int v1; int v2; int v3; } Uniform4i;
37
38typedef struct { guint v0; } Uniform1ui;
39
40#define GSK_GL_UNIFORM_ARRAY_BITS 5
41#define GSK_GL_UNIFORM_FORMAT_BITS 5
42#define GSK_GL_UNIFORM_OFFSET_BITS 21
43
44typedef struct _GskGLUniformInfo
45{
46 guint initial : 1;
47 guint format : GSK_GL_UNIFORM_FORMAT_BITS;
48 guint array_count : GSK_GL_UNIFORM_ARRAY_BITS;
49 guint offset : GSK_GL_UNIFORM_OFFSET_BITS;
50} GskGLUniformInfo;
51
52G_STATIC_ASSERT (sizeof (GskGLUniformInfo) == 4);
53
54typedef struct _GskGLUniformMapping
55{
56 const char *name;
57 GskGLUniformInfo info;
58 guint stamp;
59 int location;
60} GskGLUniformMapping;
61
62typedef struct _GskGLUniformProgram
63{
64 guint program_id;
65 guint n_uniforms : 12;
66 guint has_attachments : 1;
67 guint n_mappings;
68 GskGLUniformMapping mappings[32];
69} GskGLUniformProgram;
70
71typedef struct _GskGLUniformState
72{
73 GHashTable *programs;
74 guint8 *values_buf;
75 guint values_pos;
76 guint values_len;
77 GskGLUniformInfo apply_hash[512];
78} GskGLUniformState;
79
80typedef enum _GskGLUniformKind
81{
82 GSK_GL_UNIFORM_FORMAT_1F = 1,
83 GSK_GL_UNIFORM_FORMAT_2F,
84 GSK_GL_UNIFORM_FORMAT_3F,
85 GSK_GL_UNIFORM_FORMAT_4F,
86
87 GSK_GL_UNIFORM_FORMAT_1FV,
88 GSK_GL_UNIFORM_FORMAT_2FV,
89 GSK_GL_UNIFORM_FORMAT_3FV,
90 GSK_GL_UNIFORM_FORMAT_4FV,
91
92 GSK_GL_UNIFORM_FORMAT_1I,
93 GSK_GL_UNIFORM_FORMAT_2I,
94 GSK_GL_UNIFORM_FORMAT_3I,
95 GSK_GL_UNIFORM_FORMAT_4I,
96
97 GSK_GL_UNIFORM_FORMAT_1UI,
98
99 GSK_GL_UNIFORM_FORMAT_TEXTURE,
100
101 GSK_GL_UNIFORM_FORMAT_MATRIX,
102 GSK_GL_UNIFORM_FORMAT_ROUNDED_RECT,
103 GSK_GL_UNIFORM_FORMAT_COLOR,
104
105 GSK_GL_UNIFORM_FORMAT_LAST
106} GskGLUniformFormat;
107
108G_STATIC_ASSERT (GSK_GL_UNIFORM_FORMAT_LAST < (1 << GSK_GL_UNIFORM_FORMAT_BITS));
109
110GskGLUniformState *gsk_gl_uniform_state_new (void);
111GskGLUniformState *gsk_gl_uniform_state_ref (GskGLUniformState *state);
112void gsk_gl_uniform_state_unref (GskGLUniformState *state);
113GskGLUniformProgram *gsk_gl_uniform_state_get_program (GskGLUniformState *state,
114 guint program,
115 const GskGLUniformMapping *mappings,
116 guint n_mappings);
117void gsk_gl_uniform_state_end_frame (GskGLUniformState *state);
118gsize gsk_gl_uniform_format_size (GskGLUniformFormat format);
119gpointer gsk_gl_uniform_state_init_value (GskGLUniformState *state,
120 GskGLUniformProgram *program,
121 GskGLUniformFormat format,
122 guint array_count,
123 guint key,
124 GskGLUniformMapping **out_mapping);
125
126#define GSK_GL_UNIFORM_VALUE(base, offset) ((gpointer)((base) + ((offset) * 4)))
127#define gsk_gl_uniform_state_get_uniform_data(state,offset) GSK_GL_UNIFORM_VALUE((state)->values_buf, offset)
128
129static inline gpointer
130gsk_gl_uniform_state_get_value (GskGLUniformState *state,
131 GskGLUniformProgram *program,
132 GskGLUniformFormat format,
133 guint array_count,
134 guint key,
135 guint stamp,
136 GskGLUniformMapping **out_mapping)
137{
138 GskGLUniformMapping *mapping;
139
140 g_assert (key < G_N_ELEMENTS (program->mappings));
141 g_assert (key < program->n_mappings);
142
143 mapping = &program->mappings[key];
144
145 /* Short-circuit if the program optimized the uniform out */
146 if (mapping->location == -1)
147 return NULL;
148
149 /* If the stamp is the same, then we can ignore the request
150 * and short-circuit as early as possible. This requires the
151 * caller to increment their private stamp when they change
152 * internal state.
153 *
154 * This is generally used for the shared uniforms like projection,
155 * modelview, clip, etc to avoid so many comparisons which cost
156 * considerable CPU.
157 */
158 if (stamp != 0 && stamp == mapping->stamp)
159 return NULL;
160
161 if G_LIKELY (format == mapping->info.format && array_count <= mapping->info.array_count)
162 {
163 *out_mapping = mapping;
164 return GSK_GL_UNIFORM_VALUE (state->values_buf, mapping->info.offset);
165 }
166
167 return gsk_gl_uniform_state_init_value (state, program, format, array_count, key, out_mapping);
168}
169
170G_GNUC_PURE static inline guint
171gsk_gl_uniform_state_align (guint current_pos,
172 guint size)
173{
174 guint align = size > 8 ? 16 : (size > 4 ? 8 : 4);
175 guint masked = current_pos & (align - 1);
176
177 g_assert (size > 0);
178 g_assert (align == 4 || align == 8 || align == 16);
179 g_assert (masked < align);
180
181 return align - masked;
182}
183
184static inline gpointer
185gsk_gl_uniform_state_realloc (GskGLUniformState *state,
186 guint size,
187 guint *offset)
188{
189 guint padding = gsk_gl_uniform_state_align (current_pos: state->values_pos, size);
190
191 if G_UNLIKELY (state->values_len - padding - size < state->values_pos)
192 {
193 state->values_len *= 2;
194 state->values_buf = g_realloc (mem: state->values_buf, n_bytes: state->values_len);
195 }
196
197 /* offsets are in slots of 4 to use fewer bits */
198 g_assert ((state->values_pos + padding) % 4 == 0);
199 *offset = (state->values_pos + padding) / 4;
200 state->values_pos += padding + size;
201
202 return GSK_GL_UNIFORM_VALUE (state->values_buf, *offset);
203}
204
205#define GSK_GL_UNIFORM_STATE_REPLACE(info, u, type, count) \
206 G_STMT_START { \
207 if ((info)->info.initial && count == (info)->info.array_count) \
208 { \
209 u = GSK_GL_UNIFORM_VALUE (state->values_buf, (info)->info.offset); \
210 } \
211 else \
212 { \
213 guint offset; \
214 u = gsk_gl_uniform_state_realloc (state, sizeof(type) * MAX (1, count), &offset); \
215 g_assert (offset < (1 << GSK_GL_UNIFORM_OFFSET_BITS)); \
216 (info)->info.offset = offset; \
217 /* We might have increased array length */ \
218 (info)->info.array_count = count; \
219 } \
220 } G_STMT_END
221
222static inline void
223gsk_gl_uniform_info_changed (GskGLUniformMapping *info,
224 guint stamp)
225{
226 info->stamp = stamp;
227 info->info.initial = FALSE;
228}
229
230static inline void
231gsk_gl_uniform_state_set1f (GskGLUniformState *state,
232 GskGLUniformProgram *program,
233 guint key,
234 guint stamp,
235 float value0)
236{
237 Uniform1f *u;
238 GskGLUniformMapping *info;
239
240 g_assert (state != NULL);
241 g_assert (program != 0);
242
243 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_1F, array_count: 1, key, stamp, out_mapping: &info)))
244 {
245 if (info->info.initial || u->v0 != value0)
246 {
247 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform1f , 1);
248 u->v0 = value0;
249 gsk_gl_uniform_info_changed (info, stamp);
250 }
251 }
252}
253
254static inline void
255gsk_gl_uniform_state_set2f (GskGLUniformState *state,
256 GskGLUniformProgram *program,
257 guint key,
258 guint stamp,
259 float value0,
260 float value1)
261{
262 Uniform2f *u;
263 GskGLUniformMapping *info;
264
265 g_assert (state != NULL);
266 g_assert (program != NULL);
267
268 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_2F, array_count: 1, key, stamp, out_mapping: &info)))
269 {
270 if (info->info.initial || u->v0 != value0 || u->v1 != value1)
271 {
272 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform2f, 1);
273 u->v0 = value0;
274 u->v1 = value1;
275 gsk_gl_uniform_info_changed (info, stamp);
276 }
277 }
278}
279
280static inline void
281gsk_gl_uniform_state_set3f (GskGLUniformState *state,
282 GskGLUniformProgram *program,
283 guint key,
284 guint stamp,
285 float value0,
286 float value1,
287 float value2)
288{
289 Uniform3f *u;
290 GskGLUniformMapping *info;
291
292 g_assert (state != NULL);
293 g_assert (program != NULL);
294
295 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_3F, array_count: 1, key, stamp, out_mapping: &info)))
296 {
297 if (info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2)
298 {
299 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform3f, 1);
300 u->v0 = value0;
301 u->v1 = value1;
302 u->v2 = value2;
303 gsk_gl_uniform_info_changed (info, stamp);
304 }
305 }
306}
307
308static inline void
309gsk_gl_uniform_state_set4f (GskGLUniformState *state,
310 GskGLUniformProgram *program,
311 guint key,
312 guint stamp,
313 float value0,
314 float value1,
315 float value2,
316 float value3)
317{
318 Uniform4f *u;
319 GskGLUniformMapping *info;
320
321 g_assert (state != NULL);
322 g_assert (program != NULL);
323
324 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_4F, array_count: 1, key, stamp, out_mapping: &info)))
325 {
326 if (info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2 || u->v3 != value3)
327 {
328 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform4f, 1);
329 u->v0 = value0;
330 u->v1 = value1;
331 u->v2 = value2;
332 u->v3 = value3;
333 gsk_gl_uniform_info_changed (info, stamp);
334 }
335 }
336}
337
338static inline void
339gsk_gl_uniform_state_set1ui (GskGLUniformState *state,
340 GskGLUniformProgram *program,
341 guint key,
342 guint stamp,
343 guint value0)
344{
345 Uniform1ui *u;
346 GskGLUniformMapping *info;
347
348 g_assert (state != NULL);
349 g_assert (program != NULL);
350
351 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_1UI, array_count: 1, key, stamp, out_mapping: &info)))
352 {
353 if (info->info.initial || u->v0 != value0)
354 {
355 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform1ui, 1);
356 u->v0 = value0;
357 gsk_gl_uniform_info_changed (info, stamp);
358 }
359 }
360}
361
362static inline void
363gsk_gl_uniform_state_set1i (GskGLUniformState *state,
364 GskGLUniformProgram *program,
365 guint key,
366 guint stamp,
367 int value0)
368{
369 Uniform1i *u;
370 GskGLUniformMapping *info;
371
372 g_assert (state != NULL);
373 g_assert (program != NULL);
374
375 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_1I, array_count: 1, key, stamp, out_mapping: &info)))
376 {
377 if (info->info.initial || u->v0 != value0)
378 {
379 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform1i, 1);
380 u->v0 = value0;
381 gsk_gl_uniform_info_changed (info, stamp);
382 }
383 }
384}
385
386static inline void
387gsk_gl_uniform_state_set2i (GskGLUniformState *state,
388 GskGLUniformProgram *program,
389 guint key,
390 guint stamp,
391 int value0,
392 int value1)
393{
394 Uniform2i *u;
395 GskGLUniformMapping *info;
396
397 g_assert (state != NULL);
398 g_assert (program != NULL);
399
400 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_2I, array_count: 1, key, stamp, out_mapping: &info)))
401 {
402 if (info->info.initial || u->v0 != value0 || u->v1 != value1)
403 {
404 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform2i, 1);
405 u->v0 = value0;
406 u->v1 = value1;
407 gsk_gl_uniform_info_changed (info, stamp);
408 }
409 }
410}
411
412static inline void
413gsk_gl_uniform_state_set3i (GskGLUniformState *state,
414 GskGLUniformProgram *program,
415 guint key,
416 guint stamp,
417 int value0,
418 int value1,
419 int value2)
420{
421 Uniform3i *u;
422 GskGLUniformMapping *info;
423
424 g_assert (state != NULL);
425 g_assert (program != NULL);
426
427 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_3I, array_count: 1, key, stamp, out_mapping: &info)))
428 {
429 if (info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2)
430 {
431 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform3i, 1);
432 u->v0 = value0;
433 u->v1 = value1;
434 u->v2 = value2;
435 gsk_gl_uniform_info_changed (info, stamp);
436 }
437 }
438}
439
440static inline void
441gsk_gl_uniform_state_set4i (GskGLUniformState *state,
442 GskGLUniformProgram *program,
443 guint key,
444 guint stamp,
445 int value0,
446 int value1,
447 int value2,
448 int value3)
449{
450 Uniform4i *u;
451 GskGLUniformMapping *info;
452
453 g_assert (state != NULL);
454 g_assert (program != NULL);
455
456 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_4I, array_count: 1, key, stamp, out_mapping: &info)))
457 {
458 if (info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2 || u->v3 != value3)
459 {
460 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform4i, 1);
461 u->v0 = value0;
462 u->v1 = value1;
463 u->v2 = value2;
464 u->v3 = value3;
465 gsk_gl_uniform_info_changed (info, stamp);
466 }
467 }
468}
469
470static inline void
471gsk_gl_uniform_state_set_rounded_rect (GskGLUniformState *state,
472 GskGLUniformProgram *program,
473 guint key,
474 guint stamp,
475 const GskRoundedRect *rounded_rect)
476{
477 GskRoundedRect *u;
478 GskGLUniformMapping *info;
479
480 g_assert (state != NULL);
481 g_assert (program != NULL);
482 g_assert (rounded_rect != NULL);
483
484 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_ROUNDED_RECT, array_count: 1, key, stamp, out_mapping: &info)))
485 {
486 if (info->info.initial || memcmp (s1: u, s2: rounded_rect, n: sizeof *u) != 0)
487 {
488 GSK_GL_UNIFORM_STATE_REPLACE (info, u, GskRoundedRect, 1);
489 memcpy (dest: u, src: rounded_rect, n: sizeof *rounded_rect);
490 gsk_gl_uniform_info_changed (info, stamp);
491 }
492 }
493}
494
495static inline void
496gsk_gl_uniform_state_set_matrix (GskGLUniformState *state,
497 GskGLUniformProgram *program,
498 guint key,
499 guint stamp,
500 const graphene_matrix_t *matrix)
501{
502 graphene_matrix_t *u;
503 GskGLUniformMapping *info;
504
505 g_assert (state != NULL);
506 g_assert (program != NULL);
507 g_assert (matrix != NULL);
508
509 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_MATRIX, array_count: 1, key, stamp, out_mapping: &info)))
510 {
511 if (info->info.initial || memcmp (s1: u, s2: matrix, n: sizeof *u) != 0)
512 {
513 GSK_GL_UNIFORM_STATE_REPLACE (info, u, graphene_matrix_t, 1);
514 memcpy (dest: u, src: matrix, n: sizeof *matrix);
515 gsk_gl_uniform_info_changed (info, stamp);
516 }
517 }
518}
519
520/**
521 * gsk_gl_uniform_state_set_texture:
522 * @state: a `GskGLUniformState`
523 * @program: the program id
524 * @location: the location of the texture
525 * @texture_slot: a texturing slot such as GL_TEXTURE0
526 *
527 * Sets the uniform expecting a texture to @texture_slot. This API
528 * expects a texture slot such as GL_TEXTURE0 to reduce chances of
529 * miss-use by the caller.
530 *
531 * The value stored to the uniform is in the form of 0 for GL_TEXTURE0,
532 * 1 for GL_TEXTURE1, and so on.
533 */
534static inline void
535gsk_gl_uniform_state_set_texture (GskGLUniformState *state,
536 GskGLUniformProgram *program,
537 guint key,
538 guint stamp,
539 guint texture_slot)
540{
541 GskGLUniformMapping *info;
542 guint *u;
543
544 g_assert (texture_slot >= GL_TEXTURE0);
545 g_assert (texture_slot < GL_TEXTURE16);
546
547 texture_slot -= GL_TEXTURE0;
548
549 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_TEXTURE, array_count: 1, key, stamp, out_mapping: &info)))
550 {
551 if (info->info.initial || *u != texture_slot)
552 {
553 GSK_GL_UNIFORM_STATE_REPLACE (info, u, guint, 1);
554 *u = texture_slot;
555 gsk_gl_uniform_info_changed (info, stamp);
556 }
557 }
558}
559
560/**
561 * gsk_gl_uniform_state_set_color:
562 * @state: a `GskGLUniformState`
563 * @program: a program id > 0
564 * @location: the uniform location
565 * @color: a color to set or %NULL for transparent
566 *
567 * Sets a uniform to the color described by @color. This is a convenience
568 * function to allow callers to avoid having to translate colors to floats
569 * in other portions of the renderer.
570 */
571static inline void
572gsk_gl_uniform_state_set_color (GskGLUniformState *state,
573 GskGLUniformProgram *program,
574 guint key,
575 guint stamp,
576 const GdkRGBA *color)
577{
578 static const GdkRGBA transparent = {0};
579 GskGLUniformMapping *info;
580 GdkRGBA *u;
581
582 g_assert (state != NULL);
583 g_assert (program != NULL);
584
585 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_COLOR, array_count: 1, key, stamp, out_mapping: &info)))
586 {
587 if (color == NULL)
588 color = &transparent;
589
590 if (info->info.initial || memcmp (s1: color, s2: u, n: sizeof *u) != 0)
591 {
592 GSK_GL_UNIFORM_STATE_REPLACE (info, u, GdkRGBA, 1);
593 memcpy (dest: u, src: color, n: sizeof *color);
594 gsk_gl_uniform_info_changed (info, stamp);
595 }
596 }
597}
598
599static inline void
600gsk_gl_uniform_state_set1fv (GskGLUniformState *state,
601 GskGLUniformProgram *program,
602 guint key,
603 guint stamp,
604 guint count,
605 const float *value)
606{
607 Uniform1f *u;
608 GskGLUniformMapping *info;
609
610 g_assert (state != NULL);
611 g_assert (program != NULL);
612 g_assert (count > 0);
613
614 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_1FV, array_count: count, key, stamp, out_mapping: &info)))
615 {
616 if (info->info.initial || count != info->info.array_count || memcmp (s1: u, s2: value, n: sizeof *u * count) != 0)
617 {
618 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform1f, count);
619 memcpy (dest: u, src: value, n: sizeof (Uniform1f) * count);
620 gsk_gl_uniform_info_changed (info, stamp);
621 }
622 }
623}
624
625static inline void
626gsk_gl_uniform_state_set2fv (GskGLUniformState *state,
627 GskGLUniformProgram *program,
628 guint key,
629 guint stamp,
630 guint count,
631 const float *value)
632{
633 Uniform2f *u;
634 GskGLUniformMapping *info;
635
636 g_assert (state != NULL);
637 g_assert (program != NULL);
638 g_assert (count > 0);
639
640 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_2FV, array_count: count, key, stamp, out_mapping: &info)))
641 {
642 if (info->info.initial || count != info->info.array_count || memcmp (s1: u, s2: value, n: sizeof *u * count) != 0)
643 {
644 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform2f, count);
645 memcpy (dest: u, src: value, n: sizeof (Uniform2f) * count);
646 gsk_gl_uniform_info_changed (info, stamp);
647 }
648 }
649}
650
651static inline void
652gsk_gl_uniform_state_set3fv (GskGLUniformState *state,
653 GskGLUniformProgram *program,
654 guint key,
655 guint stamp,
656 guint count,
657 const float *value)
658{
659 Uniform3f *u;
660 GskGLUniformMapping *info;
661
662 g_assert (state != NULL);
663 g_assert (program != NULL);
664 g_assert (count > 0);
665
666 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_3FV, array_count: count, key, stamp, out_mapping: &info)))
667 {
668 if (info->info.initial || count != info->info.array_count || memcmp (s1: u, s2: value, n: sizeof *u * count) != 0)
669 {
670 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform3f, count);
671 memcpy (dest: u, src: value, n: sizeof (Uniform3f) * count);
672 gsk_gl_uniform_info_changed (info, stamp);
673 }
674 }
675}
676
677static inline void
678gsk_gl_uniform_state_set4fv (GskGLUniformState *state,
679 GskGLUniformProgram *program,
680 guint key,
681 guint stamp,
682 guint count,
683 const float *value)
684{
685 Uniform4f *u;
686 GskGLUniformMapping *info;
687
688 g_assert (state != NULL);
689 g_assert (program != NULL);
690 g_assert (count > 0);
691
692 if ((u = gsk_gl_uniform_state_get_value (state, program, format: GSK_GL_UNIFORM_FORMAT_4FV, array_count: count, key, stamp, out_mapping: &info)))
693 {
694 if (info->info.initial || count != info->info.array_count || memcmp (s1: u, s2: value, n: sizeof *u * count) != 0)
695 {
696 GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform4f, count);
697 memcpy (dest: u, src: value, n: sizeof (Uniform4f) * count);
698 gsk_gl_uniform_info_changed (info, stamp);
699 }
700 }
701}
702
703static inline guint
704gsk_gl_uniform_state_fmix (guint program,
705 guint location)
706{
707 guint h = (program << 16) | location;
708
709 h ^= h >> 16;
710 h *= 0x85ebca6b;
711 h ^= h >> 13;
712 h *= 0xc2b2ae35;
713 h ^= h >> 16;
714
715 return h;
716}
717
718/*
719 * gsk_gl_uniform_state_apply:
720 * @state: the uniform state
721 * @program: the program id
722 * @location: the location of the uniform
723 * @offset: the offset of the data within the buffer
724 * @info: the uniform info
725 *
726 * This function can be used to apply state that was previously recorded
727 * by the `GskGLUniformState`.
728 *
729 * It is specifically useful from the `GskGLCommandQueue` to execute uniform
730 * changes but only when they have changed from the current value.
731 */
732static inline void
733gsk_gl_uniform_state_apply (GskGLUniformState *state,
734 guint program,
735 guint location,
736 GskGLUniformInfo info)
737{
738 guint index = gsk_gl_uniform_state_fmix (program, location) % G_N_ELEMENTS (state->apply_hash);
739 gconstpointer dataptr = GSK_GL_UNIFORM_VALUE (state->values_buf, info.offset);
740
741 /* aligned, can treat as unsigned */
742 if (*(guint *)&info == *(guint *)&state->apply_hash[index])
743 return;
744
745 state->apply_hash[index] = info;
746
747 /* TODO: We could do additional comparisons here to make sure we are
748 * changing state.
749 */
750
751 switch (info.format)
752 {
753 case GSK_GL_UNIFORM_FORMAT_1F:
754 glUniform1fv (location, 1, dataptr);
755 break;
756
757 case GSK_GL_UNIFORM_FORMAT_2F:
758 glUniform2fv (location, 1, dataptr);
759 break;
760
761 case GSK_GL_UNIFORM_FORMAT_3F:
762 glUniform3fv (location, 1, dataptr);
763 break;
764
765 case GSK_GL_UNIFORM_FORMAT_4F:
766 glUniform4fv (location, 1, dataptr);
767 break;
768
769 case GSK_GL_UNIFORM_FORMAT_1FV:
770 glUniform1fv (location, info.array_count, dataptr);
771 break;
772
773 case GSK_GL_UNIFORM_FORMAT_2FV:
774 glUniform2fv (location, info.array_count, dataptr);
775 break;
776
777 case GSK_GL_UNIFORM_FORMAT_3FV:
778 glUniform3fv (location, info.array_count, dataptr);
779 break;
780
781 case GSK_GL_UNIFORM_FORMAT_4FV:
782 glUniform4fv (location, info.array_count, dataptr);
783 break;
784
785 case GSK_GL_UNIFORM_FORMAT_1I:
786 case GSK_GL_UNIFORM_FORMAT_TEXTURE:
787 glUniform1iv (location, 1, dataptr);
788 break;
789
790 case GSK_GL_UNIFORM_FORMAT_2I:
791 glUniform2iv (location, 1, dataptr);
792 break;
793
794 case GSK_GL_UNIFORM_FORMAT_3I:
795 glUniform3iv (location, 1, dataptr);
796 break;
797
798 case GSK_GL_UNIFORM_FORMAT_4I:
799 glUniform4iv (location, 1, dataptr);
800 break;
801
802 case GSK_GL_UNIFORM_FORMAT_1UI:
803 glUniform1uiv (location, 1, dataptr);
804 break;
805
806 case GSK_GL_UNIFORM_FORMAT_MATRIX: {
807 float mat[16];
808 graphene_matrix_to_float (m: dataptr, v: mat);
809 glUniformMatrix4fv (location, 1, GL_FALSE, mat);
810#if 0
811 /* TODO: If Graphene can give us a peek here on platforms
812 * where the format is float[16] (most/all x86_64?) then
813 * We can avoid the SIMD operation to convert the format.
814 */
815 G_STATIC_ASSERT (sizeof (graphene_matrix_t) == 16*4);
816 glUniformMatrix4fv (location, 1, GL_FALSE, dataptr);
817#endif
818 }
819 break;
820
821 case GSK_GL_UNIFORM_FORMAT_COLOR:
822 glUniform4fv (location, 1, dataptr);
823 break;
824
825 case GSK_GL_UNIFORM_FORMAT_ROUNDED_RECT:
826 glUniform4fv (location, 3, dataptr);
827 break;
828
829 default:
830 g_assert_not_reached ();
831 }
832}
833
834G_END_DECLS
835
836#endif /* GSK_GL_UNIFORM_STATE_PRIVATE_H */
837

source code of gtk/gsk/gl/gskgluniformstateprivate.h