Add Anti-Aliased Corner Radius (#18)

This commit is contained in:
William McKinnon 2022-08-29 18:25:11 -04:00 committed by GitHub
parent 3b287a73b9
commit c1f4cf17db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 189 deletions

View file

@ -2,7 +2,7 @@
Sway is an incredible window manager, and certainly one of the most well established wayland window managers. However, it is restricted to only include the functionality that existed in i3. This fork ditches the simple wlr_renderer, and replaces it with a fancy GLES2 renderer with functionality borrowed from the original simple renderer and [Hyprland](https://github.com/vaxerski/Hyprland). This, along with a couple of minor changes, expands sway's featureset to include the following:
+ **Rounded corners**
+ **Anti-aliased rounded corners**
+ **Scratchpad treated as minimize**: Allows docks, or panels with a taskbar, to correctly interpret minimize / unminimize requests ([thanks to LCBCrion](https://github.com/swaywm/sway/issues/6457))
+ **Default to not compiling swaybar**: Many users replace swaybar with the far more capable [waybar](https://github.com/Alexays/Waybar), swayFX cuts out the bloat by not including swaybar by default
+ **Add a nix flake to the repo**: Allows nixos users to easily contribute to and test this project

View file

@ -8,9 +8,12 @@ struct gles2_tex_shader {
GLint proj;
GLint tex;
GLint alpha;
GLint discardOpaque;
GLint pos_attrib;
GLint tex_attrib;
GLint width;
GLint height;
GLint position;
GLint radius;
};
struct fx_renderer {
@ -42,13 +45,14 @@ void fx_renderer_clear(const float color[static 4]);
void fx_renderer_scissor(struct wlr_box *box);
bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer,
struct wlr_texture *wlr_texture, const struct wlr_fbox *box,
const float matrix[static 9], float alpha, int radius);
bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture,
const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9],
float alpha, int radius);
bool fx_render_texture_with_matrix(struct fx_renderer *renderer,
struct wlr_texture *wlr_texture, const float matrix[static 9], float alpha, int radius);
bool fx_render_texture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture,
const struct wlr_box *dst_box, const float matrix[static 9], float alpha, int radius);
void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box, const float color[static 4], const float projection[static 9]);
void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9]);
#endif

View file

