From 479cc4e7456a93aed1a89bef8d83c1f8c43bd291 Mon Sep 17 00:00:00 2001 From: William McKinnon Date: Mon, 15 May 2023 01:11:09 -0400 Subject: [PATCH 1/3] style: simplified render_whole_output --- sway/desktop/render.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 6316a839..b566489e 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -488,32 +488,13 @@ static void render_drag_icons(struct sway_output *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); - enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform); float matrix[9]; wlr_matrix_project_box(matrix, &monitor_box, transform, 0.0, wlr_output->transform_matrix); - pixman_region32_t damage; - 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); + 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) { From 2c4fe20456851b6b8dc14b6bdc0cf9bee527a9ee Mon Sep 17 00:00:00 2001 From: William McKinnon Date: Tue, 16 May 2023 02:26:01 -0400 Subject: [PATCH 2/3] Blur damage tracking simplification (#155) * suplified conditional in find_con_effect_iterator * removed has_blur * simplified optimized blur check * moved damage expansion to output.c * removed extraneous fx_renderer_scissor * cleaned up render_output * removed unneeded damage scale * moved workspace optimized check function to workspace.c * renamed ws iterator function * added back region expansion * removed uneeded parameter from get_main_buffer_blur * returned extended damage * moved get_blur_size back to original spot (reduce diff size) * Fixed blur artifacting * Fixed damage highlight not clearing correct framebuffer * removed unneeded conditional * moved initial damage expansion to output.c * moved extended damage to the top of output_render * moved blur damage to damage_surface_iterator * ensure damage doesnt expand beyond output size * removed stdint import --------- Co-authored-by: Erik Reider --- include/sway/config.h | 4 + include/sway/tree/workspace.h | 2 + sway/config.c | 8 ++ sway/desktop/output.c | 21 +++- sway/desktop/render.c | 202 +++++++++------------------------- sway/tree/workspace.c | 15 +++ 6 files changed, 96 insertions(+), 156 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,56 +1763,24 @@ 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 (debug.damage == DAMAGE_HIGHLIGHT && damage_not_empty) { - fx_renderer_clear((float[]){1, 1, 0, 1}); - } - - if (!damage_not_empty) { + if (!pixman_region32_not_empty(damage)) { // Output isn't damaged but needs buffer swap 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) { float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; if (server.session_lock.lock == NULL) { @@ -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 From acafb20b114ea93f971e118da0233c07157286c0 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Thu, 18 May 2023 01:39:48 +0200 Subject: [PATCH 3/3] Move stencil into each framebuffer (#156) * Move stencil into each framebuffer Also fixes the stencil being added to the wrong framebuffer * Initialize texture members on framebuffer init * removed bind arg * renamed init to create, changed existing create to update * moved stencil buffer creation to new function * removed some now misleading comments --------- Co-authored-by: William McKinnon --- .../sway/desktop/fx_renderer/fx_framebuffer.h | 7 ++- .../sway/desktop/fx_renderer/fx_renderer.h | 2 - sway/desktop/fx_renderer/fx_framebuffer.c | 39 +++++++++++++-- sway/desktop/fx_renderer/fx_renderer.c | 48 +++++-------------- sway/desktop/render.c | 6 ++- 5 files changed, 56 insertions(+), 46 deletions(-) diff --git a/include/sway/desktop/fx_renderer/fx_framebuffer.h b/include/sway/desktop/fx_renderer/fx_framebuffer.h index 289b4d87..39eeb257 100644 --- a/include/sway/desktop/fx_renderer/fx_framebuffer.h +++ b/include/sway/desktop/fx_renderer/fx_framebuffer.h @@ -10,11 +10,16 @@ struct fx_framebuffer { struct fx_texture texture; GLuint fb; + GLuint stencil_buffer; }; +struct fx_framebuffer fx_framebuffer_create(); + void fx_framebuffer_bind(struct fx_framebuffer *buffer); -void fx_framebuffer_create(struct fx_framebuffer *buffer, int width, int height, bool bind); +void fx_framebuffer_update(struct fx_framebuffer *buffer, int width, int height); + +void fx_framebuffer_add_stencil_buffer(struct fx_framebuffer *buffer, int width, int height); void fx_framebuffer_release(struct fx_framebuffer *buffer); diff --git a/include/sway/desktop/fx_renderer/fx_renderer.h b/include/sway/desktop/fx_renderer/fx_renderer.h index bdbcefe1..90b68f1c 100644 --- a/include/sway/desktop/fx_renderer/fx_renderer.h +++ b/include/sway/desktop/fx_renderer/fx_renderer.h @@ -119,8 +119,6 @@ struct fx_renderer { int viewport_width, viewport_height; - GLuint stencil_buffer_id; - struct fx_framebuffer wlr_buffer; // Just the framebuffer used by wlroots struct fx_framebuffer main_buffer; // The main FB used for rendering struct fx_framebuffer blur_buffer; // Contains the blurred background for tiled windows diff --git a/sway/desktop/fx_renderer/fx_framebuffer.c b/sway/desktop/fx_renderer/fx_framebuffer.c index 6cc1dbf3..14bc454e 100644 --- a/sway/desktop/fx_renderer/fx_framebuffer.c +++ b/sway/desktop/fx_renderer/fx_framebuffer.c @@ -1,14 +1,24 @@ #include "log.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) { glBindFramebuffer(GL_FRAMEBUFFER, buffer->fb); } -void fx_framebuffer_create(struct fx_framebuffer *buffer, int width, int height, bool bind) { +void fx_framebuffer_update(struct fx_framebuffer *buffer, int width, int height) { bool firstAlloc = false; - // Create a new framebuffer if (buffer->fb == (uint32_t) -1) { glGenFramebuffers(1, &buffer->fb); firstAlloc = true; @@ -44,19 +54,38 @@ void fx_framebuffer_create(struct fx_framebuffer *buffer, int width, int height, sway_log(SWAY_DEBUG, "Framebuffer created, status %i", status); } - // Bind the default framebuffer glBindTexture(GL_TEXTURE_2D, 0); - if (bind) { - fx_framebuffer_bind(buffer); +} + +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); + glBindRenderbuffer(GL_RENDERBUFFER, buffer->stencil_buffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, buffer->stencil_buffer); + 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); } } void fx_framebuffer_release(struct fx_framebuffer *buffer) { + // Release the framebuffer if (buffer->fb != (uint32_t) -1 && buffer->fb) { glDeleteFramebuffers(1, &buffer->fb); } buffer->fb= -1; + // Release the stencil buffer + if (buffer->stencil_buffer != (uint32_t)-1 && buffer->stencil_buffer) { + glDeleteRenderbuffers(1, &buffer->stencil_buffer); + } + buffer->stencil_buffer = -1; + + // Release the texture if (buffer->texture.id) { glDeleteTextures(1, &buffer->texture.id); } diff --git a/sway/desktop/fx_renderer/fx_renderer.c b/sway/desktop/fx_renderer/fx_renderer.c index 576d50c6..46668d73 100644 --- a/sway/desktop/fx_renderer/fx_renderer.c +++ b/sway/desktop/fx_renderer/fx_renderer.c @@ -13,6 +13,7 @@ #include #include "log.h" +#include "sway/desktop/fx_renderer/fx_framebuffer.h" #include "sway/desktop/fx_renderer/fx_renderer.h" #include "sway/desktop/fx_renderer/matrix.h" #include "sway/server.h" @@ -35,30 +36,6 @@ static const GLfloat verts[] = { 0, 1, // bottom left }; -static void create_stencil_buffer(GLuint *buffer_id, int width, int height) { - if (*buffer_id != (uint32_t) -1) { - return; - } - - glGenRenderbuffers(1, buffer_id); - glBindRenderbuffer(GL_RENDERBUFFER, *buffer_id); - glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, *buffer_id); - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - sway_log(SWAY_ERROR, "Stencilbuffer incomplete, couldn't create! (FB status: %i)", status); - return; - } - sway_log(SWAY_DEBUG, "Stencilbuffer created, status %i", status); -} - -static void release_stencil_buffer(GLuint *buffer_id) { - if (*buffer_id != (uint32_t)-1 && buffer_id) { - glDeleteRenderbuffers(1, buffer_id); - } - *buffer_id = -1; -} - static GLuint compile_shader(GLuint type, const GLchar *src) { GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &src, NULL); @@ -288,12 +265,10 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) { return NULL; } - renderer->main_buffer.fb = -1; - - renderer->blur_buffer.fb = -1; - renderer->effects_buffer.fb = -1; - renderer->effects_buffer_swapped.fb = -1; - renderer->stencil_buffer_id = -1; + renderer->main_buffer = fx_framebuffer_create(); + renderer->blur_buffer = fx_framebuffer_create(); + renderer->effects_buffer = fx_framebuffer_create(); + renderer->effects_buffer_swapped = fx_framebuffer_create(); renderer->blur_buffer_dirty = true; @@ -414,7 +389,6 @@ void fx_renderer_fini(struct fx_renderer *renderer) { fx_framebuffer_release(&renderer->blur_buffer); fx_framebuffer_release(&renderer->effects_buffer); fx_framebuffer_release(&renderer->effects_buffer_swapped); - release_stencil_buffer(&renderer->stencil_buffer_id); } void fx_renderer_begin(struct fx_renderer *renderer, int width, int height) { @@ -432,10 +406,13 @@ void fx_renderer_begin(struct fx_renderer *renderer, int width, int height) { renderer->wlr_buffer.fb = wlr_fb; // Create the framebuffers - fx_framebuffer_create(&renderer->main_buffer, width, height, true); - fx_framebuffer_create(&renderer->effects_buffer, width, height, false); - fx_framebuffer_create(&renderer->effects_buffer_swapped, width, height, false); - create_stencil_buffer(&renderer->stencil_buffer_id, width, height); + fx_framebuffer_update(&renderer->main_buffer, width, height); + fx_framebuffer_update(&renderer->effects_buffer, width, height); + fx_framebuffer_update(&renderer->effects_buffer_swapped, width, height); + + // Add a stencil buffer to the main buffer & bind the main buffer + fx_framebuffer_add_stencil_buffer(&renderer->main_buffer, width, height); + fx_framebuffer_bind(&renderer->main_buffer); // refresh projection matrix matrix_projection(renderer->projection, width, height, @@ -450,7 +427,6 @@ void fx_renderer_begin(struct fx_renderer *renderer, int width, int height) { void fx_renderer_end(struct fx_renderer *renderer) { // Release the main buffer fx_framebuffer_release(&renderer->main_buffer); - release_stencil_buffer(&renderer->stencil_buffer_id); } void fx_renderer_clear(const float color[static 4]) { diff --git a/sway/desktop/render.c b/sway/desktop/render.c index fb47007f..77765b1d 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -494,8 +494,10 @@ void render_output_blur(struct sway_output *output, pixman_region32_t *damage) { 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, - output->renderer->viewport_width, output->renderer->viewport_height, true); + fx_framebuffer_update(&renderer->blur_buffer, + output->renderer->viewport_width, output->renderer->viewport_height); + fx_framebuffer_bind(&renderer->blur_buffer); + // Clear the damaged region of the blur_buffer float clear_color[] = { 0, 0, 0, 0 }; int nrects;