Compare commits

...
Sign in to create a new pull request.

22 commits

Author SHA1 Message Date
Erik Reider
be1d93b2cd Simplified detection of blur on workspace 2023-08-12 14:45:43 +02:00
Erik Reider
657da122ab Removed the need for our own main FBO, also fixes some damage bugs 2023-08-10 21:18:47 +02:00
Erik Reider
cf463ee9a3 Removed unneeded clearing of the wlr fbo before rendering onto it 2023-08-01 19:35:03 +02:00
Erik Reider
8962d460d6 Renamed extended_damage to original_damage to reflect better what it actually is 2023-08-01 19:29:10 +02:00
Erik Reider
4cf404c189 Don't scale the blur translucent region twice 2023-08-01 15:07:13 +02:00
Erik Reider
be750ae707 Merge branch 'master' into render_blur_cleanup 2023-08-01 15:06:40 +02:00
William McKinnon
5ffa10eede moved more into fx_renderer 2023-07-26 01:02:03 -04:00
William McKinnon
51fde22616 moved fx_framebuffer binds to fx_renderer 2023-07-26 00:25:23 -04:00
Erik Reider
da8c83d803 Fixed blur not switching FB 2023-07-26 00:25:46 +02:00
William McKinnon
a5a38efc00 moved more to fx_renderer 2023-07-25 17:55:43 -04:00
William McKinnon
0e4a8d0c00 restructured blur pipeline into fx_renderer 2023-07-25 17:54:29 -04:00
William McKinnon
2ed02c90a8 removed src_box 2023-07-23 23:40:09 -04:00
William McKinnon
b03ca3b50d removed unneeded wlr_fbox_from_box function 2023-07-23 23:29:17 -04:00
William McKinnon
e9f14c748c removed unneeded src_box 2023-07-23 23:25:38 -04:00
William McKinnon
27e7a9b4ff Merge remote-tracking branch 'origin' into render_blur_cleanup 2023-07-23 23:03:01 -04:00
William McKinnon
27f1bf4e75 removed uneeded fb bind 2023-07-18 23:27:39 -04:00
William McKinnon
4cc7ca6ff1 Merge remote-tracking branch 'origin' into render_blur_cleanup 2023-07-18 23:14:58 -04:00
William McKinnon
c1a1d80764 removed scaled_dst box 2023-06-05 20:35:20 -04:00
Erik Reider
abd42739a0 Minor refactors 2023-06-05 17:42:54 +02:00
Erik Reider
76b94341ed Fixed scaling issues 2023-06-05 16:44:01 +02:00
Erik Reider
2fe9f2336f Merge branch 'master' into render_blur_cleanup 2023-06-05 16:41:46 +02:00
William McKinnon
54bb0d154f refactor: removed surface_width + surface_height from render_blur() 2023-06-02 18:39:55 -04:00
7 changed files with 239 additions and 251 deletions

View file

@ -120,12 +120,22 @@ struct fx_renderer {
int viewport_width, viewport_height;
struct fx_framebuffer wlr_buffer; // Just the framebuffer used by wlroots
struct fx_framebuffer main_buffer; // The main FB used for rendering
struct fx_framebuffer blur_buffer; // Contains the blurred background for tiled windows
struct wlr_output *wlr_output;
// The framebuffer used by wlroots
struct fx_framebuffer wlr_buffer;
// Contains the blurred background for tiled windows
struct fx_framebuffer blur_buffer;
// Contains the original pixels to draw over the areas where artifact are visible
struct fx_framebuffer blur_saved_pixels_buffer;
// Blur swaps between the two effects buffers everytime it scales the image
struct fx_framebuffer effects_buffer; // Buffer used for effects
struct fx_framebuffer effects_buffer_swapped; // Swap buffer used for effects
// Buffer used for effects
struct fx_framebuffer effects_buffer;
// Swap buffer used for effects
struct fx_framebuffer effects_buffer_swapped;
// The region where there's blur
pixman_region32_t blur_padding_region;
bool blur_buffer_dirty;
@ -155,12 +165,14 @@ struct fx_renderer {
} shaders;
};
struct fx_renderer *fx_renderer_create(struct wlr_egl *egl);
struct fx_renderer *fx_renderer_create(struct wlr_egl *egl, struct wlr_output *output);
void fx_renderer_fini(struct fx_renderer *renderer);
void fx_renderer_begin(struct fx_renderer *renderer, int width, int height);
void fx_renderer_end(struct fx_renderer *renderer);
void fx_renderer_clear(const float color[static 4]);
void fx_renderer_scissor(struct wlr_box *box);
@ -187,8 +199,6 @@ void fx_render_box_shadow(struct fx_renderer *renderer, const struct wlr_box *bo
const float color[static 4], const float matrix[static 9], int radius,
float blur_sigma);
void fx_render_blur(struct fx_renderer *renderer, const float matrix[static 9],
struct fx_framebuffer **buffer, struct blur_shader *shader, const struct wlr_box *box,
int blur_radius);
struct fx_framebuffer *fx_render_main_buffer_blur(struct fx_renderer *renderer, const float matrix[static 9],
pixman_region32_t *damage, const struct wlr_box *dst_box, int blur_radius, int blur_passes);
#endif

