Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
scenefx/render/fx_renderer/shaders.c (17.5K)
1 #include <EGL/egl.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <wlr/util/log.h>
5 #include <scenefx/types/fx/clipped_region.h>
6 #include <scenefx/render/fx_renderer/fx_renderer.h>
7
8 #include "render/fx_renderer/shaders.h"
9
10 // shaders
11 #include "GLES2/gl2.h"
12 #include "common_vert_src.h"
13 #include "gradient_frag_src.h"
14 #include "corner_alpha_frag_src.h"
15 #include "quad_frag_src.h"
16 #include "quad_grad_frag_src.h"
17 #include "quad_round_frag_src.h"
18 #include "quad_grad_round_frag_src.h"
19 #include "tex_frag_src.h"
20 #include "box_shadow_frag_src.h"
21 #include "bevel_frag_src.h"
22 #include "frame_frag_src.h"
23 #include "droplet_frag_src.h"
24 #include "blur1_frag_src.h"
25 #include "blur2_frag_src.h"
26 #include "blur_effects_frag_src.h"
27
28 GLuint compile_shader(GLuint type, const GLchar *src) {
29 GLuint shader = glCreateShader(type);
30 glShaderSource(shader, 1, &src, NULL);
31 glCompileShader(shader);
32
33 GLint ok;
34 glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
35 if (ok == GL_FALSE) {
36 wlr_log(WLR_ERROR, "Failed to compile shader");
37 glDeleteShader(shader);
38 shader = 0;
39 }
40
41 return shader;
42 }
43
44 GLuint link_program(const GLchar *frag_src) {
45 GLuint vert = compile_shader(GL_VERTEX_SHADER, common_vert_src);
46 if (!vert) {
47 goto error;
48 }
49
50 GLuint frag = compile_shader(GL_FRAGMENT_SHADER, frag_src);
51 if (!frag) {
52 glDeleteShader(vert);
53 goto error;
54 }
55
56 GLuint prog = glCreateProgram();
57 glAttachShader(prog, vert);
58 glAttachShader(prog, frag);
59 glLinkProgram(prog);
60
61 glDetachShader(prog, vert);
62 glDetachShader(prog, frag);
63 glDeleteShader(vert);
64 glDeleteShader(frag);
65
66 GLint ok;
67 glGetProgramiv(prog, GL_LINK_STATUS, &ok);
68 if (ok == GL_FALSE) {
69 wlr_log(WLR_ERROR, "Failed to link shader");
70 glDeleteProgram(prog);
71 goto error;
72 }
73
74 return prog;
75
76 error:
77 return 0;
78 }
79
80
81 bool check_gl_ext(const char *exts, const char *ext) {
82 size_t extlen = strlen(ext);
83 const char *end = exts + strlen(exts);
84
85 while (exts < end) {
86 if (exts[0] == ' ') {
87 exts++;
88 continue;
89 }
90 size_t n = strcspn(exts, " ");
91 if (n == extlen && strncmp(ext, exts, n) == 0) {
92 return true;
93 }
94 exts += n;
95 }
96 return false;
97 }
98
99 void load_gl_proc(void *proc_ptr, const char *name) {
100 void *proc = (void *)eglGetProcAddress(name);
101 if (proc == NULL) {
102 wlr_log(WLR_ERROR, "FX RENDERER: eglGetProcAddress(%s) failed", name);
103 abort();
104 }
105 *(void **)proc_ptr = proc;
106 }
107
108 // Renderer-global corner-shape exponent (circular arcs by default); set once
109 // from the compositor's config via fx_renderer_set_corner_shape.
110 static float global_corner_shape = 2.0f;
111
112 void fx_renderer_set_corner_shape(float shape) {
113 global_corner_shape = shape;
114 }
115
116 float fx_corner_shape(void) {
117 return global_corner_shape;
118 }
119
120 void uniform_corner_radii_set(const struct shader_corner_radii *uniform,
121 const struct fx_corner_fradii *corners) {
122 /* The corner-SDF shaders flip Y (relative_pos.y = size.y - y) on top of
123 * an already top-down gl_FragCoord in this renderer's FBO setup, so a
124 * radius bound to the shader's "top" slots renders at the SCREEN bottom
125 * and vice versa. Every symmetric consumer (grid cells, window
126 * backgrounds — equal radii on all four corners) masked this for years;
127 * the border corner pieces are the first per-corner-asymmetric rects
128 * and rendered vertically mirrored (arc at the wrong end of the L, the
129 * clip hole's rounding on the wrong corner). Swap the vertical pairs at
130 * upload so scene-space corners land where they say. */
131 glUniform1f(uniform->top_left, corners->bottom_left);
132 glUniform1f(uniform->top_right, corners->bottom_right);
133 glUniform1f(uniform->bottom_left, corners->top_left);
134 glUniform1f(uniform->bottom_right, corners->top_right);
135 glUniform1f(uniform->shape, global_corner_shape);
136 }
137 // Shaders
138
139 bool link_quad_program(struct quad_shader *shader, bool clip) {
140 GLchar quad_src_part[2048];
141 GLchar quad_src[8192];
142 snprintf(quad_src_part, sizeof(quad_src_part),
143 quad_frag_src, clip);
144 snprintf(quad_src, sizeof(quad_src),
145 "%s\n%s\n", quad_src_part, clip ? corner_alpha_frag_src : "");
146
147 GLuint prog;
148 shader->program = prog = link_program(quad_src);
149 if (!shader->program) {
150 return false;
151 }
152
153 shader->proj = glGetUniformLocation(prog, "proj");
154 shader->color = glGetUniformLocation(prog, "color");
155 shader->pos_attrib = glGetAttribLocation(prog, "pos");
156
157 if (!clip) {
158 return true;
159 }
160 shader->effects.clip_size = glGetUniformLocation(prog, "clip_size");
161 shader->effects.clip_position = glGetUniformLocation(prog, "clip_position");
162 shader->effects.clip_radius.top_left = glGetUniformLocation(prog, "clip_radius_top_left");
163 shader->effects.clip_radius.top_right = glGetUniformLocation(prog, "clip_radius_top_right");
164 shader->effects.clip_radius.bottom_left = glGetUniformLocation(prog, "clip_radius_bottom_left");
165 shader->effects.clip_radius.bottom_right = glGetUniformLocation(prog, "clip_radius_bottom_right");
166 shader->effects.clip_radius.shape = glGetUniformLocation(prog, "corner_shape");
167
168 return true;
169 }
170
171 bool link_quad_grad_program(struct quad_grad_shader *shader, int max_len) {
172 GLchar quad_src_part[2048];
173 GLchar quad_src[4096];
174 snprintf(quad_src_part, sizeof(quad_src_part),
175 quad_grad_frag_src, max_len);
176 snprintf(quad_src, sizeof(quad_src),
177 "%s\n%s", quad_src_part, gradient_frag_src);
178
179 GLuint prog;
180 shader->program = prog = link_program(quad_src);
181 if (!shader->program) {
182 return false;
183 }
184
185 shader->proj = glGetUniformLocation(prog, "proj");
186 shader->pos_attrib = glGetAttribLocation(prog, "pos");
187 shader->size = glGetUniformLocation(prog, "size");
188 shader->colors = glGetUniformLocation(prog, "colors");
189 shader->degree = glGetUniformLocation(prog, "degree");
190 shader->grad_box = glGetUniformLocation(prog, "grad_box");
191 shader->linear = glGetUniformLocation(prog, "linear");
192 shader->origin = glGetUniformLocation(prog, "origin");
193 shader->count = glGetUniformLocation(prog, "count");
194 shader->blend = glGetUniformLocation(prog, "blend");
195
196 shader->max_len = max_len;
197
198 return true;
199 }
200
201 bool link_quad_round_program(struct quad_round_shader *shader) {
202 GLchar quad_src[8192];
203 snprintf(quad_src, sizeof(quad_src), "%s\n%s", quad_round_frag_src,
204 corner_alpha_frag_src);
205
206 GLuint prog;
207 shader->program = prog = link_program(quad_src);
208 if (!shader->program) {
209 return false;
210 }
211
212 shader->proj = glGetUniformLocation(prog, "proj");
213 shader->color = glGetUniformLocation(prog, "color");
214 shader->pos_attrib = glGetAttribLocation(prog, "pos");
215 shader->size = glGetUniformLocation(prog, "size");
216 shader->position = glGetUniformLocation(prog, "position");
217 shader->radius.top_left = glGetUniformLocation(prog, "radius_top_left");
218 shader->radius.top_right = glGetUniformLocation(prog, "radius_top_right");
219 shader->radius.bottom_left = glGetUniformLocation(prog, "radius_bottom_left");
220 shader->radius.bottom_right = glGetUniformLocation(prog, "radius_bottom_right");
221 shader->radius.shape = glGetUniformLocation(prog, "corner_shape");
222
223 shader->clip_size = glGetUniformLocation(prog, "clip_size");
224 shader->clip_position = glGetUniformLocation(prog, "clip_position");
225 shader->clip_radius.top_left = glGetUniformLocation(prog, "clip_radius_top_left");
226 shader->clip_radius.top_right = glGetUniformLocation(prog, "clip_radius_top_right");
227 shader->clip_radius.bottom_left = glGetUniformLocation(prog, "clip_radius_bottom_left");
228 shader->clip_radius.bottom_right = glGetUniformLocation(prog, "clip_radius_bottom_right");
229 shader->clip_radius.shape = glGetUniformLocation(prog, "corner_shape");
230 shader->fade_inset = glGetUniformLocation(prog, "fade_inset");
231 shader->fade_mode = glGetUniformLocation(prog, "fade_mode");
232
233 return true;
234 }
235
236 bool link_quad_grad_round_program(struct quad_grad_round_shader *shader, int max_len) {
237 GLchar quad_src_part[2048];
238 GLchar quad_src[8192];
239 snprintf(quad_src_part, sizeof(quad_src_part),
240 quad_grad_round_frag_src, max_len);
241 snprintf(quad_src, sizeof(quad_src),
242 "%s\n%s\n%s", quad_src_part, gradient_frag_src, corner_alpha_frag_src);
243
244 GLuint prog;
245 shader->program = prog = link_program(quad_src);
246 if (!shader->program) {
247 return false;
248 }
249
250 shader->proj = glGetUniformLocation(prog, "proj");
251 shader->color = glGetUniformLocation(prog, "color");
252 shader->pos_attrib = glGetAttribLocation(prog, "pos");
253 shader->size = glGetUniformLocation(prog, "size");
254 shader->position = glGetUniformLocation(prog, "position");
255 shader->radius.top_left = glGetUniformLocation(prog, "radius_top_left");
256 shader->radius.top_right = glGetUniformLocation(prog, "radius_top_right");
257 shader->radius.bottom_left = glGetUniformLocation(prog, "radius_bottom_left");
258 shader->radius.bottom_right = glGetUniformLocation(prog, "radius_bottom_right");
259 shader->radius.shape = glGetUniformLocation(prog, "corner_shape");
260
261 shader->grad_size = glGetUniformLocation(prog, "grad_size");
262 shader->colors = glGetUniformLocation(prog, "colors");
263 shader->degree = glGetUniformLocation(prog, "degree");
264 shader->grad_box = glGetUniformLocation(prog, "grad_box");
265 shader->linear = glGetUniformLocation(prog, "linear");
266 shader->origin = glGetUniformLocation(prog, "origin");
267 shader->count = glGetUniformLocation(prog, "count");
268 shader->blend = glGetUniformLocation(prog, "blend");
269
270 shader->max_len = max_len;
271
272 return true;
273 }
274
275 bool link_tex_program(struct tex_shader *shader, enum fx_tex_shader_source source,
276 bool effects) {
277 GLchar frag_src_part[4096];
278 GLchar frag_src[8192];
279 snprintf(frag_src_part, sizeof(frag_src_part),
280 tex_frag_src, source, effects);
281 snprintf(frag_src, sizeof(frag_src),
282 "%s\n%s\n", frag_src_part, effects ? corner_alpha_frag_src : "");
283
284 GLuint prog;
285 shader->program = prog = link_program(frag_src);
286 if (!shader->program) {
287 return false;
288 }
289
290 shader->proj = glGetUniformLocation(prog, "proj");
291 shader->tex = glGetUniformLocation(prog, "tex");
292 shader->alpha = glGetUniformLocation(prog, "alpha");
293 shader->pos_attrib = glGetAttribLocation(prog, "pos");
294 shader->tex_proj = glGetUniformLocation(prog, "tex_proj");
295
296 shader->discard_transparent = glGetUniformLocation(prog, "discard_transparent");
297
298 if (!effects) {
299 return true;
300 }
301 shader->effects.size = glGetUniformLocation(prog, "size");
302 shader->effects.position = glGetUniformLocation(prog, "position");
303 shader->effects.radius.top_left = glGetUniformLocation(prog, "radius_top_left");
304 shader->effects.radius.top_right = glGetUniformLocation(prog, "radius_top_right");
305 shader->effects.radius.bottom_left = glGetUniformLocation(prog, "radius_bottom_left");
306 shader->effects.radius.bottom_right = glGetUniformLocation(prog, "radius_bottom_right");
307 shader->effects.radius.shape = glGetUniformLocation(prog, "corner_shape");
308
309 shader->effects.clip_size = glGetUniformLocation(prog, "clip_size");
310 shader->effects.clip_position = glGetUniformLocation(prog, "clip_position");
311 shader->effects.clip_radius.top_left = glGetUniformLocation(prog, "clip_radius_top_left");
312 shader->effects.clip_radius.top_right = glGetUniformLocation(prog, "clip_radius_top_right");
313 shader->effects.clip_radius.bottom_left = glGetUniformLocation(prog, "clip_radius_bottom_left");
314 shader->effects.clip_radius.bottom_right = glGetUniformLocation(prog, "clip_radius_bottom_right");
315 shader->effects.clip_radius.shape = glGetUniformLocation(prog, "corner_shape");
316
317 return true;
318 }
319
320 bool link_box_shadow_program(struct box_shadow_shader *shader) {
321 GLchar shadow_src[8192];
322 snprintf(shadow_src, sizeof(shadow_src), "%s\n%s", box_shadow_frag_src,
323 corner_alpha_frag_src);
324
325 GLuint prog;
326 shader->program = prog = link_program(shadow_src);
327 if (!shader->program) {
328 return false;
329 }
330 shader->proj = glGetUniformLocation(prog, "proj");
331 shader->color = glGetUniformLocation(prog, "color");
332 shader->pos_attrib = glGetAttribLocation(prog, "pos");
333 shader->position = glGetUniformLocation(prog, "position");
334 shader->size = glGetUniformLocation(prog, "size");
335 shader->blur_sigma = glGetUniformLocation(prog, "blur_sigma");
336 shader->corner_radius = glGetUniformLocation(prog, "corner_radius");
337 shader->clip_position = glGetUniformLocation(prog, "clip_position");
338 shader->clip_size = glGetUniformLocation(prog, "clip_size");
339 shader->clip_radius.top_left = glGetUniformLocation(prog, "clip_radius_top_left");
340 shader->clip_radius.top_right = glGetUniformLocation(prog, "clip_radius_top_right");
341 shader->clip_radius.bottom_left = glGetUniformLocation(prog, "clip_radius_bottom_left");
342 shader->clip_radius.bottom_right = glGetUniformLocation(prog, "clip_radius_bottom_right");
343 shader->clip_radius.shape = glGetUniformLocation(prog, "corner_shape");
344
345 return true;
346 }
347
348 bool link_bevel_program(struct bevel_shader *shader) {
349 // Same pairing as link_box_shadow_program: the rim's SDF is the shared
350 // corner routine, so the shape follows corner_shape like every other cut.
351 GLchar bevel_src[16384];
352 snprintf(bevel_src, sizeof(bevel_src), "%s\n%s", bevel_frag_src,
353 corner_alpha_frag_src);
354
355 GLuint prog;
356 shader->program = prog = link_program(bevel_src);
357 if (!shader->program) {
358 return false;
359 }
360 shader->proj = glGetUniformLocation(prog, "proj");
361 shader->color = glGetUniformLocation(prog, "color");
362 shader->pos_attrib = glGetAttribLocation(prog, "pos");
363 shader->position = glGetUniformLocation(prog, "position");
364 shader->size = glGetUniformLocation(prog, "size");
365 shader->corner_radius = glGetUniformLocation(prog, "corner_radius");
366 shader->corner_shape = glGetUniformLocation(prog, "corner_shape");
367 shader->thickness = glGetUniformLocation(prog, "thickness");
368 shader->light_dir = glGetUniformLocation(prog, "light_dir");
369 shader->light_intensity = glGetUniformLocation(prog, "light_intensity");
370 shader->shade_intensity = glGetUniformLocation(prog, "shade_intensity");
371 shader->focus = glGetUniformLocation(prog, "focus");
372 shader->focus_color = glGetUniformLocation(prog, "focus_color");
373 shader->focus_sharpness = glGetUniformLocation(prog, "focus_sharpness");
374 shader->shoulder = glGetUniformLocation(prog, "shoulder");
375
376 return true;
377 }
378
379 bool link_frame_program(struct frame_shader *shader) {
380 // Paired with the shared corner routine, like bevel: the ring traces the
381 // same superellipse every other corner cut does.
382 GLchar frame_src[16384];
383 snprintf(frame_src, sizeof(frame_src), "%s\n%s", frame_frag_src,
384 corner_alpha_frag_src);
385
386 GLuint prog;
387 shader->program = prog = link_program(frame_src);
388 if (!shader->program) {
389 return false;
390 }
391 shader->proj = glGetUniformLocation(prog, "proj");
392 shader->color = glGetUniformLocation(prog, "color");
393 shader->pos_attrib = glGetAttribLocation(prog, "pos");
394 shader->position = glGetUniformLocation(prog, "position");
395 shader->size = glGetUniformLocation(prog, "size");
396 shader->corner_radius = glGetUniformLocation(prog, "corner_radius");
397 shader->corner_shape = glGetUniformLocation(prog, "corner_shape");
398 shader->band = glGetUniformLocation(prog, "band");
399 shader->band_min = glGetUniformLocation(prog, "band_min");
400 shader->corner_len = glGetUniformLocation(prog, "corner_len");
401 shader->gap = glGetUniformLocation(prog, "gap");
402 shader->hovered = glGetUniformLocation(prog, "hovered");
403 shader->hover_color = glGetUniformLocation(prog, "hover_color");
404 shader->swell_curve = glGetUniformLocation(prog, "swell_curve");
405 shader->bulge = glGetUniformLocation(prog, "bulge");
406 shader->exclusion = glGetUniformLocation(prog, "exclusion");
407
408 return true;
409 }
410
411 bool link_droplet_program(struct droplet_shader *shader) {
412 GLuint prog;
413 shader->program = prog = link_program(droplet_frag_src);
414 if (!shader->program) {
415 return false;
416 }
417 shader->proj = glGetUniformLocation(prog, "proj");
418 shader->pos_attrib = glGetAttribLocation(prog, "pos");
419 shader->tex = glGetUniformLocation(prog, "tex");
420 shader->tex_size = glGetUniformLocation(prog, "tex_size");
421 shader->position = glGetUniformLocation(prog, "position");
422 shader->size = glGetUniformLocation(prog, "size");
423 shader->attach_r = glGetUniformLocation(prog, "attach_r");
424 shader->sheet_r = glGetUniformLocation(prog, "sheet_r");
425 shader->bow_rise = glGetUniformLocation(prog, "bow_rise");
426 shader->blend_k = glGetUniformLocation(prog, "blend_k");
427 shader->curve = glGetUniformLocation(prog, "curve");
428 shader->band_px = glGetUniformLocation(prog, "band_px");
429 shader->refr = glGetUniformLocation(prog, "refr");
430 shader->ghost = glGetUniformLocation(prog, "ghost");
431
432 return true;
433 }
434
435 bool link_blur1_program(struct blur_shader *shader) {
436 GLuint prog;
437 shader->program = prog = link_program(blur1_frag_src);
438 if (!shader->program) {
439 return false;
440 }
441 shader->proj = glGetUniformLocation(prog, "proj");
442 shader->tex = glGetUniformLocation(prog, "tex");
443 shader->pos_attrib = glGetAttribLocation(prog, "pos");
444 shader->tex_proj = glGetUniformLocation(prog, "tex_proj");
445 shader->radius = glGetUniformLocation(prog, "radius");
446 shader->halfpixel = glGetUniformLocation(prog, "halfpixel");
447
448 return true;
449 }
450
451 bool link_blur2_program(struct blur_shader *shader) {
452 GLuint prog;
453 shader->program = prog = link_program(blur2_frag_src);
454 if (!shader->program) {
455 return false;
456 }
457 shader->proj = glGetUniformLocation(prog, "proj");
458 shader->tex = glGetUniformLocation(prog, "tex");
459 shader->pos_attrib = glGetAttribLocation(prog, "pos");
460 shader->tex_proj = glGetUniformLocation(prog, "tex_proj");
461 shader->radius = glGetUniformLocation(prog, "radius");
462 shader->halfpixel = glGetUniformLocation(prog, "halfpixel");
463
464 return true;
465 }
466
467 bool link_blur_effects_program(struct blur_effects_shader *shader) {
468 GLuint prog;
469 shader->program = prog = link_program(blur_effects_frag_src);
470 if (!shader->program) {
471 return false;
472 }
473 shader->proj = glGetUniformLocation(prog, "proj");
474 shader->tex = glGetUniformLocation(prog, "tex");
475 shader->pos_attrib = glGetAttribLocation(prog, "pos");
476 shader->tex_proj = glGetUniformLocation(prog, "tex_proj");
477 shader->noise = glGetUniformLocation(prog, "noise");
478 shader->brightness = glGetUniformLocation(prog, "brightness");
479 shader->contrast = glGetUniformLocation(prog, "contrast");
480 shader->saturation = glGetUniformLocation(prog, "saturation");
481
482 return true;
483 }