1/* gskglcompiler.c
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#include "config.h"
22
23#include <gsk/gskdebugprivate.h>
24#include <gio/gio.h>
25#include <string.h>
26
27#include "gskglcommandqueueprivate.h"
28#include "gskglcompilerprivate.h"
29#include "gskglprogramprivate.h"
30
31#define SHADER_VERSION_GLES "100"
32#define SHADER_VERSION_GLES3 "300 es"
33#define SHADER_VERSION_GL2_LEGACY "110"
34#define SHADER_VERSION_GL3_LEGACY "130"
35#define SHADER_VERSION_GL3 "150"
36
37struct _GskGLCompiler
38{
39 GObject parent_instance;
40
41 GskGLDriver *driver;
42
43 GBytes *all_preamble;
44 GBytes *fragment_preamble;
45 GBytes *vertex_preamble;
46 GBytes *fragment_source;
47 GBytes *fragment_suffix;
48 GBytes *vertex_source;
49 GBytes *vertex_suffix;
50
51 GArray *attrib_locations;
52
53 const char *glsl_version;
54
55 guint gl3 : 1;
56 guint gles : 1;
57 guint legacy : 1;
58 guint debug_shaders : 1;
59};
60
61typedef struct _GskGLProgramAttrib
62{
63 const char *name;
64 guint location;
65} GskGLProgramAttrib;
66
67static GBytes *empty_bytes;
68
69G_DEFINE_TYPE (GskGLCompiler, gsk_gl_compiler, G_TYPE_OBJECT)
70
71static void
72gsk_gl_compiler_finalize (GObject *object)
73{
74 GskGLCompiler *self = (GskGLCompiler *)object;
75
76 g_clear_pointer (&self->all_preamble, g_bytes_unref);
77 g_clear_pointer (&self->fragment_preamble, g_bytes_unref);
78 g_clear_pointer (&self->vertex_preamble, g_bytes_unref);
79 g_clear_pointer (&self->vertex_suffix, g_bytes_unref);
80 g_clear_pointer (&self->fragment_source, g_bytes_unref);
81 g_clear_pointer (&self->fragment_suffix, g_bytes_unref);
82 g_clear_pointer (&self->vertex_source, g_bytes_unref);
83 g_clear_pointer (&self->attrib_locations, g_array_unref);
84 g_clear_object (&self->driver);
85
86 G_OBJECT_CLASS (gsk_gl_compiler_parent_class)->finalize (object);
87}
88
89static void
90gsk_gl_compiler_class_init (GskGLCompilerClass *klass)
91{
92 GObjectClass *object_class = G_OBJECT_CLASS (klass);
93
94 object_class->finalize = gsk_gl_compiler_finalize;
95
96 empty_bytes = g_bytes_new (NULL, size: 0);
97}
98
99static void
100gsk_gl_compiler_init (GskGLCompiler *self)
101{
102 self->glsl_version = "150";
103 self->attrib_locations = g_array_new (FALSE, FALSE, element_size: sizeof (GskGLProgramAttrib));
104 self->all_preamble = g_bytes_ref (bytes: empty_bytes);
105 self->vertex_preamble = g_bytes_ref (bytes: empty_bytes);
106 self->fragment_preamble = g_bytes_ref (bytes: empty_bytes);
107 self->vertex_source = g_bytes_ref (bytes: empty_bytes);
108 self->vertex_suffix = g_bytes_ref (bytes: empty_bytes);
109 self->fragment_source = g_bytes_ref (bytes: empty_bytes);
110 self->fragment_suffix = g_bytes_ref (bytes: empty_bytes);
111}
112
113GskGLCompiler *
114gsk_gl_compiler_new (GskGLDriver *driver,
115 gboolean debug_shaders)
116{
117 GskGLCompiler *self;
118 GdkGLContext *context;
119
120 g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL);
121 g_return_val_if_fail (driver->shared_command_queue != NULL, NULL);
122
123 self = g_object_new (GSK_TYPE_GL_COMPILER, NULL);
124 self->driver = g_object_ref (driver);
125 self->debug_shaders = !!debug_shaders;
126
127 context = gsk_gl_command_queue_get_context (self: self->driver->shared_command_queue);
128
129 if (gdk_gl_context_get_use_es (context))
130 {
131 int maj, min;
132
133 /* for OpenGL/ES 3.0+, use "300 es" as our shader version */
134 gdk_gl_context_get_version (context, major: &maj, minor: &min);
135
136 if (maj >= 3)
137 self->glsl_version = SHADER_VERSION_GLES3;
138 else
139 {
140 self->glsl_version = SHADER_VERSION_GLES;
141 self->gles = TRUE;
142 }
143 }
144 else if (gdk_gl_context_is_legacy (context))
145 {
146 int maj, min;
147
148 gdk_gl_context_get_version (context, major: &maj, minor: &min);
149
150 /* On Windows, legacy contexts can give us a GL 4.x context */
151 if (maj >= 3)
152 self->glsl_version = SHADER_VERSION_GL3_LEGACY;
153 else
154 self->glsl_version = SHADER_VERSION_GL2_LEGACY;
155
156 self->legacy = TRUE;
157 }
158 else
159 {
160 self->glsl_version = SHADER_VERSION_GL3;
161 self->gl3 = TRUE;
162 }
163
164 gsk_gl_command_queue_make_current (self: self->driver->shared_command_queue);
165
166 return g_steal_pointer (&self);
167}
168
169void
170gsk_gl_compiler_bind_attribute (GskGLCompiler *self,
171 const char *name,
172 guint location)
173{
174 GskGLProgramAttrib attrib;
175
176 g_return_if_fail (GSK_IS_GL_COMPILER (self));
177 g_return_if_fail (name != NULL);
178 g_return_if_fail (location < 32);
179
180 attrib.name = g_intern_string (string: name);
181 attrib.location = location;
182
183 g_array_append_val (self->attrib_locations, attrib);
184}
185
186void
187gsk_gl_compiler_clear_attributes (GskGLCompiler *self)
188{
189 g_return_if_fail (GSK_IS_GL_COMPILER (self));
190
191 g_array_set_size (array: self->attrib_locations, length: 0);
192}
193
194void
195gsk_gl_compiler_set_preamble (GskGLCompiler *self,
196 GskGLCompilerKind kind,
197 GBytes *preamble_bytes)
198{
199 GBytes **loc = NULL;
200
201 g_return_if_fail (GSK_IS_GL_COMPILER (self));
202 g_return_if_fail (preamble_bytes != NULL);
203
204 if (kind == GSK_GL_COMPILER_ALL)
205 loc = &self->all_preamble;
206 else if (kind == GSK_GL_COMPILER_FRAGMENT)
207 loc = &self->fragment_preamble;
208 else if (kind == GSK_GL_COMPILER_VERTEX)
209 loc = &self->vertex_preamble;
210 else
211 g_return_if_reached ();
212
213 g_assert (loc != NULL);
214
215 if (*loc != preamble_bytes)
216 {
217 g_clear_pointer (loc, g_bytes_unref);
218 *loc = preamble_bytes ? g_bytes_ref (bytes: preamble_bytes) : NULL;
219 }
220}
221
222void
223gsk_gl_compiler_set_preamble_from_resource (GskGLCompiler *self,
224 GskGLCompilerKind kind,
225 const char *resource_path)
226{
227 GError *error = NULL;
228 GBytes *bytes;
229
230 g_return_if_fail (GSK_IS_GL_COMPILER (self));
231 g_return_if_fail (kind == GSK_GL_COMPILER_ALL ||
232 kind == GSK_GL_COMPILER_VERTEX ||
233 kind == GSK_GL_COMPILER_FRAGMENT);
234 g_return_if_fail (resource_path != NULL);
235
236 bytes = g_resources_lookup_data (path: resource_path,
237 lookup_flags: G_RESOURCE_LOOKUP_FLAGS_NONE,
238 error: &error);
239
240 if (bytes == NULL)
241 g_warning ("Cannot set shader from resource: %s", error->message);
242 else
243 gsk_gl_compiler_set_preamble (self, kind, preamble_bytes: bytes);
244
245 g_clear_pointer (&bytes, g_bytes_unref);
246 g_clear_error (err: &error);
247}
248
249void
250gsk_gl_compiler_set_source (GskGLCompiler *self,
251 GskGLCompilerKind kind,
252 GBytes *source_bytes)
253{
254 GBytes **loc = NULL;
255
256 g_return_if_fail (GSK_IS_GL_COMPILER (self));
257 g_return_if_fail (kind == GSK_GL_COMPILER_ALL ||
258 kind == GSK_GL_COMPILER_VERTEX ||
259 kind == GSK_GL_COMPILER_FRAGMENT);
260
261 if (source_bytes == NULL)
262 source_bytes = empty_bytes;
263
264 /* If kind is ALL, then we need to split the fragment and
265 * vertex shaders from the bytes and assign them individually.
266 * This safely scans for FRAGMENT_SHADER and VERTEX_SHADER as
267 * specified within the GLSL resources. Some care is taken to
268 * use GBytes which reference the original bytes instead of
269 * copying them.
270 */
271 if (kind == GSK_GL_COMPILER_ALL)
272 {
273 gsize len = 0;
274 const char *source;
275 const char *vertex_shader_start;
276 const char *fragment_shader_start;
277 const char *endpos;
278 GBytes *fragment_bytes;
279 GBytes *vertex_bytes;
280
281 g_clear_pointer (&self->fragment_source, g_bytes_unref);
282 g_clear_pointer (&self->vertex_source, g_bytes_unref);
283
284 source = g_bytes_get_data (bytes: source_bytes, size: &len);
285 endpos = source + len;
286 vertex_shader_start = g_strstr_len (haystack: source, haystack_len: len, needle: "VERTEX_SHADER");
287 fragment_shader_start = g_strstr_len (haystack: source, haystack_len: len, needle: "FRAGMENT_SHADER");
288
289 if (vertex_shader_start == NULL)
290 {
291 g_warning ("Failed to locate VERTEX_SHADER in shader source");
292 return;
293 }
294
295 if (fragment_shader_start == NULL)
296 {
297 g_warning ("Failed to locate FRAGMENT_SHADER in shader source");
298 return;
299 }
300
301 if (vertex_shader_start > fragment_shader_start)
302 {
303 g_warning ("VERTEX_SHADER must come before FRAGMENT_SHADER");
304 return;
305 }
306
307 /* Locate next newlines */
308 while (vertex_shader_start < endpos && vertex_shader_start[0] != '\n')
309 vertex_shader_start++;
310 while (fragment_shader_start < endpos && fragment_shader_start[0] != '\n')
311 fragment_shader_start++;
312
313 vertex_bytes = g_bytes_new_from_bytes (bytes: source_bytes,
314 offset: vertex_shader_start - source,
315 length: fragment_shader_start - vertex_shader_start);
316 fragment_bytes = g_bytes_new_from_bytes (bytes: source_bytes,
317 offset: fragment_shader_start - source,
318 length: endpos - fragment_shader_start);
319
320 gsk_gl_compiler_set_source (self, kind: GSK_GL_COMPILER_VERTEX, source_bytes: vertex_bytes);
321 gsk_gl_compiler_set_source (self, kind: GSK_GL_COMPILER_FRAGMENT, source_bytes: fragment_bytes);
322
323 g_bytes_unref (bytes: fragment_bytes);
324 g_bytes_unref (bytes: vertex_bytes);
325
326 return;
327 }
328
329 if (kind == GSK_GL_COMPILER_FRAGMENT)
330 loc = &self->fragment_source;
331 else if (kind == GSK_GL_COMPILER_VERTEX)
332 loc = &self->vertex_source;
333 else
334 g_return_if_reached ();
335
336 if (*loc != source_bytes)
337 {
338 g_clear_pointer (loc, g_bytes_unref);
339 *loc = g_bytes_ref (bytes: source_bytes);
340 }
341}
342
343void
344gsk_gl_compiler_set_source_from_resource (GskGLCompiler *self,
345 GskGLCompilerKind kind,
346 const char *resource_path)
347{
348 GError *error = NULL;
349 GBytes *bytes;
350
351 g_return_if_fail (GSK_IS_GL_COMPILER (self));
352 g_return_if_fail (kind == GSK_GL_COMPILER_ALL ||
353 kind == GSK_GL_COMPILER_VERTEX ||
354 kind == GSK_GL_COMPILER_FRAGMENT);
355 g_return_if_fail (resource_path != NULL);
356
357 bytes = g_resources_lookup_data (path: resource_path,
358 lookup_flags: G_RESOURCE_LOOKUP_FLAGS_NONE,
359 error: &error);
360
361 if (bytes == NULL)
362 g_warning ("Cannot set shader from resource: %s", error->message);
363 else
364 gsk_gl_compiler_set_source (self, kind, source_bytes: bytes);
365
366 g_clear_pointer (&bytes, g_bytes_unref);
367 g_clear_error (err: &error);
368}
369
370void
371gsk_gl_compiler_set_suffix (GskGLCompiler *self,
372 GskGLCompilerKind kind,
373 GBytes *suffix_bytes)
374{
375 GBytes **loc;
376
377 g_return_if_fail (GSK_IS_GL_COMPILER (self));
378 g_return_if_fail (kind == GSK_GL_COMPILER_VERTEX ||
379 kind == GSK_GL_COMPILER_FRAGMENT);
380 g_return_if_fail (suffix_bytes != NULL);
381
382 if (suffix_bytes == NULL)
383 suffix_bytes = empty_bytes;
384
385 if (kind == GSK_GL_COMPILER_FRAGMENT)
386 loc = &self->fragment_suffix;
387 else if (kind == GSK_GL_COMPILER_VERTEX)
388 loc = &self->vertex_suffix;
389 else
390 g_return_if_reached ();
391
392 if (*loc != suffix_bytes)
393 {
394 g_clear_pointer (loc, g_bytes_unref);
395 *loc = g_bytes_ref (bytes: suffix_bytes);
396 }
397}
398
399void
400gsk_gl_compiler_set_suffix_from_resource (GskGLCompiler *self,
401 GskGLCompilerKind kind,
402 const char *resource_path)
403{
404 GError *error = NULL;
405 GBytes *bytes;
406
407 g_return_if_fail (GSK_IS_GL_COMPILER (self));
408 g_return_if_fail (kind == GSK_GL_COMPILER_VERTEX ||
409 kind == GSK_GL_COMPILER_FRAGMENT);
410 g_return_if_fail (resource_path != NULL);
411
412 bytes = g_resources_lookup_data (path: resource_path,
413 lookup_flags: G_RESOURCE_LOOKUP_FLAGS_NONE,
414 error: &error);
415
416 if (bytes == NULL)
417 g_warning ("Cannot set suffix from resource: %s", error->message);
418 else
419 gsk_gl_compiler_set_suffix (self, kind, suffix_bytes: bytes);
420
421 g_clear_pointer (&bytes, g_bytes_unref);
422 g_clear_error (err: &error);
423}
424
425static void
426prepend_line_numbers (char *code,
427 GString *s)
428{
429 char *p;
430 int line;
431
432 p = code;
433 line = 1;
434 while (*p)
435 {
436 char *end = strchr (s: p, c: '\n');
437 if (end)
438 end = end + 1; /* Include newline */
439 else
440 end = p + strlen (s: p);
441
442 g_string_append_printf (string: s, format: "%3d| ", line++);
443 g_string_append_len (string: s, val: p, len: end - p);
444
445 p = end;
446 }
447}
448
449static gboolean
450check_shader_error (int shader_id,
451 GError **error)
452{
453 GLint status;
454 GLint log_len;
455 GLint code_len;
456 char *buffer;
457 char *code;
458 GString *s;
459
460 glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status);
461
462 if G_LIKELY (status == GL_TRUE)
463 return TRUE;
464
465 glGetShaderiv (shader_id, GL_INFO_LOG_LENGTH, &log_len);
466 buffer = g_malloc0 (n_bytes: log_len + 1);
467 glGetShaderInfoLog (shader_id, log_len, NULL, buffer);
468
469 glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
470 code = g_malloc0 (n_bytes: code_len + 1);
471 glGetShaderSource (shader_id, code_len, NULL, code);
472
473 s = g_string_new (init: "");
474 prepend_line_numbers (code, s);
475
476 g_set_error (err: error,
477 GDK_GL_ERROR,
478 code: GDK_GL_ERROR_COMPILATION_FAILED,
479 format: "Compilation failure in shader.\n"
480 "Source Code: %s\n"
481 "\n"
482 "Error Message:\n"
483 "%s\n"
484 "\n",
485 s->str,
486 buffer);
487
488 g_string_free (string: s, TRUE);
489 g_free (mem: buffer);
490 g_free (mem: code);
491
492 return FALSE;
493}
494
495static void
496print_shader_info (const char *prefix,
497 int shader_id,
498 const char *name)
499{
500 if (GSK_DEBUG_CHECK(SHADERS))
501 {
502 int code_len;
503
504 glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
505
506 if (code_len > 0)
507 {
508 char *code;
509 GString *s;
510
511 code = g_malloc0 (n_bytes: code_len + 1);
512 glGetShaderSource (shader_id, code_len, NULL, code);
513
514 s = g_string_new (NULL);
515 prepend_line_numbers (code, s);
516
517 g_message ("%s %d, %s:\n%s",
518 prefix, shader_id,
519 name ? name : "unnamed",
520 s->str);
521 g_string_free (string: s, TRUE);
522 g_free (mem: code);
523 }
524 }
525}
526
527static const char *
528get_shader_string (GBytes *bytes)
529{
530 /* 0 length bytes will give us NULL back */
531 const char *str = g_bytes_get_data (bytes, NULL);
532 return str ? str : "";
533}
534
535GskGLProgram *
536gsk_gl_compiler_compile (GskGLCompiler *self,
537 const char *name,
538 const char *clip,
539 GError **error)
540{
541 char version[32];
542 const char *debug = "";
543 const char *legacy = "";
544 const char *gl3 = "";
545 const char *gles = "";
546 int program_id;
547 int vertex_id;
548 int fragment_id;
549 int status;
550
551 g_return_val_if_fail (GSK_IS_GL_COMPILER (self), NULL);
552 g_return_val_if_fail (self->all_preamble != NULL, NULL);
553 g_return_val_if_fail (self->fragment_preamble != NULL, NULL);
554 g_return_val_if_fail (self->vertex_preamble != NULL, NULL);
555 g_return_val_if_fail (self->fragment_source != NULL, NULL);
556 g_return_val_if_fail (self->vertex_source != NULL, NULL);
557 g_return_val_if_fail (self->driver != NULL, NULL);
558
559 gsk_gl_command_queue_make_current (self: self->driver->command_queue);
560
561 g_snprintf (string: version, n: sizeof version, format: "#version %s\n", self->glsl_version);
562
563 if (self->debug_shaders)
564 debug = "#define GSK_DEBUG 1\n";
565
566 if (self->legacy)
567 legacy = "#define GSK_LEGACY 1\n";
568
569 if (self->gles)
570 gles = "#define GSK_GLES 1\n";
571
572 if (self->gl3)
573 gl3 = "#define GSK_GL3 1\n";
574
575 vertex_id = glCreateShader (GL_VERTEX_SHADER);
576 glShaderSource (vertex_id,
577 10,
578 (const char *[]) {
579 version, debug, legacy, gl3, gles,
580 clip,
581 get_shader_string (bytes: self->all_preamble),
582 get_shader_string (bytes: self->vertex_preamble),
583 get_shader_string (bytes: self->vertex_source),
584 get_shader_string (bytes: self->vertex_suffix),
585 },
586 (int[]) {
587 strlen (s: version),
588 strlen (s: debug),
589 strlen (s: legacy),
590 strlen (s: gl3),
591 strlen (s: gles),
592 strlen (s: clip),
593 g_bytes_get_size (bytes: self->all_preamble),
594 g_bytes_get_size (bytes: self->vertex_preamble),
595 g_bytes_get_size (bytes: self->vertex_source),
596 g_bytes_get_size (bytes: self->vertex_suffix),
597 });
598 glCompileShader (vertex_id);
599
600 if (!check_shader_error (shader_id: vertex_id, error))
601 {
602 glDeleteShader (vertex_id);
603 return NULL;
604 }
605
606 print_shader_info (prefix: "Vertex shader", shader_id: vertex_id, name);
607
608 fragment_id = glCreateShader (GL_FRAGMENT_SHADER);
609 glShaderSource (fragment_id,
610 10,
611 (const char *[]) {
612 version, debug, legacy, gl3, gles,
613 clip,
614 get_shader_string (bytes: self->all_preamble),
615 get_shader_string (bytes: self->fragment_preamble),
616 get_shader_string (bytes: self->fragment_source),
617 get_shader_string (bytes: self->fragment_suffix),
618 },
619 (int[]) {
620 strlen (s: version),
621 strlen (s: debug),
622 strlen (s: legacy),
623 strlen (s: gl3),
624 strlen (s: gles),
625 strlen (s: clip),
626 g_bytes_get_size (bytes: self->all_preamble),
627 g_bytes_get_size (bytes: self->fragment_preamble),
628 g_bytes_get_size (bytes: self->fragment_source),
629 g_bytes_get_size (bytes: self->fragment_suffix),
630 });
631 glCompileShader (fragment_id);
632
633 if (!check_shader_error (shader_id: fragment_id, error))
634 {
635 glDeleteShader (vertex_id);
636 glDeleteShader (fragment_id);
637 return NULL;
638 }
639
640 print_shader_info (prefix: "Fragment shader", shader_id: fragment_id, name);
641
642 program_id = glCreateProgram ();
643 glAttachShader (program_id, vertex_id);
644 glAttachShader (program_id, fragment_id);
645
646 for (guint i = 0; i < self->attrib_locations->len; i++)
647 {
648 const GskGLProgramAttrib *attrib;
649
650 attrib = &g_array_index (self->attrib_locations, GskGLProgramAttrib, i);
651 glBindAttribLocation (program_id, attrib->location, attrib->name);
652 }
653
654 glLinkProgram (program_id);
655
656 glGetProgramiv (program_id, GL_LINK_STATUS, &status);
657
658 glDetachShader (program_id, vertex_id);
659 glDeleteShader (vertex_id);
660
661 glDetachShader (program_id, fragment_id);
662 glDeleteShader (fragment_id);
663
664 if (status == GL_FALSE)
665 {
666 char *buffer = NULL;
667 int log_len = 0;
668
669 glGetProgramiv (program_id, GL_INFO_LOG_LENGTH, &log_len);
670
671 if (log_len > 0)
672 {
673 /* log_len includes NULL */
674 buffer = g_malloc0 (n_bytes: log_len);
675 glGetProgramInfoLog (program_id, log_len, NULL, buffer);
676 }
677
678 g_warning ("Linking failure in shader:\n%s",
679 buffer ? buffer : "");
680
681 g_set_error (err: error,
682 GDK_GL_ERROR,
683 code: GDK_GL_ERROR_LINK_FAILED,
684 format: "Linking failure in shader: %s",
685 buffer ? buffer : "");
686
687 g_free (mem: buffer);
688
689 glDeleteProgram (program_id);
690
691 return NULL;
692 }
693
694 return gsk_gl_program_new (driver: self->driver, name, program_id);
695}
696

source code of gtk/gsk/gl/gskglcompiler.c