summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
Diffstat (limited to 'render')
-rw-r--r--render/fx_renderer/fx_effect_framebuffers.c55
-rw-r--r--render/fx_renderer/fx_pass.c280
-rw-r--r--render/fx_renderer/fx_renderer.c47
-rw-r--r--render/fx_renderer/fx_texture.c1
-rw-r--r--render/fx_renderer/gles2/shaders/meson.build2
-rw-r--r--render/fx_renderer/gles2/shaders/quad_round.frag39
-rw-r--r--render/fx_renderer/gles2/shaders/rounded_border_corner.frag36
-rw-r--r--render/fx_renderer/gles2/shaders/tex.frag18
-rw-r--r--render/fx_renderer/meson.build1
-rw-r--r--render/fx_renderer/shaders.c51
10 files changed, 442 insertions, 88 deletions
diff --git a/render/fx_renderer/fx_effect_framebuffers.c b/render/fx_renderer/fx_effect_framebuffers.c
new file mode 100644
index 0000000..4589b21
--- /dev/null
+++ b/render/fx_renderer/fx_effect_framebuffers.c
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <wlr/types/wlr_output.h>
+#include <wlr/util/addon.h>
+#include <wlr/util/log.h>
+
+#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
+
+static void addon_handle_destroy(struct wlr_addon *addon) {
+ struct fx_effect_framebuffers *fbos = wl_container_of(addon, fbos, addon);
+ wlr_addon_finish(&fbos->addon);
+ free(fbos);
+}
+
+static const struct wlr_addon_interface fbos_addon_impl = {
+ .name = "fx_effect_framebuffers",
+ .destroy = addon_handle_destroy,
+};
+
+static bool fx_effect_framebuffers_assign(struct wlr_output *output,
+ struct fx_effect_framebuffers *fbos) {
+ wlr_addon_init(&fbos->addon, &output->addons, output, &fbos_addon_impl);
+ return true;
+}
+
+struct fx_effect_framebuffers *fx_effect_framebuffers_try_get(struct wlr_output *output) {
+ struct fx_effect_framebuffers *fbos = NULL;
+
+ struct wlr_addon *addon = wlr_addon_find(&output->addons, output,
+ &fbos_addon_impl);
+ if (!addon) {
+ goto create_new;
+ return NULL;
+ }
+
+ if (!(fbos = wl_container_of(addon, fbos, addon))) {
+ goto create_new;
+ }
+ return fbos;
+
+create_new:;
+ fbos = calloc(1, sizeof(*fbos));
+ if (!fbos) {
+ wlr_log(WLR_ERROR, "Could not allocate a fx_effect_framebuffers");
+ abort();
+ }
+ fbos->blur_buffer_dirty = false;
+
+ if (!fx_effect_framebuffers_assign(output, fbos)) {
+ wlr_log(WLR_ERROR, "Could not assign fx_effect_framebuffers to output: '%s'",
+ output->name);
+ abort();
+ }
+ return fbos;
+}
diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c
index f12eda5..f3a9485 100644
--- a/render/fx_renderer/fx_pass.c
+++ b/render/fx_renderer/fx_pass.c
@@ -13,6 +13,8 @@
#include "render/fx_renderer/fx_renderer.h"
#include "render/fx_renderer/matrix.h"
#include "render/pass.h"
+#include "scenefx/render/fx_renderer/fx_renderer.h"
+#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
#include "scenefx/types/fx/blur_data.h"
#include "scenefx/types/fx/shadow_data.h"
@@ -22,8 +24,10 @@ struct fx_render_texture_options fx_render_texture_options_default(
const struct wlr_render_texture_options *base) {
struct fx_render_texture_options options = {
.corner_radius = 0,
+ .has_titlebar = false,
.discard_transparent = false,
- .scale = 1.0f,
+ .dim = 0.0f,
+ .dim_color = { 1, 1, 1, 1 },
.clip_box = NULL,
};
memcpy(&options.base, base, sizeof(*base));
@@ -33,12 +37,16 @@ struct fx_render_texture_options fx_render_texture_options_default(
struct fx_render_rect_options fx_render_rect_options_default(
const struct wlr_render_rect_options *base) {
struct fx_render_rect_options options = {
- .scale = 1.0f,
+ .base = *base,
};
- memcpy(&options.base, base, sizeof(*base));
return options;
}
+// Gets a non-transformed wlr_box
+static struct wlr_box get_monitor_box(struct wlr_output *output) {
+ return (struct wlr_box) { 0, 0, output->width, output->height };
+}
+
///
/// Base Wlroots pass functions
///
@@ -278,7 +286,7 @@ void fx_render_pass_add_texture(struct fx_gles_render_pass *pass,
wlr_render_texture_options_get_dst_box(options, &dst_box);
float alpha = wlr_render_texture_options_get_alpha(options);
- struct wlr_box *clip_box = &dst_box;
+ const struct wlr_box *clip_box = &dst_box;
if (!wlr_box_empty(fx_options->clip_box)) {
clip_box = fx_options->clip_box;
}
@@ -289,8 +297,12 @@ void fx_render_pass_add_texture(struct fx_gles_render_pass *pass,
src_fbox.height /= options->texture->height;
push_fx_debug(renderer);
- setup_blending(!texture->has_alpha && alpha == 1.0 ?
- WLR_RENDER_BLEND_MODE_NONE : options->blend_mode);
+ bool has_alpha = texture->has_alpha
+ || alpha < 1.0
+ || fx_options->corner_radius > 0
+ || fx_options->discard_transparent
+ || (fx_options->dim && fx_options->dim_color.a < 1.0);
+ setup_blending(!has_alpha ? WLR_RENDER_BLEND_MODE_NONE : options->blend_mode);
glUseProgram(shader->program);
@@ -313,7 +325,11 @@ void fx_render_pass_add_texture(struct fx_gles_render_pass *pass,
glUniform2f(shader->size, clip_box->width, clip_box->height);
glUniform2f(shader->position, clip_box->x, clip_box->y);
glUniform1f(shader->radius, fx_options->corner_radius);
+ glUniform1f(shader->has_titlebar, fx_options->has_titlebar);
glUniform1f(shader->discard_transparent, fx_options->discard_transparent);
+ glUniform1f(shader->dim, fx_options->dim);
+ struct wlr_render_color dim_color = fx_options->dim_color;
+ glUniform4f(shader->dim_color, dim_color.r, dim_color.g, dim_color.b, dim_color.a);
set_proj_matrix(shader->proj, pass->projection_matrix, &dst_box);
set_tex_matrix(shader->tex_proj, options->transform, &src_fbox);
@@ -347,15 +363,95 @@ void fx_render_pass_add_rect(struct fx_gles_render_pass *pass,
pop_fx_debug(renderer);
}
-void fx_render_pass_add_stencil_mask(struct fx_gles_render_pass *pass,
- const struct fx_render_rect_options *fx_options, int corner_radius) {
+void fx_render_pass_add_rounded_rect(struct fx_gles_render_pass *pass,
+ const struct fx_render_rounded_rect_options *fx_options) {
const struct wlr_render_rect_options *options = &fx_options->base;
struct fx_renderer *renderer = pass->buffer->renderer;
+ struct quad_round_shader *shader = NULL;
+ switch (fx_options->corner_location) {
+ case ALL:
+ shader = &renderer->shaders.quad_round;
+ break;
+ case TOP_LEFT:
+ shader = &renderer->shaders.quad_round_tl;
+ break;
+ case TOP_RIGHT:
+ shader = &renderer->shaders.quad_round_tr;
+ break;
+ case BOTTOM_LEFT:
+ shader = &renderer->shaders.quad_round_bl;
+ break;
+ case BOTTOM_RIGHT:
+ shader = &renderer->shaders.quad_round_br;
+ break;
+ default:
+ wlr_log(WLR_ERROR, "Invalid Corner Location. Aborting render");
+ abort();
+ }
+
const struct wlr_render_color *color = &options->color;
struct wlr_box box;
wlr_render_rect_options_get_box(options, pass->buffer->buffer, &box);
+
+ push_fx_debug(renderer);
+ setup_blending(WLR_RENDER_BLEND_MODE_PREMULTIPLIED);
+
+ glUseProgram(shader->program);
+
+ set_proj_matrix(shader->proj, pass->projection_matrix, &box);
+ glUniform4f(shader->color, color->r, color->g, color->b, color->a);
+
+ glUniform2f(shader->size, box.width, box.height);
+ glUniform2f(shader->position, box.x, box.y);
+ glUniform1f(shader->radius, fx_options->corner_radius);
+
+ render(&box, options->clip, shader->pos_attrib);
+
+ pop_fx_debug(renderer);
+}
+
+void fx_render_pass_add_rounded_border_corner(struct fx_gles_render_pass *pass,
+ const struct fx_render_rounded_border_corner_options *fx_options) {
+ const struct wlr_render_rect_options *options = &fx_options->base;
+
+ struct fx_renderer *renderer = pass->buffer->renderer;
+
+ const struct wlr_render_color *color = &options->color;
+ struct wlr_box box;
+ wlr_render_rect_options_get_box(options, pass->buffer->buffer, &box);
+ assert(box.width > 0 && box.width == box.height); // should be a perfect square since we are drawing a circle
+
+ push_fx_debug(renderer);
+ setup_blending(WLR_RENDER_BLEND_MODE_PREMULTIPLIED);
+
+ glUseProgram(renderer->shaders.rounded_border_corner.program);
+
+ set_proj_matrix(renderer->shaders.rounded_border_corner.proj, pass->projection_matrix, &box);
+ glUniform4f(renderer->shaders.rounded_border_corner.color, color->r, color->g, color->b, color->a);
+
+ glUniform1f(renderer->shaders.rounded_border_corner.is_top_left, fx_options->corner_location == TOP_LEFT);
+ glUniform1f(renderer->shaders.rounded_border_corner.is_top_right, fx_options->corner_location == TOP_RIGHT);
+ glUniform1f(renderer->shaders.rounded_border_corner.is_bottom_left, fx_options->corner_location == BOTTOM_LEFT);
+ glUniform1f(renderer->shaders.rounded_border_corner.is_bottom_right, fx_options->corner_location == BOTTOM_RIGHT);
+
+ glUniform2f(renderer->shaders.rounded_border_corner.position, box.x, box.y);
+ glUniform1f(renderer->shaders.rounded_border_corner.radius, fx_options->corner_radius);
+ glUniform2f(renderer->shaders.rounded_border_corner.half_size, box.width / 2.0, box.height / 2.0);
+ glUniform1f(renderer->shaders.rounded_border_corner.half_thickness, fx_options->border_thickness / 2.0);
+
+ render(&box, options->clip, renderer->shaders.rounded_border_corner.pos_attrib);
+
+ pop_fx_debug(renderer);
+}
+
+void fx_render_pass_add_stencil_mask(struct fx_gles_render_pass *pass,
+ const struct fx_render_stencil_box_options *options) {
+
+ struct fx_renderer *renderer = pass->buffer->renderer;
+
+ struct wlr_box box = options->box;
assert(box.width > 0 && box.height > 0);
push_fx_debug(renderer);
@@ -364,10 +460,9 @@ void fx_render_pass_add_stencil_mask(struct fx_gles_render_pass *pass,
glUseProgram(renderer->shaders.stencil_mask.program);
set_proj_matrix(renderer->shaders.stencil_mask.proj, pass->projection_matrix, &box);
- glUniform4f(renderer->shaders.stencil_mask.color, color->r, color->g, color->b, color->a);
glUniform2f(renderer->shaders.stencil_mask.half_size, box.width * 0.5, box.height * 0.5);
glUniform2f(renderer->shaders.stencil_mask.position, box.x, box.y);
- glUniform1f(renderer->shaders.stencil_mask.radius, corner_radius);
+ glUniform1f(renderer->shaders.stencil_mask.radius, options->corner_radius);
render(&box, options->clip, renderer->shaders.stencil_mask.pos_attrib);
@@ -375,35 +470,25 @@ void fx_render_pass_add_stencil_mask(struct fx_gles_render_pass *pass,
}
void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass,
- const struct fx_render_rect_options *fx_options,
- int corner_radius, struct shadow_data *shadow_data) {
- const struct wlr_render_rect_options *options = &fx_options->base;
-
+ const struct fx_render_box_shadow_options *options) {
struct fx_renderer *renderer = pass->buffer->renderer;
+ struct shadow_data *shadow_data = options->shadow_data;
const struct wlr_render_color *color = &shadow_data->color;
- struct wlr_box box;
- wlr_render_rect_options_get_box(options, pass->buffer->buffer, &box);
- assert(box.width > 0 && box.height > 0);
- struct wlr_box surface_box = box;
- float blur_sigma = shadow_data->blur_sigma * fx_options->scale;
-
- // Extend the size of the box
- box.x -= blur_sigma;
- box.y -= blur_sigma;
- box.width += blur_sigma * 2;
- box.height += blur_sigma * 2;
+ struct wlr_box shadow_box = options->shadow_box;
+ assert(shadow_box.width > 0 && shadow_box.height > 0);
+ struct wlr_box surface_box = options->clip_box;
+ float blur_sigma = shadow_data->blur_sigma;
pixman_region32_t render_region;
pixman_region32_init(&render_region);
pixman_region32_t inner_region;
- pixman_region32_init(&inner_region);
- pixman_region32_union_rect(&inner_region, &inner_region,
- surface_box.x + corner_radius * 0.5,
- surface_box.y + corner_radius * 0.5,
- surface_box.width - corner_radius,
- surface_box.height - corner_radius);
+ pixman_region32_init_rect(&inner_region,
+ surface_box.x + options->corner_radius * 0.5,
+ surface_box.y + options->corner_radius * 0.5,
+ fmax(surface_box.width - options->corner_radius, 0),
+ fmax(surface_box.height - options->corner_radius, 0));
pixman_region32_subtract(&render_region, options->clip, &inner_region);
pixman_region32_fini(&inner_region);
@@ -412,7 +497,12 @@ void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass,
// Init stencil work
stencil_mask_init();
// Draw the rounded rect as a mask
- fx_render_pass_add_stencil_mask(pass, fx_options, corner_radius);
+ struct fx_render_stencil_box_options stencil_options = {
+ .box = options->clip_box,
+ .corner_radius = options->corner_radius,
+ .clip = options->clip,
+ };
+ fx_render_pass_add_stencil_mask(pass, &stencil_options);
stencil_mask_close(false);
// blending will practically always be needed (unless we have a madman
@@ -422,14 +512,15 @@ void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass,
glUseProgram(renderer->shaders.box_shadow.program);
- set_proj_matrix(renderer->shaders.box_shadow.proj, pass->projection_matrix, &box);
+ set_proj_matrix(renderer->shaders.box_shadow.proj, pass->projection_matrix, &shadow_box);
glUniform4f(renderer->shaders.box_shadow.color, color->r, color->g, color->b, color->a);
glUniform1f(renderer->shaders.box_shadow.blur_sigma, blur_sigma);
- glUniform1f(renderer->shaders.box_shadow.corner_radius, corner_radius);
- glUniform2f(renderer->shaders.box_shadow.size, box.width, box.height);
- glUniform2f(renderer->shaders.box_shadow.position, box.x, box.y);
+ glUniform1f(renderer->shaders.box_shadow.corner_radius, options->corner_radius);
+ glUniform2f(renderer->shaders.box_shadow.size, shadow_box.width, shadow_box.height);
+ glUniform2f(renderer->shaders.box_shadow.position, shadow_box.x, shadow_box.y);
+
+ render(&shadow_box, &render_region, renderer->shaders.box_shadow.pos_attrib);
- render(&box, &render_region, renderer->shaders.box_shadow.pos_attrib);
pixman_region32_fini(&render_region);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
@@ -448,16 +539,18 @@ static void render_blur_segments(struct fx_gles_render_pass *pass,
struct blur_data *blur_data = fx_options->blur_data;
// Swap fbo
- if (fx_options->current_buffer == renderer->effects_buffer) {
- fx_framebuffer_bind(renderer->effects_buffer_swapped);
+ if (fx_options->current_buffer == pass->fx_effect_framebuffers->effects_buffer) {
+ fx_framebuffer_bind(pass->fx_effect_framebuffers->effects_buffer_swapped);
} else {
- fx_framebuffer_bind(renderer->effects_buffer);
+ fx_framebuffer_bind(pass->fx_effect_framebuffers->effects_buffer);
}
options->texture = fx_texture_from_buffer(&renderer->wlr_renderer,
fx_options->current_buffer->buffer);
struct fx_texture *texture = fx_get_texture(options->texture);
+ check_tex_src_box(options);
+
/*
* Render
*/
@@ -487,9 +580,7 @@ static void render_blur_segments(struct fx_gles_render_pass *pass,
glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
case WLR_SCALE_FILTER_NEAREST:
- glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- break;
+ abort();
}
glUniform1i(shader->tex, 0);
@@ -516,10 +607,10 @@ static void render_blur_segments(struct fx_gles_render_pass *pass,
wlr_texture_destroy(options->texture);
// Swap buffer. We don't want to draw to the same buffer
- if (fx_options->current_buffer != renderer->effects_buffer) {
- fx_options->current_buffer = renderer->effects_buffer;
+ if (fx_options->current_buffer != pass->fx_effect_framebuffers->effects_buffer) {
+ fx_options->current_buffer = pass->fx_effect_framebuffers->effects_buffer;
} else {
- fx_options->current_buffer = renderer->effects_buffer_swapped;
+ fx_options->current_buffer = pass->fx_effect_framebuffers->effects_buffer_swapped;
}
}
@@ -562,9 +653,7 @@ static void render_blur_effects(struct fx_gles_render_pass *pass,
glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
case WLR_SCALE_FILTER_NEAREST:
- glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- break;
+ abort();
}
glUniform1i(shader.tex, 0);
@@ -589,12 +678,13 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p
struct fx_render_blur_pass_options *fx_options) {
struct fx_renderer *renderer = pass->buffer->renderer;
struct blur_data *blur_data = fx_options->blur_data;
+ struct wlr_box monitor_box = get_monitor_box(pass->output);
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_copy(&damage, fx_options->tex_options.base.clip);
wlr_region_transform(&damage, &damage, fx_options->tex_options.base.transform,
- fx_options->monitor_box.width, fx_options->monitor_box.height);
+ monitor_box.width, monitor_box.height);
wlr_region_expand(&damage, &damage, blur_data_calc_size(fx_options->blur_data));
@@ -603,14 +693,16 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p
pixman_region32_init(&scaled_damage);
fx_options->tex_options.base.src_box = (struct wlr_fbox) {
- fx_options->monitor_box.x,
- fx_options->monitor_box.y,
- fx_options->monitor_box.width,
- fx_options->monitor_box.height,
+ monitor_box.x,
+ monitor_box.y,
+ monitor_box.width,
+ monitor_box.height,
};
- fx_options->tex_options.base.dst_box = fx_options->monitor_box;
+ fx_options->tex_options.base.dst_box = monitor_box;
// Clip the blur to the damage
fx_options->tex_options.base.clip = &scaled_damage;
+ // Artifacts with NEAREST filter
+ fx_options->tex_options.base.filter_mode = WLR_SCALE_FILTER_BILINEAR;
// Downscale
for (int i = 0; i < blur_data->num_passes; ++i) {
@@ -630,19 +722,19 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p
// Render additional blur effects like saturation, noise, contrast, etc...
if (blur_data_should_parameters_blur_effects(blur_data)
&& pixman_region32_not_empty(&damage)) {
- if (fx_options->current_buffer == renderer->effects_buffer) {
- fx_framebuffer_bind(renderer->effects_buffer_swapped);
+ if (fx_options->current_buffer == pass->fx_effect_framebuffers->effects_buffer) {
+ fx_framebuffer_bind(pass->fx_effect_framebuffers->effects_buffer_swapped);
} else {
- fx_framebuffer_bind(renderer->effects_buffer);
+ fx_framebuffer_bind(pass->fx_effect_framebuffers->effects_buffer);
}
fx_options->tex_options.base.clip = &damage;
fx_options->tex_options.base.texture = fx_texture_from_buffer(
&renderer->wlr_renderer, fx_options->current_buffer->buffer);
render_blur_effects(pass, fx_options);
- if (fx_options->current_buffer != renderer->effects_buffer) {
- fx_options->current_buffer = renderer->effects_buffer;
+ if (fx_options->current_buffer != pass->fx_effect_framebuffers->effects_buffer) {
+ fx_options->current_buffer = pass->fx_effect_framebuffers->effects_buffer;
} else {
- fx_options->current_buffer = renderer->effects_buffer_swapped;
+ fx_options->current_buffer = pass->fx_effect_framebuffers->effects_buffer_swapped;
}
}
@@ -656,6 +748,11 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p
void fx_render_pass_add_blur(struct fx_gles_render_pass *pass,
struct fx_render_blur_pass_options *fx_options) {
+ if (pass->buffer->renderer->basic_renderer) {
+ wlr_log(WLR_ERROR, "Please use 'fx_renderer_begin_buffer_pass' instead of "
+ "'wlr_renderer_begin_buffer_pass' to use advanced effects");
+ abort();
+ }
struct fx_renderer *renderer = pass->buffer->renderer;
struct fx_render_texture_options *tex_options = &fx_options->tex_options;
const struct wlr_render_texture_options *options = &tex_options->base;
@@ -674,7 +771,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass,
goto damage_finish;
}
- struct fx_framebuffer *buffer = renderer->optimized_blur_buffer;
+ struct fx_framebuffer *buffer = pass->fx_effect_framebuffers->optimized_blur_buffer;
if (!buffer || !fx_options->use_optimized_blur) {
pixman_region32_translate(&translucent_region, dst_box.x, dst_box.y);
pixman_region32_intersect(&translucent_region, &translucent_region, options->clip);
@@ -691,7 +788,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass,
blur_texture->has_alpha = true;
// Get a stencil of the window ignoring transparent regions
- if (fx_options->ignore_transparent) {
+ if (fx_options->ignore_transparent && fx_options->tex_options.base.texture) {
stencil_mask_init();
struct fx_render_texture_options tex_options = fx_options->tex_options;
@@ -702,7 +799,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass,
}
// Draw the blurred texture
- tex_options->base.dst_box = fx_options->monitor_box;
+ tex_options->base.dst_box = get_monitor_box(pass->output);
tex_options->base.src_box = (struct wlr_fbox) {
.x = 0,
.y = 0,
@@ -715,7 +812,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass,
wlr_texture_destroy(&blur_texture->wlr_texture);
// Finish stenciling
- if (fx_options->ignore_transparent) {
+ if (fx_options->ignore_transparent && fx_options->tex_options.base.texture) {
stencil_mask_fini();
}
@@ -725,8 +822,13 @@ damage_finish:
void fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass,
struct fx_render_blur_pass_options *fx_options) {
+ if (pass->buffer->renderer->basic_renderer) {
+ wlr_log(WLR_ERROR, "Please use 'fx_renderer_begin_buffer_pass' instead of "
+ "'wlr_renderer_begin_buffer_pass' to use advanced effects");
+ abort();
+ }
struct fx_renderer *renderer = pass->buffer->renderer;
- struct wlr_box monitor_box = fx_options->monitor_box;
+ struct wlr_box monitor_box = get_monitor_box(pass->output);
pixman_region32_t fake_damage;
pixman_region32_init_rect(&fake_damage, 0, 0, monitor_box.width, monitor_box.height);
@@ -738,27 +840,42 @@ void fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass,
struct fx_framebuffer *buffer = get_main_buffer_blur(pass, &blur_options);
// Update the optimized blur buffer if invalid
- fx_framebuffer_get_or_create_custom(renderer, fx_options->output,
- &renderer->optimized_blur_buffer);
+ fx_framebuffer_get_or_create_custom(renderer, pass->output,
+ &pass->fx_effect_framebuffers->optimized_blur_buffer);
// Render the newly blurred content into the blur_buffer
- fx_renderer_read_to_buffer(pass, &fake_damage, renderer->optimized_blur_buffer, buffer);
+ fx_renderer_read_to_buffer(pass, &fake_damage,
+ pass->fx_effect_framebuffers->optimized_blur_buffer, buffer, false);
pixman_region32_fini(&fake_damage);
- renderer->blur_buffer_dirty = false;
+ pass->fx_effect_framebuffers->blur_buffer_dirty = false;
}
void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass,
- pixman_region32_t *region, struct fx_framebuffer *dst_buffer,
- struct fx_framebuffer *src_buffer) {
- if (!pixman_region32_not_empty(region)) {
+ pixman_region32_t *_region, struct fx_framebuffer *dst_buffer,
+ struct fx_framebuffer *src_buffer, bool transformed_region) {
+ if (!_region || !pixman_region32_not_empty(_region)) {
return;
}
+ pixman_region32_t region;
+ pixman_region32_init(&region);
+ pixman_region32_copy(&region, _region);
+
+ // Restore the transformed region to normal
+ if (pass->output && transformed_region) {
+ int ow, oh;
+ wlr_output_transformed_resolution(pass->output, &ow, &oh);
+ enum wl_output_transform transform =
+ wlr_output_transform_invert(pass->output->transform);
+ wlr_region_transform(&region, &region, transform, ow, oh);
+ }
+
struct wlr_texture *src_tex =
fx_texture_from_buffer(&pass->buffer->renderer->wlr_renderer, src_buffer->buffer);
if (src_tex == NULL) {
+ pixman_region32_fini(&region);
return;
}
@@ -766,7 +883,8 @@ void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass,
fx_framebuffer_bind(dst_buffer);
wlr_render_pass_add_texture(&pass->base, &(struct wlr_render_texture_options) {
.texture = src_tex,
- .clip = region,
+ .clip = &region,
+ .transform = WL_OUTPUT_TRANSFORM_NORMAL,
.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
.dst_box = (struct wlr_box){
.width = dst_buffer->buffer->width,
@@ -783,6 +901,8 @@ void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass,
// Bind back to the main WLR buffer
fx_framebuffer_bind(pass->buffer);
+
+ pixman_region32_fini(&region);
}
@@ -841,6 +961,7 @@ struct fx_gles_render_pass *fx_renderer_begin_buffer_pass(
struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer,
struct wlr_output *output, const struct wlr_buffer_pass_options *options) {
struct fx_renderer *renderer = fx_get_renderer(wlr_renderer);
+ renderer->basic_renderer = false;
if (!wlr_egl_make_current(renderer->egl)) {
return NULL;
}
@@ -857,10 +978,13 @@ struct fx_gles_render_pass *fx_renderer_begin_buffer_pass(
}
// Update the buffers if needed
+ struct fx_effect_framebuffers *fbos = NULL;
+ // For per output framebuffers
if (output) {
- fx_framebuffer_get_or_create_custom(renderer, output, &renderer->blur_saved_pixels_buffer);
- fx_framebuffer_get_or_create_custom(renderer, output, &renderer->effects_buffer);
- fx_framebuffer_get_or_create_custom(renderer, output, &renderer->effects_buffer_swapped);
+ fbos = fx_effect_framebuffers_try_get(output);
+ fx_framebuffer_get_or_create_custom(renderer, output, &fbos->blur_saved_pixels_buffer);
+ fx_framebuffer_get_or_create_custom(renderer, output, &fbos->effects_buffer);
+ fx_framebuffer_get_or_create_custom(renderer, output, &fbos->effects_buffer_swapped);
}
pixman_region32_init(&renderer->blur_padding_region);
@@ -869,5 +993,7 @@ struct fx_gles_render_pass *fx_renderer_begin_buffer_pass(
if (!pass) {
return NULL;
}
+ pass->fx_effect_framebuffers = fbos;
+ pass->output = output;
return pass;
}
diff --git a/render/fx_renderer/fx_renderer.c b/render/fx_renderer/fx_renderer.c
index 0923555..0b9e1a4 100644
--- a/render/fx_renderer/fx_renderer.c
+++ b/render/fx_renderer/fx_renderer.c
@@ -3,6 +3,7 @@
https://gitlab.freedesktop.org/wlroots/wlroots/-/tree/master/render/gles2
*/
+#include "render/fx_renderer/shaders.h"
#define _POSIX_C_SOURCE 199309L
#include <assert.h>
#include <drm_fourcc.h>
@@ -20,10 +21,11 @@
#include <wlr/util/log.h>
#include "render/egl.h"
+#include "scenefx/render/pass.h"
#include "render/pixel_format.h"
#include "render/fx_renderer/util.h"
#include "render/fx_renderer/fx_renderer.h"
-#include "scenefx/fx_renderer/fx_renderer.h"
+#include "scenefx/render/fx_renderer/fx_renderer.h"
#include "render/fx_renderer/matrix.h"
#include "util/time.h"
@@ -453,6 +455,8 @@ static void fx_renderer_destroy(struct wlr_renderer *wlr_renderer) {
static struct wlr_render_pass *begin_buffer_pass(struct wlr_renderer *wlr_renderer,
struct wlr_buffer *wlr_buffer, const struct wlr_buffer_pass_options *options) {
+ struct fx_renderer *renderer = fx_get_renderer(wlr_renderer);
+ renderer->basic_renderer = true;
struct fx_gles_render_pass *pass =
fx_renderer_begin_buffer_pass(wlr_renderer, wlr_buffer, NULL, options);
if (!pass) {
@@ -638,6 +642,33 @@ static bool link_shaders(struct fx_renderer *renderer) {
wlr_log(WLR_ERROR, "Could not link quad shader");
goto error;
}
+
+ // rounded quad fragment shaders
+ if (!link_quad_round_program(&renderer->shaders.quad_round, SHADER_SOURCE_QUAD_ROUND)) {
+ wlr_log(WLR_ERROR, "Could not link quad shader");
+ goto error;
+ }
+ // rounded quad fragment shaders
+ if (!link_quad_round_program(&renderer->shaders.quad_round_tl, SHADER_SOURCE_QUAD_ROUND_TOP_LEFT)) {
+ wlr_log(WLR_ERROR, "Could not link quad shader");
+ goto error;
+ }
+ // rounded quad fragment shaders
+ if (!link_quad_round_program(&renderer->shaders.quad_round_tr, SHADER_SOURCE_QUAD_ROUND_TOP_RIGHT)) {
+ wlr_log(WLR_ERROR, "Could not link quad shader");
+ goto error;
+ }
+ // rounded quad fragment shaders
+ if (!link_quad_round_program(&renderer->shaders.quad_round_bl, SHADER_SOURCE_QUAD_ROUND_BOTTOM_LEFT)) {
+ wlr_log(WLR_ERROR, "Could not link quad shader");
+ goto error;
+ }
+ // rounded quad fragment shaders
+ if (!link_quad_round_program(&renderer->shaders.quad_round_br, SHADER_SOURCE_QUAD_ROUND_BOTTOM_RIGHT)) {
+ wlr_log(WLR_ERROR, "Could not link quad shader");
+ goto error;
+ }
+
// fragment shaders
if (!link_tex_program(&renderer->shaders.tex_rgba, SHADER_SOURCE_TEXTURE_RGBA)) {
wlr_log(WLR_ERROR, "Could not link tex_RGBA shader");
@@ -652,6 +683,12 @@ static bool link_shaders(struct fx_renderer *renderer) {
goto error;
}
+ // border corner shader
+ if (!link_rounded_border_corner_program(&renderer->shaders.rounded_border_corner)) {
+ wlr_log(WLR_ERROR, "Could not link rounded border corner shader");
+ goto error;
+ }
+
// stencil mask shader
if (!link_stencil_mask_program(&renderer->shaders.stencil_mask)) {
wlr_log(WLR_ERROR, "Could not link stencil mask shader");
@@ -681,9 +718,15 @@ static bool link_shaders(struct fx_renderer *renderer) {
error:
glDeleteProgram(renderer->shaders.quad.program);
+ glDeleteProgram(renderer->shaders.quad_round.program);
+ glDeleteProgram(renderer->shaders.quad_round_tl.program);
+ glDeleteProgram(renderer->shaders.quad_round_tr.program);
+ glDeleteProgram(renderer->shaders.quad_round_bl.program);
+ glDeleteProgram(renderer->shaders.quad_round_br.program);
glDeleteProgram(renderer->shaders.tex_rgba.program);
glDeleteProgram(renderer->shaders.tex_rgbx.program);
glDeleteProgram(renderer->shaders.tex_ext.program);
+ glDeleteProgram(renderer->shaders.rounded_border_corner.program);
glDeleteProgram(renderer->shaders.stencil_mask.program);
glDeleteProgram(renderer->shaders.box_shadow.program);
glDeleteProgram(renderer->shaders.blur1.program);
@@ -816,8 +859,6 @@ struct wlr_renderer *fx_renderer_create_egl(struct wlr_egl *egl) {
goto error;
}
- renderer->blur_buffer_dirty = false;
-
pop_fx_debug(renderer);
wlr_log(WLR_INFO, "FX RENDERER: Shaders Initialized Successfully");
diff --git a/render/fx_renderer/fx_texture.c b/render/fx_renderer/fx_texture.c
index 1952311..e22c0f9 100644
--- a/render/fx_renderer/fx_texture.c
+++ b/render/fx_renderer/fx_texture.c
@@ -5,6 +5,7 @@
#include <wlr/util/log.h>
#include <drm_fourcc.h>
+#include "scenefx/render/fx_renderer/fx_renderer.h"
#include "render/fx_renderer/fx_renderer.h"
#include "render/pixel_format.h"
#include "render/egl.h"
diff --git a/render/fx_renderer/gles2/shaders/meson.build b/render/fx_renderer/gles2/shaders/meson.build
index a751e1a..fb83e0c 100644
--- a/render/fx_renderer/gles2/shaders/meson.build
+++ b/render/fx_renderer/gles2/shaders/meson.build
@@ -3,7 +3,9 @@ embed = find_program('./embed.sh', native: true)
shaders = [
'common.vert',
'quad.frag',
+ 'quad_round.frag',
'tex.frag',
+ 'rounded_border_corner.frag',
'box_shadow.frag',
'stencil_mask.frag',
'blur1.frag',
diff --git a/render/fx_renderer/gles2/shaders/quad_round.frag b/render/fx_renderer/gles2/shaders/quad_round.frag
new file mode 100644
index 0000000..02e9902
--- /dev/null
+++ b/render/fx_renderer/gles2/shaders/quad_round.frag
@@ -0,0 +1,39 @@
+#define SOURCE_QUAD_ROUND 1
+#define SOURCE_QUAD_ROUND_TOP_LEFT 2
+#define SOURCE_QUAD_ROUND_TOP_RIGHT 3
+#define SOURCE_QUAD_ROUND_BOTTOM_RIGHT 4
+#define SOURCE_QUAD_ROUND_BOTTOM_LEFT 5
+
+#if !defined(SOURCE)
+#error "Missing shader preamble"
+#endif
+
+precision mediump float;
+varying vec4 v_color;
+varying vec2 v_texcoord;
+
+uniform vec2 size;
+uniform vec2 position;
+uniform float radius;
+
+vec2 getCornerDist() {
+#if SOURCE == SOURCE_QUAD_ROUND
+ vec2 half_size = size * 0.5;
+ return abs(gl_FragCoord.xy - position - half_size) - half_size + radius;
+#elif SOURCE == SOURCE_QUAD_ROUND_TOP_LEFT
+ return abs(gl_FragCoord.xy - position - size) - size + radius;
+#elif SOURCE == SOURCE_QUAD_ROUND_TOP_RIGHT
+ return abs(gl_FragCoord.xy - position - vec2(0, size.y)) - size + radius;
+#elif SOURCE == SOURCE_QUAD_ROUND_BOTTOM_RIGHT
+ return abs(gl_FragCoord.xy - position) - size + radius;
+#elif SOURCE == SOURCE_QUAD_ROUND_BOTTOM_LEFT
+ return abs(gl_FragCoord.xy - position - vec2(size.x, 0)) - size + radius;
+#endif
+}
+
+void main() {
+ vec2 q = getCornerDist();
+ float dist = min(max(q.x,q.y), 0.0) + length(max(q, 0.0)) - radius;
+ float smoothedAlpha = 1.0 - smoothstep(-1.0, 0.5, dist);
+ gl_FragColor = mix(vec4(0), v_color, smoothedAlpha);
+}
diff --git a/render/fx_renderer/gles2/shaders/rounded_border_corner.frag b/render/fx_renderer/gles2/shaders/rounded_border_corner.frag
new file mode 100644
index 0000000..7699299
--- /dev/null
+++ b/render/fx_renderer/gles2/shaders/rounded_border_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/render/fx_renderer/gles2/shaders/tex.frag b/render/fx_renderer/gles2/shaders/tex.frag
index b7ba3fc..d08c95d 100644
--- a/render/fx_renderer/gles2/shaders/tex.frag
+++ b/render/fx_renderer/gles2/shaders/tex.frag
@@ -29,7 +29,10 @@ uniform float alpha;
uniform vec2 size;
uniform vec2 position;
uniform float radius;
+uniform bool has_titlebar;
uniform bool discard_transparent;
+uniform float dim;
+uniform vec4 dim_color;
vec4 sample_texture() {
#if SOURCE == SOURCE_TEXTURE_RGBA || SOURCE == SOURCE_TEXTURE_EXTERNAL
@@ -40,12 +43,15 @@ vec4 sample_texture() {
}
void main() {
- gl_FragColor = sample_texture() * 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.0, 0.5, d);
- gl_FragColor = mix(vec4(0), gl_FragColor, smooth);
+ gl_FragColor = mix(sample_texture(), dim_color, dim) * alpha;
+
+ if (!has_titlebar || gl_FragCoord.y - position.y > radius) {
+ 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.0, 0.5, d);
+ gl_FragColor = mix(vec4(0), gl_FragColor, smooth);
+ }
}
if (discard_transparent && gl_FragColor.a == 0.0) {
diff --git a/render/fx_renderer/meson.build b/render/fx_renderer/meson.build
index 10e757b..041fca7 100644
--- a/render/fx_renderer/meson.build
+++ b/render/fx_renderer/meson.build
@@ -11,6 +11,7 @@ wlr_files += files(
'pixel_format.c',
'fx_pass.c',
'fx_framebuffer.c',
+ 'fx_effect_framebuffers.c',
'fx_texture.c',
'fx_renderer.c',
)
diff --git a/render/fx_renderer/shaders.c b/render/fx_renderer/shaders.c
index cd15eea..ad8fb3c 100644
--- a/render/fx_renderer/shaders.c
+++ b/render/fx_renderer/shaders.c
@@ -3,13 +3,15 @@
#include <stdlib.h>
#include <wlr/util/log.h>
-#include "render/fx_renderer/fx_renderer.h"
#include "render/fx_renderer/shaders.h"
// shaders
+#include "GLES2/gl2.h"
#include "common_vert_src.h"
#include "quad_frag_src.h"
+#include "quad_round_frag_src.h"
#include "tex_frag_src.h"
+#include "rounded_border_corner_frag_src.h"
#include "stencil_mask_frag_src.h"
#include "box_shadow_frag_src.h"
#include "blur1_frag_src.h"
@@ -113,6 +115,27 @@ bool link_quad_program(struct quad_shader *shader) {
return true;
}
+bool link_quad_round_program(struct quad_round_shader *shader, enum fx_rounded_quad_shader_source source) {
+ GLchar quad_src[2048];
+ snprintf(quad_src, sizeof(quad_src),
+ "#define SOURCE %d\n%s", source, quad_round_frag_src);
+
+ GLuint prog;
+ shader->program = prog = link_program(quad_src);
+ if (!shader->program) {
+ return false;
+ }
+
+ shader->proj = glGetUniformLocation(prog, "proj");
+ shader->color = glGetUniformLocation(prog, "color");
+ shader->pos_attrib = glGetAttribLocation(prog, "pos");
+ shader->size = glGetUniformLocation(prog, "size");
+ shader->position = glGetUniformLocation(prog, "position");
+ shader->radius = glGetUniformLocation(prog, "radius");
+
+ return true;
+}
+
bool link_tex_program(struct tex_shader *shader,
enum fx_tex_shader_source source) {
GLchar frag_src[2048];
@@ -133,7 +156,32 @@ bool link_tex_program(struct tex_shader *shader,
shader->size = glGetUniformLocation(prog, "size");
shader->position = glGetUniformLocation(prog, "position");
shader->radius = glGetUniformLocation(prog, "radius");
+ shader->has_titlebar = glGetUniformLocation(prog, "has_titlebar");
shader->discard_transparent = glGetUniformLocation(prog, "discard_transparent");
+ shader->dim = glGetUniformLocation(prog, "dim");
+ shader->dim_color = glGetUniformLocation(prog, "dim_color");
+
+ return true;
+}
+
+bool link_rounded_border_corner_program(struct rounded_border_corner_shader *shader) {
+ GLuint prog;
+ shader->program = prog = link_program(rounded_border_corner_frag_src);
+ if (!shader->program) {
+ return false;
+ }
+
+ shader->proj = glGetUniformLocation(prog, "proj");
+ shader->color = glGetUniformLocation(prog, "color");
+ shader->pos_attrib = glGetAttribLocation(prog, "pos");
+ shader->is_top_left = glGetUniformLocation(prog, "is_top_left");
+ shader->is_top_right = glGetUniformLocation(prog, "is_top_right");
+ shader->is_bottom_left = glGetUniformLocation(prog, "is_bottom_left");
+ shader->is_bottom_right = glGetUniformLocation(prog, "is_bottom_right");
+ shader->position = glGetUniformLocation(prog, "position");
+ shader->radius = glGetUniformLocation(prog, "radius");
+ shader->half_size = glGetUniformLocation(prog, "half_size");
+ shader->half_thickness = glGetUniformLocation(prog, "half_thickness");
return true;
}
@@ -146,7 +194,6 @@ bool link_stencil_mask_program(struct stencil_mask_shader *shader) {
}
shader->proj = glGetUniformLocation(prog, "proj");
- shader->color = glGetUniformLocation(prog, "color");
shader->pos_attrib = glGetAttribLocation(prog, "pos");
shader->position = glGetUniformLocation(prog, "position");
shader->half_size = glGetUniformLocation(prog, "half_size");