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 | |
37 | struct _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 | |
61 | typedef struct _GskGLProgramAttrib |
62 | { |
63 | const char *name; |
64 | guint location; |
65 | } GskGLProgramAttrib; |
66 | |
67 | static GBytes *empty_bytes; |
68 | |
69 | G_DEFINE_TYPE (GskGLCompiler, gsk_gl_compiler, G_TYPE_OBJECT) |
70 | |
71 | static void |
72 | gsk_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 | |
89 | static void |
90 | gsk_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 | |
99 | static void |
100 | gsk_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 | |
113 | GskGLCompiler * |
114 | gsk_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 | |
169 | void |
170 | gsk_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 | |
186 | void |
187 | gsk_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 | |
194 | void |
195 | gsk_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 | |
222 | void |
223 | gsk_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 | |
249 | void |
250 | gsk_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 | |
343 | void |
344 | gsk_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 | |
370 | void |
371 | gsk_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 | |
399 | void |
400 | gsk_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 | |
425 | static void |
426 | prepend_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 | |
449 | static gboolean |
450 | check_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 | |
495 | static void |
496 | print_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 | |
527 | static const char * |
528 | get_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 | |
535 | GskGLProgram * |
536 | gsk_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 | |