@ -43,57 +43,19 @@ const GLchar tex_fragment_src_rgba[] =
"uniform sampler2D tex;\n"
"uniform float alpha;\n"
"\n"
"uniform vec2 topLeft;\n"
"uniform vec2 bottomRight;\n"
"uniform vec2 fullSize;\n"
"uniform float width;\n"
"uniform float height;\n"
"uniform vec2 position;\n"
"uniform float radius;\n"
"\n"
"uniform int discardOpaque;\n"
"\n"
"void main() {\n"
" vec4 pixColor = texture2D(tex, v_texcoord);\n"
"\n"
" if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) {\n"
" discard;\n"
" return;\n"
" }\n"
"\n"
" vec2 pixCoord = fullSize * v_texcoord;\n"
"\n"
" if (pixCoord[0] < topLeft[0]) {\n"
" // we're close left\n"
" if (pixCoord[1] < topLeft[1]) {\n"
// top
" if (distance(topLeft, pixCoord) > radius) {\n"
" discard;\n"
" return;\n"
" }\n"
" } else if (pixCoord[1] > bottomRight[1]) {\n"
// bottom
" if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord) > radius) {\n"
" discard;\n"
" return;\n"
" }\n"
" }\n"
" }\n"
" else if (pixCoord[0] > bottomRight[0]) {\n"
// we're close right
" if (pixCoord[1] < topLeft[1]) {\n"
// top
" if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord) > radius) {\n"
" discard;\n"
" return;\n"
" }\n"
" } else if (pixCoord[1] > bottomRight[1]) {\n"
// bottom
" if (distance(bottomRight, pixCoord) > radius) {\n"
" discard;\n"
" return;\n"
" }\n"
" }\n"
" }\n"
"\n"
" gl_FragColor = pixColor * alpha;\n"
" gl_FragColor = texture2D(tex, v_texcoord) * alpha;\n"
" vec2 corner_distance = min(gl_FragCoord.xy - position, position + vec2(width, height) - gl_FragCoord.xy);\n"
" if (max(corner_distance.x, corner_distance.y) < radius) {\n"
" float d = radius - distance(corner_distance, vec2(radius, radius));\n"
" float smooth = smoothstep(-1.0f, 1.0f, d);\n"
" gl_FragColor = mix(vec4(0), gl_FragColor, smooth);\n"
" }\n"
"}\n";
const GLchar tex_fragment_src_rgbx[] =
@ -102,56 +64,19 @@ const GLchar tex_fragment_src_rgbx[] =
"uniform sampler2D tex;\n"
"uniform float alpha;\n"
"\n"
"uniform vec2 topLeft;\n"
"uniform vec2 bottomRight;\n"
"uniform vec2 fullSize;\n"
"uniform float width;\n"
"uniform float height;\n"
"uniform vec2 position;\n"
"uniform float radius;\n"
"\n"
"uniform int discardOpaque;\n"
"\n"
"void main() {\n"
"\n"
" if (discardOpaque == 1 && alpha == 1.0) {\n"
" discard;\n"
" return;\n"
" }\n"
"\n"
" vec2 pixCoord = fullSize * v_texcoord;\n"
"\n"
" if (pixCoord[0] < topLeft[0]) {\n"
// we're close left
" if (pixCoord[1] < topLeft[1]) {\n"
// top
" if (distance(topLeft, pixCoord) > radius) {\n"
" discard;\n"
" return;\n"
" }\n"
" } else if (pixCoord[1] > bottomRight[1]) {\n"
// bottom
" if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord) > radius) {\n"
" discard;\n"
" return;\n"
" }\n"
" }\n"
" }\n"
" else if (pixCoord[0] > bottomRight[0]) {\n"
// we're close right
" if (pixCoord[1] < topLeft[1]) {\n"
// top
" if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord) > radius) {\n"
" discard;\n"
" return;\n"
" }\n"
" } else if (pixCoord[1] > bottomRight[1]) {\n"
// bottom
" if (distance(bottomRight, pixCoord) > radius) {\n"
" discard;\n"
" return;\n"
" }\n"
" }\n"
" }\n"
"\n"
" gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha;\n"
" vec2 corner_distance = min(gl_FragCoord.xy - position, position + vec2(width, height) - gl_FragCoord.xy);\n"
" if (max(corner_distance.x, corner_distance.y) < radius) {\n"
" float d = radius - distance(corner_distance, vec2(radius, radius));\n"
" float smooth = smoothstep(-1.0f, 1.0f, d);\n"
" gl_FragColor = mix(vec4(0), gl_FragColor, smooth);\n"
" }\n"
"}\n";
const GLchar tex_fragment_src_external[] =
@ -161,58 +86,19 @@ const GLchar tex_fragment_src_external[] =
"uniform samplerExternalOES texture0;\n"
"uniform float alpha;\n"
"\n"
"uniform vec2 topLeft;\n"
"uniform vec2 bottomRight;\n"
"uniform vec2 fullSize;\n"
"uniform float width;\n"
"uniform float height;\n"
"uniform vec2 position;\n"
"uniform float radius;\n"
"\n"
"uniform int discardOpaque;\n"
"\n"
"void main() {\n"
"\n"
" vec4 pixColor = texture2D(texture0, v_texcoord);\n"
"\n"
" if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) {\n"
" discard;\n"
" return;\n"
" }\n"
"\n"
" vec2 pixCoord = fullSize * v_texcoord;\n"
"\n"
" if (pixCoord[0] < topLeft[0]) {\n"
// we're close left
" if (pixCoord[1] < topLeft[1]) {\n"
// top
" if (distance(topLeft, pixCoord) > radius) {\n"
" discard;\n"
" return;\n"
" }\n"
" } else if (pixCoord[1] > bottomRight[1]) {\n"
// bottom
" if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord) > radius) {\n"
" discard;\n"
" return;\n"
" }\n"
" }\n"
" }\n"
" else if (pixCoord[0] > bottomRight[0]) {\n"
// we're close right
" if (pixCoord[1] < topLeft[1]) {\n"
// top
" if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord) > radius) {\n"
" discard;\n"
" return;\n"
" }\n"
" } else if (pixCoord[1] > bottomRight[1]) {\n"
// bottom
" if (distance(bottomRight, pixCoord) > radius) {\n"
" discard;\n"
" return;\n"
" }\n"
" }\n"
" }\n"
"\n"
" gl_FragColor = pixColor * alpha;\n"
" gl_FragColor = texture2D(texture0, v_texcoord) * alpha;\n"
" vec2 corner_distance = min(gl_FragCoord.xy - position, position + vec2(width, height) - gl_FragCoord.xy);\n"
" if (max(corner_distance.x, corner_distance.y) < radius) {\n"
" float d = radius - distance(corner_distance, vec2(radius, radius));\n"
" float smooth = smoothstep(-1.0f, 1.0f, d);\n"
" gl_FragColor = mix(vec4(0), gl_FragColor, smooth);\n"
" }\n"
"}\n";
const GLchar frag_blur_1[] =
@ -259,4 +145,3 @@ const GLchar frag_blur_2[] =
"}\n";
#endif

