diff --git a/include/sway/desktop/shaders.h b/include/sway/desktop/shaders.h deleted file mode 100644 index 6a9f8863..00000000 --- a/include/sway/desktop/shaders.h +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef _SWAY_SHADERS_H -#define _SWAY_SHADERS_H - -#include - -// Colored quads -const GLchar quad_vertex_src[] = -"uniform mat3 proj;\n" -"uniform vec4 color;\n" -"attribute vec2 pos;\n" -"attribute vec2 texcoord;\n" -"varying vec4 v_color;\n" -"varying vec2 v_texcoord;\n" -"\n" -"void main() {\n" -" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" -" v_color = color;\n" -" v_texcoord = texcoord;\n" -"}\n"; - -const GLchar quad_fragment_src[] = -"precision mediump float;\n" -"varying vec4 v_color;\n" -"varying vec2 v_texcoord;\n" -"\n" -"void main() {\n" -" gl_FragColor = v_color;\n" -"}\n"; - -// Textured quads -const GLchar tex_vertex_src[] = -"uniform mat3 proj;\n" -"attribute vec2 pos;\n" -"attribute vec2 texcoord;\n" -"varying vec2 v_texcoord;\n" -"\n" -"void main() {\n" -" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" -" v_texcoord = texcoord;\n" -"}\n"; - -const GLchar tex_fragment_src_rgba[] = -"precision mediump float;\n" -"varying vec2 v_texcoord;\n" -"uniform sampler2D tex;\n" -"uniform float alpha;\n" -"\n" -"uniform vec2 size;\n" -"uniform vec2 position;\n" -"uniform float radius;\n" -"\n" -"void main() {\n" -" gl_FragColor = texture2D(tex, v_texcoord) * alpha;\n" -" vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy);\n" -" if (max(corner_distance.x, corner_distance.y) < radius) {\n" -" float d = radius - distance(corner_distance, vec2(radius));\n" -" float smooth = smoothstep(-1.0f, 0.5f, d);\n" -" gl_FragColor = mix(vec4(0), gl_FragColor, smooth);\n" -" }\n" -"}\n"; - -const GLchar tex_fragment_src_rgbx[] = -"precision mediump float;\n" -"varying vec2 v_texcoord;\n" -"uniform sampler2D tex;\n" -"uniform float alpha;\n" -"\n" -"uniform vec2 size;\n" -"uniform vec2 position;\n" -"uniform float radius;\n" -"\n" -"void main() {\n" -" gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha;\n" -" vec2 corner_distance = min(gl_FragCoord.xy - position, position + size - gl_FragCoord.xy);\n" -" if (max(corner_distance.x, corner_distance.y) < radius) {\n" -" float d = radius - distance(corner_distance, vec2(radius));\n" -" float smooth = smoothstep(-1.0f, 0.5f, d);\n" -" gl_FragColor = mix(vec4(0), gl_FragColor, smooth);\n" -" }\n" -"}\n"; - -const GLchar tex_fragment_src_external[] = -"#extension GL_OES_EGL_image_external : require\n" -"\n" -"precision mediump float;\n" -"varying vec2 v_texcoord;\n" -"uniform samplerExternalOES texture0;\n" -"uniform float alpha;\n" -"\n" -"uniform vec2 size;\n" -"uniform vec2 position;\n" -"uniform float radius;\n" -"\n" -"void main() {\n" -" gl_FragColor = texture2D(texture0, v_texcoord) * alpha;\n" -" vec2 corner_distance = min(gl_FragCoord.xy - position, position + size - gl_FragCoord.xy);\n" -" if (max(corner_distance.x, corner_distance.y) < radius) {\n" -" float d = radius - distance(corner_distance, vec2(radius));\n" -" float smooth = smoothstep(-1.0f, 0.5f, d);\n" -" gl_FragColor = mix(vec4(0), gl_FragColor, smooth);\n" -" }\n" -"}\n"; - -const GLchar corner_fragment_src[] = -"precision mediump float;\n" -"varying vec4 v_color;\n" -"varying vec2 v_texcoord;\n" -"\n" -"uniform bool is_top_left;\n" -"uniform bool is_top_right;\n" -"uniform bool is_bottom_left;\n" -"uniform bool is_bottom_right;\n" -"\n" -"uniform vec2 position;\n" -"uniform float radius;\n" -"uniform vec2 half_size;\n" -"uniform float half_thickness;\n" -"\n" -"float roundedBoxSDF(vec2 center, vec2 size, float radius) {\n" -" return length(max(abs(center) - size + radius, 0.0)) - radius;\n" -"}\n" -"\n" -"void main() {\n" -" vec2 center = gl_FragCoord.xy - position - half_size;\n" -" float distance = roundedBoxSDF(center, half_size - half_thickness, radius + half_thickness);\n" -" float smoothedAlphaOuter = 1.0 - smoothstep(-1.0, 1.0, distance - half_thickness);\n" -// Create an inner circle that isn't as anti-aliased as the outer ring -" float smoothedAlphaInner = 1.0 - smoothstep(-1.0, 0.5, distance + half_thickness);\n" -" gl_FragColor = mix(vec4(0), v_color, smoothedAlphaOuter - smoothedAlphaInner);\n" -"\n" -" if (is_top_left && (center.y > 0.0 || center.x > 0.0)) {\n" -" discard;\n" -" } else if (is_top_right && (center.y > 0.0 || center.x < 0.0)) {\n" -" discard;\n" -" } else if (is_bottom_left && (center.y < 0.0 || center.x > 0.0)) {\n" -" discard;\n" -" } else if (is_bottom_right && (center.y < 0.0 || center.x < 0.0)) {\n" -" discard;\n" -" }\n" -"}\n"; - -#endif diff --git a/sway/desktop/fx_renderer.c b/sway/desktop/fx_renderer.c index 90ed8957..7af4a313 100644 --- a/sway/desktop/fx_renderer.c +++ b/sway/desktop/fx_renderer.c @@ -14,10 +14,18 @@ #include #include "log.h" #include "sway/desktop/fx_renderer.h" -#include "sway/desktop/shaders.h" #include "sway/output.h" #include "sway/server.h" +// shaders +#include "quad_vert_src.h" +#include "quad_frag_src.h" +#include "corner_frag_src.h" +#include "tex_vert_src.h" +#include "tex_rgba_frag_src.h" +#include "tex_rgbx_frag_src.h" +#include "tex_external_frag_src.h" + static const GLfloat verts[] = { 1, 0, // top right 0, 0, // top left @@ -125,7 +133,7 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) { // init shaders GLuint prog; - prog = link_program(quad_vertex_src, quad_fragment_src); + prog = link_program(quad_vert_src, quad_frag_src); renderer->shaders.quad.program = prog; if (!renderer->shaders.quad.program) { goto error; @@ -135,7 +143,7 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) { renderer->shaders.quad.pos_attrib = glGetAttribLocation(prog, "pos"); // Border corners - prog = link_program(quad_vertex_src, corner_fragment_src); + prog = link_program(quad_vert_src, corner_frag_src); renderer->shaders.corner.program = prog; if (!renderer->shaders.corner.program) { goto error; @@ -153,15 +161,15 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) { renderer->shaders.corner.half_thickness = glGetUniformLocation(prog, "half_thickness"); // fragment shaders - prog = link_program(tex_vertex_src, tex_fragment_src_rgba); + prog = link_program(tex_vert_src, tex_rgba_frag_src); if (!init_frag_shader(&renderer->shaders.tex_rgba, prog)) { goto error; } - prog = link_program(tex_vertex_src, tex_fragment_src_rgbx); + prog = link_program(tex_vert_src, tex_rgbx_frag_src); if (!init_frag_shader(&renderer->shaders.tex_rgbx, prog)) { goto error; } - prog = link_program(tex_vertex_src, tex_fragment_src_external); + prog = link_program(tex_vert_src, tex_external_frag_src); if (!init_frag_shader(&renderer->shaders.tex_ext, prog)) { goto error; } diff --git a/sway/desktop/shaders/corner.frag b/sway/desktop/shaders/corner.frag new file mode 100644 index 00000000..9c5f0981 --- /dev/null +++ b/sway/desktop/shaders/corner.frag @@ -0,0 +1,36 @@ +precision mediump float; +varying vec4 v_color; +varying vec2 v_texcoord; + +uniform bool is_top_left; +uniform bool is_top_right; +uniform bool is_bottom_left; +uniform bool is_bottom_right; + +uniform vec2 position; +uniform float radius; +uniform vec2 half_size; +uniform float half_thickness; + +float roundedBoxSDF(vec2 center, vec2 size, float radius) { + return length(max(abs(center) - size + radius, 0.0)) - radius; +} + +void main() { + vec2 center = gl_FragCoord.xy - position - half_size; + float distance = roundedBoxSDF(center, half_size - half_thickness, radius + half_thickness); + float smoothedAlphaOuter = 1.0 - smoothstep(-1.0, 1.0, distance - half_thickness); +// Create an inner circle that isn't as anti-aliased as the outer ring + float smoothedAlphaInner = 1.0 - smoothstep(-1.0, 0.5, distance + half_thickness); + gl_FragColor = mix(vec4(0), v_color, smoothedAlphaOuter - smoothedAlphaInner); + + if (is_top_left && (center.y > 0.0 || center.x > 0.0)) { + discard; + } else if (is_top_right && (center.y > 0.0 || center.x < 0.0)) { + discard; + } else if (is_bottom_left && (center.y < 0.0 || center.x > 0.0)) { + discard; + } else if (is_bottom_right && (center.y < 0.0 || center.x < 0.0)) { + discard; + } +} diff --git a/sway/desktop/shaders/embed.sh b/sway/desktop/shaders/embed.sh new file mode 100644 index 00000000..47f07892 --- /dev/null +++ b/sway/desktop/shaders/embed.sh @@ -0,0 +1,11 @@ +#!/bin/sh -eu + +var=${1:-data} +hex="$(od -A n -t x1 -v)" + +echo "static const char $var[] = {" +for byte in $hex; do + echo " 0x$byte," +done +echo " 0x00," +echo "};" diff --git a/sway/desktop/shaders/meson.build b/sway/desktop/shaders/meson.build new file mode 100644 index 00000000..8eb12079 --- /dev/null +++ b/sway/desktop/shaders/meson.build @@ -0,0 +1,24 @@ +embed = find_program('./embed.sh', native: true) + +shaders = [ + 'quad.vert', + 'quad.frag', + 'tex.vert', + 'corner.frag', + 'tex_rgba.frag', + 'tex_rgbx.frag', + 'tex_external.frag', +] + +foreach name : shaders + output = name.underscorify() + '_src.h' + var = name.underscorify() + '_src' + sway_sources += custom_target( + output, + command: [embed, var], + input: name, + output: output, + feed: true, + capture: true, + ) +endforeach diff --git a/sway/desktop/shaders/quad.frag b/sway/desktop/shaders/quad.frag new file mode 100644 index 00000000..7c763272 --- /dev/null +++ b/sway/desktop/shaders/quad.frag @@ -0,0 +1,7 @@ +precision mediump float; +varying vec4 v_color; +varying vec2 v_texcoord; + +void main() { + gl_FragColor = v_color; +} diff --git a/sway/desktop/shaders/quad.vert b/sway/desktop/shaders/quad.vert new file mode 100644 index 00000000..811e0f2d --- /dev/null +++ b/sway/desktop/shaders/quad.vert @@ -0,0 +1,12 @@ +uniform mat3 proj; +uniform vec4 color; +attribute vec2 pos; +attribute vec2 texcoord; +varying vec4 v_color; +varying vec2 v_texcoord; + +void main() { + gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); + v_color = color; + v_texcoord = texcoord; +} diff --git a/sway/desktop/shaders/tex.vert b/sway/desktop/shaders/tex.vert new file mode 100644 index 00000000..3026521b --- /dev/null +++ b/sway/desktop/shaders/tex.vert @@ -0,0 +1,9 @@ +uniform mat3 proj; +attribute vec2 pos; +attribute vec2 texcoord; +varying vec2 v_texcoord; + +void main() { + gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); + v_texcoord = texcoord; +} diff --git a/sway/desktop/shaders/tex_external.frag b/sway/desktop/shaders/tex_external.frag new file mode 100644 index 00000000..404688c2 --- /dev/null +++ b/sway/desktop/shaders/tex_external.frag @@ -0,0 +1,20 @@ +#extension GL_OES_EGL_image_external : require + +precision mediump float; +varying vec2 v_texcoord; +uniform samplerExternalOES texture0; +uniform float alpha; + +uniform vec2 size; +uniform vec2 position; +uniform float radius; + +void main() { + gl_FragColor = texture2D(texture0, v_texcoord) * alpha; + vec2 corner_distance = min(gl_FragCoord.xy - position, position + size - gl_FragCoord.xy); + if (max(corner_distance.x, corner_distance.y) < radius) { + float d = radius - distance(corner_distance, vec2(radius)); + float smooth = smoothstep(-1.0f, 0.5f, d); + gl_FragColor = mix(vec4(0), gl_FragColor, smooth); + } +} diff --git a/sway/desktop/shaders/tex_rgba.frag b/sway/desktop/shaders/tex_rgba.frag new file mode 100644 index 00000000..1886fab4 --- /dev/null +++ b/sway/desktop/shaders/tex_rgba.frag @@ -0,0 +1,18 @@ +precision mediump float; +varying vec2 v_texcoord; +uniform sampler2D tex; +uniform float alpha; + +uniform vec2 size; +uniform vec2 position; +uniform float radius; + +void main() { + gl_FragColor = texture2D(tex, v_texcoord) * alpha; + vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy); + if (max(corner_distance.x, corner_distance.y) < radius) { + float d = radius - distance(corner_distance, vec2(radius)); + float smooth = smoothstep(-1.0f, 0.5f, d); + gl_FragColor = mix(vec4(0), gl_FragColor, smooth); + } +} diff --git a/sway/desktop/shaders/tex_rgbx.frag b/sway/desktop/shaders/tex_rgbx.frag new file mode 100644 index 00000000..cb6f1432 --- /dev/null +++ b/sway/desktop/shaders/tex_rgbx.frag @@ -0,0 +1,18 @@ +precision mediump float; +varying vec2 v_texcoord; +uniform sampler2D tex; +uniform float alpha; + +uniform vec2 size; +uniform vec2 position; +uniform float radius; + +void main() { + gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha; + vec2 corner_distance = min(gl_FragCoord.xy - position, position + size - gl_FragCoord.xy); + if (max(corner_distance.x, corner_distance.y) < radius) { + float d = radius - distance(corner_distance, vec2(radius)); + float smooth = smoothstep(-1.0f, 0.5f, d); + gl_FragColor = mix(vec4(0), gl_FragColor, smooth); + } +} diff --git a/sway/meson.build b/sway/meson.build index 46aa0d0a..85bd04ff 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -206,6 +206,8 @@ sway_sources = files( 'tree/output.c', ) +subdir('desktop/shaders') + sway_deps = [ cairo, drm,