Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
scenefx/render/fx_renderer/shaders.c (18K)
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 shader->compress_ceil = glGetUniformLocation(prog, "compress_ceil");
298 shader->compress_knee = glGetUniformLocation(prog, "compress_knee");
299 shader->compress_invert = glGetUniformLocation(prog, "compress_invert");
300
301 if (!effects) {
302 return true;
303 }
304 shader->effects.size = glGetUniformLocation(prog, "size");
305 shader->effects.position = glGetUniformLocation(prog, "position");
306 shader->effects.radius.top_left = glGetUniformLocation(prog, "radius_top_left");
307 shader->effects.radius.top_right = glGetUniformLocation(prog, "radius_top_right");
308 shader->effects.radius.bottom_left = glGetUniformLocation(prog, "radius_bottom_left");
309 shader->effects.radius.bottom_right = glGetUniformLocation(prog, "radius_bottom_right");
310 shader->effects.radius.shape = glGetUniformLocation(prog, "corner_shape");
311
312 shader->effects.clip_size = glGetUniformLocation(prog, "clip_size");
313 shader->effects.clip_position = glGetUniformLocation(prog, "clip_position");
314 shader->effects.clip_radius.top_left = glGetUniformLocation(prog, "clip_radius_top_left");
315 shader->effects.clip_radius.top_right = glGetUniformLocation(prog, "clip_radius_top_right");
316 shader->effects.clip_radius.bottom_left = glGetUniformLocation(prog, "clip_radius_bottom_left");
317 shader->effects.clip_radius.bottom_right = glGetUniformLocation(prog, "clip_radius_bottom_right");
318 shader->effects.clip_radius.shape = glGetUniformLocation(prog, "corner_shape");
319
320 return true;
321 }
322
323 bool link_box_shadow_program(struct box_shadow_shader *shader) {
324 GLchar shadow_src[8192];
325 snprintf(shadow_src, sizeof(shadow_src), "%s\n%s", box_shadow_frag_src,
326 corner_alpha_frag_src);
327
328 GLuint prog;
329 shader->program = prog = link_program(shadow_src);
330 if (!shader->program) {
331 return false;
332 }
333 shader->proj = glGetUniformLocation(prog, "proj");
334 shader->color = glGetUniformLocation(prog, "color");
335 shader->pos_attrib = glGetAttribLocation(prog, "pos");
336 shader->position = glGetUniformLocation(prog, "position");
337 shader->size = glGetUniformLocation(prog, "size");
338 shader->blur_sigma = glGetUniformLocation(prog, "blur_sigma");
339 shader->corner_radius = glGetUniformLocation(prog, "corner_radius");
340 shader->clip_position = glGetUniformLocation(prog, "clip_position");
341 shader->clip_size = glGetUniformLocation(prog, "clip_size");
342 shader->clip_radius.top_left = glGetUniformLocation(prog, "clip_radius_top_left");
343 shader->clip_radius.top_right = glGetUniformLocation(prog, "clip_radius_top_right");
344 shader->clip_radius.bottom_left = glGetUniformLocation(prog, "clip_radius_bottom_left");
345 shader->clip_radius.bottom_right = glGetUniformLocation(prog, "clip_radius_bottom_right");
346 shader->clip_radius.shape = glGetUniformLocation(prog, "corner_shape");
347
348 return true;
349 }
350
351 bool link_bevel_program(struct bevel_shader *shader) {
352 // Same pairing as link_box_shadow_program: the rim's SDF is the shared
353 // corner routine, so the shape follows corner_shape like every other cut.
354 GLchar bevel_src[16384];
355 snprintf(bevel_src, sizeof(bevel_src), "%s\n%s", bevel_frag_src,
356 corner_alpha_frag_src);
357
358 GLuint prog;
359 shader->program = prog = link_program(bevel_src);
360 if (!shader->program) {
361 return false;
362 }
363 shader->proj = glGetUniformLocation(prog, "proj");
364 shader->color = glGetUniformLocation(prog, "color");
365 shader->pos_attrib = glGetAttribLocation(prog, "pos");
366 shader->position = glGetUniformLocation(prog, "position");
367 shader->size = glGetUniformLocation(prog, "size");
368 shader->corner_radius = glGetUniformLocation(prog, "corner_radius");
369 shader->corner_shape = glGetUniformLocation(prog, "corner_shape");
370 shader->thickness = glGetUniformLocation(prog, "thickness");
371 shader->light_dir = glGetUniformLocation(prog, "light_dir");
372 shader->light_intensity = glGetUniformLocation(prog, "light_intensity");
373 shader->shade_intensity = glGetUniformLocation(prog, "shade_intensity");
374 shader->focus = glGetUniformLocation(prog, "focus");
375 shader->focus_color = glGetUniformLocation(prog, "focus_color");
376 shader->focus_sharpness = glGetUniformLocation(prog, "focus_sharpness");
377 shader->shoulder = glGetUniformLocation(prog, "shoulder");
378
379 return true;
380 }
381
382 bool link_frame_program(struct frame_shader *shader) {
383 // Paired with the shared corner routine, like bevel: the ring traces the
384 // same superellipse every other corner cut does.
385 GLchar frame_src[16384];
386 snprintf(frame_src, sizeof(frame_src), "%s\n%s", frame_frag_src,
387 corner_alpha_frag_src);
388
389 GLuint prog;
390 shader->program = prog = link_program(frame_src);
391 if (!shader->program) {
392 return false;
393 }
394 shader->proj = glGetUniformLocation(prog, "proj");
395 shader->color = glGetUniformLocation(prog, "color");
396 shader->pos_attrib = glGetAttribLocation(prog, "pos");
397 shader->position = glGetUniformLocation(prog, "position");
398 shader->size = glGetUniformLocation(prog, "size");
399 shader->corner_radius = glGetUniformLocation(prog, "corner_radius");
400 shader->corner_shape = glGetUniformLocation(prog, "corner_shape");
401 shader->band = glGetUniformLocation(prog, "band");
402 shader->band_min = glGetUniformLocation(prog, "band_min");
403 shader->corner_len = glGetUniformLocation(prog, "corner_len");
404 shader->gap = glGetUniformLocation(prog, "gap");
405 shader->hovered = glGetUniformLocation(prog, "hovered");
406 shader->hover_color = glGetUniformLocation(prog, "hover_color");
407 shader->swell_curve = glGetUniformLocation(prog, "swell_curve");
408 shader->bulge = glGetUniformLocation(prog, "bulge");
409 shader->exclusion = glGetUniformLocation(prog, "exclusion");
410 shader->buttons = glGetUniformLocation(prog, "buttons");
411
412 return true;
413 }
414
415 bool link_droplet_program(struct droplet_shader *shader) {
416 GLuint prog;
417 shader->program = prog = link_program(droplet_frag_src);
418 if (!shader->program) {
419 return false;
420 }
421 shader->proj = glGetUniformLocation(prog, "proj");
422 shader->pos_attrib = glGetAttribLocation(prog, "pos");
423 shader->tex = glGetUniformLocation(prog, "tex");
424 shader->tex_size = glGetUniformLocation(prog, "tex_size");
425 shader->position = glGetUniformLocation(prog, "position");
426 shader->size = glGetUniformLocation(prog, "size");
427 shader->attach_r = glGetUniformLocation(prog, "attach_r");
428 shader->sheet_r = glGetUniformLocation(prog, "sheet_r");
429 shader->bow_rise = glGetUniformLocation(prog, "bow_rise");
430 shader->blend_k = glGetUniformLocation(prog, "blend_k");
431 shader->curve = glGetUniformLocation(prog, "curve");
432 shader->band_px = glGetUniformLocation(prog, "band_px");
433 shader->refr = glGetUniformLocation(prog, "refr");
434 shader->ghost = glGetUniformLocation(prog, "ghost");
435 shader->compress_ceil = glGetUniformLocation(prog, "compress_ceil");
436 shader->compress_knee = glGetUniformLocation(prog, "compress_knee");
437 shader->compress_invert = glGetUniformLocation(prog, "compress_invert");
438
439 return true;
440 }
441
442 bool link_blur1_program(struct blur_shader *shader) {
443 GLuint prog;
444 shader->program = prog = link_program(blur1_frag_src);
445 if (!shader->program) {
446 return false;
447 }
448 shader->proj = glGetUniformLocation(prog, "proj");
449 shader->tex = glGetUniformLocation(prog, "tex");
450 shader->pos_attrib = glGetAttribLocation(prog, "pos");
451 shader->tex_proj = glGetUniformLocation(prog, "tex_proj");
452 shader->radius = glGetUniformLocation(prog, "radius");
453 shader->halfpixel = glGetUniformLocation(prog, "halfpixel");
454
455 return true;
456 }
457
458 bool link_blur2_program(struct blur_shader *shader) {
459 GLuint prog;
460 shader->program = prog = link_program(blur2_frag_src);
461 if (!shader->program) {
462 return false;
463 }
464 shader->proj = glGetUniformLocation(prog, "proj");
465 shader->tex = glGetUniformLocation(prog, "tex");
466 shader->pos_attrib = glGetAttribLocation(prog, "pos");
467 shader->tex_proj = glGetUniformLocation(prog, "tex_proj");
468 shader->radius = glGetUniformLocation(prog, "radius");
469 shader->halfpixel = glGetUniformLocation(prog, "halfpixel");
470
471 return true;
472 }
473
474 bool link_blur_effects_program(struct blur_effects_shader *shader) {
475 GLuint prog;
476 shader->program = prog = link_program(blur_effects_frag_src);
477 if (!shader->program) {
478 return false;
479 }
480 shader->proj = glGetUniformLocation(prog, "proj");
481 shader->tex = glGetUniformLocation(prog, "tex");
482 shader->pos_attrib = glGetAttribLocation(prog, "pos");
483 shader->tex_proj = glGetUniformLocation(prog, "tex_proj");
484 shader->noise = glGetUniformLocation(prog, "noise");
485 shader->brightness = glGetUniformLocation(prog, "brightness");
486 shader->contrast = glGetUniformLocation(prog, "contrast");
487 shader->saturation = glGetUniformLocation(prog, "saturation");
488
489 return true;
490 }