Merge branch 'master' into toplevel-effects
This commit is contained in:
commit
c7d4943a62
10 changed files with 174 additions and 246 deletions
|
@ -764,6 +764,10 @@ void translate_keysyms(struct input_config *input_config);
|
||||||
|
|
||||||
void binding_add_translated(struct sway_binding *binding, list_t *bindings);
|
void binding_add_translated(struct sway_binding *binding, list_t *bindings);
|
||||||
|
|
||||||
|
int config_get_blur_size();
|
||||||
|
|
||||||
|
bool config_should_parameters_blur();
|
||||||
|
|
||||||
/* Global config singleton. */
|
/* Global config singleton. */
|
||||||
extern struct sway_config *config;
|
extern struct sway_config *config;
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,13 @@ struct fx_framebuffer {
|
||||||
GLuint stencil_buffer;
|
GLuint stencil_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct fx_framebuffer fx_framebuffer_create();
|
||||||
|
|
||||||
void fx_framebuffer_bind(struct fx_framebuffer *buffer);
|
void fx_framebuffer_bind(struct fx_framebuffer *buffer);
|
||||||
|
|
||||||
void fx_framebuffer_create(struct fx_framebuffer *buffer, int width, int height,
|
void fx_framebuffer_update(struct fx_framebuffer *buffer, int width, int height);
|
||||||
bool bind, bool create_stencil_buffer);
|
|
||||||
|
void fx_framebuffer_add_stencil_buffer(struct fx_framebuffer *buffer, int width, int height);
|
||||||
|
|
||||||
void fx_framebuffer_release(struct fx_framebuffer *buffer);
|
void fx_framebuffer_release(struct fx_framebuffer *buffer);
|
||||||
|
|
||||||
|
|
|
@ -9,19 +9,6 @@
|
||||||
#include "sway/desktop/fx_renderer/fx_framebuffer.h"
|
#include "sway/desktop/fx_renderer/fx_framebuffer.h"
|
||||||
#include "sway/desktop/fx_renderer/fx_texture.h"
|
#include "sway/desktop/fx_renderer/fx_texture.h"
|
||||||
|
|
||||||
#define get_undecorated_decoration_data() \
|
|
||||||
(struct decoration_data) { \
|
|
||||||
.alpha = 1.0f, \
|
|
||||||
.dim = 0.0f, \
|
|
||||||
.dim_color = config->dim_inactive_colors.unfocused, \
|
|
||||||
.corner_radius = 0, \
|
|
||||||
.saturation = 1.0f, \
|
|
||||||
.has_titlebar = false, \
|
|
||||||
.blur = false, \
|
|
||||||
.can_blur_xray = false, \
|
|
||||||
.shadow = false, \
|
|
||||||
}
|
|
||||||
|
|
||||||
enum corner_location { TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, ALL, NONE };
|
enum corner_location { TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, ALL, NONE };
|
||||||
|
|
||||||
enum fx_tex_shader_source {
|
enum fx_tex_shader_source {
|
||||||
|
@ -50,6 +37,8 @@ struct decoration_data {
|
||||||
bool shadow;
|
bool shadow;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct decoration_data get_undecorated_decoration_data();
|
||||||
|
|
||||||
struct blur_shader {
|
struct blur_shader {
|
||||||
GLuint program;
|
GLuint program;
|
||||||
GLint proj;
|
GLint proj;
|
||||||
|
|
|
@ -92,6 +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);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -1093,3 +1093,11 @@ void translate_keysyms(struct input_config *input_config) {
|
||||||
sway_log(SWAY_DEBUG, "Translated keysyms using config for device '%s'",
|
sway_log(SWAY_DEBUG, "Translated keysyms using config for device '%s'",
|
||||||
input_config->identifier);
|
input_config->identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int config_get_blur_size() {
|
||||||
|
return pow(2, config->blur_params.num_passes) * config->blur_params.radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool config_should_parameters_blur() {
|
||||||
|
return config->blur_params.radius > 0 && config->blur_params.num_passes > 0;
|
||||||
|
}
|
||||||
|
|
|
@ -1,15 +1,24 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "sway/desktop/fx_renderer/fx_framebuffer.h"
|
#include "sway/desktop/fx_renderer/fx_framebuffer.h"
|
||||||
|
|
||||||
|
struct fx_framebuffer fx_framebuffer_create() {
|
||||||
|
return (struct fx_framebuffer) {
|
||||||
|
.fb = -1,
|
||||||
|
.stencil_buffer = -1,
|
||||||
|
.texture.id = 0,
|
||||||
|
.texture.target = 0,
|
||||||
|
.texture.width = -1,
|
||||||
|
.texture.height = -1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void fx_framebuffer_bind(struct fx_framebuffer *buffer) {
|
void fx_framebuffer_bind(struct fx_framebuffer *buffer) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, buffer->fb);
|
glBindFramebuffer(GL_FRAMEBUFFER, buffer->fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fx_framebuffer_create(struct fx_framebuffer *buffer, int width, int height,
|
void fx_framebuffer_update(struct fx_framebuffer *buffer, int width, int height) {
|
||||||
bool bind, bool create_stencil_buffer) {
|
|
||||||
bool firstAlloc = false;
|
bool firstAlloc = false;
|
||||||
|
|
||||||
// Create a new framebuffer
|
|
||||||
if (buffer->fb == (uint32_t) -1) {
|
if (buffer->fb == (uint32_t) -1) {
|
||||||
glGenFramebuffers(1, &buffer->fb);
|
glGenFramebuffers(1, &buffer->fb);
|
||||||
firstAlloc = true;
|
firstAlloc = true;
|
||||||
|
@ -45,23 +54,21 @@ void fx_framebuffer_create(struct fx_framebuffer *buffer, int width, int height,
|
||||||
sway_log(SWAY_DEBUG, "Framebuffer created, status %i", status);
|
sway_log(SWAY_DEBUG, "Framebuffer created, status %i", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create_stencil_buffer && buffer->stencil_buffer == (uint32_t) -1) {
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fx_framebuffer_add_stencil_buffer(struct fx_framebuffer *buffer, int width, int height) {
|
||||||
|
if (buffer->stencil_buffer == (uint32_t) -1) {
|
||||||
glGenRenderbuffers(1, &buffer->stencil_buffer);
|
glGenRenderbuffers(1, &buffer->stencil_buffer);
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, buffer->stencil_buffer);
|
glBindRenderbuffer(GL_RENDERBUFFER, buffer->stencil_buffer);
|
||||||
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);
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, buffer->stencil_buffer);
|
||||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
sway_log(SWAY_ERROR, "Stencilbuffer incomplete, couldn't create! (FB status: %i)", status);
|
sway_log(SWAY_ERROR, "Stencil buffer incomplete, couldn't create! (FB status: %i)", status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sway_log(SWAY_DEBUG, "Stencilbuffer created, status %i", status);
|
sway_log(SWAY_DEBUG, "Stencil buffer created, status %i", status);
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the default framebuffer
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
if (bind) {
|
|
||||||
fx_framebuffer_bind(buffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +85,6 @@ void fx_framebuffer_release(struct fx_framebuffer *buffer) {
|
||||||
}
|
}
|
||||||
buffer->stencil_buffer = -1;
|
buffer->stencil_buffer = -1;
|
||||||
|
|
||||||
|
|
||||||
// Release the texture
|
// Release the texture
|
||||||
if (buffer->texture.id) {
|
if (buffer->texture.id) {
|
||||||
glDeleteTextures(1, &buffer->texture.id);
|
glDeleteTextures(1, &buffer->texture.id);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <wlr/util/box.h>
|
#include <wlr/util/box.h>
|
||||||
|
|
||||||
#include "log.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_renderer.h"
|
||||||
#include "sway/desktop/fx_renderer/matrix.h"
|
#include "sway/desktop/fx_renderer/matrix.h"
|
||||||
#include "sway/server.h"
|
#include "sway/server.h"
|
||||||
|
@ -35,6 +36,20 @@ static const GLfloat verts[] = {
|
||||||
0, 1, // bottom left
|
0, 1, // bottom left
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct decoration_data get_undecorated_decoration_data() {
|
||||||
|
return (struct decoration_data) {
|
||||||
|
.alpha = 1.0f,
|
||||||
|
.dim = 0.0f,
|
||||||
|
.dim_color = config->dim_inactive_colors.unfocused,
|
||||||
|
.corner_radius = 0,
|
||||||
|
.saturation = 1.0f,
|
||||||
|
.has_titlebar = false,
|
||||||
|
.blur = false,
|
||||||
|
.can_blur_xray = false, \
|
||||||
|
.shadow = false, \
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static GLuint compile_shader(GLuint type, const GLchar *src) {
|
static GLuint compile_shader(GLuint type, const GLchar *src) {
|
||||||
GLuint shader = glCreateShader(type);
|
GLuint shader = glCreateShader(type);
|
||||||
glShaderSource(shader, 1, &src, NULL);
|
glShaderSource(shader, 1, &src, NULL);
|
||||||
|
@ -264,15 +279,10 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer->main_buffer.fb = -1;
|
renderer->main_buffer = fx_framebuffer_create();
|
||||||
renderer->main_buffer.stencil_buffer = -1;
|
renderer->blur_buffer = fx_framebuffer_create();
|
||||||
|
renderer->effects_buffer = fx_framebuffer_create();
|
||||||
renderer->blur_buffer.fb = -1;
|
renderer->effects_buffer_swapped = fx_framebuffer_create();
|
||||||
renderer->blur_buffer.stencil_buffer = -1;
|
|
||||||
renderer->effects_buffer.fb = -1;
|
|
||||||
renderer->effects_buffer.stencil_buffer = -1;
|
|
||||||
renderer->effects_buffer_swapped.fb = -1;
|
|
||||||
renderer->effects_buffer_swapped.stencil_buffer = -1;
|
|
||||||
|
|
||||||
renderer->blur_buffer_dirty = true;
|
renderer->blur_buffer_dirty = true;
|
||||||
|
|
||||||
|
@ -410,9 +420,13 @@ void fx_renderer_begin(struct fx_renderer *renderer, int width, int height) {
|
||||||
renderer->wlr_buffer.fb = wlr_fb;
|
renderer->wlr_buffer.fb = wlr_fb;
|
||||||
|
|
||||||
// Create the framebuffers
|
// Create the framebuffers
|
||||||
fx_framebuffer_create(&renderer->main_buffer, width, height, true, true);
|
fx_framebuffer_update(&renderer->main_buffer, width, height);
|
||||||
fx_framebuffer_create(&renderer->effects_buffer, width, height, false, false);
|
fx_framebuffer_update(&renderer->effects_buffer, width, height);
|
||||||
fx_framebuffer_create(&renderer->effects_buffer_swapped, width, height, false, false);
|
fx_framebuffer_update(&renderer->effects_buffer_swapped, width, height);
|
||||||
|
|
||||||
|
// Add a stencil buffer to the main buffer & bind the main buffer
|
||||||
|
fx_framebuffer_add_stencil_buffer(&renderer->main_buffer, width, height);
|
||||||
|
fx_framebuffer_bind(&renderer->main_buffer);
|
||||||
|
|
||||||
// refresh projection matrix
|
// refresh projection matrix
|
||||||
matrix_projection(renderer->projection, width, height,
|
matrix_projection(renderer->projection, width, height,
|
||||||
|
|
|
@ -693,6 +693,16 @@ static void damage_surface_iterator(struct sway_output *output,
|
||||||
ceil(output->wlr_output->scale) - surface->current.scale);
|
ceil(output->wlr_output->scale) - surface->current.scale);
|
||||||
}
|
}
|
||||||
pixman_region32_translate(&damage, box.x, box.y);
|
pixman_region32_translate(&damage, box.x, box.y);
|
||||||
|
|
||||||
|
if (view) {
|
||||||
|
int blur_size = view->container->blur_enabled ? config_get_blur_size() : 0;
|
||||||
|
wlr_region_expand(&damage, &damage, blur_size);
|
||||||
|
box.x -= blur_size;
|
||||||
|
box.y -= blur_size;
|
||||||
|
box.width += blur_size * 2;
|
||||||
|
box.height += blur_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);
|
||||||
}
|
}
|
||||||
|
@ -749,12 +759,14 @@ static void damage_child_views_iterator(struct sway_container *con,
|
||||||
|
|
||||||
void output_damage_whole_container(struct sway_output *output,
|
void output_damage_whole_container(struct sway_output *output,
|
||||||
struct sway_container *con) {
|
struct sway_container *con) {
|
||||||
|
int shadow_sigma = con->shadow_enabled ? config->shadow_blur_sigma : 0;
|
||||||
|
|
||||||
// Pad the box by 1px, because the width is a double and might be a fraction
|
// Pad the box by 1px, because the width is a double and might be a fraction
|
||||||
struct wlr_box box = {
|
struct wlr_box box = {
|
||||||
.x = con->current.x - output->lx - 1,
|
.x = con->current.x - output->lx - 1 - shadow_sigma,
|
||||||
.y = con->current.y - output->ly - 1,
|
.y = con->current.y - output->ly - 1 - shadow_sigma,
|
||||||
.width = con->current.width + 2,
|
.width = con->current.width + 2 + shadow_sigma * 2,
|
||||||
.height = con->current.height + 2,
|
.height = con->current.height + 2 + shadow_sigma * 2,
|
||||||
};
|
};
|
||||||
scale_box(&box, output->wlr_output->scale);
|
scale_box(&box, output->wlr_output->scale);
|
||||||
if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
|
if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
|
||||||
|
@ -977,7 +989,6 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
transaction_commit_dirty();
|
transaction_commit_dirty();
|
||||||
|
|
||||||
// From sway upstream (fixes damage_ring bounds being INT_MAX)
|
|
||||||
int width, height;
|
int width, height;
|
||||||
wlr_output_transformed_resolution(output->wlr_output, &width, &height);
|
wlr_output_transformed_resolution(output->wlr_output, &width, &height);
|
||||||
wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
|
wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
|
||||||
|
|
|
@ -32,13 +32,6 @@
|
||||||
#include "sway/tree/view.h"
|
#include "sway/tree/view.h"
|
||||||
#include "sway/tree/workspace.h"
|
#include "sway/tree/workspace.h"
|
||||||
|
|
||||||
struct workspace_effect_info {
|
|
||||||
bool container_wants_blur;
|
|
||||||
bool container_wants_shadow;
|
|
||||||
bool should_render_optimized_blur;
|
|
||||||
int expanded_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
int get_blur_size() {
|
int get_blur_size() {
|
||||||
return pow(2, config->blur_params.num_passes) * config->blur_params.radius;
|
return pow(2, config->blur_params.num_passes) * config->blur_params.radius;
|
||||||
}
|
}
|
||||||
|
@ -227,7 +220,7 @@ void render_blur_segments(struct fx_renderer *renderer,
|
||||||
|
|
||||||
// Blurs the main_buffer content and returns the blurred framebuffer
|
// 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,
|
struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct sway_output *output,
|
||||||
pixman_region32_t *original_damage, const float box_matrix[static 9], const struct wlr_box *box) {
|
pixman_region32_t *original_damage, const struct wlr_box *box) {
|
||||||
struct wlr_output *wlr_output = output->wlr_output;
|
struct wlr_output *wlr_output = output->wlr_output;
|
||||||
struct wlr_box monitor_box = get_monitor_box(wlr_output);
|
struct wlr_box monitor_box = get_monitor_box(wlr_output);
|
||||||
|
|
||||||
|
@ -241,9 +234,9 @@ struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct
|
||||||
pixman_region32_t damage;
|
pixman_region32_t damage;
|
||||||
pixman_region32_init(&damage);
|
pixman_region32_init(&damage);
|
||||||
pixman_region32_copy(&damage, original_damage);
|
pixman_region32_copy(&damage, original_damage);
|
||||||
wlr_region_transform(&damage, &damage, transform,
|
wlr_region_transform(&damage, &damage, transform, monitor_box.width, monitor_box.height);
|
||||||
monitor_box.width, monitor_box.height);
|
|
||||||
wlr_region_expand(&damage, &damage, 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->main_buffer;
|
||||||
|
@ -338,8 +331,7 @@ void render_blur(bool optimized, struct sway_output *output,
|
||||||
pixman_region32_intersect(&inverse_opaque, &inverse_opaque, &damage);
|
pixman_region32_intersect(&inverse_opaque, &inverse_opaque, &damage);
|
||||||
|
|
||||||
// Render the blur into its own buffer
|
// Render the blur into its own buffer
|
||||||
buffer = get_main_buffer_blur(renderer, output, &inverse_opaque,
|
buffer = get_main_buffer_blur(renderer, output, &inverse_opaque, dst_box);
|
||||||
wlr_output->transform_matrix, dst_box);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the blurred texture
|
// Draw the blurred texture
|
||||||
|
@ -546,35 +538,16 @@ static void render_drag_icons(struct sway_output *output,
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_whole_output(struct fx_renderer *renderer, struct wlr_output *wlr_output,
|
void render_whole_output(struct fx_renderer *renderer, struct wlr_output *wlr_output,
|
||||||
pixman_region32_t *original_damage, struct fx_texture *texture) {
|
pixman_region32_t *output_damage, struct fx_texture *texture) {
|
||||||
struct wlr_box monitor_box = get_monitor_box(wlr_output);
|
struct wlr_box monitor_box = get_monitor_box(wlr_output);
|
||||||
|
|
||||||
enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform);
|
enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform);
|
||||||
float matrix[9];
|
float matrix[9];
|
||||||
wlr_matrix_project_box(matrix, &monitor_box, transform, 0.0, wlr_output->transform_matrix);
|
wlr_matrix_project_box(matrix, &monitor_box, transform, 0.0, wlr_output->transform_matrix);
|
||||||
|
|
||||||
pixman_region32_t damage;
|
render_texture(wlr_output, output_damage, texture, NULL, &monitor_box, matrix, get_undecorated_decoration_data());
|
||||||
pixman_region32_init(&damage);
|
|
||||||
pixman_region32_union_rect(&damage, &damage, monitor_box.x, monitor_box.y,
|
|
||||||
monitor_box.width, monitor_box.height);
|
|
||||||
pixman_region32_intersect(&damage, &damage, original_damage);
|
|
||||||
bool damaged = pixman_region32_not_empty(&damage);
|
|
||||||
if (!damaged) {
|
|
||||||
goto damage_finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nrects;
|
|
||||||
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
|
|
||||||
for (int i = 0; i < nrects; ++i) {
|
|
||||||
scissor_output(wlr_output, &rects[i]);
|
|
||||||
fx_render_texture_with_matrix(renderer, texture, &monitor_box, matrix, get_undecorated_decoration_data());
|
|
||||||
}
|
|
||||||
|
|
||||||
damage_finish:
|
|
||||||
pixman_region32_fini(&damage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_monitor_blur(struct sway_output *output, pixman_region32_t *damage) {
|
void render_output_blur(struct sway_output *output, pixman_region32_t *damage) {
|
||||||
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;
|
||||||
|
|
||||||
|
@ -583,13 +556,13 @@ void render_monitor_blur(struct sway_output *output, pixman_region32_t *damage)
|
||||||
pixman_region32_init_rect(&fake_damage, 0, 0, monitor_box.width, monitor_box.height);
|
pixman_region32_init_rect(&fake_damage, 0, 0, monitor_box.width, monitor_box.height);
|
||||||
|
|
||||||
// Render the blur
|
// Render the blur
|
||||||
struct fx_framebuffer *buffer = get_main_buffer_blur(renderer, output, &fake_damage,
|
struct fx_framebuffer *buffer = get_main_buffer_blur(renderer, output, &fake_damage, &monitor_box);
|
||||||
wlr_output->transform_matrix, &monitor_box);
|
|
||||||
|
|
||||||
// Render the newly blurred content into the blur_buffer
|
// Render the newly blurred content into the blur_buffer
|
||||||
fx_framebuffer_create(&renderer->blur_buffer,
|
fx_framebuffer_update(&renderer->blur_buffer,
|
||||||
output->renderer->viewport_width, output->renderer->viewport_height,
|
output->renderer->viewport_width, output->renderer->viewport_height);
|
||||||
true, false);
|
fx_framebuffer_bind(&renderer->blur_buffer);
|
||||||
|
|
||||||
// Clear the damaged region of the blur_buffer
|
// Clear the damaged region of the blur_buffer
|
||||||
float clear_color[] = { 0, 0, 0, 0 };
|
float clear_color[] = { 0, 0, 0, 0 };
|
||||||
int nrects;
|
int nrects;
|
||||||
|
@ -822,7 +795,7 @@ static void render_saved_view(struct sway_view *view, struct sway_output *output
|
||||||
deco_data.corner_radius *= wlr_output->scale;
|
deco_data.corner_radius *= wlr_output->scale;
|
||||||
|
|
||||||
// render blur
|
// render blur
|
||||||
if (deco_data.blur && should_parameters_blur()) {
|
if (deco_data.blur && config_should_parameters_blur()) {
|
||||||
struct wlr_gles2_texture_attribs attribs;
|
struct wlr_gles2_texture_attribs attribs;
|
||||||
wlr_gles2_texture_get_attribs(saved_buf->buffer->texture, &attribs);
|
wlr_gles2_texture_get_attribs(saved_buf->buffer->texture, &attribs);
|
||||||
|
|
||||||
|
@ -1779,109 +1752,6 @@ static void render_seatops(struct sway_output *output,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct find_effect_iter_data {
|
|
||||||
struct workspace_effect_info *effect_info;
|
|
||||||
bool blur_buffer_dirty;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool find_con_effect_iterator(struct sway_container *con, void* _data) {
|
|
||||||
struct sway_view *view = con->view;
|
|
||||||
struct find_effect_iter_data *data = _data;
|
|
||||||
struct workspace_effect_info *effect_info = data->effect_info;
|
|
||||||
|
|
||||||
if (!view) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (con->blur_enabled && !view->surface->opaque) {
|
|
||||||
effect_info->container_wants_blur = true;
|
|
||||||
|
|
||||||
bool is_floating = container_is_floating(con);
|
|
||||||
// Check if we should render optimized blur
|
|
||||||
if (data->blur_buffer_dirty
|
|
||||||
// Only test floating windows when xray is enabled
|
|
||||||
&& (!is_floating || (is_floating && config->blur_xray))) {
|
|
||||||
effect_info->should_render_optimized_blur = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (con->shadow_enabled) {
|
|
||||||
effect_info->container_wants_shadow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop the iteration if all of the effects have been found.
|
|
||||||
// Ensures that no effect is skipped if returning early
|
|
||||||
return effect_info->container_wants_blur
|
|
||||||
&& effect_info->container_wants_shadow
|
|
||||||
&& effect_info->should_render_optimized_blur;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct workspace_effect_info get_workspace_effect_info(struct sway_output *sway_output) {
|
|
||||||
struct fx_renderer *renderer = sway_output->renderer;
|
|
||||||
struct sway_workspace *workspace = sway_output->current.active_workspace;
|
|
||||||
|
|
||||||
struct workspace_effect_info effect_info = {
|
|
||||||
.container_wants_blur = false,
|
|
||||||
.container_wants_shadow = false,
|
|
||||||
.should_render_optimized_blur = false,
|
|
||||||
.expanded_size = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!workspace_is_visible(workspace)) {
|
|
||||||
return effect_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate through the workspace containers and check if any effects are requested
|
|
||||||
struct find_effect_iter_data iter_data = {
|
|
||||||
.effect_info = &effect_info,
|
|
||||||
.blur_buffer_dirty = renderer->blur_buffer_dirty
|
|
||||||
};
|
|
||||||
workspace_find_container(workspace, find_con_effect_iterator, &iter_data);
|
|
||||||
|
|
||||||
if (effect_info.container_wants_blur
|
|
||||||
&& effect_info.container_wants_shadow
|
|
||||||
&& effect_info.should_render_optimized_blur) {
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if any layer-shell surfaces will render effects
|
|
||||||
size_t len = sizeof(sway_output->layers) / sizeof(sway_output->layers[0]);
|
|
||||||
for (size_t i = 0; i < len; ++i) {
|
|
||||||
struct sway_layer_surface *lsurface;
|
|
||||||
wl_list_for_each(lsurface, &sway_output->layers[i], link) {
|
|
||||||
struct decoration_data deco_data = lsurface->deco_data;
|
|
||||||
if (deco_data.blur && !lsurface->layer_surface->surface->opaque) {
|
|
||||||
effect_info.container_wants_blur = true;
|
|
||||||
// Check if we should render optimized blur
|
|
||||||
if (renderer->blur_buffer_dirty && config->blur_xray
|
|
||||||
&& lsurface->layer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND
|
|
||||||
&& lsurface->layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) {
|
|
||||||
effect_info.should_render_optimized_blur = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (deco_data.shadow) {
|
|
||||||
effect_info.container_wants_shadow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effect_info.container_wants_blur
|
|
||||||
&& effect_info.container_wants_shadow
|
|
||||||
&& effect_info.should_render_optimized_blur) {
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
end:;
|
|
||||||
// Set the expanded damage region
|
|
||||||
bool shadow_enabled = effect_info.container_wants_shadow || config->shadow_enabled;
|
|
||||||
int shadow_sigma = shadow_enabled ? config->shadow_blur_sigma : 0;
|
|
||||||
bool blur_enabled = effect_info.container_wants_blur || config->blur_enabled;
|
|
||||||
int blur_size = blur_enabled ? get_blur_size() : 0;
|
|
||||||
// +1 as a margin of error
|
|
||||||
effect_info.expanded_size = MAX(shadow_sigma, blur_size) + 1;
|
|
||||||
|
|
||||||
return effect_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
void output_render(struct sway_output *output, struct timespec *when,
|
void output_render(struct sway_output *output, struct timespec *when,
|
||||||
pixman_region32_t *damage) {
|
pixman_region32_t *damage) {
|
||||||
struct wlr_output *wlr_output = output->wlr_output;
|
struct wlr_output *wlr_output = output->wlr_output;
|
||||||
|
@ -1892,12 +1762,18 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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),
|
||||||
|
@ -1905,56 +1781,24 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
|
|
||||||
fx_renderer_begin(renderer, monitor_box.width, monitor_box.height);
|
fx_renderer_begin(renderer, monitor_box.width, monitor_box.height);
|
||||||
|
|
||||||
int width, height;
|
int output_width, output_height;
|
||||||
wlr_output_transformed_resolution(wlr_output, &width, &height);
|
wlr_output_transformed_resolution(wlr_output, &output_width, &output_height);
|
||||||
|
|
||||||
if (debug.damage == DAMAGE_RERENDER) {
|
if (debug.damage == DAMAGE_RERENDER) {
|
||||||
pixman_region32_union_rect(damage, damage, 0, 0, width, height);
|
pixman_region32_union_rect(damage, damage, 0, 0, output_width, output_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_blur = false;
|
if (!pixman_region32_not_empty(damage)) {
|
||||||
bool blur_optimize_should_render = false;
|
|
||||||
bool damage_not_empty = pixman_region32_not_empty(damage);
|
|
||||||
pixman_region32_t extended_damage;
|
|
||||||
pixman_region32_init(&extended_damage);
|
|
||||||
if (!fullscreen_con && !server.session_lock.locked && damage_not_empty) {
|
|
||||||
// Check if there are any windows to blur
|
|
||||||
struct workspace_effect_info effect_info = get_workspace_effect_info(output);
|
|
||||||
has_blur = effect_info.container_wants_blur || config->blur_enabled;
|
|
||||||
if (effect_info.should_render_optimized_blur) {
|
|
||||||
blur_optimize_should_render = true;
|
|
||||||
// Damage the whole output
|
|
||||||
pixman_region32_union_rect(damage, damage, 0, 0, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extend the damaged region
|
|
||||||
int expanded_size = effect_info.expanded_size;
|
|
||||||
if (expanded_size > 0) {
|
|
||||||
int32_t damage_width = damage->extents.x2 - damage->extents.x1;
|
|
||||||
int32_t damage_height = damage->extents.y2 - damage->extents.y1;
|
|
||||||
// Limit the damage extent to the size of the monitor to prevent overflow
|
|
||||||
if (damage_width > width || damage_height > height) {
|
|
||||||
pixman_region32_intersect_rect(damage, damage, 0, 0, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_region_expand(damage, damage, expanded_size);
|
|
||||||
pixman_region32_copy(&extended_damage, damage);
|
|
||||||
wlr_region_expand(damage, damage, expanded_size);
|
|
||||||
} else {
|
|
||||||
pixman_region32_copy(&extended_damage, damage);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pixman_region32_copy(&extended_damage, damage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug.damage == DAMAGE_HIGHLIGHT && damage_not_empty) {
|
|
||||||
fx_renderer_clear((float[]){1, 1, 0, 1});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!damage_not_empty) {
|
|
||||||
// Output isn't damaged but needs buffer swap
|
// Output isn't damaged but needs buffer swap
|
||||||
goto renderer_end;
|
goto renderer_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
if (server.session_lock.locked) {
|
||||||
float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
if (server.session_lock.lock == NULL) {
|
if (server.session_lock.lock == NULL) {
|
||||||
|
@ -2028,6 +1872,19 @@ 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 should_render_blur = should_workspace_have_blur(workspace);
|
||||||
|
if (should_render_blur) {
|
||||||
|
// 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 {
|
||||||
|
wlr_region_expand(damage, damage, config_get_blur_size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
|
float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
|
||||||
|
|
||||||
int nrects;
|
int nrects;
|
||||||
|
@ -2042,9 +1899,10 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
render_layer_toplevel(output, damage,
|
render_layer_toplevel(output, damage,
|
||||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
|
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
|
||||||
|
|
||||||
bool blur_enabled = has_blur && should_parameters_blur();
|
// check if the background needs to be blurred
|
||||||
if (blur_enabled && blur_optimize_should_render && renderer->blur_buffer_dirty) {
|
if (config_should_parameters_blur() && renderer->blur_buffer_dirty && should_render_blur) {
|
||||||
render_monitor_blur(output, damage);
|
pixman_region32_union_rect(damage, damage, 0, 0, output_width, output_height);
|
||||||
|
render_output_blur(output, damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
render_workspace(output, damage, workspace, workspace->current.focused);
|
render_workspace(output, damage, workspace, workspace->current.focused);
|
||||||
|
@ -2094,6 +1952,7 @@ render_overlay:
|
||||||
renderer_end:
|
renderer_end:
|
||||||
// Draw the contents of our buffer into the wlr buffer
|
// Draw the contents of our buffer into the wlr buffer
|
||||||
fx_framebuffer_bind(&renderer->wlr_buffer);
|
fx_framebuffer_bind(&renderer->wlr_buffer);
|
||||||
|
|
||||||
float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
if (pixman_region32_not_empty(&extended_damage)) {
|
if (pixman_region32_not_empty(&extended_damage)) {
|
||||||
int nrects;
|
int nrects;
|
||||||
|
@ -2103,34 +1962,30 @@ renderer_end:
|
||||||
fx_renderer_clear(clear_color);
|
fx_renderer_clear(clear_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_whole_output(renderer, wlr_output, &extended_damage, &renderer->main_buffer.texture);
|
render_whole_output(renderer, wlr_output, &extended_damage, &renderer->main_buffer.texture);
|
||||||
fx_renderer_scissor(NULL);
|
|
||||||
fx_renderer_end(renderer);
|
fx_renderer_end(renderer);
|
||||||
|
|
||||||
|
fx_renderer_scissor(NULL);
|
||||||
|
|
||||||
// Draw the software cursors
|
// Draw the software cursors
|
||||||
wlr_renderer_begin(output->server->wlr_renderer, wlr_output->width, wlr_output->height);
|
wlr_renderer_begin(output->server->wlr_renderer, wlr_output->width, wlr_output->height);
|
||||||
wlr_output_render_software_cursors(wlr_output, damage);
|
wlr_output_render_software_cursors(wlr_output, damage);
|
||||||
wlr_renderer_end(output->server->wlr_renderer);
|
wlr_renderer_end(output->server->wlr_renderer);
|
||||||
fx_renderer_scissor(NULL);
|
|
||||||
|
|
||||||
pixman_region32_t frame_damage;
|
pixman_region32_t frame_damage;
|
||||||
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);
|
||||||
* Extend the frame damage by the blur size to properly calc damage for the
|
pixman_region32_fini(&extended_damage);
|
||||||
* next buffer swap. Thanks Emersion for your excellent damage tracking blog-post!
|
|
||||||
*/
|
|
||||||
wlr_region_transform(&frame_damage, &extended_damage, transform, width, height);
|
|
||||||
|
|
||||||
if (debug.damage != DAMAGE_DEFAULT || blur_optimize_should_render) {
|
if (debug.damage != DAMAGE_DEFAULT) {
|
||||||
pixman_region32_union_rect(&frame_damage, &frame_damage,
|
pixman_region32_union_rect(&frame_damage, &frame_damage,
|
||||||
0, 0, wlr_output->width, wlr_output->height);
|
0, 0, wlr_output->width, wlr_output->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_output_set_damage(wlr_output, &frame_damage);
|
wlr_output_set_damage(wlr_output, &frame_damage);
|
||||||
|
|
||||||
pixman_region32_fini(&extended_damage);
|
|
||||||
pixman_region32_fini(&frame_damage);
|
pixman_region32_fini(&frame_damage);
|
||||||
|
|
||||||
if (!wlr_output_commit(wlr_output)) {
|
if (!wlr_output_commit(wlr_output)) {
|
||||||
|
|
|
@ -5,11 +5,13 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
#include <wayland-util.h>
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
#include "sway/input/input-manager.h"
|
#include "sway/input/input-manager.h"
|
||||||
#include "sway/input/cursor.h"
|
#include "sway/input/cursor.h"
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
#include "sway/ipc-server.h"
|
#include "sway/ipc-server.h"
|
||||||
|
#include "sway/layers.h"
|
||||||
#include "sway/output.h"
|
#include "sway/output.h"
|
||||||
#include "sway/tree/arrange.h"
|
#include "sway/tree/arrange.h"
|
||||||
#include "sway/tree/container.h"
|
#include "sway/tree/container.h"
|
||||||
|
@ -690,6 +692,40 @@ void workspace_detect_urgent(struct sway_workspace *workspace) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool find_blurred_con_iterator(struct sway_container *con, void *data) {
|
||||||
|
struct sway_view *view = con->view;
|
||||||
|
if (!view) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return con->blur_enabled && !view->surface->opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool should_workspace_have_blur(struct sway_workspace *ws) {
|
||||||
|
if (!workspace_is_visible(ws)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((bool)workspace_find_container(ws, find_blurred_con_iterator, NULL)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any layer-shell surfaces will render effects
|
||||||
|
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) {
|
||||||
|
struct sway_layer_surface *lsurface;
|
||||||
|
wl_list_for_each(lsurface, &sway_output->layers[i], link) {
|
||||||
|
if (lsurface->deco_data.blur
|
||||||
|
&& !lsurface->layer_surface->surface->opaque
|
||||||
|
&& lsurface->layer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
// Tiling
|
// Tiling
|
||||||
|
|
Loading…
Add table
Reference in a new issue