View file

@ -140,7 +140,10 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
renderer->shaders.tex_rgba.alpha = glGetUniformLocation(prog, "alpha");
renderer->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos");
renderer->shaders.tex_rgba.tex_attrib = glGetAttribLocation(prog, "texcoord");
renderer->shaders.tex_rgba.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
renderer->shaders.tex_rgba.width = glGetUniformLocation(prog, "width");
renderer->shaders.tex_rgba.height = glGetUniformLocation(prog, "height");
renderer->shaders.tex_rgba.position = glGetUniformLocation(prog, "position");
renderer->shaders.tex_rgba.radius = glGetUniformLocation(prog, "radius");
prog = link_program(tex_vertex_src, tex_fragment_src_rgbx);
renderer->shaders.tex_rgbx.program = prog;
@ -152,7 +155,10 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
renderer->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha");
renderer->shaders.tex_rgbx.pos_attrib = glGetAttribLocation(prog, "pos");
renderer->shaders.tex_rgbx.tex_attrib = glGetAttribLocation(prog, "texcoord");
renderer->shaders.tex_rgbx.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
renderer->shaders.tex_rgbx.width = glGetUniformLocation(prog, "width");
renderer->shaders.tex_rgbx.height = glGetUniformLocation(prog, "height");
renderer->shaders.tex_rgbx.position = glGetUniformLocation(prog, "position");
renderer->shaders.tex_rgbx.radius = glGetUniformLocation(prog, "radius");
prog = link_program(tex_vertex_src, tex_fragment_src_external);
renderer->shaders.tex_ext.program = prog;
@ -164,7 +170,11 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
renderer->shaders.tex_ext.alpha = glGetUniformLocation(prog, "alpha");
renderer->shaders.tex_ext.pos_attrib = glGetAttribLocation(prog, "pos");
renderer->shaders.tex_ext.tex_attrib = glGetAttribLocation(prog, "texcoord");
renderer->shaders.tex_ext.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
renderer->shaders.tex_ext.width = glGetUniformLocation(prog, "width");
renderer->shaders.tex_ext.height = glGetUniformLocation(prog, "height");
renderer->shaders.tex_ext.position = glGetUniformLocation(prog, "position");
renderer->shaders.tex_ext.radius = glGetUniformLocation(prog, "radius");
prog = link_program(tex_vertex_src, tex_fragment_src_rgba);
wlr_egl_unset_current(renderer->egl);
@ -218,9 +228,9 @@ void fx_renderer_scissor(struct wlr_box *box) {
Rendering Functions
*************************/
bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer,
struct wlr_texture *wlr_texture, const struct wlr_fbox *box,
const float matrix[static 9], float alpha, int radius) {
bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture,
const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9],
float alpha, int radius) {
assert(wlr_texture_is_gles2(wlr_texture));
struct wlr_gles2_texture_attribs texture_attrs;
@ -260,7 +270,8 @@ bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer,
// to GL_FALSE
wlr_matrix_transpose(gl_matrix, gl_matrix);
if (!texture_attrs.has_alpha && alpha == 1.0) {
// if there's no opacity or rounded corners we don't need to blend
if (!texture_attrs.has_alpha && alpha == 1.0 && !radius) {
glDisable(GL_BLEND);
} else {
glEnable(GL_BLEND);
@ -276,12 +287,17 @@ bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer,
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix);
glUniform1i(shader->tex, 0);
glUniform1f(shader->alpha, alpha);
glUniform1i(shader->discardOpaque, 0); // TODO
const GLfloat x1 = box->x / wlr_texture->width;
const GLfloat y1 = box->y / wlr_texture->height;
const GLfloat x2 = (box->x + box->width) / wlr_texture->width;
const GLfloat y2 = (box->y + box->height) / wlr_texture->height;
// rounded corners
glUniform1f(shader->width, dst_box->width);
glUniform1f(shader->height, dst_box->height);
glUniform2f(shader->position, dst_box->x, dst_box->y);
glUniform1f(shader->radius, radius);
const GLfloat x1 = src_box->x / wlr_texture->width;
const GLfloat y1 = src_box->y / wlr_texture->height;
const GLfloat x2 = (src_box->x + src_box->width) / wlr_texture->width;
const GLfloat y2 = (src_box->y + src_box->height) / wlr_texture->height;
const GLfloat texcoord[] = {
x2, y1, // top right
x1, y1, // top left
@ -289,23 +305,6 @@ bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer,
x1, y2, // bottom left
};
glUniform2f(
glGetUniformLocation(shader->program, "topLeft"),
radius,
radius
);
glUniform2f(
glGetUniformLocation(shader->program, "bottomRight"),
wlr_texture->width - radius,
wlr_texture->height - radius
);
glUniform2f(
glGetUniformLocation(shader->program, "fullSize"),
wlr_texture->width,
wlr_texture->height
);
glUniform1f(glGetUniformLocation(shader->program, "radius"), radius);
glVertexAttribPointer(shader->pos_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
glVertexAttribPointer(shader->tex_attrib, 2, GL_FLOAT, GL_FALSE, 0, texcoord);
@ -322,15 +321,15 @@ bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer,
return true;
}
bool fx_render_texture_with_matrix(struct fx_renderer *renderer,
struct wlr_texture *wlr_texture, const float matrix[static 9], float alpha, int radius) {
struct wlr_fbox box = {
bool fx_render_texture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture,
const struct wlr_box *dst_box, const float matrix[static 9], float alpha, int radius) {
struct wlr_fbox src_box = {
.x = 0,
.y = 0,
.width = wlr_texture->width,
.height = wlr_texture->height,
};
return fx_render_subtexture_with_matrix(renderer, wlr_texture, &box, matrix, alpha, radius);
return fx_render_subtexture_with_matrix(renderer, wlr_texture, &src_box, dst_box, matrix, alpha, radius);
}
void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box, const float color[static 4], const float projection[static 9]) {
@ -344,7 +343,7 @@ void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box, con
float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
// TODO: investigate why matrix is flipped prior to this cmd
// TODO: investigate why matrix is flipped prior to this cmd
// wlr_matrix_multiply(gl_matrix, flip_180, gl_matrix);
wlr_matrix_transpose(gl_matrix, gl_matrix);
@ -369,4 +368,3 @@ void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box, con
glDisableVertexAttribArray(renderer->shaders.quad.pos_attrib);
}

View file

@ -122,9 +122,9 @@ static void render_texture(struct wlr_output *wlr_output,
scissor_output(wlr_output, &rects[i]);
set_scale_filter(wlr_output, texture, output->scale_filter);
if (src_box != NULL) {
fx_render_subtexture_with_matrix(renderer, texture, src_box, matrix, alpha, corner_radius);
fx_render_subtexture_with_matrix(renderer, texture, src_box, dst_box, matrix, alpha, corner_radius);
} else {
fx_render_texture_with_matrix(renderer, texture, matrix, alpha, corner_radius);
fx_render_texture_with_matrix(renderer, texture, dst_box, matrix, alpha, corner_radius);
}
}