1 #include "config.h"
2
3 #include "gskglshaderbuilderprivate.h"
4
5 #include "gskdebugprivate.h"
6
7 #include <gdk/gdk.h>
8 #include <epoxy/gl.h>
9
10 void
gsk_gl_shader_builder_init(GskGLShaderBuilder * self,const char * common_preamble_resource_path,const char * vs_preamble_resource_path,const char * fs_preamble_resource_path)11 gsk_gl_shader_builder_init (GskGLShaderBuilder *self,
12 const char *common_preamble_resource_path,
13 const char *vs_preamble_resource_path,
14 const char *fs_preamble_resource_path)
15 {
16 memset (self, 0, sizeof (*self));
17
18 self->preamble = g_resources_lookup_data (common_preamble_resource_path, 0, NULL);
19 self->vs_preamble = g_resources_lookup_data (vs_preamble_resource_path, 0, NULL);
20 self->fs_preamble = g_resources_lookup_data (fs_preamble_resource_path, 0, NULL);
21
22 g_assert (self->preamble);
23 g_assert (self->vs_preamble);
24 g_assert (self->fs_preamble);
25 }
26
27 void
gsk_gl_shader_builder_finish(GskGLShaderBuilder * self)28 gsk_gl_shader_builder_finish (GskGLShaderBuilder *self)
29 {
30 g_bytes_unref (self->preamble);
31 g_bytes_unref (self->vs_preamble);
32 g_bytes_unref (self->fs_preamble);
33 }
34
35 void
gsk_gl_shader_builder_set_glsl_version(GskGLShaderBuilder * self,int version)36 gsk_gl_shader_builder_set_glsl_version (GskGLShaderBuilder *self,
37 int version)
38 {
39 self->version = version;
40 }
41
42 static void
prepend_line_numbers(char * code,GString * s)43 prepend_line_numbers (char *code,
44 GString *s)
45 {
46 char *p;
47 int line;
48
49 p = code;
50 line = 1;
51 while (*p)
52 {
53 char *end = strchr (p, '\n');
54 if (end)
55 end = end + 1; /* Include newline */
56 else
57 end = p + strlen (p);
58
59 g_string_append_printf (s, "%3d| ", line++);
60 g_string_append_len (s, p, end - p);
61
62 p = end;
63 }
64 }
65
66 static gboolean
check_shader_error(int shader_id,int shader_type,const char * resource_path,GError ** error)67 check_shader_error (int shader_id,
68 int shader_type,
69 const char *resource_path,
70 GError **error)
71 {
72 int status;
73 int log_len;
74 char *buffer;
75 int code_len;
76 char *code;
77 GString *s;
78
79 glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status);
80
81 if (G_LIKELY (status == GL_TRUE))
82 return TRUE;
83
84 glGetShaderiv (shader_id, GL_INFO_LOG_LENGTH, &log_len);
85 buffer = g_malloc0 (log_len + 1);
86 glGetShaderInfoLog (shader_id, log_len, NULL, buffer);
87
88 glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
89 code = g_malloc0 (code_len + 1);
90 glGetShaderSource (shader_id, code_len, NULL, code);
91
92 s = g_string_new ("");
93 prepend_line_numbers (code, s);
94
95 g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_COMPILATION_FAILED,
96 "Compilation failure in %s shader %s.\nSource Code:\n%s\n\nError Message:\n%s\n\n",
97 (shader_type == GL_FRAGMENT_SHADER ? "fragment" : "vertex"),
98 resource_path,
99 s->str,
100 buffer);
101
102 g_string_free (s, TRUE);
103 g_free (buffer);
104 g_free (code);
105
106 return FALSE;
107 }
108
109 static void
print_shader_info(const char * prefix,int shader_id,const char * resource_path)110 print_shader_info (const char *prefix,
111 int shader_id,
112 const char *resource_path)
113 {
114 if (GSK_DEBUG_CHECK(SHADERS))
115 {
116 int code_len;
117 char *code;
118 GString *s;
119
120 glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
121 code = g_malloc0 (code_len + 1);
122 glGetShaderSource (shader_id, code_len, NULL, code);
123
124 s = g_string_new ("");
125 prepend_line_numbers (code, s);
126
127 g_message ("%s %d, %s:\n%s", prefix, shader_id, resource_path, s->str);
128 g_string_free (s, TRUE);
129 g_free (code);
130 }
131 }
132
133 int
gsk_gl_shader_builder_create_program(GskGLShaderBuilder * self,const char * resource_path,const char * extra_fragment_snippet,gsize extra_fragment_length,GError ** error)134 gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
135 const char *resource_path,
136 const char *extra_fragment_snippet,
137 gsize extra_fragment_length,
138 GError **error)
139 {
140
141 GBytes *source_bytes = g_resources_lookup_data (resource_path, 0, NULL);
142 char version_buffer[64];
143 const char *source;
144 const char *vertex_shader_start;
145 const char *fragment_shader_start;
146 int vertex_id;
147 int fragment_id;
148 int program_id = -1;
149 int status;
150
151 g_assert (source_bytes);
152
153 source = g_bytes_get_data (source_bytes, NULL);
154 vertex_shader_start = strstr (source, "VERTEX_SHADER");
155 fragment_shader_start = strstr (source, "FRAGMENT_SHADER");
156
157 g_assert (vertex_shader_start);
158 g_assert (fragment_shader_start);
159
160 /* They both start at the next newline */
161 vertex_shader_start = strstr (vertex_shader_start, "\n");
162 fragment_shader_start = strstr (fragment_shader_start, "\n");
163
164 g_snprintf (version_buffer, sizeof (version_buffer),
165 "#version %d\n", self->version);
166
167 vertex_id = glCreateShader (GL_VERTEX_SHADER);
168 glShaderSource (vertex_id, 8,
169 (const char *[]) {
170 version_buffer,
171 self->debugging ? "#define GSK_DEBUG 1\n" : "",
172 self->legacy ? "#define GSK_LEGACY 1\n" : "",
173 self->gl3 ? "#define GSK_GL3 1\n" : "",
174 self->gles ? "#define GSK_GLES 1\n" : "",
175 g_bytes_get_data (self->preamble, NULL),
176 g_bytes_get_data (self->vs_preamble, NULL),
177 vertex_shader_start
178 },
179 (int[]) {
180 -1,
181 -1,
182 -1,
183 -1,
184 -1,
185 -1,
186 -1,
187 fragment_shader_start - vertex_shader_start
188 });
189 glCompileShader (vertex_id);
190
191 if (!check_shader_error (vertex_id, GL_VERTEX_SHADER, resource_path, error))
192 {
193 glDeleteShader (vertex_id);
194 goto out;
195 }
196
197 print_shader_info ("Vertex shader", vertex_id, resource_path);
198
199 fragment_id = glCreateShader (GL_FRAGMENT_SHADER);
200 glShaderSource (fragment_id, 9,
201 (const char *[]) {
202 version_buffer,
203 self->debugging ? "#define GSK_DEBUG 1\n" : "",
204 self->legacy ? "#define GSK_LEGACY 1\n" : "",
205 self->gl3 ? "#define GSK_GL3 1\n" : "",
206 self->gles ? "#define GSK_GLES 1\n" : "",
207 g_bytes_get_data (self->preamble, NULL),
208 g_bytes_get_data (self->fs_preamble, NULL),
209 fragment_shader_start,
210 extra_fragment_snippet ? extra_fragment_snippet : ""
211 },
212 (int[]) {
213 -1,
214 -1,
215 -1,
216 -1,
217 -1,
218 -1,
219 -1,
220 -1,
221 extra_fragment_length,
222 });
223 glCompileShader (fragment_id);
224
225 if (!check_shader_error (fragment_id, GL_FRAGMENT_SHADER, resource_path, error))
226 {
227 glDeleteShader (fragment_id);
228 goto out;
229 }
230
231 print_shader_info ("Fragment shader", fragment_id, resource_path);
232
233 program_id = glCreateProgram ();
234 glAttachShader (program_id, vertex_id);
235 glAttachShader (program_id, fragment_id);
236 glBindAttribLocation (program_id, 0, "aPosition");
237 glBindAttribLocation (program_id, 1, "aUv");
238 glLinkProgram (program_id);
239 glDetachShader (program_id, vertex_id);
240 glDetachShader (program_id, fragment_id);
241
242 glGetProgramiv (program_id, GL_LINK_STATUS, &status);
243 if (status == GL_FALSE)
244 {
245 char *buffer = NULL;
246 int log_len = 0;
247
248 glGetProgramiv (program_id, GL_INFO_LOG_LENGTH, &log_len);
249
250 buffer = g_malloc0 (log_len + 1);
251 glGetProgramInfoLog (program_id, log_len, NULL, buffer);
252
253 g_warning ("Linking failure in shader:\n%s", buffer);
254 g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_LINK_FAILED,
255 "Linking failure in shader: %s", buffer);
256
257 g_free (buffer);
258
259 glDeleteProgram (program_id);
260 program_id = -1;
261 }
262
263 glDeleteShader (vertex_id);
264 glDeleteShader (fragment_id);
265
266 out:
267 g_bytes_unref (source_bytes);
268
269 return program_id;
270 }
271
272