refactor: simplify blur (#219)
* refactor: removed surface_width + surface_height from render_blur() * Fixed scaling issues * Minor refactors * removed scaled_dst box * removed uneeded fb bind * removed unneeded src_box * removed unneeded wlr_fbox_from_box function * removed src_box * Don't scale the blur translucent region twice * Renamed extended_damage to original_damage to reflect better what it actually is * Removed unneeded clearing of the wlr fbo before rendering onto it * Removed the need for our own main FBO, also fixes some damage bugs * Simplified detection of blur on workspace * cleaned up comments --------- Co-authored-by: Erik Reider <35975961+ErikReider@users.noreply.github.com>
This commit is contained in:
parent
13eeea5ed5
commit
6f6991a1b3
|
@ -120,12 +120,22 @@ struct fx_renderer {
|
||||||
|
|
||||||
int viewport_width, viewport_height;
|
int viewport_width, viewport_height;
|
||||||
|
|
||||||
struct fx_framebuffer wlr_buffer; // Just the framebuffer used by wlroots
|
struct wlr_output *wlr_output;
|
||||||
struct fx_framebuffer main_buffer; // The main FB used for rendering
|
|
||||||
struct fx_framebuffer blur_buffer; // Contains the blurred background for tiled windows
|
// 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
|
// Blur swaps between the two effects buffers everytime it scales the image
|
||||||
struct fx_framebuffer effects_buffer; // Buffer used for effects
|
// Buffer used for effects
|
||||||
struct fx_framebuffer effects_buffer_swapped; // Swap 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;
|
bool blur_buffer_dirty;
|
||||||
|
|
||||||
|
@ -155,12 +165,14 @@ struct fx_renderer {
|
||||||
} shaders;
|
} 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_fini(struct fx_renderer *renderer);
|
||||||
|
|
||||||
void fx_renderer_begin(struct fx_renderer *renderer, int width, int height);
|
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_clear(const float color[static 4]);
|
||||||
|
|
||||||
void fx_renderer_scissor(struct wlr_box *box);
|
void fx_renderer_scissor(struct wlr_box *box);
|
||||||
|
|
|
@ -92,7 +92,8 @@ struct sway_output *workspace_output_get_highest_available(
|
||||||
|
|
||||||
void workspace_detect_urgent(struct sway_workspace *workspace);
|
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 workspace_for_each_container(struct sway_workspace *ws,
|
||||||
void (*f)(struct sway_container *con, void *data), void *data);
|
void (*f)(struct sway_container *con, void *data), void *data);
|
||||||
|
|
|
@ -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) {
|
if (first_alloc || buffer->stencil_buffer.width != width || buffer->stencil_buffer.height != height) {
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, buffer->stencil_buffer.rb);
|
glBindRenderbuffer(GL_RENDERBUFFER, buffer->stencil_buffer.rb);
|
||||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
|
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.width = width;
|
||||||
buffer->stencil_buffer.height = height;
|
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) {
|
void fx_framebuffer_release(struct fx_framebuffer *buffer) {
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "sway/desktop/fx_renderer/fx_framebuffer.h"
|
#include "sway/desktop/fx_renderer/fx_framebuffer.h"
|
||||||
#include "sway/desktop/fx_renderer/fx_renderer.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/desktop/fx_renderer/matrix.h"
|
||||||
#include "sway/server.h"
|
#include "sway/server.h"
|
||||||
|
|
||||||
|
@ -251,12 +253,14 @@ static void load_gl_proc(void *proc_ptr, const char *name) {
|
||||||
*(void **)proc_ptr = proc;
|
*(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));
|
struct fx_renderer *renderer = calloc(1, sizeof(struct fx_renderer));
|
||||||
if (renderer == NULL) {
|
if (renderer == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderer->wlr_output = wlr_output;
|
||||||
|
|
||||||
// TODO: wlr_egl_make_current or eglMakeCurrent?
|
// TODO: wlr_egl_make_current or eglMakeCurrent?
|
||||||
// TODO: assert instead of conditional statement?
|
// TODO: assert instead of conditional statement?
|
||||||
if (!eglMakeCurrent(wlr_egl_get_display(egl), EGL_NO_SURFACE, EGL_NO_SURFACE,
|
if (!eglMakeCurrent(wlr_egl_get_display(egl), EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||||
|
@ -265,8 +269,9 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer->main_buffer = fx_framebuffer_create();
|
renderer->wlr_buffer = fx_framebuffer_create();
|
||||||
renderer->blur_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 = fx_framebuffer_create();
|
||||||
renderer->effects_buffer_swapped = fx_framebuffer_create();
|
renderer->effects_buffer_swapped = fx_framebuffer_create();
|
||||||
|
|
||||||
|
@ -385,8 +390,8 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
void fx_renderer_fini(struct fx_renderer *renderer) {
|
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_buffer);
|
||||||
|
fx_framebuffer_release(&renderer->blur_saved_pixels_buffer);
|
||||||
fx_framebuffer_release(&renderer->effects_buffer);
|
fx_framebuffer_release(&renderer->effects_buffer);
|
||||||
fx_framebuffer_release(&renderer->effects_buffer_swapped);
|
fx_framebuffer_release(&renderer->effects_buffer_swapped);
|
||||||
}
|
}
|
||||||
|
@ -396,32 +401,36 @@ void fx_renderer_begin(struct fx_renderer *renderer, int width, int height) {
|
||||||
renderer->viewport_width = width;
|
renderer->viewport_width = width;
|
||||||
renderer->viewport_height = height;
|
renderer->viewport_height = height;
|
||||||
|
|
||||||
// Store the wlr framebuffer
|
// Store the wlr FBO
|
||||||
GLint wlr_fb = -1;
|
renderer->wlr_buffer.fb =
|
||||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &wlr_fb);
|
wlr_gles2_renderer_get_current_fbo(renderer->wlr_output->renderer);
|
||||||
if (wlr_fb < 0) {
|
// Get the fx_texture
|
||||||
sway_log(SWAY_ERROR, "Failed to get wlr framebuffer!");
|
struct wlr_texture *wlr_texture = wlr_texture_from_buffer(
|
||||||
abort();
|
renderer->wlr_output->renderer, renderer->wlr_output->back_buffer);
|
||||||
}
|
renderer->wlr_buffer.texture = fx_texture_from_wlr_texture(wlr_texture);
|
||||||
renderer->wlr_buffer.fb = wlr_fb;
|
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
|
// 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, width, height);
|
||||||
fx_framebuffer_update(&renderer->effects_buffer_swapped, width, height);
|
fx_framebuffer_update(&renderer->effects_buffer_swapped, width, height);
|
||||||
|
|
||||||
// Add a stencil buffer to the main buffer & bind the main buffer
|
// Add a stencil buffer to the main buffer & bind the main buffer
|
||||||
fx_framebuffer_bind(&renderer->main_buffer);
|
fx_framebuffer_bind(&renderer->wlr_buffer);
|
||||||
fx_framebuffer_add_stencil_buffer(&renderer->main_buffer, width, height);
|
|
||||||
|
pixman_region32_init(&renderer->blur_padding_region);
|
||||||
|
|
||||||
// refresh projection matrix
|
// refresh projection matrix
|
||||||
matrix_projection(renderer->projection, width, height,
|
matrix_projection(renderer->projection, width, height,
|
||||||
WL_OUTPUT_TRANSFORM_FLIPPED_180);
|
WL_OUTPUT_TRANSFORM_FLIPPED_180);
|
||||||
|
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
// Bind to our main framebuffer
|
void fx_renderer_end(struct fx_renderer *renderer) {
|
||||||
fx_framebuffer_bind(&renderer->main_buffer);
|
pixman_region32_fini(&renderer->blur_padding_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fx_renderer_clear(const float color[static 4]) {
|
void fx_renderer_clear(const float color[static 4]) {
|
||||||
|
|
|
@ -697,36 +697,6 @@ static void damage_surface_iterator(struct sway_output *output,
|
||||||
}
|
}
|
||||||
pixman_region32_translate(&damage, box.x, box.y);
|
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)) {
|
if (wlr_damage_ring_add(&output->damage_ring, &damage)) {
|
||||||
wlr_output_schedule_frame(output->wlr_output);
|
wlr_output_schedule_frame(output->wlr_output);
|
||||||
}
|
}
|
||||||
|
@ -983,7 +953,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
// Init FX Renderer
|
// Init FX Renderer
|
||||||
struct wlr_egl *egl = wlr_gles2_renderer_get_egl(server->wlr_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) {
|
if (!output->renderer) {
|
||||||
sway_log(SWAY_ERROR, "Failed to create fx_renderer");
|
sway_log(SWAY_ERROR, "Failed to create fx_renderer");
|
||||||
abort();
|
abort();
|
||||||
|
|
|
@ -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...
|
// TODO: Remove this ugly abomination with a complete border rework...
|
||||||
enum corner_location get_rotated_corner(enum corner_location corner_location,
|
enum corner_location get_rotated_corner(enum corner_location corner_location,
|
||||||
enum wl_output_transform transform) {
|
enum wl_output_transform transform) {
|
||||||
|
@ -239,11 +229,11 @@ struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct
|
||||||
wlr_region_expand(&damage, &damage, config_get_blur_size());
|
wlr_region_expand(&damage, &damage, config_get_blur_size());
|
||||||
|
|
||||||
// Initially blur main_buffer content into the effects_buffers
|
// Initially blur main_buffer content into the effects_buffers
|
||||||
struct fx_framebuffer *current_buffer = &renderer->main_buffer;
|
struct fx_framebuffer *current_buffer = &renderer->wlr_buffer;
|
||||||
|
|
||||||
// Bind to blur framebuffer
|
// Bind to blur framebuffer
|
||||||
fx_framebuffer_bind(&renderer->effects_buffer);
|
fx_framebuffer_bind(&renderer->effects_buffer);
|
||||||
glBindTexture(renderer->main_buffer.texture.target, renderer->main_buffer.texture.id);
|
glBindTexture(renderer->wlr_buffer.texture.target, renderer->wlr_buffer.texture.id);
|
||||||
|
|
||||||
// damage region will be scaled, make a temp
|
// damage region will be scaled, make a temp
|
||||||
pixman_region32_t tempDamage;
|
pixman_region32_t tempDamage;
|
||||||
|
@ -271,61 +261,42 @@ struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct
|
||||||
pixman_region32_fini(&damage);
|
pixman_region32_fini(&damage);
|
||||||
|
|
||||||
// Bind back to the default buffer
|
// Bind back to the default buffer
|
||||||
fx_framebuffer_bind(&renderer->main_buffer);
|
fx_framebuffer_bind(&renderer->wlr_buffer);
|
||||||
|
|
||||||
return current_buffer;
|
return current_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_blur(bool optimized, struct sway_output *output,
|
void render_blur(bool optimized, struct sway_output *output, pixman_region32_t *output_damage,
|
||||||
pixman_region32_t *output_damage, const struct wlr_fbox *src_box,
|
const struct wlr_box *dst_box, pixman_region32_t *opaque_region, int corner_radius,
|
||||||
const struct wlr_box *dst_box, pixman_region32_t *opaque_region,
|
bool should_round_top) {
|
||||||
int surface_width, int surface_height, int32_t surface_scale,
|
|
||||||
int corner_radius, bool should_round_top) {
|
|
||||||
struct wlr_output *wlr_output = output->wlr_output;
|
struct wlr_output *wlr_output = output->wlr_output;
|
||||||
struct fx_renderer *renderer = output->renderer;
|
struct fx_renderer *renderer = output->renderer;
|
||||||
|
|
||||||
// Check if damage is inside of box rect
|
// Check if damage is inside of box rect
|
||||||
pixman_region32_t damage = create_damage(*dst_box, output_damage);
|
pixman_region32_t damage = create_damage(*dst_box, output_damage);
|
||||||
|
|
||||||
pixman_region32_t inverse_opaque;
|
pixman_region32_t translucent_region;
|
||||||
pixman_region32_init(&inverse_opaque);
|
pixman_region32_init(&translucent_region);
|
||||||
|
|
||||||
if (!pixman_region32_not_empty(&damage)) {
|
if (!pixman_region32_not_empty(&damage)) {
|
||||||
goto damage_finish;
|
goto damage_finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Gets the translucent region
|
||||||
* Capture the back_buffer and blur it
|
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);
|
||||||
pixman_box32_t surface_box = {
|
if (!pixman_region32_not_empty(&translucent_region)) {
|
||||||
.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)) {
|
|
||||||
goto damage_finish;
|
goto damage_finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_region_scale(&inverse_opaque, &inverse_opaque, wlr_output->scale);
|
|
||||||
|
|
||||||
struct fx_framebuffer *buffer = &renderer->blur_buffer;
|
struct fx_framebuffer *buffer = &renderer->blur_buffer;
|
||||||
if (!buffer->texture.id || !optimized) {
|
if (!buffer->texture.id || !optimized) {
|
||||||
pixman_region32_translate(&inverse_opaque, dst_box->x, dst_box->y);
|
pixman_region32_translate(&translucent_region, dst_box->x, dst_box->y);
|
||||||
pixman_region32_intersect(&inverse_opaque, &inverse_opaque, &damage);
|
pixman_region32_intersect(&translucent_region, &translucent_region, &damage);
|
||||||
|
|
||||||
// Render the blur into its own buffer
|
// Render the blur into its own buffer
|
||||||
buffer = get_main_buffer_blur(renderer, output, &inverse_opaque, dst_box);
|
buffer = get_main_buffer_blur(renderer, output, &translucent_region, dst_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the blurred texture
|
// Draw the blurred texture
|
||||||
|
@ -337,11 +308,11 @@ void render_blur(bool optimized, struct sway_output *output,
|
||||||
struct decoration_data deco_data = get_undecorated_decoration_data();
|
struct decoration_data deco_data = get_undecorated_decoration_data();
|
||||||
deco_data.corner_radius = corner_radius;
|
deco_data.corner_radius = corner_radius;
|
||||||
deco_data.has_titlebar = should_round_top;
|
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:
|
damage_finish:
|
||||||
pixman_region32_fini(&damage);
|
pixman_region32_fini(&damage);
|
||||||
pixman_region32_fini(&inverse_opaque);
|
pixman_region32_fini(&translucent_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
// _box.x and .y are expected to be layout-local
|
// _box.x and .y are expected to be layout-local
|
||||||
|
@ -428,7 +399,6 @@ static void render_surface_iterator(struct sway_output *output,
|
||||||
dst_box.x = fmax(dst_box.x, clip_box->x);
|
dst_box.x = fmax(dst_box.x, clip_box->x);
|
||||||
dst_box.y = fmax(dst_box.y, clip_box->y);
|
dst_box.y = fmax(dst_box.y, clip_box->y);
|
||||||
}
|
}
|
||||||
|
|
||||||
scale_box(&dst_box, wlr_output->scale);
|
scale_box(&dst_box, wlr_output->scale);
|
||||||
|
|
||||||
struct decoration_data deco_data = data->deco_data;
|
struct decoration_data deco_data = data->deco_data;
|
||||||
|
@ -450,15 +420,9 @@ static void render_surface_iterator(struct sway_output *output,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_alpha) {
|
if (has_alpha) {
|
||||||
bool should_optimize_blur = view ?
|
bool should_optimize_blur = view ? !container_is_floating_or_child(view->container) ||
|
||||||
!container_is_floating_or_child(view->container) || config->blur_xray
|
config->blur_xray : false;
|
||||||
: false;
|
render_blur(should_optimize_blur, output, output_damage, &dst_box, &opaque_region,
|
||||||
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,
|
|
||||||
deco_data.corner_radius, deco_data.has_titlebar);
|
deco_data.corner_radius, deco_data.has_titlebar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,7 +541,7 @@ void render_output_blur(struct sway_output *output, pixman_region32_t *damage) {
|
||||||
fx_renderer_clear(clear_color);
|
fx_renderer_clear(clear_color);
|
||||||
}
|
}
|
||||||
render_whole_output(renderer, wlr_output, &fake_damage, &buffer->texture);
|
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);
|
pixman_region32_fini(&fake_damage);
|
||||||
|
|
||||||
|
@ -832,13 +796,9 @@ static void render_saved_view(struct sway_view *view, struct sway_output *output
|
||||||
pixman_region32_init(&opaque_region);
|
pixman_region32_init(&opaque_region);
|
||||||
pixman_region32_union_rect(&opaque_region, &opaque_region, 0, 0, 0, 0);
|
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;
|
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,
|
render_blur(should_optimize_blur, output, damage, &dst_box, &opaque_region,
|
||||||
saved_buf->width, saved_buf->height, 1, deco_data.corner_radius, deco_data.has_titlebar);
|
deco_data.corner_radius, deco_data.has_titlebar);
|
||||||
|
|
||||||
pixman_region32_fini(&opaque_region);
|
pixman_region32_fini(&opaque_region);
|
||||||
}
|
}
|
||||||
|
@ -1792,18 +1752,12 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
return;
|
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;
|
struct sway_container *fullscreen_con = root->fullscreen_global;
|
||||||
if (!fullscreen_con) {
|
if (!fullscreen_con) {
|
||||||
fullscreen_con = workspace->current.fullscreen;
|
fullscreen_con = workspace->current.fullscreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: generate the monitor box in fx_renderer (since it already has a wlr_output)
|
||||||
struct wlr_box monitor_box = get_monitor_box(wlr_output);
|
struct wlr_box monitor_box = get_monitor_box(wlr_output);
|
||||||
wlr_box_transform(&monitor_box, &monitor_box,
|
wlr_box_transform(&monitor_box, &monitor_box,
|
||||||
wlr_output_transform_invert(wlr_output->transform),
|
wlr_output_transform_invert(wlr_output->transform),
|
||||||
|
@ -1816,7 +1770,6 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
|
|
||||||
if (debug.damage == DAMAGE_RERENDER) {
|
if (debug.damage == DAMAGE_RERENDER) {
|
||||||
pixman_region32_union_rect(damage, damage, 0, 0, output_width, output_height);
|
pixman_region32_union_rect(damage, damage, 0, 0, output_width, output_height);
|
||||||
pixman_region32_copy(&extended_damage, damage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pixman_region32_not_empty(damage)) {
|
if (!pixman_region32_not_empty(damage)) {
|
||||||
|
@ -1825,9 +1778,7 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug.damage == DAMAGE_HIGHLIGHT) {
|
if (debug.damage == DAMAGE_HIGHLIGHT) {
|
||||||
fx_framebuffer_bind(&renderer->wlr_buffer);
|
|
||||||
fx_renderer_clear((float[]){1, 1, 0, 1});
|
fx_renderer_clear((float[]){1, 1, 0, 1});
|
||||||
fx_framebuffer_bind(&renderer->main_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server.session_lock.locked) {
|
if (server.session_lock.locked) {
|
||||||
|
@ -1903,24 +1854,57 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
render_unmanaged(output, damage, &root->xwayland_unmanaged);
|
render_unmanaged(output, damage, &root->xwayland_unmanaged);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
bool workspace_has_blur = should_workspace_have_blur(workspace);
|
pixman_region32_t blur_region;
|
||||||
|
pixman_region32_init(&blur_region);
|
||||||
|
bool workspace_has_blur = workspace_get_blur_info(workspace, &blur_region);
|
||||||
|
// Expand the damage to compensate for blur
|
||||||
if (workspace_has_blur) {
|
if (workspace_has_blur) {
|
||||||
if (config_should_parameters_blur() && renderer->blur_buffer_dirty) {
|
// Skip the blur artifact prevention if damaging the whole viewport
|
||||||
|
if (renderer->blur_buffer_dirty) {
|
||||||
// Needs to be extended before clearing
|
// Needs to be extended before clearing
|
||||||
pixman_region32_union_rect(damage, damage, 0, 0, output_width, output_height);
|
pixman_region32_union_rect(damage, damage,
|
||||||
pixman_region32_union_rect(&extended_damage, &extended_damage, 0, 0, output_width, output_height);
|
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);
|
|
||||||
} else {
|
} else {
|
||||||
wlr_region_expand(damage, damage, config_get_blur_size());
|
// copy the surrounding content where the blur would display artifacts
|
||||||
|
// and draw it above the artifacts
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// capture the padding pixels around the blur where 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};
|
float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
|
||||||
|
|
||||||
|
@ -1937,7 +1921,7 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
|
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
|
||||||
|
|
||||||
// check if the background needs to be blurred
|
// 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);
|
render_output_blur(output, damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1985,21 +1969,15 @@ render_overlay:
|
||||||
render_drag_icons(output, damage, &root->drag_icons);
|
render_drag_icons(output, damage, &root->drag_icons);
|
||||||
|
|
||||||
renderer_end:
|
renderer_end:
|
||||||
// Draw the contents of our buffer into the wlr buffer
|
// Not needed if we damaged the whole viewport
|
||||||
fx_framebuffer_bind(&renderer->wlr_buffer);
|
if (!renderer->blur_buffer_dirty) {
|
||||||
|
// Render the saved pixels over the blur artifacts
|
||||||
float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
// TODO: Investigate blitting instead
|
||||||
if (pixman_region32_not_empty(&extended_damage)) {
|
render_whole_output(renderer, wlr_output, &renderer->blur_padding_region,
|
||||||
int nrects;
|
&renderer->blur_saved_pixels_buffer.texture);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render_whole_output(renderer, wlr_output, &extended_damage, &renderer->main_buffer.texture);
|
fx_renderer_end(output->renderer);
|
||||||
|
|
||||||
fx_renderer_scissor(NULL);
|
fx_renderer_scissor(NULL);
|
||||||
|
|
||||||
// Draw the software cursors
|
// Draw the software cursors
|
||||||
|
@ -2011,8 +1989,7 @@ renderer_end:
|
||||||
pixman_region32_init(&frame_damage);
|
pixman_region32_init(&frame_damage);
|
||||||
|
|
||||||
enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform);
|
enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform);
|
||||||
wlr_region_transform(&frame_damage, &extended_damage, transform, output_width, output_height);
|
wlr_region_transform(&frame_damage, damage, transform, output_width, output_height);
|
||||||
pixman_region32_fini(&extended_damage);
|
|
||||||
|
|
||||||
if (debug.damage != DAMAGE_DEFAULT) {
|
if (debug.damage != DAMAGE_DEFAULT) {
|
||||||
pixman_region32_union_rect(&frame_damage, &frame_damage,
|
pixman_region32_union_rect(&frame_damage, &frame_damage,
|
||||||
|
|
|
@ -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;
|
struct sway_view *view = con->view;
|
||||||
if (!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) {
|
bool workspace_get_blur_info(struct sway_workspace *ws, pixman_region32_t *blur_region) {
|
||||||
if (!workspace_is_visible(ws)) {
|
if (!workspace_is_visible(ws) || !config_should_parameters_blur()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((bool)workspace_find_container(ws, find_blurred_con_iterator, NULL)) {
|
// Each toplevel
|
||||||
return true;
|
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;
|
struct sway_output *sway_output = ws->output;
|
||||||
size_t len = sizeof(sway_output->layers) / sizeof(sway_output->layers[0]);
|
size_t len = sizeof(sway_output->layers) / sizeof(sway_output->layers[0]);
|
||||||
for (size_t i = 0; i < len; ++i) {
|
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) {
|
wl_list_for_each(lsurface, &sway_output->layers[i], link) {
|
||||||
if (lsurface->has_blur && !lsurface->layer_surface->surface->opaque
|
if (lsurface->has_blur && !lsurface->layer_surface->surface->opaque
|
||||||
&& lsurface->layer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) {
|
&& 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,
|
void workspace_for_each_container(struct sway_workspace *ws,
|
||||||
|
|
Loading…
Reference in a new issue