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 | |
26 | G_BEGIN_DECLS |
27 | |
28 | typedef struct { float v0; } Uniform1f; |
29 | typedef struct { float v0; float v1; } Uniform2f; |
30 | typedef struct { float v0; float v1; float v2; } Uniform3f; |
31 | typedef struct { float v0; float v1; float v2; float v3; } Uniform4f; |
32 | |
33 | typedef struct { int v0; } Uniform1i; |
34 | typedef struct { int v0; int v1; } Uniform2i; |
35 | typedef struct { int v0; int v1; int v2; } Uniform3i; |
36 | typedef struct { int v0; int v1; int v2; int v3; } Uniform4i; |
37 | |
38 | typedef 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 | |
44 | typedef 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 | |
52 | G_STATIC_ASSERT (sizeof (GskGLUniformInfo) == 4); |
53 | |
54 | typedef struct _GskGLUniformMapping |
55 | { |
56 | const char *name; |
57 | GskGLUniformInfo info; |
58 | guint stamp; |
59 | int location; |
60 | } GskGLUniformMapping; |
61 | |
62 | typedef 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 | |
71 | typedef 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 | |
80 | typedef 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 | |
108 | G_STATIC_ASSERT (GSK_GL_UNIFORM_FORMAT_LAST < (1 << GSK_GL_UNIFORM_FORMAT_BITS)); |
109 | |
110 | GskGLUniformState *gsk_gl_uniform_state_new (void); |
111 | GskGLUniformState *gsk_gl_uniform_state_ref (GskGLUniformState *state); |
112 | void gsk_gl_uniform_state_unref (GskGLUniformState *state); |
113 | GskGLUniformProgram *gsk_gl_uniform_state_get_program (GskGLUniformState *state, |
114 | guint program, |
115 | const GskGLUniformMapping *mappings, |
116 | guint n_mappings); |
117 | void gsk_gl_uniform_state_end_frame (GskGLUniformState *state); |
118 | gsize gsk_gl_uniform_format_size (GskGLUniformFormat format); |
119 | gpointer 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 | |
129 | static inline gpointer |
130 | gsk_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 | |
170 | G_GNUC_PURE static inline guint |
171 | gsk_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 | |
184 | static inline gpointer |
185 | gsk_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 | |
222 | static inline void |
223 | gsk_gl_uniform_info_changed (GskGLUniformMapping *info, |
224 | guint stamp) |
225 | { |
226 | info->stamp = stamp; |
227 | info->info.initial = FALSE; |
228 | } |
229 | |
230 | static inline void |
231 | gsk_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 | |
254 | static inline void |
255 | gsk_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 | |
280 | static inline void |
281 | gsk_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 | |
308 | static inline void |
309 | gsk_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 | |
338 | static inline void |
339 | gsk_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 | |
362 | static inline void |
363 | gsk_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 | |
386 | static inline void |
387 | gsk_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 | |
412 | static inline void |
413 | gsk_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 | |
440 | static inline void |
441 | gsk_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 | |
470 | static inline void |
471 | gsk_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 | |
495 | static inline void |
496 | gsk_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 | */ |
534 | static inline void |
535 | gsk_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 | */ |
571 | static inline void |
572 | gsk_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 | |
599 | static inline void |
600 | gsk_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 | |
625 | static inline void |
626 | gsk_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 | |
651 | static inline void |
652 | gsk_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 | |
677 | static inline void |
678 | gsk_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 | |
703 | static inline guint |
704 | gsk_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 | */ |
732 | static inline void |
733 | gsk_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 | |
834 | G_END_DECLS |
835 | |
836 | #endif /* GSK_GL_UNIFORM_STATE_PRIVATE_H */ |
837 | |