View file

@ -92,7 +92,8 @@ struct sway_output *workspace_output_get_highest_available(
void workspace_detect_urgent(struct sway_workspace *workspace);
bool should_workspace_have_blur(struct sway_workspace *ws);
bool workspace_get_blur_info(struct sway_workspace *ws,
pixman_region32_t *blur_region);
void workspace_for_each_container(struct sway_workspace *ws,
void (*f)(struct sway_container *con, void *data), void *data);

View file

@ -67,17 +67,11 @@ void fx_framebuffer_add_stencil_buffer(struct fx_framebuffer *buffer, int width,
if (first_alloc || buffer->stencil_buffer.width != width || buffer->stencil_buffer.height != height) {
glBindRenderbuffer(GL_RENDERBUFFER, buffer->stencil_buffer.rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, buffer->stencil_buffer.rb);
buffer->stencil_buffer.width = width;
buffer->stencil_buffer.height = height;
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
sway_log(SWAY_ERROR, "Stencil buffer incomplete, couldn't create! (FB status: %i)", status);
return;
}
sway_log(SWAY_DEBUG, "Stencil buffer created, status %i", status);
}
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, buffer->stencil_buffer.rb);
}
void fx_framebuffer_release(struct fx_framebuffer *buffer) {

View file

@ -11,10 +11,13 @@
#include <wlr/render/gles2.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/util/box.h>
#include <wlr/util/region.h>
#include "log.h"
#include "sway/desktop/fx_renderer/fx_framebuffer.h"
#include "sway/desktop/fx_renderer/fx_renderer.h"
#include "sway/desktop/fx_renderer/fx_stencilbuffer.h"
#include "sway/desktop/fx_renderer/fx_texture.h"
#include "sway/desktop/fx_renderer/matrix.h"
#include "sway/server.h"
@ -251,12 +254,14 @@ static void load_gl_proc(void *proc_ptr, const char *name) {
*(void **)proc_ptr = proc;
}
struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
struct fx_renderer *fx_renderer_create(struct wlr_egl *egl, struct wlr_output *wlr_output) {
struct fx_renderer *renderer = calloc(1, sizeof(struct fx_renderer));
if (renderer == NULL) {
return NULL;
}
renderer->wlr_output = wlr_output;
// TODO: wlr_egl_make_current or eglMakeCurrent?
// TODO: assert instead of conditional statement?
if (!eglMakeCurrent(wlr_egl_get_display(egl), EGL_NO_SURFACE, EGL_NO_SURFACE,
@ -265,8 +270,9 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
return NULL;
}
renderer->main_buffer = fx_framebuffer_create();
renderer->wlr_buffer = fx_framebuffer_create();
renderer->blur_buffer = fx_framebuffer_create();
renderer->blur_saved_pixels_buffer = fx_framebuffer_create();
renderer->effects_buffer = fx_framebuffer_create();
renderer->effects_buffer_swapped = fx_framebuffer_create();
@ -385,8 +391,8 @@ error:
}
void fx_renderer_fini(struct fx_renderer *renderer) {
fx_framebuffer_release(&renderer->main_buffer);
fx_framebuffer_release(&renderer->blur_buffer);
fx_framebuffer_release(&renderer->blur_saved_pixels_buffer);
fx_framebuffer_release(&renderer->effects_buffer);
fx_framebuffer_release(&renderer->effects_buffer_swapped);
}
@ -396,32 +402,36 @@ void fx_renderer_begin(struct fx_renderer *renderer, int width, int height) {
renderer->viewport_width = width;
renderer->viewport_height = height;
// Store the wlr framebuffer
GLint wlr_fb = -1;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &wlr_fb);
if (wlr_fb < 0) {
sway_log(SWAY_ERROR, "Failed to get wlr framebuffer!");
abort();
}
renderer->wlr_buffer.fb = wlr_fb;
// Store the wlr FBO
renderer->wlr_buffer.fb =
wlr_gles2_renderer_get_current_fbo(renderer->wlr_output->renderer);
// Get the fx_texture
struct wlr_texture *wlr_texture = wlr_texture_from_buffer(
renderer->wlr_output->renderer, renderer->wlr_output->back_buffer);
renderer->wlr_buffer.texture = fx_texture_from_wlr_texture(wlr_texture);
wlr_texture_destroy(wlr_texture);
// Add the stencil to the wlr fbo
fx_framebuffer_add_stencil_buffer(&renderer->wlr_buffer, width, height);
// Create the framebuffers
fx_framebuffer_update(&renderer->main_buffer, width, height);
fx_framebuffer_update(&renderer->blur_saved_pixels_buffer, width, height);
fx_framebuffer_update(&renderer->effects_buffer, width, height);
fx_framebuffer_update(&renderer->effects_buffer_swapped, width, height);
// Add a stencil buffer to the main buffer & bind the main buffer
fx_framebuffer_bind(&renderer->main_buffer);
fx_framebuffer_add_stencil_buffer(&renderer->main_buffer, width, height);
fx_framebuffer_bind(&renderer->wlr_buffer);
pixman_region32_init(&renderer->blur_padding_region);
// refresh projection matrix
matrix_projection(renderer->projection, width, height,
WL_OUTPUT_TRANSFORM_FLIPPED_180);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
// Bind to our main framebuffer
fx_framebuffer_bind(&renderer->main_buffer);
void fx_renderer_end(struct fx_renderer *renderer) {
pixman_region32_fini(&renderer->blur_padding_region);
}
void fx_renderer_clear(const float color[static 4]) {
@ -806,12 +816,8 @@ void fx_render_box_shadow(struct fx_renderer *renderer, const struct wlr_box *bo
glDisable(GL_STENCIL_TEST);
}
void fx_render_blur(struct fx_renderer *renderer, const float matrix[static 9],
struct fx_framebuffer **buffer, struct blur_shader *shader,
const struct wlr_box *box, int blur_radius) {
glDisable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
void fx_render_blur_pass(struct fx_renderer *renderer, const float gl_matrix[static 9],
struct blur_shader *shader, const struct wlr_box *box, int blur_radius, struct fx_framebuffer **buffer) {
glActiveTexture(GL_TEXTURE0);
glBindTexture((*buffer)->texture.target, (*buffer)->texture.id);
@ -822,8 +828,6 @@ void fx_render_blur(struct fx_renderer *renderer, const float matrix[static 9],
// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
// to GL_FALSE
float gl_matrix[9];
wlr_matrix_transpose(gl_matrix, matrix);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix);
glUniform1i(shader->tex, 0);
@ -846,3 +850,72 @@ void fx_render_blur(struct fx_renderer *renderer, const float matrix[static 9],
glDisableVertexAttribArray(shader->pos_attrib);
glDisableVertexAttribArray(shader->tex_attrib);
}
void fx_render_blur_segments(struct fx_renderer *renderer, const float gl_matrix[static 9],
pixman_region32_t *damage, struct fx_framebuffer **buffer, struct blur_shader* shader,
const struct wlr_box *box, int blur_radius) {
if (*buffer == &renderer->effects_buffer) {
fx_framebuffer_bind(&renderer->effects_buffer_swapped);
} else {
fx_framebuffer_bind(&renderer->effects_buffer);
}
if (pixman_region32_not_empty(damage)) {
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
for (int i = 0; i < nrects; ++i) {
const pixman_box32_t box = rects[i];
struct wlr_box new_box = { box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1 };
fx_renderer_scissor(&new_box);
fx_render_blur_pass(renderer, gl_matrix, shader, &new_box, blur_radius, buffer);
}
}
if (*buffer != &renderer->effects_buffer) {
*buffer = &renderer->effects_buffer;
} else {
*buffer = &renderer->effects_buffer_swapped;
}
}
struct fx_framebuffer *fx_render_main_buffer_blur(struct fx_renderer *renderer, const float matrix[static 9],
pixman_region32_t *damage, const struct wlr_box *dst_box, int blur_radius, int blur_passes) {
glDisable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
struct fx_framebuffer *current_buffer = &renderer->wlr_buffer;
// Bind to blur framebuffer
fx_framebuffer_bind(&renderer->effects_buffer);
glBindTexture(renderer->wlr_buffer.texture.target, renderer->wlr_buffer.texture.id);
float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
wlr_matrix_transpose(gl_matrix, gl_matrix);
// damage region will be scaled, make a temp
pixman_region32_t temp_damage;
pixman_region32_init(&temp_damage);
// Downscale
for (int i = 0; i < blur_passes; ++i) {
wlr_region_scale(&temp_damage, damage, 1.0f / (1 << (i + 1)));
fx_render_blur_segments(renderer, gl_matrix, &temp_damage, &current_buffer,
&renderer->shaders.blur1, dst_box, blur_radius);
}
// Upscale
for (int i = blur_passes - 1; i >= 0; --i) {
// when upsampling we make the region twice as big
wlr_region_scale(&temp_damage, damage, 1.0f / (1 << i));
fx_render_blur_segments(renderer, gl_matrix, &temp_damage, &current_buffer,
&renderer->shaders.blur2, dst_box, blur_radius);
}
pixman_region32_fini(&temp_damage);
// Bind back to the default buffer
fx_framebuffer_bind(&renderer->wlr_buffer);
return current_buffer;
}

View file

@ -697,36 +697,6 @@ static void damage_surface_iterator(struct sway_output *output,
}
pixman_region32_translate(&damage, box.x, box.y);
// Extend view/layer damage size
int effect_size = 0;
if (view && view->container->blur_enabled) {
// Don't check for shadow, gets extended in `output_damage_whole_container`
effect_size = config_get_blur_size();
} else if (wlr_surface_is_layer_surface(surface)) {
struct wlr_layer_surface_v1 *layer = wlr_layer_surface_v1_from_wlr_surface(surface);
struct sway_layer_surface *sway_layer = layer_from_wlr_layer_surface_v1(layer);
int blur_size = sway_layer->has_blur? config_get_blur_size(): 0;
int shadow_sigma = sway_layer->has_shadow? config->shadow_blur_sigma: 0;
effect_size = MAX(blur_size, shadow_sigma);
}
if (effect_size > 0) {
if (pixman_region32_not_empty(&damage)) {
int output_width, output_height;
wlr_output_transformed_resolution(output->wlr_output, &output_width, &output_height);
int32_t damage_width = damage.extents.x2 - damage.extents.x1;
int32_t damage_height = damage.extents.y2 - damage.extents.y1;
if (damage_width > output_width || damage_height > output_height) {
pixman_region32_intersect_rect(&damage, &damage, 0, 0, output_width, output_height);
} else {
wlr_region_expand(&damage, &damage, effect_size);
}
}
box.x -= effect_size;
box.y -= effect_size;
box.width += effect_size * 2;
box.height += effect_size * 2;
}
if (wlr_damage_ring_add(&output->damage_ring, &damage)) {
wlr_output_schedule_frame(output->wlr_output);
}
@ -983,7 +953,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
// Init FX Renderer
struct wlr_egl *egl = wlr_gles2_renderer_get_egl(server->wlr_renderer);
output->renderer = fx_renderer_create(egl);
output->renderer = fx_renderer_create(egl, wlr_output);
if (!output->renderer) {
sway_log(SWAY_ERROR, "Failed to create fx_renderer");
abort();

View file

@ -44,16 +44,6 @@ struct decoration_data get_undecorated_decoration_data() {
};
}
// TODO: contribute wlroots function to allow creating an fbox from a box?
struct wlr_fbox wlr_fbox_from_wlr_box(struct wlr_box *box) {
return (struct wlr_fbox) {
.x = box->x,
.y = box->y,
.width = box->width,
.height = box->height,
};
}
// TODO: Remove this ugly abomination with a complete border rework...
enum corner_location get_rotated_corner(enum corner_location corner_location,
enum wl_output_transform transform) {
@ -189,38 +179,9 @@ damage_finish:
pixman_region32_fini(&damage);
}
/* Renders the blur for each damaged rect and swaps the buffer */
void render_blur_segments(struct fx_renderer *renderer,
const float matrix[static 9], pixman_region32_t* damage,
struct fx_framebuffer **buffer, struct blur_shader* shader,
const struct wlr_box *box, int blur_radius) {
if (*buffer == &renderer->effects_buffer) {
fx_framebuffer_bind(&renderer->effects_buffer_swapped);
} else {
fx_framebuffer_bind(&renderer->effects_buffer);
}
if (pixman_region32_not_empty(damage)) {
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
for (int i = 0; i < nrects; ++i) {
const pixman_box32_t box = rects[i];
struct wlr_box new_box = { box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1 };
fx_renderer_scissor(&new_box);
fx_render_blur(renderer, matrix, buffer, shader, &new_box, blur_radius);
}
}
if (*buffer != &renderer->effects_buffer) {
*buffer = &renderer->effects_buffer;
} else {
*buffer = &renderer->effects_buffer_swapped;
}
}
// Blurs the main_buffer content and returns the blurred framebuffer
struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct sway_output *output,
pixman_region32_t *original_damage, const struct wlr_box *box) {
struct fx_framebuffer *render_main_buffer_blur(struct sway_output *output,
pixman_region32_t *original_damage, const struct wlr_box *dst_box) {
struct fx_renderer *renderer = output->renderer;
struct wlr_output *wlr_output = output->wlr_output;
struct wlr_box monitor_box = get_monitor_box(wlr_output);
@ -228,104 +189,51 @@ struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct
float matrix[9];
wlr_matrix_project_box(matrix, &monitor_box, transform, 0, wlr_output->transform_matrix);
float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_copy(&damage, original_damage);
wlr_region_transform(&damage, &damage, transform, monitor_box.width, monitor_box.height);
wlr_region_expand(&damage, &damage, config_get_blur_size());
// Initially blur main_buffer content into the effects_buffers
struct fx_framebuffer *current_buffer = &renderer->main_buffer;
struct fx_framebuffer *current_buffer = fx_render_main_buffer_blur(renderer, matrix, &damage,
dst_box, config->blur_params.radius, config->blur_params.num_passes);
// Bind to blur framebuffer
fx_framebuffer_bind(&renderer->effects_buffer);
glBindTexture(renderer->main_buffer.texture.target, renderer->main_buffer.texture.id);
// damage region will be scaled, make a temp
pixman_region32_t tempDamage;
pixman_region32_init(&tempDamage);
int blur_radius = config->blur_params.radius;
int blur_passes = config->blur_params.num_passes;
// Downscale
for (int i = 0; i < blur_passes; ++i) {
wlr_region_scale(&tempDamage, &damage, 1.0f / (1 << (i + 1)));
render_blur_segments(renderer, gl_matrix, &tempDamage, &current_buffer,
&renderer->shaders.blur1, box, blur_radius);
}
// Upscale
for (int i = blur_passes - 1; i >= 0; --i) {
// when upsampling we make the region twice as big
wlr_region_scale(&tempDamage, &damage, 1.0f / (1 << i));
render_blur_segments(renderer, gl_matrix, &tempDamage, &current_buffer,
&renderer->shaders.blur2, box, blur_radius);
}
pixman_region32_fini(&tempDamage);
pixman_region32_fini(&damage);
// Bind back to the default buffer
fx_framebuffer_bind(&renderer->main_buffer);
return current_buffer;
}
void render_blur(bool optimized, struct sway_output *output,
pixman_region32_t *output_damage, const struct wlr_fbox *src_box,
const struct wlr_box *dst_box, pixman_region32_t *opaque_region,
int surface_width, int surface_height, int32_t surface_scale,
int corner_radius, bool should_round_top) {
void render_blur(bool optimized, struct sway_output *output, pixman_region32_t *output_damage,
const struct wlr_box *dst_box, pixman_region32_t *opaque_region, int corner_radius,
bool should_round_top) {
struct wlr_output *wlr_output = output->wlr_output;
struct fx_renderer *renderer = output->renderer;
// Check if damage is inside of box rect
pixman_region32_t damage = create_damage(*dst_box, output_damage);
pixman_region32_t inverse_opaque;
pixman_region32_init(&inverse_opaque);
pixman_region32_t translucent_region;
pixman_region32_init(&translucent_region);
if (!pixman_region32_not_empty(&damage)) {
goto damage_finish;
}
/*
* Capture the back_buffer and blur it
*/
pixman_box32_t surface_box = {
.x1 = 0,
.y1 = 0,
.x2 = dst_box->width / wlr_output->scale,
.y2 = dst_box->height / wlr_output->scale,
};
wlr_region_scale(&inverse_opaque, &inverse_opaque, wlr_output->scale);
// Gets the non opaque region
pixman_region32_copy(&inverse_opaque, opaque_region);
pixman_region32_inverse(&inverse_opaque, &inverse_opaque, &surface_box);
pixman_region32_intersect_rect(&inverse_opaque, &inverse_opaque, 0, 0,
surface_width * surface_scale,
surface_height * surface_scale);
if (!pixman_region32_not_empty(&inverse_opaque)) {
// Gets the translucent region
pixman_box32_t surface_box = { 0, 0, dst_box->width, dst_box->height };
pixman_region32_copy(&translucent_region, opaque_region);
pixman_region32_inverse(&translucent_region, &translucent_region, &surface_box);
if (!pixman_region32_not_empty(&translucent_region)) {
goto damage_finish;
}
wlr_region_scale(&inverse_opaque, &inverse_opaque, wlr_output->scale);
struct fx_framebuffer *buffer = &renderer->blur_buffer;
if (!buffer->texture.id || !optimized) {
pixman_region32_translate(&inverse_opaque, dst_box->x, dst_box->y);
pixman_region32_intersect(&inverse_opaque, &inverse_opaque, &damage);
pixman_region32_translate(&translucent_region, dst_box->x, dst_box->y);
pixman_region32_intersect(&translucent_region, &translucent_region, &damage);
// Render the blur into its own buffer
buffer = get_main_buffer_blur(renderer, output, &inverse_opaque, dst_box);
buffer = render_main_buffer_blur(output, &translucent_region, dst_box);
}
// Draw the blurred texture
@ -337,11 +245,11 @@ void render_blur(bool optimized, struct sway_output *output,
struct decoration_data deco_data = get_undecorated_decoration_data();
deco_data.corner_radius = corner_radius;
deco_data.has_titlebar = should_round_top;
render_texture(wlr_output, &damage, &buffer->texture, src_box, dst_box, matrix, deco_data);
render_texture(wlr_output, &damage, &buffer->texture, NULL, dst_box, matrix, deco_data);
damage_finish:
pixman_region32_fini(&damage);
pixman_region32_fini(&inverse_opaque);
pixman_region32_fini(&translucent_region);
}
// _box.x and .y are expected to be layout-local
@ -428,7 +336,6 @@ static void render_surface_iterator(struct sway_output *output,
dst_box.x = fmax(dst_box.x, clip_box->x);
dst_box.y = fmax(dst_box.y, clip_box->y);
}
scale_box(&dst_box, wlr_output->scale);
struct decoration_data deco_data = data->deco_data;
@ -453,12 +360,7 @@ static void render_surface_iterator(struct sway_output *output,
bool should_optimize_blur = view ?
!container_is_floating_or_child(view->container) || config->blur_xray
: false;
struct wlr_box monitor_box = get_monitor_box(wlr_output);
wlr_box_transform(&monitor_box, &monitor_box,
wlr_output_transform_invert(wlr_output->transform), monitor_box.width, monitor_box.height);
struct wlr_fbox blur_src_box = wlr_fbox_from_wlr_box(&monitor_box);
render_blur(should_optimize_blur, output, output_damage, &blur_src_box, &dst_box, &opaque_region,
surface->current.width, surface->current.height, surface->current.scale,
render_blur(should_optimize_blur, output, output_damage, &dst_box, &opaque_region,
deco_data.corner_radius, deco_data.has_titlebar);
}
@ -561,7 +463,7 @@ void render_output_blur(struct sway_output *output, pixman_region32_t *damage) {
pixman_region32_init_rect(&fake_damage, 0, 0, monitor_box.width, monitor_box.height);
// Render the blur
struct fx_framebuffer *buffer = get_main_buffer_blur(renderer, output, &fake_damage, &monitor_box);
struct fx_framebuffer *buffer = render_main_buffer_blur(output, &fake_damage, &monitor_box);
// Render the newly blurred content into the blur_buffer
fx_framebuffer_update(&renderer->blur_buffer,
@ -577,7 +479,7 @@ void render_output_blur(struct sway_output *output, pixman_region32_t *damage) {
fx_renderer_clear(clear_color);
}
render_whole_output(renderer, wlr_output, &fake_damage, &buffer->texture);
fx_framebuffer_bind(&renderer->main_buffer);
fx_framebuffer_bind(&renderer->wlr_buffer);
pixman_region32_fini(&fake_damage);
@ -832,13 +734,9 @@ static void render_saved_view(struct sway_view *view, struct sway_output *output
pixman_region32_init(&opaque_region);
pixman_region32_union_rect(&opaque_region, &opaque_region, 0, 0, 0, 0);
struct wlr_box monitor_box = get_monitor_box(wlr_output);
wlr_box_transform(&monitor_box, &monitor_box,
wlr_output_transform_invert(wlr_output->transform), monitor_box.width, monitor_box.height);
struct wlr_fbox src_box = wlr_fbox_from_wlr_box(&monitor_box);
bool should_optimize_blur = !container_is_floating_or_child(view->container) || config->blur_xray;
render_blur(should_optimize_blur, output, damage, &src_box, &dst_box, &opaque_region,
saved_buf->width, saved_buf->height, 1, deco_data.corner_radius, deco_data.has_titlebar);
render_blur(should_optimize_blur, output, damage, &dst_box, &opaque_region,
deco_data.corner_radius, deco_data.has_titlebar);
pixman_region32_fini(&opaque_region);
}
@ -1792,13 +1690,6 @@ void output_render(struct sway_output *output, struct timespec *when,
return;
}
/* we need to track extended damage for blur (as it is expanded in output.c),
before we expand it again later in this function
*/
pixman_region32_t extended_damage;
pixman_region32_init(&extended_damage);
pixman_region32_copy(&extended_damage, damage);
struct sway_container *fullscreen_con = root->fullscreen_global;
if (!fullscreen_con) {
fullscreen_con = workspace->current.fullscreen;
@ -1816,7 +1707,6 @@ void output_render(struct sway_output *output, struct timespec *when,
if (debug.damage == DAMAGE_RERENDER) {
pixman_region32_union_rect(damage, damage, 0, 0, output_width, output_height);
pixman_region32_copy(&extended_damage, damage);
}
if (!pixman_region32_not_empty(damage)) {
@ -1825,9 +1715,7 @@ void output_render(struct sway_output *output, struct timespec *when,
}
if (debug.damage == DAMAGE_HIGHLIGHT) {
fx_framebuffer_bind(&renderer->wlr_buffer);
fx_renderer_clear((float[]){1, 1, 0, 1});
fx_framebuffer_bind(&renderer->main_buffer);
}
if (server.session_lock.locked) {
@ -1903,24 +1791,66 @@ void output_render(struct sway_output *output, struct timespec *when,
render_unmanaged(output, damage, &root->xwayland_unmanaged);
#endif
} else {
bool workspace_has_blur = should_workspace_have_blur(workspace);
// Gather the whole region where blur is drawn (all surfaces on
// the focused workspace)
pixman_region32_t blur_region;
pixman_region32_init(&blur_region);
bool workspace_has_blur = workspace_get_blur_info(workspace, &blur_region);
// Expend the damage to compensate for blur
if (workspace_has_blur) {
if (config_should_parameters_blur() && renderer->blur_buffer_dirty) {
// Skip all of the blur artifact prevention if we're damaging the
// whole viewport
if (renderer->blur_buffer_dirty) {
// Needs to be extended before clearing
pixman_region32_union_rect(damage, damage, 0, 0, output_width, output_height);
pixman_region32_union_rect(&extended_damage, &extended_damage, 0, 0, output_width, output_height);
}
// ensure that the damage isn't expanding past the output's size
int32_t damage_width = damage->extents.x2 - damage->extents.x1;
int32_t damage_height = damage->extents.y2 - damage->extents.y1;
if (damage_width > output_width || damage_height > output_height) {
pixman_region32_intersect_rect(damage, damage, 0, 0, output_width, output_height);
pixman_region32_intersect_rect(&extended_damage, &extended_damage, 0, 0, output_width, output_height);
pixman_region32_union_rect(damage, damage,
0, 0, output_width, output_height);
} else {
wlr_region_expand(damage, damage, config_get_blur_size());
// To remove blur edge artifacts we need to copy the surrounding
// content where the blur would display artifacts and draw it
// above the artifacts, i.e resetting the affected areas to look
// like they did in the previous frame (these areas haven't changed
// so we don't have to worry about that).
// ensure that the damage isn't expanding past the output's size
int32_t damage_width = damage->extents.x2 - damage->extents.x1;
int32_t damage_height = damage->extents.y2 - damage->extents.y1;
if (damage_width > output_width || damage_height > output_height) {
pixman_region32_intersect_rect(damage, damage,
0, 0, output_width, output_height);
} else {
// Expand the original damage to compensate for surrounding
// blurred views to avoid sharp edges between damage regions
wlr_region_expand(damage, damage, config_get_blur_size());
}
pixman_region32_t extended_damage;
pixman_region32_init(&extended_damage);
pixman_region32_intersect(&extended_damage, damage, &blur_region);
// Expand the region to compensate for blur artifacts
wlr_region_expand(&extended_damage, &extended_damage, config_get_blur_size());
// Limit to the monitors viewport
pixman_region32_intersect_rect(&extended_damage, &extended_damage,
0, 0, output_width, output_height);
// Make sure that we ONLY capture the padding pixels around the
// blur (around the expanded region) where the artifacts will
// be drawn
pixman_region32_subtract(&renderer->blur_padding_region,
&extended_damage, damage);
// Combine into the surface damage (we need to redraw the padding
// area as well)
pixman_region32_union(damage, damage, &extended_damage);
pixman_region32_fini(&extended_damage);
// Capture the padding pixels before blur for later use
fx_framebuffer_bind(&renderer->blur_saved_pixels_buffer);
// TODO: Investigate blitting instead
render_whole_output(renderer, wlr_output,
&renderer->blur_padding_region, &renderer->wlr_buffer.texture);
fx_framebuffer_bind(&renderer->wlr_buffer);
}
}
pixman_region32_fini(&blur_region);
float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
@ -1937,7 +1867,7 @@ void output_render(struct sway_output *output, struct timespec *when,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
// check if the background needs to be blurred
if (config_should_parameters_blur() && renderer->blur_buffer_dirty && workspace_has_blur) {
if (workspace_has_blur && renderer->blur_buffer_dirty) {
render_output_blur(output, damage);
}
@ -1985,21 +1915,15 @@ render_overlay:
render_drag_icons(output, damage, &root->drag_icons);
renderer_end:
// Draw the contents of our buffer into the wlr buffer
fx_framebuffer_bind(&renderer->wlr_buffer);
float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
if (pixman_region32_not_empty(&extended_damage)) {
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&extended_damage, &nrects);
for (int i = 0; i < nrects; ++i) {
scissor_output(wlr_output, &rects[i]);
fx_renderer_clear(clear_color);
}
// Not needed if we damaged the whole viewport
if (!renderer->blur_buffer_dirty) {
// Render the saved pixels over the blur artifacts
// TODO: Investigate blitting instead
render_whole_output(renderer, wlr_output, &renderer->blur_padding_region,
&renderer->blur_saved_pixels_buffer.texture);
}
render_whole_output(renderer, wlr_output, &extended_damage, &renderer->main_buffer.texture);
fx_renderer_end(output->renderer);
fx_renderer_scissor(NULL);
// Draw the software cursors
@ -2011,8 +1935,7 @@ renderer_end:
pixman_region32_init(&frame_damage);
enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform);
wlr_region_transform(&frame_damage, &extended_damage, transform, output_width, output_height);
pixman_region32_fini(&extended_damage);
wlr_region_transform(&frame_damage, damage, transform, output_width, output_height);
if (debug.damage != DAMAGE_DEFAULT) {
pixman_region32_union_rect(&frame_damage, &frame_damage,

View file

@ -692,24 +692,39 @@ void workspace_detect_urgent(struct sway_workspace *workspace) {
}
}
static bool find_blurred_con_iterator(struct sway_container *con, void *data) {
struct blur_region_data {
struct sway_workspace *ws;
pixman_region32_t *blur_region;
};
static void find_blurred_region_iterator(struct sway_container *con, void *data) {
struct sway_view *view = con->view;
if (!view) {
return false;
return;
}
struct blur_region_data *region_data = data;
struct sway_workspace *ws = region_data->ws;
pixman_region32_t *blur_region = region_data->blur_region;
if (con->blur_enabled && !view->surface->opaque) {
pixman_region32_union_rect(blur_region, blur_region,
floor(con->current.x) - ws->output->lx,
floor(con->current.y) - ws->output->ly,
con->current.width, con->current.height);
}
return con->blur_enabled && !view->surface->opaque;
}
bool should_workspace_have_blur(struct sway_workspace *ws) {
if (!workspace_is_visible(ws)) {
bool workspace_get_blur_info(struct sway_workspace *ws, pixman_region32_t *blur_region) {
if (!workspace_is_visible(ws) || !config_should_parameters_blur()) {
return false;
}
if ((bool)workspace_find_container(ws, find_blurred_con_iterator, NULL)) {
return true;
}
// Each toplevel
struct blur_region_data data = { ws, blur_region };
workspace_for_each_container(ws, find_blurred_region_iterator, &data);
// Check if any layer-shell surfaces will render effects
// Each Layer
struct sway_output *sway_output = ws->output;
size_t len = sizeof(sway_output->layers) / sizeof(sway_output->layers[0]);
for (size_t i = 0; i < len; ++i) {
@ -717,12 +732,14 @@ bool should_workspace_have_blur(struct sway_workspace *ws) {
wl_list_for_each(lsurface, &sway_output->layers[i], link) {
if (lsurface->has_blur && !lsurface->layer_surface->surface->opaque
&& lsurface->layer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) {
return true;
struct wlr_box *geo = &lsurface->geo;
pixman_region32_union_rect(blur_region, blur_region,
geo->x, geo->y, geo->width, geo->height);
}
}
}
return false;
return pixman_region32_not_empty(blur_region);
}
void workspace_for_each_container(struct sway_workspace *ws,