diff options
| -rw-r--r-- | include/sway/config.h | 4 | ||||
| -rw-r--r-- | include/sway/tree/workspace.h | 2 | ||||
| -rw-r--r-- | sway/config.c | 8 | ||||
| -rw-r--r-- | sway/desktop/output.c | 21 | ||||
| -rw-r--r-- | sway/desktop/render.c | 200 | ||||
| -rw-r--r-- | sway/tree/workspace.c | 15 | 
6 files changed, 95 insertions, 155 deletions
diff --git a/include/sway/config.h b/include/sway/config.h index cabc9cf5..d84eef69 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -761,6 +761,10 @@ void translate_keysyms(struct input_config *input_config);  void binding_add_translated(struct sway_binding *binding, list_t *bindings); +int config_get_blur_size(); + +bool config_should_parameters_blur(); +  /* Global config singleton. */  extern struct sway_config *config; diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index b3d93a81..2ff51ea3 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -92,6 +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); +  void workspace_for_each_container(struct sway_workspace *ws,  		void (*f)(struct sway_container *con, void *data), void *data); diff --git a/sway/config.c b/sway/config.c index 85e53679..04c75171 100644 --- a/sway/config.c +++ b/sway/config.c @@ -1084,3 +1084,11 @@ void translate_keysyms(struct input_config *input_config) {  	sway_log(SWAY_DEBUG, "Translated keysyms using config for device '%s'",  			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; +} diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 45c2f1c4..45bbf0b8 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -689,6 +689,16 @@ static void damage_surface_iterator(struct sway_output *output,  			ceil(output->wlr_output->scale) - surface->current.scale);  	}  	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)) {  		wlr_output_schedule_frame(output->wlr_output);  	} @@ -745,12 +755,14 @@ static void damage_child_views_iterator(struct sway_container *con,  void output_damage_whole_container(struct sway_output *output,  		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  	struct wlr_box box = { -		.x = con->current.x - output->lx - 1, -		.y = con->current.y - output->ly - 1, -		.width = con->current.width + 2, -		.height = con->current.height + 2, +		.x = con->current.x - output->lx - 1 - shadow_sigma, +		.y = con->current.y - output->ly - 1 - shadow_sigma, +		.width = con->current.width + 2 + shadow_sigma * 2, +		.height = con->current.height + 2 + shadow_sigma * 2,  	};  	scale_box(&box, output->wlr_output->scale);  	if (wlr_damage_ring_add_box(&output->damage_ring, &box)) { @@ -973,7 +985,6 @@ void handle_new_output(struct wl_listener *listener, void *data) {  	transaction_commit_dirty(); -	// From sway upstream (fixes damage_ring bounds being INT_MAX)  	int width, height;  	wlr_output_transformed_resolution(output->wlr_output, &width, &height);  	wlr_damage_ring_set_bounds(&output->damage_ring, width, height); diff --git a/sway/desktop/render.c b/sway/desktop/render.c index b566489e..fb47007f 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -38,13 +38,6 @@ struct render_data {  	struct decoration_data deco_data;  }; -struct workspace_effect_info { -	bool container_wants_blur; -	bool container_wants_shadow; -	bool should_render_optimized_blur; -	int expanded_size; -}; -  struct decoration_data get_undecorated_decoration_data() {  	return (struct decoration_data) {  		.alpha = 1.0f, @@ -57,13 +50,6 @@ struct decoration_data get_undecorated_decoration_data() {  	};  } -int get_blur_size() { -	return pow(2, config->blur_params.num_passes) * config->blur_params.radius; -} - -bool should_parameters_blur() { -	return config->blur_params.radius > 0 && config->blur_params.num_passes > 0; -}  // TODO: contribute wlroots function to allow creating an fbox from a box?  struct wlr_fbox wlr_fbox_from_wlr_box(struct wlr_box *box) { @@ -241,7 +227,7 @@ void render_blur_segments(struct fx_renderer *renderer,  // 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 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_box monitor_box = get_monitor_box(wlr_output); @@ -255,9 +241,9 @@ struct fx_framebuffer *get_main_buffer_blur(struct fx_renderer *renderer, struct  	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, get_blur_size()); +	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; @@ -352,8 +338,7 @@ void render_blur(bool optimized, struct sway_output *output,  		pixman_region32_intersect(&inverse_opaque, &inverse_opaque, &damage);  		// Render the blur into its own buffer -		buffer = get_main_buffer_blur(renderer, output, &inverse_opaque, -				wlr_output->transform_matrix, dst_box); +		buffer = get_main_buffer_blur(renderer, output, &inverse_opaque, dst_box);  	}  	// Draw the blurred texture @@ -408,7 +393,7 @@ static void render_surface_iterator(struct sway_output *output,  	deco_data.corner_radius *= wlr_output->scale;  	// render blur (view->surface == surface excludes blurring subsurfaces) -	if (deco_data.blur && should_parameters_blur() && view->surface == surface) { +	if (deco_data.blur && config_should_parameters_blur() && view->surface == surface) {  		pixman_region32_t opaque_region;  		pixman_region32_init(&opaque_region); @@ -497,7 +482,7 @@ void render_whole_output(struct fx_renderer *renderer, struct wlr_output *wlr_ou  	render_texture(wlr_output, output_damage, texture, NULL, &monitor_box, matrix, get_undecorated_decoration_data());  } -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 fx_renderer *renderer = output->renderer; @@ -506,8 +491,7 @@ 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);  	// Render the blur -	struct fx_framebuffer *buffer = get_main_buffer_blur(renderer, output, &fake_damage, -			wlr_output->transform_matrix, &monitor_box); +	struct fx_framebuffer *buffer = get_main_buffer_blur(renderer, output, &fake_damage, &monitor_box);  	// Render the newly blurred content into the blur_buffer  	fx_framebuffer_create(&renderer->blur_buffer, @@ -799,7 +783,7 @@ static void render_saved_view(struct sway_view *view, struct sway_output *output  		deco_data.corner_radius *= wlr_output->scale;  		// render blur -		if (deco_data.blur && should_parameters_blur()) { +		if (deco_data.blur && config_should_parameters_blur()) {  			struct wlr_gles2_texture_attribs attribs;  			wlr_gles2_texture_get_attribs(saved_buf->buffer->texture, &attribs); @@ -1750,75 +1734,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); - -	// 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,  		pixman_region32_t *damage) {  	struct wlr_output *wlr_output = output->wlr_output; @@ -1829,12 +1744,18 @@ 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;  	} -  	struct wlr_box monitor_box = get_monitor_box(wlr_output);  	wlr_box_transform(&monitor_box, &monitor_box,  			wlr_output_transform_invert(wlr_output->transform), @@ -1842,54 +1763,22 @@ void output_render(struct sway_output *output, struct timespec *when,  	fx_renderer_begin(renderer, monitor_box.width, monitor_box.height); -	int width, height; -	wlr_output_transformed_resolution(wlr_output, &width, &height); +	int output_width, output_height; +	wlr_output_transformed_resolution(wlr_output, &output_width, &output_height); +  	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; -	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 (!pixman_region32_not_empty(damage)) { +		// Output isn't damaged but needs buffer swap +		goto renderer_end;  	} -	if (debug.damage == DAMAGE_HIGHLIGHT && damage_not_empty) { +	if (debug.damage == DAMAGE_HIGHLIGHT) { +		fx_framebuffer_bind(&renderer->wlr_buffer);  		fx_renderer_clear((float[]){1, 1, 0, 1}); -	} - -	if (!damage_not_empty) { -		// Output isn't damaged but needs buffer swap -		goto renderer_end; +		fx_framebuffer_bind(&renderer->main_buffer);  	}  	if (server.session_lock.locked) { @@ -1965,6 +1854,19 @@ void output_render(struct sway_output *output, struct timespec *when,  		render_unmanaged(output, damage, &root->xwayland_unmanaged);  #endif  	} 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};  		int nrects; @@ -1979,9 +1881,10 @@ void output_render(struct sway_output *output, struct timespec *when,  		render_layer_toplevel(output, damage,  			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); -		bool blur_enabled = has_blur && should_parameters_blur(); -		if (blur_enabled && blur_optimize_should_render && renderer->blur_buffer_dirty) { -			render_monitor_blur(output, damage); +		// check if the background needs to be blurred +		if (config_should_parameters_blur() && renderer->blur_buffer_dirty && should_render_blur) { +			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); @@ -2029,6 +1932,7 @@ render_overlay:  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; @@ -2038,34 +1942,30 @@ renderer_end:  			fx_renderer_clear(clear_color);  		}  	} +  	render_whole_output(renderer, wlr_output, &extended_damage, &renderer->main_buffer.texture); -	fx_renderer_scissor(NULL);  	fx_renderer_end(renderer); +	fx_renderer_scissor(NULL); +  	// Draw the software cursors  	wlr_renderer_begin(output->server->wlr_renderer, wlr_output->width, wlr_output->height);  	wlr_output_render_software_cursors(wlr_output, damage);  	wlr_renderer_end(output->server->wlr_renderer); -	fx_renderer_scissor(NULL);  	pixman_region32_t frame_damage;  	pixman_region32_init(&frame_damage);  	enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform); -	/* -	 * Extend the frame damage by the blur size to properly calc damage for the -	 * next buffer swap. Thanks Emersion for your excellent damage tracking blog-post! -	 */ -	wlr_region_transform(&frame_damage, &extended_damage, transform, width, height); +	wlr_region_transform(&frame_damage, &extended_damage, transform, output_width, output_height); +	pixman_region32_fini(&extended_damage); -	if (debug.damage != DAMAGE_DEFAULT || blur_optimize_should_render) { +	if (debug.damage != DAMAGE_DEFAULT) {  		pixman_region32_union_rect(&frame_damage, &frame_damage,  			0, 0, wlr_output->width, wlr_output->height);  	}  	wlr_output_set_damage(wlr_output, &frame_damage); - -	pixman_region32_fini(&extended_damage);  	pixman_region32_fini(&frame_damage);  	if (!wlr_output_commit(wlr_output)) { diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index ee940466..161b1e9c 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -690,6 +690,21 @@ 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; +	} +	return (bool)workspace_find_container(ws, find_blurred_con_iterator, NULL); +} +  void workspace_for_each_container(struct sway_workspace *ws,  		void (*f)(struct sway_container *con, void *data), void *data) {  	// Tiling  | 
