From b2a4dafb804d8b7e199fcbeb0bd020e9c2d9510c Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sun, 28 Jan 2024 14:38:46 +0100 Subject: [PATCH 01/18] Initial blur implementation --- include/render/fx_renderer/fx_renderer.h | 28 +- include/render/fx_renderer/shaders.h | 22 ++ include/render/pass.h | 25 +- include/scenefx/fx_renderer/fx_renderer.h | 1 + include/scenefx/types/fx/blur_data.h | 19 ++ include/scenefx/types/fx/shadow_data.h | 4 +- include/scenefx/types/wlr_scene.h | 24 +- render/fx_renderer/fx_framebuffer.c | 33 +++ render/fx_renderer/fx_pass.c | 265 +++++++++++++++++- render/fx_renderer/fx_renderer.c | 23 +- render/fx_renderer/gles2/shaders/blur1.frag | 21 ++ render/fx_renderer/gles2/shaders/blur2.frag | 25 ++ render/fx_renderer/gles2/shaders/meson.build | 2 + .../gles2/shaders/stencil_mask.frag | 14 +- render/fx_renderer/gles2/shaders/tex.frag | 5 + render/fx_renderer/shaders.c | 53 +++- tinywl/tinywl.c | 5 + types/fx/blur_data.c | 17 ++ types/fx/meson.build | 3 +- types/scene/wlr_scene.c | 256 +++++++++++++++-- 20 files changed, 780 insertions(+), 65 deletions(-) create mode 100644 include/scenefx/types/fx/blur_data.h create mode 100644 render/fx_renderer/gles2/shaders/blur1.frag create mode 100644 render/fx_renderer/gles2/shaders/blur2.frag create mode 100644 types/fx/blur_data.c diff --git a/include/render/fx_renderer/fx_renderer.h b/include/render/fx_renderer/fx_renderer.h index 4a95634..cce2b3a 100644 --- a/include/render/fx_renderer/fx_renderer.h +++ b/include/render/fx_renderer/fx_renderer.h @@ -48,6 +48,10 @@ struct fx_framebuffer { struct wlr_addon addon; }; +/** Should only be used with custom fbs */ +void fx_framebuffer_get_or_create_bufferless(struct fx_renderer *fx_renderer, + struct wlr_output *output, struct fx_framebuffer **fx_buffer); + struct fx_framebuffer *fx_framebuffer_get_or_create(struct fx_renderer *renderer, struct wlr_buffer *wlr_buffer); @@ -141,20 +145,28 @@ struct fx_renderer { PFNGLGETINTEGER64VEXTPROC glGetInteger64vEXT; } procs; - struct { - struct quad_shader quad; - struct tex_shader tex_rgba; - struct tex_shader tex_rgbx; - struct tex_shader tex_ext; - struct box_shadow_shader box_shadow; - struct stencil_mask_shader stencil_mask; - } shaders; + struct shaders shaders; struct wl_list buffers; // fx_framebuffer.link struct wl_list textures; // fx_texture.link struct fx_framebuffer *current_buffer; uint32_t viewport_width, viewport_height; + + // 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 + // 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 wlr_renderer_is_fx(struct wlr_renderer *wlr_renderer); diff --git a/include/render/fx_renderer/shaders.h b/include/render/fx_renderer/shaders.h index 92a14d5..fa458f7 100644 --- a/include/render/fx_renderer/shaders.h +++ b/include/render/fx_renderer/shaders.h @@ -37,6 +37,7 @@ struct tex_shader { GLint size; GLint position; GLint radius; + GLint discard_transparent; }; struct stencil_mask_shader { @@ -60,6 +61,27 @@ struct box_shadow_shader { GLint corner_radius; }; +struct blur_shader { + GLuint program; + GLint proj; + GLint tex_proj; + GLint tex; + GLint pos_attrib; + GLint radius; + GLint halfpixel; +}; + +struct shaders { + struct quad_shader quad; + struct tex_shader tex_rgba; + struct tex_shader tex_rgbx; + struct tex_shader tex_ext; + struct box_shadow_shader box_shadow; + struct stencil_mask_shader stencil_mask; + struct blur_shader blur1; + struct blur_shader blur2; +}; + bool link_shaders(struct fx_renderer *renderer); #endif diff --git a/include/render/pass.h b/include/render/pass.h index 52666fe..1edac24 100644 --- a/include/render/pass.h +++ b/include/render/pass.h @@ -20,14 +20,16 @@ struct fx_gles_render_pass { * Callers must call wlr_render_pass_submit() once they are done with the * render pass. */ -struct fx_gles_render_pass *fx_renderer_begin_buffer_pass(struct wlr_renderer *renderer, - struct wlr_buffer *buffer, const struct wlr_buffer_pass_options *options); +struct fx_gles_render_pass *fx_renderer_begin_buffer_pass(struct wlr_renderer *wlr_renderer, + struct wlr_buffer *wlr_buffer, struct wlr_output *output, + const struct wlr_buffer_pass_options *options); struct fx_render_texture_options { struct wlr_render_texture_options base; float scale; struct wlr_box *clip_box; // Used to clip csd. Ignored if NULL int corner_radius; + bool discard_transparent; }; struct fx_render_texture_options fx_render_texture_options_default( @@ -41,6 +43,13 @@ struct fx_render_rect_options { struct fx_render_rect_options fx_render_rect_options_default( const struct wlr_render_rect_options *base); +struct fx_render_blur_options { + struct fx_render_texture_options tex_options; + struct wlr_scene_buffer *scene_buffer; + struct wlr_box monitor_box; + struct blur_data *blur_data; +}; + /** * Render a fx texture. */ @@ -66,4 +75,16 @@ void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass, const struct fx_render_rect_options *fx_options, int corner_radius, struct shadow_data *shadow_data); +/** + * Render blur. + */ +void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, + struct fx_render_blur_options *fx_options); + +/** + * Render from one buffer to another + */ +void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass, struct wlr_renderer *renderer, + pixman_region32_t *region, struct fx_framebuffer *dst_buffer, struct fx_framebuffer *src_buffer); + #endif diff --git a/include/scenefx/fx_renderer/fx_renderer.h b/include/scenefx/fx_renderer/fx_renderer.h index 2e64ffb..3578dae 100644 --- a/include/scenefx/fx_renderer/fx_renderer.h +++ b/include/scenefx/fx_renderer/fx_renderer.h @@ -2,6 +2,7 @@ #define SCENEFX_FX_OPENGL_H #include +#include struct wlr_renderer *fx_renderer_create_with_drm_fd(int drm_fd); struct wlr_renderer *fx_renderer_create(struct wlr_backend *backend); diff --git a/include/scenefx/types/fx/blur_data.h b/include/scenefx/types/fx/blur_data.h new file mode 100644 index 0000000..5d5d29b --- /dev/null +++ b/include/scenefx/types/fx/blur_data.h @@ -0,0 +1,19 @@ +#ifndef TYPES_FX_BLUR_DATA_H +#define TYPES_FX_BLUR_DATA_H + +#include +#include + +struct blur_data { + int num_passes; + int radius; + bool ignore_transparent; +}; + +struct blur_data blur_data_get_default(void); + +bool scene_buffer_should_blur(bool backdrop_blur, struct blur_data *blur_data); + +int blur_data_calc_size(struct blur_data *blur_data); + +#endif diff --git a/include/scenefx/types/fx/shadow_data.h b/include/scenefx/types/fx/shadow_data.h index d96a084..4982078 100644 --- a/include/scenefx/types/fx/shadow_data.h +++ b/include/scenefx/types/fx/shadow_data.h @@ -1,5 +1,5 @@ -#ifndef TYPES_DECORATION_DATA -#define TYPES_DECORATION_DATA +#ifndef TYPES_FX_SHADOW_DATA_H +#define TYPES_FX_SHADOW_DATA_H #include #include diff --git a/include/scenefx/types/wlr_scene.h b/include/scenefx/types/wlr_scene.h index 21558d8..e3893b2 100644 --- a/include/scenefx/types/wlr_scene.h +++ b/include/scenefx/types/wlr_scene.h @@ -21,6 +21,7 @@ #include #include "scenefx/types/fx/shadow_data.h" +#include "scenefx/types/fx/blur_data.h" #include #include #include @@ -111,6 +112,8 @@ struct wlr_scene { enum wlr_scene_debug_damage_option debug_damage_option; bool direct_scanout; bool calculate_visibility; + + struct blur_data blur_data; }; /** A scene-graph node displaying a single surface. */ @@ -176,9 +179,12 @@ struct wlr_scene_buffer { */ struct wlr_scene_output *primary_output; - float opacity; int corner_radius; struct shadow_data shadow_data; + bool backdrop_blur; + bool backdrop_blur_optimized; + + float opacity; enum wlr_scale_filter_mode filter_mode; struct wlr_fbox src_box; int dst_width, dst_height; @@ -313,6 +319,9 @@ struct wlr_scene *wlr_scene_create(void); void wlr_scene_set_presentation(struct wlr_scene *scene, struct wlr_presentation *presentation); +/** Sets the global blur parameters */ +void wlr_scene_set_blur_data(struct wlr_scene *scene, struct blur_data blur_data); + /** * Handles linux_dmabuf_v1 feedback for all surfaces in the scene. * @@ -461,6 +470,19 @@ void wlr_scene_buffer_set_corner_radius(struct wlr_scene_buffer *scene_buffer, void wlr_scene_buffer_set_shadow_data(struct wlr_scene_buffer *scene_buffer, struct shadow_data shadow_data); +/** +* Sets the whether or not the buffer should render backdrop blur +*/ +void wlr_scene_buffer_set_backdrop_blur(struct wlr_scene_buffer *scene_buffer, + bool enabled); + +/** +* Sets the whether the backdrop blur should use optimized blur or not +* TODO: Add function to update `blur_buffer` +*/ +void wlr_scene_buffer_set_backdrop_blur_optimized(struct wlr_scene_buffer *scene_buffer, + bool enabled); + /** * Calls the buffer's frame_done signal. */ diff --git a/render/fx_renderer/fx_framebuffer.c b/render/fx_renderer/fx_framebuffer.c index fea101b..66b37de 100644 --- a/render/fx_renderer/fx_framebuffer.c +++ b/render/fx_renderer/fx_framebuffer.c @@ -20,6 +20,37 @@ static const struct wlr_addon_interface buffer_addon_impl = { .destroy = handle_buffer_destroy, }; +void fx_framebuffer_get_or_create_bufferless(struct fx_renderer *renderer, + struct wlr_output *output, struct fx_framebuffer **fx_framebuffer) { + struct wlr_allocator *allocator = output->allocator; + struct wlr_swapchain *swapchain = output->swapchain; + int width = output->width; + int height = output->height; + struct wlr_buffer *wlr_buffer = NULL; + + if (*fx_framebuffer == NULL) { + wlr_buffer = wlr_allocator_create_buffer(allocator, width, height, + &swapchain->format); + if (wlr_buffer == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate buffer"); + return; + } + } else { + if ((wlr_buffer = (*fx_framebuffer)->buffer) && + wlr_buffer->width == width && + wlr_buffer->height == height) { + return; + } + // Create a new wlr_buffer if it's null or if the output size has + // changed + fx_framebuffer_destroy(*fx_framebuffer); + wlr_buffer_drop(wlr_buffer); + wlr_buffer = wlr_allocator_create_buffer(allocator, + width, height, &swapchain->format); + } + *fx_framebuffer = fx_framebuffer_get_or_create(renderer, wlr_buffer); +} + struct fx_framebuffer *fx_framebuffer_get_or_create(struct fx_renderer *renderer, struct wlr_buffer *wlr_buffer) { struct wlr_addon *addon = @@ -128,6 +159,8 @@ void fx_framebuffer_destroy(struct fx_framebuffer *fx_buffer) { fx_buffer->fbo = -1; glDeleteRenderbuffers(1, &fx_buffer->rbo); fx_buffer->rbo = -1; + glDeleteRenderbuffers(1, &fx_buffer->sb); + fx_buffer->sb = -1; wlr_egl_destroy_image(fx_buffer->renderer->egl, fx_buffer->image); diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index 231de33..cda0335 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -4,14 +4,18 @@ #include #include #include +#include #include #include +#include #include "render/egl.h" #include "render/fx_renderer/fx_renderer.h" #include "render/fx_renderer/matrix.h" #include "render/pass.h" +#include "scenefx/types/fx/blur_data.h" #include "scenefx/types/fx/shadow_data.h" +#include "scenefx/types/wlr_scene.h" #define MAX_QUADS 86 // 4kb @@ -19,6 +23,7 @@ struct fx_render_texture_options fx_render_texture_options_default( const struct wlr_render_texture_options *base) { struct fx_render_texture_options options = { .corner_radius = 0, + .discard_transparent = false, .scale = 1.0f, .clip_box = NULL, }; @@ -74,6 +79,8 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { wlr_buffer_unlock(pass->buffer->buffer); free(pass); + pixman_region32_fini(&renderer->blur_padding_region); + return true; } @@ -307,6 +314,7 @@ void fx_render_pass_add_texture(struct fx_gles_render_pass *pass, glUniform2f(shader->size, clip_box->width, clip_box->height); glUniform2f(shader->position, clip_box->x, clip_box->y); glUniform1f(shader->radius, fx_options->corner_radius); + glUniform1f(shader->discard_transparent, fx_options->discard_transparent); set_proj_matrix(shader->proj, pass->projection_matrix, &dst_box); set_tex_matrix(shader->tex_proj, options->transform, &src_fbox); @@ -432,6 +440,249 @@ void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass, pop_fx_debug(renderer); } +/* Renders the blur for each damaged rect and swaps the buffer */ +static void render_blur_segments(struct fx_gles_render_pass *pass, + struct fx_renderer *renderer, struct fx_render_blur_options *fx_options, + struct fx_framebuffer **buffer, struct blur_shader* shader) { + struct fx_render_texture_options *tex_options = &fx_options->tex_options; + struct wlr_render_texture_options *options = &tex_options->base; + struct blur_data *blur_data = fx_options->blur_data; + + // Swap fbo + if (*buffer == renderer->effects_buffer) { + fx_framebuffer_bind(renderer->effects_buffer_swapped); + } else { + fx_framebuffer_bind(renderer->effects_buffer); + } + + options->texture = + fx_texture_from_buffer( &renderer->wlr_renderer, (*buffer)->buffer); + struct fx_texture_attribs attribs; + fx_texture_get_attribs(options->texture, &attribs); + + /* + * Render + */ + + struct wlr_box dst_box; + struct wlr_fbox src_fbox; + wlr_render_texture_options_get_src_box(options, &src_fbox); + wlr_render_texture_options_get_dst_box(options, &dst_box); + src_fbox.x /= options->texture->width; + src_fbox.y /= options->texture->height; + src_fbox.width /= options->texture->width; + src_fbox.height /= options->texture->height; + + glDisable(GL_BLEND); + glDisable(GL_STENCIL_TEST); + + push_fx_debug(renderer); + + glUseProgram(shader->program); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(attribs.target, attribs.tex); + + switch (options->filter_mode) { + case WLR_SCALE_FILTER_BILINEAR: + glTexParameteri(attribs.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(attribs.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + case WLR_SCALE_FILTER_NEAREST: + glTexParameteri(attribs.target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(attribs.target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + } + + glUniform1i(shader->tex, 0); + glUniform1f(shader->radius, blur_data->radius); + + if (shader == &renderer->shaders.blur1) { + glUniform2f(shader->halfpixel, + 0.5f / (options->texture->width / 2.0f), + 0.5f / (options->texture->height / 2.0f)); + } else { + glUniform2f(shader->halfpixel, + 0.5f / (options->texture->width * 2.0f), + 0.5f / (options->texture->height * 2.0f)); + } + + set_proj_matrix(shader->proj, pass->projection_matrix, &dst_box); + set_tex_matrix(shader->tex_proj, options->transform, &src_fbox); + + render(&dst_box, options->clip, shader->pos_attrib); + + glBindTexture(attribs.target, 0); + pop_fx_debug(renderer); + + wlr_texture_destroy(options->texture); + + // Swap buffer + if (*buffer != renderer->effects_buffer) { + *buffer = renderer->effects_buffer; + } else { + *buffer = renderer->effects_buffer_swapped; + } +} + +// Blurs the main_buffer content and returns the blurred framebuffer +static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *pass, + struct fx_renderer *renderer, struct fx_render_blur_options *fx_options, + pixman_region32_t *original_damage) { + struct blur_data *blur_data = fx_options->blur_data; + + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_copy(&damage, original_damage); + wlr_region_transform(&damage, &damage, fx_options->tex_options.base.transform, + fx_options->monitor_box.width, fx_options->monitor_box.height); + + wlr_region_expand(&damage, &damage, blur_data_calc_size(fx_options->blur_data)); + + // damage region will be scaled, make a temp + pixman_region32_t scaled_damage; + pixman_region32_init(&scaled_damage); + + fx_options->tex_options.base.src_box = (struct wlr_fbox) { + fx_options->monitor_box.x, + fx_options->monitor_box.y, + fx_options->monitor_box.width, + fx_options->monitor_box.height, + }; + fx_options->tex_options.base.dst_box = fx_options->monitor_box; + // Clip the blur to the damage + fx_options->tex_options.base.clip = &scaled_damage; + + // Initially draw from the current WLR texture + struct fx_framebuffer *current_buffer = pass->buffer; + + // Downscale + for (int i = 0; i < blur_data->num_passes; ++i) { + wlr_region_scale(&scaled_damage, &damage, 1.0f / (1 << (i + 1))); + render_blur_segments(pass, renderer, fx_options, ¤t_buffer, + &renderer->shaders.blur1); + } + + // Upscale + for (int i = blur_data->num_passes - 1; i >= 0; --i) { + // when upsampling we make the region twice as big + wlr_region_scale(&scaled_damage, &damage, 1.0f / (1 << i)); + render_blur_segments(pass, renderer, fx_options, ¤t_buffer, + &renderer->shaders.blur2); + } + + pixman_region32_fini(&scaled_damage); + pixman_region32_fini(&damage); + + // Bind back to the default buffer + fx_framebuffer_bind(pass->buffer); + + return current_buffer; +} + +void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, + struct fx_render_blur_options *fx_options) { + struct fx_renderer *renderer = pass->buffer->renderer; + struct fx_render_texture_options *tex_options = &fx_options->tex_options; + const struct wlr_render_texture_options *options = &tex_options->base; + struct wlr_scene_buffer *scene_buffer = fx_options->scene_buffer; + + pixman_region32_t translucent_region; + pixman_region32_init(&translucent_region); + + struct wlr_box dst_box; + wlr_render_texture_options_get_dst_box(options, &dst_box); + + // Gets the translucent region + pixman_box32_t surface_box = { 0, 0, dst_box.width, dst_box.height }; + pixman_region32_copy(&translucent_region, &scene_buffer->opaque_region); + pixman_region32_inverse(&translucent_region, &translucent_region, &surface_box); + if (!pixman_region32_not_empty(&translucent_region)) { + goto damage_finish; + } + + struct fx_framebuffer *buffer = renderer->blur_buffer; + if (!buffer || !scene_buffer->backdrop_blur_optimized) { + pixman_region32_translate(&translucent_region, dst_box.x, dst_box.y); + pixman_region32_intersect(&translucent_region, &translucent_region, options->clip); + + // Render the blur into its own buffer + struct fx_render_blur_options blur_options = *fx_options; + buffer = get_main_buffer_blur(pass, renderer, &blur_options, &translucent_region); + } + struct wlr_texture *wlr_texture = + fx_texture_from_buffer(&renderer->wlr_renderer, buffer->buffer); + struct fx_texture *blur_texture = fx_get_texture(wlr_texture); + blur_texture->has_alpha = true; + + // Get a stencil of the window ignoring transparent regions + if (fx_options->blur_data->ignore_transparent) { + stencil_mask_init(); + + struct fx_render_texture_options tex_options = fx_options->tex_options; + tex_options.discard_transparent = true; + fx_render_pass_add_texture(pass, &tex_options); + + stencil_mask_close(true); + } + + // Draw the blurred texture + tex_options->base.dst_box = fx_options->monitor_box; + tex_options->base.src_box = (struct wlr_fbox) { + .x = fx_options->monitor_box.x, + .y = fx_options->monitor_box.y, + .width = fx_options->monitor_box.width, + .height = fx_options->monitor_box.height, + }; + tex_options->base.texture = &blur_texture->wlr_texture; + fx_render_pass_add_texture(pass, tex_options); + + wlr_texture_destroy(&blur_texture->wlr_texture); + + // Finish stenciling + if (fx_options->blur_data->ignore_transparent) { + stencil_mask_fini(); + } + +damage_finish: + pixman_region32_fini(&translucent_region); +} + +void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass, struct wlr_renderer *renderer, + pixman_region32_t *region, struct fx_framebuffer *dst_buffer, struct fx_framebuffer *src_buffer) { + if (!pixman_region32_not_empty(region)) { + return; + } + + struct wlr_texture *src_tex = fx_texture_from_buffer(renderer, src_buffer->buffer); + if (src_tex == NULL) { + return; + } + + // Draw onto the dst_buffer + fx_framebuffer_bind(dst_buffer); + wlr_render_pass_add_texture(&pass->base, &(struct wlr_render_texture_options) { + .texture = src_tex, + .clip = region, + .blend_mode = WLR_RENDER_BLEND_MODE_NONE, + .dst_box = (struct wlr_box){ + .width = dst_buffer->buffer->width, + .height = dst_buffer->buffer->height, + }, + .src_box = (struct wlr_fbox){ + .x = 0, + .y = 0, + .width = src_buffer->buffer->width, + .height = src_buffer->buffer->height, + }, + }); + wlr_texture_destroy(src_tex); + + // Bind back to the main WLR buffer + fx_framebuffer_bind(pass->buffer); +} + + static const char *reset_status_str(GLenum status) { switch (status) { case GL_GUILTY_CONTEXT_RESET_KHR: @@ -483,8 +734,9 @@ static struct fx_gles_render_pass *begin_buffer_pass(struct fx_framebuffer *buff return pass; } -struct fx_gles_render_pass *fx_renderer_begin_buffer_pass(struct wlr_renderer *wlr_renderer, - struct wlr_buffer *wlr_buffer, const struct wlr_buffer_pass_options *options) { +struct fx_gles_render_pass *fx_renderer_begin_buffer_pass( + struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer, + struct wlr_output *output, const struct wlr_buffer_pass_options *options) { struct fx_renderer *renderer = fx_get_renderer(wlr_renderer); if (!wlr_egl_make_current(renderer->egl)) { return NULL; @@ -501,6 +753,15 @@ struct fx_gles_render_pass *fx_renderer_begin_buffer_pass(struct wlr_renderer *w return NULL; } + // Update the buffers if needed + if (output) { + fx_framebuffer_get_or_create_bufferless(renderer, output, &renderer->blur_saved_pixels_buffer); + fx_framebuffer_get_or_create_bufferless(renderer, output, &renderer->effects_buffer); + fx_framebuffer_get_or_create_bufferless(renderer, output, &renderer->effects_buffer_swapped); + } + + pixman_region32_init(&renderer->blur_padding_region); + struct fx_gles_render_pass *pass = begin_buffer_pass(buffer, timer); if (!pass) { return NULL; diff --git a/render/fx_renderer/fx_renderer.c b/render/fx_renderer/fx_renderer.c index 0b20d7e..1a41232 100644 --- a/render/fx_renderer/fx_renderer.c +++ b/render/fx_renderer/fx_renderer.c @@ -66,7 +66,7 @@ struct fx_render_timer *fx_get_render_timer(struct wlr_render_timer *wlr_timer) return timer; } -static bool fx_bind_main_buffer(struct wlr_renderer *wlr_renderer, +static bool fx_bind_buffer(struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer) { struct fx_renderer *renderer = fx_get_renderer(wlr_renderer); @@ -138,6 +138,8 @@ static bool fx_renderer_begin(struct wlr_renderer *wlr_renderer, uint32_t width, renderer->viewport_width = width; renderer->viewport_height = height; + pixman_region32_init(&renderer->blur_padding_region); + // refresh projection matrix matrix_projection(renderer->projection, width, height, WL_OUTPUT_TRANSFORM_FLIPPED_180); @@ -153,8 +155,8 @@ static bool fx_renderer_begin(struct wlr_renderer *wlr_renderer, uint32_t width, } static void fx_renderer_end(struct wlr_renderer *wlr_renderer) { - fx_get_renderer_in_context(wlr_renderer); - // no-op + struct fx_renderer *renderer = fx_get_renderer_in_context(wlr_renderer); + pixman_region32_fini(&renderer->blur_padding_region); } static void fx_renderer_clear(struct wlr_renderer *wlr_renderer, @@ -239,6 +241,7 @@ static bool fx_render_subtexture_with_matrix( glUniform2f(shader->size, box->width, box->height); glUniform2f(shader->position, box->x, box->y); glUniform1f(shader->radius, 0); + glUniform1f(shader->discard_transparent, false); float tex_matrix[9]; wlr_matrix_identity(tex_matrix); @@ -451,7 +454,7 @@ static void fx_renderer_destroy(struct wlr_renderer *wlr_renderer) { static struct wlr_render_pass *begin_buffer_pass(struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer, const struct wlr_buffer_pass_options *options) { struct fx_gles_render_pass *pass = - fx_renderer_begin_buffer_pass(wlr_renderer, wlr_buffer, options); + fx_renderer_begin_buffer_pass(wlr_renderer, wlr_buffer, NULL, options); if (!pass) { return NULL; } @@ -530,7 +533,7 @@ static void fx_render_timer_destroy(struct wlr_render_timer *wlr_timer) { static const struct wlr_renderer_impl renderer_impl = { .destroy = fx_renderer_destroy, - .bind_buffer = fx_bind_main_buffer, + .bind_buffer = fx_bind_buffer, .begin = fx_renderer_begin, .end = fx_renderer_end, .clear = fx_renderer_clear, @@ -751,6 +754,9 @@ struct wlr_renderer *fx_renderer_create_egl(struct wlr_egl *egl) { if (!link_shaders(renderer)) { goto error; } + + renderer->blur_buffer_dirty = false; + pop_fx_debug(renderer); wlr_log(WLR_INFO, "FX RENDERER: Shaders Initialized Successfully"); @@ -760,13 +766,6 @@ struct wlr_renderer *fx_renderer_create_egl(struct wlr_egl *egl) { return &renderer->wlr_renderer; error: - glDeleteProgram(renderer->shaders.quad.program); - glDeleteProgram(renderer->shaders.tex_rgba.program); - glDeleteProgram(renderer->shaders.tex_rgbx.program); - glDeleteProgram(renderer->shaders.tex_ext.program); - glDeleteProgram(renderer->shaders.stencil_mask.program); - glDeleteProgram(renderer->shaders.box_shadow.program); - pop_fx_debug(renderer); if (renderer->exts.KHR_debug) { diff --git a/render/fx_renderer/gles2/shaders/blur1.frag b/render/fx_renderer/gles2/shaders/blur1.frag new file mode 100644 index 0000000..4545b0c --- /dev/null +++ b/render/fx_renderer/gles2/shaders/blur1.frag @@ -0,0 +1,21 @@ +precision mediump float; +varying mediump vec2 v_texcoord; +uniform sampler2D tex; + +uniform float radius; +uniform vec2 halfpixel; + +void main() { + vec2 uv = v_texcoord * 2.0; + + vec4 sum = texture2D(tex, uv) * 4.0; + sum += texture2D(tex, uv - halfpixel.xy * radius); + sum += texture2D(tex, uv + halfpixel.xy * radius); + sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius); + sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius); + + gl_FragColor = sum / 8.0; + + // REMOVE + // gl_FragColor = texture2D(tex, uv); +} diff --git a/render/fx_renderer/gles2/shaders/blur2.frag b/render/fx_renderer/gles2/shaders/blur2.frag new file mode 100644 index 0000000..263c8f6 --- /dev/null +++ b/render/fx_renderer/gles2/shaders/blur2.frag @@ -0,0 +1,25 @@ +precision mediump float; +varying mediump vec2 v_texcoord; +uniform sampler2D tex; + +uniform float radius; +uniform vec2 halfpixel; + +void main() { + vec2 uv = v_texcoord / 2.0; + + vec4 sum = texture2D(tex, uv + vec2(-halfpixel.x * 2.0, 0.0) * radius); + + sum += texture2D(tex, uv + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0; + sum += texture2D(tex, uv + vec2(0.0, halfpixel.y * 2.0) * radius); + sum += texture2D(tex, uv + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0; + sum += texture2D(tex, uv + vec2(halfpixel.x * 2.0, 0.0) * radius); + sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius) * 2.0; + sum += texture2D(tex, uv + vec2(0.0, -halfpixel.y * 2.0) * radius); + sum += texture2D(tex, uv + vec2(-halfpixel.x, -halfpixel.y) * radius) * 2.0; + + gl_FragColor = sum / 12.0; + + // REMOVE + // gl_FragColor = texture2D(tex, uv); +} diff --git a/render/fx_renderer/gles2/shaders/meson.build b/render/fx_renderer/gles2/shaders/meson.build index 42f066e..a95d69b 100644 --- a/render/fx_renderer/gles2/shaders/meson.build +++ b/render/fx_renderer/gles2/shaders/meson.build @@ -6,6 +6,8 @@ shaders = [ 'tex.frag', 'box_shadow.frag', 'stencil_mask.frag', + 'blur1.frag', + 'blur2.frag', ] foreach name : shaders diff --git a/render/fx_renderer/gles2/shaders/stencil_mask.frag b/render/fx_renderer/gles2/shaders/stencil_mask.frag index 523adc8..e1fd76a 100644 --- a/render/fx_renderer/gles2/shaders/stencil_mask.frag +++ b/render/fx_renderer/gles2/shaders/stencil_mask.frag @@ -11,12 +11,12 @@ uniform vec2 position; uniform float radius; void main() { - vec2 q = abs(gl_FragCoord.xy - position - half_size) - half_size + radius; - float dist = min(max(q.x,q.y), 0.0) + length(max(q, 0.0)) - radius; - float smoothedAlpha = 1.0 - smoothstep(-1.0, 0.5, dist); - gl_FragColor = mix(vec4(0.0), vec4(1.0), smoothedAlpha); + vec2 q = abs(gl_FragCoord.xy - position - half_size) - half_size + radius; + float dist = min(max(q.x,q.y), 0.0) + length(max(q, 0.0)) - radius; + float smoothedAlpha = 1.0 - smoothstep(-1.0, 0.5, dist); + gl_FragColor = mix(vec4(0.0), vec4(1.0), smoothedAlpha); - if (gl_FragColor.a < 1.0) { - discard; - } + if (gl_FragColor.a < 1.0) { + discard; + } } diff --git a/render/fx_renderer/gles2/shaders/tex.frag b/render/fx_renderer/gles2/shaders/tex.frag index 8c14373..b7ba3fc 100644 --- a/render/fx_renderer/gles2/shaders/tex.frag +++ b/render/fx_renderer/gles2/shaders/tex.frag @@ -29,6 +29,7 @@ uniform float alpha; uniform vec2 size; uniform vec2 position; uniform float radius; +uniform bool discard_transparent; vec4 sample_texture() { #if SOURCE == SOURCE_TEXTURE_RGBA || SOURCE == SOURCE_TEXTURE_EXTERNAL @@ -46,4 +47,8 @@ void main() { float smooth = smoothstep(-1.0, 0.5, d); gl_FragColor = mix(vec4(0), gl_FragColor, smooth); } + + if (discard_transparent && gl_FragColor.a == 0.0) { + discard; + } } diff --git a/render/fx_renderer/shaders.c b/render/fx_renderer/shaders.c index 9257ca3..52e2069 100644 --- a/render/fx_renderer/shaders.c +++ b/render/fx_renderer/shaders.c @@ -12,6 +12,8 @@ #include "tex_frag_src.h" #include "stencil_mask_frag_src.h" #include "box_shadow_frag_src.h" +#include "blur1_frag_src.h" +#include "blur2_frag_src.h" GLuint compile_shader(GLuint type, const GLchar *src) { GLuint shader = glCreateShader(type); @@ -130,6 +132,7 @@ static bool link_tex_program(struct tex_shader *shader, shader->size = glGetUniformLocation(prog, "size"); shader->position = glGetUniformLocation(prog, "position"); shader->radius = glGetUniformLocation(prog, "radius"); + shader->discard_transparent = glGetUniformLocation(prog, "discard_transparent"); return true; } @@ -168,36 +171,74 @@ static bool link_box_shadow_program(struct box_shadow_shader *shader) { return true; } +static bool link_blur_program(struct blur_shader *shader, const char *shader_program) { + GLuint prog; + shader->program = prog = link_program(shader_program); + if (!shader->program) { + return false; + } + shader->proj = glGetUniformLocation(prog, "proj"); + shader->tex = glGetUniformLocation(prog, "tex"); + shader->pos_attrib = glGetAttribLocation(prog, "pos"); + shader->tex_proj = glGetUniformLocation(prog, "tex_proj"); + shader->radius = glGetUniformLocation(prog, "radius"); + shader->halfpixel = glGetUniformLocation(prog, "halfpixel"); + + return true; +} + bool link_shaders(struct fx_renderer *renderer) { // quad fragment shader if (!link_quad_program(&renderer->shaders.quad)) { wlr_log(WLR_ERROR, "Could not link quad shader"); - return false; + goto error; } // fragment shaders if (!link_tex_program(&renderer->shaders.tex_rgba, SHADER_SOURCE_TEXTURE_RGBA)) { wlr_log(WLR_ERROR, "Could not link tex_RGBA shader"); - return false; + goto error; } if (!link_tex_program(&renderer->shaders.tex_rgbx, SHADER_SOURCE_TEXTURE_RGBX)) { wlr_log(WLR_ERROR, "Could not link tex_RGBX shader"); - return false; + goto error; } if (!link_tex_program(&renderer->shaders.tex_ext, SHADER_SOURCE_TEXTURE_EXTERNAL)) { wlr_log(WLR_ERROR, "Could not link tex_EXTERNAL shader"); - return false; + goto error; } // stencil mask shader if (!link_stencil_mask_program(&renderer->shaders.stencil_mask)) { wlr_log(WLR_ERROR, "Could not link stencil mask shader"); - return false; + goto error; } // box shadow shader if (!link_box_shadow_program(&renderer->shaders.box_shadow)) { wlr_log(WLR_ERROR, "Could not link box shadow shader"); - return false; + goto error; + } + + // Blur shaders + if (!link_blur_program(&renderer->shaders.blur1, blur1_frag_src)) { + wlr_log(WLR_ERROR, "Could not link blur1 shader"); + goto error; + } + if (!link_blur_program(&renderer->shaders.blur2, blur2_frag_src)) { + wlr_log(WLR_ERROR, "Could not link blur2 shader"); + goto error; } return true; + +error: + glDeleteProgram(renderer->shaders.quad.program); + glDeleteProgram(renderer->shaders.tex_rgba.program); + glDeleteProgram(renderer->shaders.tex_rgbx.program); + glDeleteProgram(renderer->shaders.tex_ext.program); + glDeleteProgram(renderer->shaders.stencil_mask.program); + glDeleteProgram(renderer->shaders.box_shadow.program); + glDeleteProgram(renderer->shaders.blur1.program); + glDeleteProgram(renderer->shaders.blur2.program); + + return false; } diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 994574f..dd83e44 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -590,6 +590,11 @@ static void output_configure_scene(struct wlr_scene_node *node, if (!wlr_subsurface_try_from_wlr_surface(xdg_surface->surface)) { wlr_scene_buffer_set_corner_radius(buffer, toplevel->corner_radius); wlr_scene_buffer_set_shadow_data(buffer, toplevel->shadow_data); + wlr_scene_buffer_set_backdrop_blur(buffer, true); + // TODO: `ADD_FUNCTION_HERE` + // Can be used to call `ADD_FUNCTION_HERE` to only blur e.g. + // the BACKGROUND and BOTTOM layers + wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false); } } } else if (node->type == WLR_SCENE_NODE_TREE) { diff --git a/types/fx/blur_data.c b/types/fx/blur_data.c new file mode 100644 index 0000000..28c40d7 --- /dev/null +++ b/types/fx/blur_data.c @@ -0,0 +1,17 @@ +#include "scenefx/types/fx/blur_data.h" + +struct blur_data blur_data_get_default(void) { + return (struct blur_data) { + .radius = 0, + .num_passes = 0, + .ignore_transparent = true, + }; +} + +bool scene_buffer_should_blur(bool backdrop_blur, struct blur_data *blur_data) { + return backdrop_blur && blur_data->radius > 0 && blur_data->num_passes > 0; +} + +int blur_data_calc_size(struct blur_data *blur_data) { + return pow(2, blur_data->num_passes + 1) * blur_data->radius; +} diff --git a/types/fx/meson.build b/types/fx/meson.build index b7f0207..2170f35 100644 --- a/types/fx/meson.build +++ b/types/fx/meson.build @@ -1,3 +1,4 @@ wlr_files += files( - 'shadow_data.c' + 'shadow_data.c', + 'blur_data.c', ) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 266dc63..b027062 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -17,6 +17,8 @@ #include #include "render/pass.h" +#include "render/fx_renderer/fx_renderer.h" +#include "scenefx/types/fx/blur_data.h" #include "scenefx/types/fx/shadow_data.h" #include "types/wlr_buffer.h" #include "types/wlr_output.h" @@ -176,6 +178,8 @@ struct wlr_scene *wlr_scene_create(void) { scene->direct_scanout = !env_parse_bool("WLR_SCENE_DISABLE_DIRECT_SCANOUT"); scene->calculate_visibility = !env_parse_bool("WLR_SCENE_DISABLE_VISIBILITY"); + scene->blur_data = blur_data_get_default(); + return scene; } @@ -256,14 +260,6 @@ static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y, return; } - if (scene_buffer->corner_radius > 0) { - return; - } - - if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { - return; - } - if (!buffer_is_opaque(scene_buffer->buffer)) { pixman_region32_copy(opaque, &scene_buffer->opaque_region); pixman_region32_intersect_rect(opaque, opaque, 0, 0, width, height); @@ -644,8 +640,11 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, wl_signal_init(&scene_buffer->events.frame_done); pixman_region32_init(&scene_buffer->opaque_region); scene_buffer->opacity = 1; + scene_buffer->corner_radius = 0; scene_buffer->shadow_data = shadow_data_get_default(); + scene_buffer->backdrop_blur = false; + scene_buffer->backdrop_blur_optimized = false; scene_node_update(&scene_buffer->node, NULL); @@ -893,6 +892,38 @@ void wlr_scene_buffer_set_shadow_data(struct wlr_scene_buffer *scene_buffer, scene_node_update(&scene_buffer->node, NULL); } +void wlr_scene_buffer_set_backdrop_blur(struct wlr_scene_buffer *scene_buffer, + bool enabled) { + if (scene_buffer->backdrop_blur != enabled) { + scene_buffer->backdrop_blur = enabled; + // Mark the blur buffers as dirty + struct wlr_scene *scene = scene_node_get_root(&scene_buffer->node); + struct wlr_scene_output *current_output; + wl_list_for_each(current_output, &scene->outputs, link) { + struct wlr_output *output = current_output->output; + struct fx_renderer *renderer = fx_get_renderer(output->renderer); + renderer->blur_buffer_dirty = true; + } + scene_node_update(&scene->tree.node, NULL); + } +} + +void wlr_scene_buffer_set_backdrop_blur_optimized(struct wlr_scene_buffer *scene_buffer, + bool enabled) { + if (scene_buffer->backdrop_blur_optimized != enabled) { + scene_buffer->backdrop_blur_optimized = enabled; + // Mark the blur buffers as dirty + struct wlr_scene *scene = scene_node_get_root(&scene_buffer->node); + struct wlr_scene_output *current_output; + wl_list_for_each(current_output, &scene->outputs, link) { + struct wlr_output *output = current_output->output; + struct fx_renderer *renderer = fx_get_renderer(output->renderer); + renderer->blur_buffer_dirty = true; + } + scene_node_update(&scene->tree.node, NULL); + } +} + static struct wlr_texture *scene_buffer_get_texture( struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) { struct wlr_client_buffer *client_buffer = @@ -1282,20 +1313,6 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren wlr_output_transform_invert(scene_buffer->transform); transform = wlr_output_transform_compose(transform, data->transform); - // Shadow - if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { - struct fx_render_rect_options shadow_options = { - .base = { - .box = xdg_box, - .clip = &render_region, // Render with the original extended clip region - }, - .scale = data->scale, - }; - fx_render_pass_add_box_shadow(data->render_pass, &shadow_options, - scene_buffer->corner_radius * data->scale, - &scene_buffer->shadow_data); - } - struct fx_render_texture_options tex_options = { .base = (struct wlr_render_texture_options){ .texture = texture, @@ -1311,7 +1328,60 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .scale = data->scale, .clip_box = &xdg_box, .corner_radius = scene_buffer->corner_radius * data->scale, + .discard_transparent = false, }; + + // Blur + struct wlr_scene *scene = data->output->scene; + if (scene_buffer_should_blur(scene_buffer->backdrop_blur, &scene->blur_data)) { + pixman_region32_t opaque_region; + pixman_region32_init(&opaque_region); + + bool has_alpha = false; + if (scene_buffer->opacity < 1.0) { + has_alpha = true; + pixman_region32_union_rect(&opaque_region, &opaque_region, 0, 0, 0, 0); + } else { + struct wlr_scene_surface *scene_surface + = wlr_scene_surface_try_from_buffer(scene_buffer); + has_alpha = !scene_surface->surface->opaque; + pixman_region32_copy(&opaque_region, &scene_surface->surface->opaque_region); + } + + if (has_alpha) { + struct wlr_output *output = data->output->output; + int width, height; + wlr_output_transformed_resolution(output, &width, &height); + struct wlr_box monitor_box = { 0, 0, width, height }; + wlr_box_transform(&monitor_box, &monitor_box, + wlr_output_transform_invert(output->transform), + monitor_box.width, monitor_box.height); + struct fx_render_blur_options blur_options = { + .tex_options = tex_options, + .scene_buffer = scene_buffer, + .monitor_box = monitor_box, + .blur_data = &scene->blur_data, + }; + fx_render_pass_add_blur(data->render_pass, &blur_options); + + } + pixman_region32_fini(&opaque_region); + } + + // Shadow + if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { + struct fx_render_rect_options shadow_options = { + .base = { + .box = xdg_box, + .clip = &render_region, // Render with the original extended clip region + }, + .scale = data->scale, + }; + fx_render_pass_add_box_shadow(data->render_pass, &shadow_options, + scene_buffer->corner_radius * data->scale, + &scene_buffer->shadow_data); + } + fx_render_pass_add_texture(data->render_pass, &tex_options); struct wlr_scene_output_sample_event sample_event = { @@ -1344,6 +1414,29 @@ void wlr_scene_set_presentation(struct wlr_scene *scene, wl_signal_add(&presentation->events.destroy, &scene->presentation_destroy); } +void wlr_scene_set_blur_data(struct wlr_scene *scene, struct blur_data blur_data) { + struct blur_data *buff_data = &scene->blur_data; + if (buff_data->radius == blur_data.radius && + buff_data->num_passes && blur_data.num_passes) { + return; + } + + memcpy(&scene->blur_data, &blur_data, + sizeof(struct blur_data)); + // Mark the blur buffers as dirty + struct wlr_scene_output *current_output; + wl_list_for_each(current_output, &scene->outputs, link) { + struct wlr_output *output = current_output->output; + struct fx_renderer *renderer = fx_get_renderer(output->renderer); + renderer->blur_buffer_dirty = true; + } + scene_node_update(&scene->tree.node, NULL); +} + +static bool wlr_scene_should_blur(struct wlr_scene *scene) { + return scene->blur_data.radius > 0 && scene->blur_data.num_passes > 0; +} + static void scene_handle_linux_dmabuf_v1_destroy(struct wl_listener *listener, void *data) { struct wlr_scene *scene = @@ -1733,6 +1826,55 @@ static bool scene_entry_try_direct_scanout(struct render_list_entry *entry, return true; } +struct blur_info { + bool has_blur; + bool has_optimized; +}; + +static struct blur_info workspace_get_blur_info(int list_len, + struct render_list_entry *list_data, struct wlr_scene_output *scene_output, + pixman_region32_t *blur_region) { + // TODO: Check if a check for "is current workspace" is also needed + if (!wlr_scene_should_blur(scene_output->scene)) { + return (struct blur_info) { + .has_blur = false, + .has_optimized = false, + }; + } + + bool has_optimized = false; + for (int i = list_len - 1; i >= 0; i--) { + struct wlr_scene_node *node = list_data[i].node; + switch (node->type) { + case WLR_SCENE_NODE_BUFFER:; + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_try_from_buffer(scene_buffer); + assert(scene_buffer->buffer); + if (scene_buffer->backdrop_blur && scene_surface && + !scene_surface->surface->opaque) { + int x, y; + wlr_scene_node_coords(node, &x, &y); + pixman_region32_union_rect(blur_region, blur_region, + (x - scene_output->x) * scene_output->output->scale, + (y - scene_output->y) * scene_output->output->scale, + scene_buffer->dst_width * scene_output->output->scale, + scene_buffer->dst_height * scene_output->output->scale); + if (scene_buffer->backdrop_blur_optimized) { + has_optimized = true; + } + } + break; + default: + break; + } + } + return (struct blur_info) { + .has_blur = pixman_region32_not_empty(blur_region), + .has_optimized = has_optimized, + }; +} + bool wlr_scene_output_commit(struct wlr_scene_output *scene_output, const struct wlr_scene_output_state_options *options) { if (!scene_output->output->needs_frame && !pixman_region32_not_empty( @@ -1918,9 +2060,10 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, timer->pre_render_duration = timespec_to_nsec(&duration); } + struct fx_renderer *renderer = fx_get_renderer(output->renderer); struct fx_gles_render_pass *render_pass = - fx_renderer_begin_buffer_pass(output->renderer, buffer, - &(struct wlr_buffer_pass_options){ + fx_renderer_begin_buffer_pass(output->renderer, buffer, output, + &(struct wlr_buffer_pass_options) { .timer = timer ? timer->render_timer : NULL, } ); @@ -1934,6 +2077,61 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring, buffer_age, &render_data.damage); + // Blur artifact prevention + pixman_region32_t *damage = &render_data.damage; + pixman_region32_t blur_region; + pixman_region32_init(&blur_region); + struct blur_info blur_info = + workspace_get_blur_info(list_len, list_data, scene_output, &blur_region); + // Expand the damage to compensate for blur + if (blur_info.has_blur) { + // Skip the blur artifact prevention if damaging the whole viewport + if (renderer->blur_buffer_dirty) { + // Needs to be extended before clearing + pixman_region32_union_rect(&render_data.damage, &render_data.damage, + 0, 0, output->width, output->height); + } else { + // copy the surrounding content where the blur would display artifacts + // and draw it above the artifacts + struct blur_data *blur_data = &scene_output->scene->blur_data; + int output_width, output_height; + wlr_output_transformed_resolution(output, &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); + } else { + // Expand the original damage to compensate for surrounding + // blurred views to avoid sharp edges between damage regions + wlr_region_expand(damage, damage, blur_data_calc_size(blur_data)); + } + + 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, blur_data_calc_size(blur_data)); + // 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_renderer_read_to_buffer(render_pass, &renderer->wlr_renderer, &renderer->blur_padding_region, + renderer->blur_saved_pixels_buffer, render_pass->buffer); + } + } + pixman_region32_fini(&blur_region); + pixman_region32_t background; pixman_region32_init(&background); pixman_region32_copy(&background, &render_data.damage); @@ -1980,6 +2178,8 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, for (int i = list_len - 1; i >= 0; i--) { struct render_list_entry *entry = &list_data[i]; + // TODO: Implement dirty + renderer->blur_buffer_dirty = false; scene_entry_render(entry, &render_data); if (entry->node->type == WLR_SCENE_NODE_BUFFER) { @@ -1996,6 +2196,14 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, } } + // Not needed if we damaged the whole viewport + if (!renderer->blur_buffer_dirty) { + // TODO: Investigate blitting instead + // Render the saved pixels over the blur artifacts + fx_renderer_read_to_buffer(render_pass, &renderer->wlr_renderer, &renderer->blur_padding_region, + render_pass->buffer, renderer->blur_saved_pixels_buffer); + } + if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { struct highlight_region *damage; wl_list_for_each(damage, &scene_output->damage_highlight_regions, link) { From d4ce9fbd7b4a8ee0c4502065a6d1a954a5d6a577 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Mon, 29 Jan 2024 15:59:37 +0100 Subject: [PATCH 02/18] Added additional blur effects from SwayFX --- include/render/fx_renderer/shaders.h | 13 +++ include/scenefx/types/fx/blur_data.h | 8 ++ render/fx_renderer/fx_pass.c | 81 +++++++++++++++++++ .../gles2/shaders/blur_effects.frag | 60 ++++++++++++++ render/fx_renderer/gles2/shaders/meson.build | 1 + render/fx_renderer/shaders.c | 24 ++++++ types/fx/blur_data.c | 25 +++++- types/scene/wlr_scene.c | 3 +- 8 files changed, 211 insertions(+), 4 deletions(-) create mode 100644 render/fx_renderer/gles2/shaders/blur_effects.frag diff --git a/include/render/fx_renderer/shaders.h b/include/render/fx_renderer/shaders.h index fa458f7..b1ae247 100644 --- a/include/render/fx_renderer/shaders.h +++ b/include/render/fx_renderer/shaders.h @@ -71,6 +71,18 @@ struct blur_shader { GLint halfpixel; }; +struct blur_effects_shader { + GLuint program; + GLint proj; + GLint tex_proj; + GLint tex; + GLint pos_attrib; + GLfloat noise; + GLfloat brightness; + GLfloat contrast; + GLfloat saturation; +}; + struct shaders { struct quad_shader quad; struct tex_shader tex_rgba; @@ -80,6 +92,7 @@ struct shaders { struct stencil_mask_shader stencil_mask; struct blur_shader blur1; struct blur_shader blur2; + struct blur_effects_shader blur_effects; }; bool link_shaders(struct fx_renderer *renderer); diff --git a/include/scenefx/types/fx/blur_data.h b/include/scenefx/types/fx/blur_data.h index 5d5d29b..0dba533 100644 --- a/include/scenefx/types/fx/blur_data.h +++ b/include/scenefx/types/fx/blur_data.h @@ -7,6 +7,10 @@ struct blur_data { int num_passes; int radius; + float noise; + float brightness; + float contrast; + float saturation; bool ignore_transparent; }; @@ -14,6 +18,10 @@ struct blur_data blur_data_get_default(void); bool scene_buffer_should_blur(bool backdrop_blur, struct blur_data *blur_data); +bool blur_data_should_parameters_blur_effects(struct blur_data *blur_data); + +bool blur_data_cmp(struct blur_data *a, struct blur_data *b); + int blur_data_calc_size(struct blur_data *blur_data); #endif diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index cda0335..f7b2765 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -525,6 +525,67 @@ static void render_blur_segments(struct fx_gles_render_pass *pass, } } +static void render_blur_effects(struct fx_gles_render_pass *pass, + struct fx_render_blur_options *fx_options) { + struct fx_render_texture_options *tex_options = &fx_options->tex_options; + struct wlr_render_texture_options *options = &tex_options->base; + + check_tex_src_box(options); + + struct fx_renderer *renderer = pass->buffer->renderer; + struct blur_data *blur_data = fx_options->blur_data; + struct fx_texture *texture = fx_get_texture(options->texture); + + struct blur_effects_shader shader = renderer->shaders.blur_effects; + + struct wlr_box dst_box; + struct wlr_fbox src_fbox; + wlr_render_texture_options_get_src_box(options, &src_fbox); + wlr_render_texture_options_get_dst_box(options, &dst_box); + + src_fbox.x /= options->texture->width; + src_fbox.y /= options->texture->height; + src_fbox.width /= options->texture->width; + src_fbox.height /= options->texture->height; + + glDisable(GL_BLEND); + glDisable(GL_STENCIL_TEST); + + push_fx_debug(renderer); + + glUseProgram(shader.program); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex); + + switch (options->filter_mode) { + case WLR_SCALE_FILTER_BILINEAR: + glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + case WLR_SCALE_FILTER_NEAREST: + glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + } + + glUniform1i(shader.tex, 0); + glUniform1f(shader.noise, blur_data->noise); + glUniform1f(shader.brightness, blur_data->brightness); + glUniform1f(shader.contrast, blur_data->contrast); + glUniform1f(shader.saturation, blur_data->saturation); + + set_proj_matrix(shader.proj, pass->projection_matrix, &dst_box); + set_tex_matrix(shader.tex_proj, options->transform, &src_fbox); + + render(&dst_box, options->clip, shader.pos_attrib); + + glBindTexture(texture->target, 0); + pop_fx_debug(renderer); + + wlr_texture_destroy(options->texture); +} + // Blurs the main_buffer content and returns the blurred framebuffer static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *pass, struct fx_renderer *renderer, struct fx_render_blur_options *fx_options, @@ -572,6 +633,26 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p } pixman_region32_fini(&scaled_damage); + + // Render additional blur effects like saturation, noise, contrast, etc... + if (blur_data_should_parameters_blur_effects(blur_data) + && pixman_region32_not_empty(&damage)) { + if (current_buffer == renderer->effects_buffer) { + fx_framebuffer_bind(renderer->effects_buffer_swapped); + } else { + fx_framebuffer_bind(renderer->effects_buffer); + } + fx_options->tex_options.base.clip = &damage; + fx_options->tex_options.base.texture = fx_texture_from_buffer( + &renderer->wlr_renderer, current_buffer->buffer); + render_blur_effects(pass, fx_options); + if (current_buffer != renderer->effects_buffer) { + current_buffer = renderer->effects_buffer; + } else { + current_buffer = renderer->effects_buffer_swapped; + } + } + pixman_region32_fini(&damage); // Bind back to the default buffer diff --git a/render/fx_renderer/gles2/shaders/blur_effects.frag b/render/fx_renderer/gles2/shaders/blur_effects.frag new file mode 100644 index 0000000..fcead5d --- /dev/null +++ b/render/fx_renderer/gles2/shaders/blur_effects.frag @@ -0,0 +1,60 @@ +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif + +varying vec2 v_texcoord; + +uniform sampler2D tex; + +uniform float noise; +uniform float brightness; +uniform float contrast; +uniform float saturation; + +mat4 brightnessMatrix() { + float b = brightness - 1.0; + return mat4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + b, b, b, 1); +} + +mat4 contrastMatrix() { + float t = (1.0 - contrast) / 2.0; + return mat4(contrast, 0, 0, 0, + 0, contrast, 0, 0, + 0, 0, contrast, 0, + t, t, t, 1); +} + +mat4 saturationMatrix() { + vec3 luminance = vec3(0.3086, 0.6094, 0.0820); + float oneMinusSat = 1.0 - saturation; + vec3 red = vec3(luminance.x * oneMinusSat); + red+= vec3(saturation, 0, 0); + vec3 green = vec3(luminance.y * oneMinusSat); + green += vec3(0, saturation, 0); + vec3 blue = vec3(luminance.z * oneMinusSat); + blue += vec3(0, 0, saturation); + return mat4(red, 0, + green, 0, + blue, 0, + 0, 0, 0, 1); +} + +// Fast generative noise function +float hash(vec2 p) { + return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); +} + +void main() { + vec4 color = texture2D(tex, v_texcoord); + color *= brightnessMatrix() * contrastMatrix() * saturationMatrix(); + float noiseHash = hash(v_texcoord); + float noiseAmount = (mod(noiseHash, 1.0) - 0.5); + color.rgb += noiseAmount * noise; + + gl_FragColor = color; +} diff --git a/render/fx_renderer/gles2/shaders/meson.build b/render/fx_renderer/gles2/shaders/meson.build index a95d69b..a751e1a 100644 --- a/render/fx_renderer/gles2/shaders/meson.build +++ b/render/fx_renderer/gles2/shaders/meson.build @@ -8,6 +8,7 @@ shaders = [ 'stencil_mask.frag', 'blur1.frag', 'blur2.frag', + 'blur_effects.frag', ] foreach name : shaders diff --git a/render/fx_renderer/shaders.c b/render/fx_renderer/shaders.c index 52e2069..8705c6d 100644 --- a/render/fx_renderer/shaders.c +++ b/render/fx_renderer/shaders.c @@ -14,6 +14,7 @@ #include "box_shadow_frag_src.h" #include "blur1_frag_src.h" #include "blur2_frag_src.h" +#include "blur_effects_frag_src.h" GLuint compile_shader(GLuint type, const GLchar *src) { GLuint shader = glCreateShader(type); @@ -187,6 +188,24 @@ static bool link_blur_program(struct blur_shader *shader, const char *shader_pro return true; } +static bool link_blur_effects_program(struct blur_effects_shader *shader) { + GLuint prog; + shader->program = prog = link_program(blur_effects_frag_src); + if (!shader->program) { + return false; + } + shader->proj = glGetUniformLocation(prog, "proj"); + shader->tex = glGetUniformLocation(prog, "tex"); + shader->pos_attrib = glGetAttribLocation(prog, "pos"); + shader->tex_proj = glGetUniformLocation(prog, "tex_proj"); + shader->noise = glGetUniformLocation(prog, "noise"); + shader->brightness = glGetUniformLocation(prog, "brightness"); + shader->contrast = glGetUniformLocation(prog, "contrast"); + shader->saturation = glGetUniformLocation(prog, "saturation"); + + return true; +} + bool link_shaders(struct fx_renderer *renderer) { // quad fragment shader if (!link_quad_program(&renderer->shaders.quad)) { @@ -227,6 +246,10 @@ bool link_shaders(struct fx_renderer *renderer) { wlr_log(WLR_ERROR, "Could not link blur2 shader"); goto error; } + if (!link_blur_effects_program(&renderer->shaders.blur_effects)) { + wlr_log(WLR_ERROR, "Could not link blur_effects shader"); + goto error; + } return true; @@ -239,6 +262,7 @@ bool link_shaders(struct fx_renderer *renderer) { glDeleteProgram(renderer->shaders.box_shadow.program); glDeleteProgram(renderer->shaders.blur1.program); glDeleteProgram(renderer->shaders.blur2.program); + glDeleteProgram(renderer->shaders.blur_effects.program); return false; } diff --git a/types/fx/blur_data.c b/types/fx/blur_data.c index 28c40d7..a7e328e 100644 --- a/types/fx/blur_data.c +++ b/types/fx/blur_data.c @@ -2,9 +2,13 @@ struct blur_data blur_data_get_default(void) { return (struct blur_data) { - .radius = 0, - .num_passes = 0, + .radius = 5, + .num_passes = 3, .ignore_transparent = true, + .noise = 0.02, + .brightness = 0.9, + .contrast = 0.9, + .saturation = 1.1, }; } @@ -12,6 +16,23 @@ bool scene_buffer_should_blur(bool backdrop_blur, struct blur_data *blur_data) { return backdrop_blur && blur_data->radius > 0 && blur_data->num_passes > 0; } +bool blur_data_should_parameters_blur_effects(struct blur_data *blur_data) { + return blur_data->brightness != 1.0f + || blur_data->saturation != 1.0f + || blur_data->contrast != 1.0f + || blur_data->noise > 0.0f; +} + +bool blur_data_cmp(struct blur_data *a, struct blur_data *b) { + return a->radius == b->radius && + a->num_passes && b->num_passes && + a->ignore_transparent == b->ignore_transparent && + a->noise == b->noise && + a->brightness == b->brightness && + a->contrast == b->contrast && + a->saturation == b->saturation; +} + int blur_data_calc_size(struct blur_data *blur_data) { return pow(2, blur_data->num_passes + 1) * blur_data->radius; } diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index b027062..076a799 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1416,8 +1416,7 @@ void wlr_scene_set_presentation(struct wlr_scene *scene, void wlr_scene_set_blur_data(struct wlr_scene *scene, struct blur_data blur_data) { struct blur_data *buff_data = &scene->blur_data; - if (buff_data->radius == blur_data.radius && - buff_data->num_passes && blur_data.num_passes) { + if (blur_data_cmp(buff_data, &blur_data)) { return; } From 12cfaef281949d80d44b702e768a88b29b5a76fe Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:32:28 +0100 Subject: [PATCH 03/18] Simplified blur pass functions to match the other pass functions --- render/fx_renderer/fx_pass.c | 42 +++++++++++++++++------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index f7b2765..0feb2c6 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -440,12 +440,13 @@ void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass, pop_fx_debug(renderer); } -/* Renders the blur for each damaged rect and swaps the buffer */ +// Renders the blur for each damaged rect and swaps the buffer static void render_blur_segments(struct fx_gles_render_pass *pass, - struct fx_renderer *renderer, struct fx_render_blur_options *fx_options, - struct fx_framebuffer **buffer, struct blur_shader* shader) { + struct fx_render_blur_options *fx_options, struct fx_framebuffer **buffer, + struct blur_shader* shader) { struct fx_render_texture_options *tex_options = &fx_options->tex_options; struct wlr_render_texture_options *options = &tex_options->base; + struct fx_renderer *renderer = pass->buffer->renderer; struct blur_data *blur_data = fx_options->blur_data; // Swap fbo @@ -455,10 +456,8 @@ static void render_blur_segments(struct fx_gles_render_pass *pass, fx_framebuffer_bind(renderer->effects_buffer); } - options->texture = - fx_texture_from_buffer( &renderer->wlr_renderer, (*buffer)->buffer); - struct fx_texture_attribs attribs; - fx_texture_get_attribs(options->texture, &attribs); + options->texture = fx_texture_from_buffer(&renderer->wlr_renderer, (*buffer)->buffer); + struct fx_texture *texture = fx_get_texture(options->texture); /* * Render @@ -481,16 +480,16 @@ static void render_blur_segments(struct fx_gles_render_pass *pass, glUseProgram(shader->program); glActiveTexture(GL_TEXTURE0); - glBindTexture(attribs.target, attribs.tex); + glBindTexture(texture->target, texture->tex); switch (options->filter_mode) { case WLR_SCALE_FILTER_BILINEAR: - glTexParameteri(attribs.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(attribs.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break; case WLR_SCALE_FILTER_NEAREST: - glTexParameteri(attribs.target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(attribs.target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); break; } @@ -512,12 +511,12 @@ static void render_blur_segments(struct fx_gles_render_pass *pass, render(&dst_box, options->clip, shader->pos_attrib); - glBindTexture(attribs.target, 0); + glBindTexture(texture->target, 0); pop_fx_debug(renderer); wlr_texture_destroy(options->texture); - // Swap buffer + // Swap buffer. We don't want to draw to the same buffer if (*buffer != renderer->effects_buffer) { *buffer = renderer->effects_buffer; } else { @@ -588,13 +587,13 @@ static void render_blur_effects(struct fx_gles_render_pass *pass, // Blurs the main_buffer content and returns the blurred framebuffer static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *pass, - struct fx_renderer *renderer, struct fx_render_blur_options *fx_options, - pixman_region32_t *original_damage) { + struct fx_render_blur_options *fx_options) { + struct fx_renderer *renderer = pass->buffer->renderer; struct blur_data *blur_data = fx_options->blur_data; pixman_region32_t damage; pixman_region32_init(&damage); - pixman_region32_copy(&damage, original_damage); + pixman_region32_copy(&damage, fx_options->tex_options.base.clip); wlr_region_transform(&damage, &damage, fx_options->tex_options.base.transform, fx_options->monitor_box.width, fx_options->monitor_box.height); @@ -620,16 +619,14 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p // Downscale for (int i = 0; i < blur_data->num_passes; ++i) { wlr_region_scale(&scaled_damage, &damage, 1.0f / (1 << (i + 1))); - render_blur_segments(pass, renderer, fx_options, ¤t_buffer, - &renderer->shaders.blur1); + render_blur_segments(pass, fx_options, ¤t_buffer, &renderer->shaders.blur1); } // Upscale for (int i = blur_data->num_passes - 1; i >= 0; --i) { // when upsampling we make the region twice as big wlr_region_scale(&scaled_damage, &damage, 1.0f / (1 << i)); - render_blur_segments(pass, renderer, fx_options, ¤t_buffer, - &renderer->shaders.blur2); + render_blur_segments(pass, fx_options, ¤t_buffer, &renderer->shaders.blur2); } pixman_region32_fini(&scaled_damage); @@ -689,7 +686,8 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, // Render the blur into its own buffer struct fx_render_blur_options blur_options = *fx_options; - buffer = get_main_buffer_blur(pass, renderer, &blur_options, &translucent_region); + blur_options.tex_options.base.clip = &translucent_region; + buffer = get_main_buffer_blur(pass, &blur_options); } struct wlr_texture *wlr_texture = fx_texture_from_buffer(&renderer->wlr_renderer, buffer->buffer); From 9e9a5a84816407a3cdede64cd47f8fc8978fae8c Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Fri, 2 Feb 2024 18:29:59 +0100 Subject: [PATCH 04/18] Minor fixes --- include/render/pass.h | 5 +++-- render/fx_renderer/fx_pass.c | 8 +++++--- render/fx_renderer/gles2/shaders/blur1.frag | 3 --- render/fx_renderer/gles2/shaders/blur2.frag | 3 --- types/scene/wlr_scene.c | 4 ++-- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/include/render/pass.h b/include/render/pass.h index 1edac24..1094544 100644 --- a/include/render/pass.h +++ b/include/render/pass.h @@ -84,7 +84,8 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, /** * Render from one buffer to another */ -void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass, struct wlr_renderer *renderer, - pixman_region32_t *region, struct fx_framebuffer *dst_buffer, struct fx_framebuffer *src_buffer); +void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass, + pixman_region32_t *region, struct fx_framebuffer *dst_buffer, + struct fx_framebuffer *src_buffer); #endif diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index 0feb2c6..f92a53e 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -727,13 +727,15 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, pixman_region32_fini(&translucent_region); } -void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass, struct wlr_renderer *renderer, - pixman_region32_t *region, struct fx_framebuffer *dst_buffer, struct fx_framebuffer *src_buffer) { +void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass, + pixman_region32_t *region, struct fx_framebuffer *dst_buffer, + struct fx_framebuffer *src_buffer) { if (!pixman_region32_not_empty(region)) { return; } - struct wlr_texture *src_tex = fx_texture_from_buffer(renderer, src_buffer->buffer); + struct wlr_texture *src_tex = + fx_texture_from_buffer(&pass->buffer->renderer->wlr_renderer, src_buffer->buffer); if (src_tex == NULL) { return; } diff --git a/render/fx_renderer/gles2/shaders/blur1.frag b/render/fx_renderer/gles2/shaders/blur1.frag index 4545b0c..e7cb1be 100644 --- a/render/fx_renderer/gles2/shaders/blur1.frag +++ b/render/fx_renderer/gles2/shaders/blur1.frag @@ -15,7 +15,4 @@ void main() { sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius); gl_FragColor = sum / 8.0; - - // REMOVE - // gl_FragColor = texture2D(tex, uv); } diff --git a/render/fx_renderer/gles2/shaders/blur2.frag b/render/fx_renderer/gles2/shaders/blur2.frag index 263c8f6..3755a29 100644 --- a/render/fx_renderer/gles2/shaders/blur2.frag +++ b/render/fx_renderer/gles2/shaders/blur2.frag @@ -19,7 +19,4 @@ void main() { sum += texture2D(tex, uv + vec2(-halfpixel.x, -halfpixel.y) * radius) * 2.0; gl_FragColor = sum / 12.0; - - // REMOVE - // gl_FragColor = texture2D(tex, uv); } diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 076a799..3842736 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -2125,7 +2125,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, pixman_region32_fini(&extended_damage); // Capture the padding pixels before blur for later use - fx_renderer_read_to_buffer(render_pass, &renderer->wlr_renderer, &renderer->blur_padding_region, + fx_renderer_read_to_buffer(render_pass, &renderer->blur_padding_region, renderer->blur_saved_pixels_buffer, render_pass->buffer); } } @@ -2199,7 +2199,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, if (!renderer->blur_buffer_dirty) { // TODO: Investigate blitting instead // Render the saved pixels over the blur artifacts - fx_renderer_read_to_buffer(render_pass, &renderer->wlr_renderer, &renderer->blur_padding_region, + fx_renderer_read_to_buffer(render_pass, &renderer->blur_padding_region, render_pass->buffer, renderer->blur_saved_pixels_buffer); } From 732555902e78f0e67eeb321a2c127c1fd9cb9714 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Fri, 2 Feb 2024 19:17:26 +0100 Subject: [PATCH 05/18] Added support for optimized blur --- include/render/fx_renderer/fx_renderer.h | 2 +- include/render/pass.h | 7 +++ include/scenefx/types/wlr_scene.h | 8 ++++ render/fx_renderer/fx_pass.c | 35 ++++++++++++--- types/scene/wlr_scene.c | 57 ++++++++++++------------ 5 files changed, 75 insertions(+), 34 deletions(-) diff --git a/include/render/fx_renderer/fx_renderer.h b/include/render/fx_renderer/fx_renderer.h index cce2b3a..70d746a 100644 --- a/include/render/fx_renderer/fx_renderer.h +++ b/include/render/fx_renderer/fx_renderer.h @@ -154,7 +154,7 @@ struct fx_renderer { uint32_t viewport_width, viewport_height; // Contains the blurred background for tiled windows - struct fx_framebuffer *blur_buffer; + struct fx_framebuffer *optimized_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 diff --git a/include/render/pass.h b/include/render/pass.h index 1094544..e264ef0 100644 --- a/include/render/pass.h +++ b/include/render/pass.h @@ -46,6 +46,7 @@ struct fx_render_rect_options fx_render_rect_options_default( struct fx_render_blur_options { struct fx_render_texture_options tex_options; struct wlr_scene_buffer *scene_buffer; + struct wlr_output *output; struct wlr_box monitor_box; struct blur_data *blur_data; }; @@ -81,6 +82,12 @@ void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass, void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, struct fx_render_blur_options *fx_options); +/** + * Render optimized blur. + */ +void fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass, + struct fx_render_blur_options *fx_options); + /** * Render from one buffer to another */ diff --git a/include/scenefx/types/wlr_scene.h b/include/scenefx/types/wlr_scene.h index e3893b2..e8fd960 100644 --- a/include/scenefx/types/wlr_scene.h +++ b/include/scenefx/types/wlr_scene.h @@ -483,6 +483,14 @@ void wlr_scene_buffer_set_backdrop_blur(struct wlr_scene_buffer *scene_buffer, void wlr_scene_buffer_set_backdrop_blur_optimized(struct wlr_scene_buffer *scene_buffer, bool enabled); +/** + * Tells the renderer to re-render the optimized blur. + * + * An example use would be to call this when a "static" node changes, like a + * wallpaper. + */ +void wlr_scene_optimized_blur_mark_dirty(struct wlr_scene *scene); + /** * Calls the buffer's frame_done signal. */ diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index f92a53e..cb98ef6 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -679,7 +679,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, goto damage_finish; } - struct fx_framebuffer *buffer = renderer->blur_buffer; + struct fx_framebuffer *buffer = renderer->optimized_blur_buffer; if (!buffer || !scene_buffer->backdrop_blur_optimized) { pixman_region32_translate(&translucent_region, dst_box.x, dst_box.y); pixman_region32_intersect(&translucent_region, &translucent_region, options->clip); @@ -708,10 +708,10 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, // Draw the blurred texture tex_options->base.dst_box = fx_options->monitor_box; tex_options->base.src_box = (struct wlr_fbox) { - .x = fx_options->monitor_box.x, - .y = fx_options->monitor_box.y, - .width = fx_options->monitor_box.width, - .height = fx_options->monitor_box.height, + .x = 0, + .y = 0, + .width = buffer->buffer->width, + .height = buffer->buffer->height, }; tex_options->base.texture = &blur_texture->wlr_texture; fx_render_pass_add_texture(pass, tex_options); @@ -727,6 +727,31 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, pixman_region32_fini(&translucent_region); } +void fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass, + struct fx_render_blur_options *fx_options) { + struct fx_renderer *renderer = pass->buffer->renderer; + struct wlr_box monitor_box = fx_options->monitor_box; + + pixman_region32_t fake_damage; + pixman_region32_init_rect(&fake_damage, 0, 0, monitor_box.width, monitor_box.height); + + // Render the blur into its own buffer + struct fx_render_blur_options blur_options = *fx_options; + blur_options.tex_options.base.clip = &fake_damage; + struct fx_framebuffer *buffer = get_main_buffer_blur(pass, &blur_options); + + // Update the optimized blur buffer if invalid + fx_framebuffer_get_or_create_bufferless(renderer, fx_options->output, + &renderer->optimized_blur_buffer); + + // Render the newly blurred content into the blur_buffer + fx_renderer_read_to_buffer(pass, &fake_damage, renderer->optimized_blur_buffer, buffer); + + pixman_region32_fini(&fake_damage); + + renderer->blur_buffer_dirty = false; +} + void fx_renderer_read_to_buffer(struct fx_gles_render_pass *pass, pixman_region32_t *region, struct fx_framebuffer *dst_buffer, struct fx_framebuffer *src_buffer) { diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 3842736..94a0820 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -896,15 +896,7 @@ void wlr_scene_buffer_set_backdrop_blur(struct wlr_scene_buffer *scene_buffer, bool enabled) { if (scene_buffer->backdrop_blur != enabled) { scene_buffer->backdrop_blur = enabled; - // Mark the blur buffers as dirty - struct wlr_scene *scene = scene_node_get_root(&scene_buffer->node); - struct wlr_scene_output *current_output; - wl_list_for_each(current_output, &scene->outputs, link) { - struct wlr_output *output = current_output->output; - struct fx_renderer *renderer = fx_get_renderer(output->renderer); - renderer->blur_buffer_dirty = true; - } - scene_node_update(&scene->tree.node, NULL); + wlr_scene_optimized_blur_mark_dirty(scene_node_get_root(&scene_buffer->node)); } } @@ -912,16 +904,23 @@ void wlr_scene_buffer_set_backdrop_blur_optimized(struct wlr_scene_buffer *scene bool enabled) { if (scene_buffer->backdrop_blur_optimized != enabled) { scene_buffer->backdrop_blur_optimized = enabled; - // Mark the blur buffers as dirty - struct wlr_scene *scene = scene_node_get_root(&scene_buffer->node); - struct wlr_scene_output *current_output; - wl_list_for_each(current_output, &scene->outputs, link) { - struct wlr_output *output = current_output->output; - struct fx_renderer *renderer = fx_get_renderer(output->renderer); - renderer->blur_buffer_dirty = true; - } - scene_node_update(&scene->tree.node, NULL); + wlr_scene_optimized_blur_mark_dirty(scene_node_get_root(&scene_buffer->node)); + } +} + +static void output_optimized_blur_mark_dirty(struct wlr_output *output) { + struct fx_renderer *renderer = fx_get_renderer(output->renderer); + renderer->blur_buffer_dirty = true; +} + +void wlr_scene_optimized_blur_mark_dirty(struct wlr_scene *scene) { + // Mark the blur buffers as dirty + struct wlr_scene_output *current_output; + wl_list_for_each(current_output, &scene->outputs, link) { + struct wlr_output *output = current_output->output; + output_optimized_blur_mark_dirty(output); } + scene_node_update(&scene->tree.node, NULL); } static struct wlr_texture *scene_buffer_get_texture( @@ -1359,9 +1358,16 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren struct fx_render_blur_options blur_options = { .tex_options = tex_options, .scene_buffer = scene_buffer, + .output = output, .monitor_box = monitor_box, .blur_data = &scene->blur_data, }; + // Re-render the optimized blur buffer when needed + if (data->render_pass->buffer->renderer->blur_buffer_dirty + && scene_buffer->backdrop_blur_optimized) { + fx_render_pass_add_optimized_blur(data->render_pass, &blur_options); + } + // Render the actual blur behind the surface fx_render_pass_add_blur(data->render_pass, &blur_options); } @@ -1422,14 +1428,8 @@ void wlr_scene_set_blur_data(struct wlr_scene *scene, struct blur_data blur_data memcpy(&scene->blur_data, &blur_data, sizeof(struct blur_data)); - // Mark the blur buffers as dirty - struct wlr_scene_output *current_output; - wl_list_for_each(current_output, &scene->outputs, link) { - struct wlr_output *output = current_output->output; - struct fx_renderer *renderer = fx_get_renderer(output->renderer); - renderer->blur_buffer_dirty = true; - } - scene_node_update(&scene->tree.node, NULL); + + wlr_scene_optimized_blur_mark_dirty(scene); } static bool wlr_scene_should_blur(struct wlr_scene *scene) { @@ -1484,6 +1484,9 @@ static void scene_output_update_geometry(struct wlr_scene_output *scene_output, wlr_damage_ring_add_whole(&scene_output->damage_ring); wlr_output_schedule_frame(scene_output->output); + // Re-render the optimized blur when the output is changed + output_optimized_blur_mark_dirty(scene_output->output); + scene_node_output_update(&scene_output->scene->tree.node, &scene_output->scene->outputs, NULL, force_update ? scene_output : NULL); } @@ -2177,8 +2180,6 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, for (int i = list_len - 1; i >= 0; i--) { struct render_list_entry *entry = &list_data[i]; - // TODO: Implement dirty - renderer->blur_buffer_dirty = false; scene_entry_render(entry, &render_data); if (entry->node->type == WLR_SCENE_NODE_BUFFER) { From 2976de244fc29a8e8735df7634f1f9fee721b564 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Fri, 2 Feb 2024 19:25:50 +0100 Subject: [PATCH 06/18] tinywl: Don't set decoration values every frame --- tinywl/tinywl.c | 82 +++++++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 51 deletions(-) diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index dd83e44..1b482ca 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -557,55 +557,6 @@ static void server_cursor_frame(struct wl_listener *listener, void *data) { wlr_seat_pointer_notify_frame(server->seat); } -static void output_configure_scene(struct wlr_scene_node *node, - struct tinywl_toplevel *toplevel) { - if (!node->enabled) { - return; - } - - struct tinywl_toplevel *_toplevel = node->data; - if (_toplevel) { - toplevel = _toplevel; - } - - if (node->type == WLR_SCENE_NODE_BUFFER) { - struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); - - struct wlr_scene_surface * scene_surface = - wlr_scene_surface_try_from_buffer(buffer); - if (!scene_surface) { - return; - } - - struct wlr_xdg_surface *xdg_surface = - wlr_xdg_surface_try_from_wlr_surface(scene_surface->surface); - - if (toplevel && - xdg_surface && - xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - // TODO: Be able to set whole decoration_data instead of calling - // each individually? - wlr_scene_buffer_set_opacity(buffer, toplevel->opacity); - - if (!wlr_subsurface_try_from_wlr_surface(xdg_surface->surface)) { - wlr_scene_buffer_set_corner_radius(buffer, toplevel->corner_radius); - wlr_scene_buffer_set_shadow_data(buffer, toplevel->shadow_data); - wlr_scene_buffer_set_backdrop_blur(buffer, true); - // TODO: `ADD_FUNCTION_HERE` - // Can be used to call `ADD_FUNCTION_HERE` to only blur e.g. - // the BACKGROUND and BOTTOM layers - wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false); - } - } - } else if (node->type == WLR_SCENE_NODE_TREE) { - struct wlr_scene_tree *tree = wl_container_of(node, tree, node); - struct wlr_scene_node *node; - wl_list_for_each(node, &tree->children, link) { - output_configure_scene(node, toplevel); - } - } -} - static void output_frame(struct wl_listener *listener, void *data) { /* This function is called every time an output is ready to display a frame, * generally at the output's refresh rate (e.g. 60Hz). */ @@ -615,8 +566,6 @@ static void output_frame(struct wl_listener *listener, void *data) { struct wlr_scene_output *scene_output = wlr_scene_get_scene_output( scene, output->wlr_output); - output_configure_scene(&scene_output->scene->tree.node, NULL); - /* Render the scene if needed and commit the output */ wlr_scene_output_commit(scene_output, NULL); @@ -708,10 +657,41 @@ static void server_new_output(struct wl_listener *listener, void *data) { wlr_scene_output_layout_add_output(server->scene_layout, l_output, scene_output); } +static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int sx, + int sy, void *user_data) { + struct tinywl_toplevel *toplevel = user_data; + + struct wlr_scene_surface * scene_surface = wlr_scene_surface_try_from_buffer(buffer); + if (!scene_surface) { + return; + } + + struct wlr_xdg_surface *xdg_surface = + wlr_xdg_surface_try_from_wlr_surface(scene_surface->surface); + if (toplevel && + xdg_surface && + xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + // TODO: Be able to set whole decoration_data instead of calling + // each individually? + wlr_scene_buffer_set_opacity(buffer, toplevel->opacity); + + if (!wlr_subsurface_try_from_wlr_surface(xdg_surface->surface)) { + wlr_scene_buffer_set_corner_radius(buffer, toplevel->corner_radius); + wlr_scene_buffer_set_shadow_data(buffer, toplevel->shadow_data); + + wlr_scene_buffer_set_backdrop_blur(buffer, true); + wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false); + } + } +} + static void xdg_toplevel_map(struct wl_listener *listener, void *data) { /* Called when the surface is mapped, or ready to display on-screen. */ struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, map); + wlr_scene_node_for_each_buffer(&toplevel->scene_tree->node, + iter_xdg_scene_buffers, toplevel); + wl_list_insert(&toplevel->server->toplevels, &toplevel->link); focus_toplevel(toplevel, toplevel->xdg_toplevel->base->surface); From c025d1a746540909436224a141e5a8e4692839b9 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 3 Feb 2024 14:04:04 +0100 Subject: [PATCH 07/18] Updated public blur function docs --- include/scenefx/types/wlr_scene.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/scenefx/types/wlr_scene.h b/include/scenefx/types/wlr_scene.h index e8fd960..cd1a051 100644 --- a/include/scenefx/types/wlr_scene.h +++ b/include/scenefx/types/wlr_scene.h @@ -478,13 +478,13 @@ void wlr_scene_buffer_set_backdrop_blur(struct wlr_scene_buffer *scene_buffer, /** * Sets the whether the backdrop blur should use optimized blur or not -* TODO: Add function to update `blur_buffer` */ void wlr_scene_buffer_set_backdrop_blur_optimized(struct wlr_scene_buffer *scene_buffer, bool enabled); /** - * Tells the renderer to re-render the optimized blur. + * Tells the renderer to re-render the optimized blur. Very expensive so should + * only be called when needed. * * An example use would be to call this when a "static" node changes, like a * wallpaper. From b054240c798b61e05f9953cf4161690b9c22ee53 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 3 Feb 2024 14:04:56 +0100 Subject: [PATCH 08/18] Simplified blur buffer management --- include/render/pass.h | 1 + render/fx_renderer/fx_pass.c | 35 +++++++++++++++++------------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/render/pass.h b/include/render/pass.h index e264ef0..3e16d39 100644 --- a/include/render/pass.h +++ b/include/render/pass.h @@ -48,6 +48,7 @@ struct fx_render_blur_options { struct wlr_scene_buffer *scene_buffer; struct wlr_output *output; struct wlr_box monitor_box; + struct fx_framebuffer *current_buffer; struct blur_data *blur_data; }; diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index cb98ef6..aeb1344 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -442,21 +442,21 @@ void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass, // Renders the blur for each damaged rect and swaps the buffer static void render_blur_segments(struct fx_gles_render_pass *pass, - struct fx_render_blur_options *fx_options, struct fx_framebuffer **buffer, - struct blur_shader* shader) { + struct fx_render_blur_options *fx_options, struct blur_shader* shader) { struct fx_render_texture_options *tex_options = &fx_options->tex_options; struct wlr_render_texture_options *options = &tex_options->base; struct fx_renderer *renderer = pass->buffer->renderer; struct blur_data *blur_data = fx_options->blur_data; // Swap fbo - if (*buffer == renderer->effects_buffer) { + if (fx_options->current_buffer == renderer->effects_buffer) { fx_framebuffer_bind(renderer->effects_buffer_swapped); } else { fx_framebuffer_bind(renderer->effects_buffer); } - options->texture = fx_texture_from_buffer(&renderer->wlr_renderer, (*buffer)->buffer); + options->texture = fx_texture_from_buffer(&renderer->wlr_renderer, + fx_options->current_buffer->buffer); struct fx_texture *texture = fx_get_texture(options->texture); /* @@ -517,10 +517,10 @@ static void render_blur_segments(struct fx_gles_render_pass *pass, wlr_texture_destroy(options->texture); // Swap buffer. We don't want to draw to the same buffer - if (*buffer != renderer->effects_buffer) { - *buffer = renderer->effects_buffer; + if (fx_options->current_buffer != renderer->effects_buffer) { + fx_options->current_buffer = renderer->effects_buffer; } else { - *buffer = renderer->effects_buffer_swapped; + fx_options->current_buffer = renderer->effects_buffer_swapped; } } @@ -613,20 +613,17 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p // Clip the blur to the damage fx_options->tex_options.base.clip = &scaled_damage; - // Initially draw from the current WLR texture - struct fx_framebuffer *current_buffer = pass->buffer; - // Downscale for (int i = 0; i < blur_data->num_passes; ++i) { wlr_region_scale(&scaled_damage, &damage, 1.0f / (1 << (i + 1))); - render_blur_segments(pass, fx_options, ¤t_buffer, &renderer->shaders.blur1); + render_blur_segments(pass, fx_options, &renderer->shaders.blur1); } // Upscale for (int i = blur_data->num_passes - 1; i >= 0; --i) { // when upsampling we make the region twice as big wlr_region_scale(&scaled_damage, &damage, 1.0f / (1 << i)); - render_blur_segments(pass, fx_options, ¤t_buffer, &renderer->shaders.blur2); + render_blur_segments(pass, fx_options, &renderer->shaders.blur2); } pixman_region32_fini(&scaled_damage); @@ -634,19 +631,19 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p // Render additional blur effects like saturation, noise, contrast, etc... if (blur_data_should_parameters_blur_effects(blur_data) && pixman_region32_not_empty(&damage)) { - if (current_buffer == renderer->effects_buffer) { + if (fx_options->current_buffer == renderer->effects_buffer) { fx_framebuffer_bind(renderer->effects_buffer_swapped); } else { fx_framebuffer_bind(renderer->effects_buffer); } fx_options->tex_options.base.clip = &damage; fx_options->tex_options.base.texture = fx_texture_from_buffer( - &renderer->wlr_renderer, current_buffer->buffer); + &renderer->wlr_renderer, fx_options->current_buffer->buffer); render_blur_effects(pass, fx_options); - if (current_buffer != renderer->effects_buffer) { - current_buffer = renderer->effects_buffer; + if (fx_options->current_buffer != renderer->effects_buffer) { + fx_options->current_buffer = renderer->effects_buffer; } else { - current_buffer = renderer->effects_buffer_swapped; + fx_options->current_buffer = renderer->effects_buffer_swapped; } } @@ -655,7 +652,7 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p // Bind back to the default buffer fx_framebuffer_bind(pass->buffer); - return current_buffer; + return fx_options->current_buffer; } void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, @@ -687,6 +684,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, // Render the blur into its own buffer struct fx_render_blur_options blur_options = *fx_options; blur_options.tex_options.base.clip = &translucent_region; + blur_options.current_buffer = pass->buffer; buffer = get_main_buffer_blur(pass, &blur_options); } struct wlr_texture *wlr_texture = @@ -738,6 +736,7 @@ void fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass, // Render the blur into its own buffer struct fx_render_blur_options blur_options = *fx_options; blur_options.tex_options.base.clip = &fake_damage; + blur_options.current_buffer = pass->buffer; struct fx_framebuffer *buffer = get_main_buffer_blur(pass, &blur_options); // Update the optimized blur buffer if invalid From 30c31018ba6618bd3ab0e27dc14195ec550ee01b Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 3 Feb 2024 15:39:25 +0100 Subject: [PATCH 09/18] Moved ignore transparent bool into a per buffer option --- include/render/pass.h | 1 + include/scenefx/types/fx/blur_data.h | 1 - include/scenefx/types/wlr_scene.h | 8 ++++++++ render/fx_renderer/fx_pass.c | 4 ++-- tinywl/tinywl.c | 1 + types/fx/blur_data.c | 2 -- types/scene/wlr_scene.c | 10 ++++++++++ 7 files changed, 22 insertions(+), 5 deletions(-) diff --git a/include/render/pass.h b/include/render/pass.h index 3e16d39..3ba951d 100644 --- a/include/render/pass.h +++ b/include/render/pass.h @@ -50,6 +50,7 @@ struct fx_render_blur_options { struct wlr_box monitor_box; struct fx_framebuffer *current_buffer; struct blur_data *blur_data; + bool ignore_transparent; }; /** diff --git a/include/scenefx/types/fx/blur_data.h b/include/scenefx/types/fx/blur_data.h index 0dba533..5afda75 100644 --- a/include/scenefx/types/fx/blur_data.h +++ b/include/scenefx/types/fx/blur_data.h @@ -11,7 +11,6 @@ struct blur_data { float brightness; float contrast; float saturation; - bool ignore_transparent; }; struct blur_data blur_data_get_default(void); diff --git a/include/scenefx/types/wlr_scene.h b/include/scenefx/types/wlr_scene.h index cd1a051..4af8a7f 100644 --- a/include/scenefx/types/wlr_scene.h +++ b/include/scenefx/types/wlr_scene.h @@ -183,6 +183,7 @@ struct wlr_scene_buffer { struct shadow_data shadow_data; bool backdrop_blur; bool backdrop_blur_optimized; + bool backdrop_blur_ignore_transparent; float opacity; enum wlr_scale_filter_mode filter_mode; @@ -482,6 +483,13 @@ void wlr_scene_buffer_set_backdrop_blur(struct wlr_scene_buffer *scene_buffer, void wlr_scene_buffer_set_backdrop_blur_optimized(struct wlr_scene_buffer *scene_buffer, bool enabled); +/** +* Sets the whether the backdrop blur should not render in fully transparent +* segments. +*/ +void wlr_scene_buffer_set_backdrop_blur_ignore_transparent( + struct wlr_scene_buffer *scene_buffer, bool enabled); + /** * Tells the renderer to re-render the optimized blur. Very expensive so should * only be called when needed. diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index aeb1344..3e5f097 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -693,7 +693,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, blur_texture->has_alpha = true; // Get a stencil of the window ignoring transparent regions - if (fx_options->blur_data->ignore_transparent) { + if (fx_options->ignore_transparent) { stencil_mask_init(); struct fx_render_texture_options tex_options = fx_options->tex_options; @@ -717,7 +717,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, wlr_texture_destroy(&blur_texture->wlr_texture); // Finish stenciling - if (fx_options->blur_data->ignore_transparent) { + if (fx_options->ignore_transparent) { stencil_mask_fini(); } diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 1b482ca..32488f6 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -681,6 +681,7 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int sx, wlr_scene_buffer_set_backdrop_blur(buffer, true); wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false); + wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, true); } } } diff --git a/types/fx/blur_data.c b/types/fx/blur_data.c index a7e328e..0458cea 100644 --- a/types/fx/blur_data.c +++ b/types/fx/blur_data.c @@ -4,7 +4,6 @@ struct blur_data blur_data_get_default(void) { return (struct blur_data) { .radius = 5, .num_passes = 3, - .ignore_transparent = true, .noise = 0.02, .brightness = 0.9, .contrast = 0.9, @@ -26,7 +25,6 @@ bool blur_data_should_parameters_blur_effects(struct blur_data *blur_data) { bool blur_data_cmp(struct blur_data *a, struct blur_data *b) { return a->radius == b->radius && a->num_passes && b->num_passes && - a->ignore_transparent == b->ignore_transparent && a->noise == b->noise && a->brightness == b->brightness && a->contrast == b->contrast && diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 94a0820..467f0b1 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -645,6 +645,7 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, scene_buffer->shadow_data = shadow_data_get_default(); scene_buffer->backdrop_blur = false; scene_buffer->backdrop_blur_optimized = false; + scene_buffer->backdrop_blur_ignore_transparent = true; scene_node_update(&scene_buffer->node, NULL); @@ -908,6 +909,14 @@ void wlr_scene_buffer_set_backdrop_blur_optimized(struct wlr_scene_buffer *scene } } +void wlr_scene_buffer_set_backdrop_blur_ignore_transparent( + struct wlr_scene_buffer *scene_buffer, bool enabled) { + if (scene_buffer->backdrop_blur_ignore_transparent != enabled) { + scene_buffer->backdrop_blur_ignore_transparent = enabled; + wlr_scene_optimized_blur_mark_dirty(scene_node_get_root(&scene_buffer->node)); + } +} + static void output_optimized_blur_mark_dirty(struct wlr_output *output) { struct fx_renderer *renderer = fx_get_renderer(output->renderer); renderer->blur_buffer_dirty = true; @@ -1361,6 +1370,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .output = output, .monitor_box = monitor_box, .blur_data = &scene->blur_data, + .ignore_transparent = scene_buffer->backdrop_blur_ignore_transparent, }; // Re-render the optimized blur buffer when needed if (data->render_pass->buffer->renderer->blur_buffer_dirty From 8e61703da48f2c70f66c2374466fb9e3afb00297 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 3 Feb 2024 16:35:00 +0100 Subject: [PATCH 10/18] Clip the scene_buffer when blur is enabled --- types/scene/wlr_scene.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 467f0b1..fcb6b04 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1213,7 +1213,8 @@ static void clip_xdg(struct wlr_scene_node *node, // Don't clip if the scene buffer doesn't have any effects if (!scene_buffer || (scene_buffer->corner_radius == 0 && - !scene_buffer_has_shadow(&scene_buffer->shadow_data))) { + !scene_buffer_has_shadow(&scene_buffer->shadow_data) && + !scene_buffer->backdrop_blur)) { return; } From e2e6d495b61a039600e825ae6cd6d5542a9eda21 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 3 Feb 2024 16:38:06 +0100 Subject: [PATCH 11/18] Added back corner and shadow checks in opaque_region function --- types/scene/wlr_scene.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index fcb6b04..f4bc94f 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -260,6 +260,14 @@ static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y, return; } + if (scene_buffer->corner_radius > 0) { + return; + } + + if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { + return; + } + if (!buffer_is_opaque(scene_buffer->buffer)) { pixman_region32_copy(opaque, &scene_buffer->opaque_region); pixman_region32_intersect_rect(opaque, opaque, 0, 0, width, height); From 6c97812a228f8f6f262174d4fd3b3f04dc1a69e7 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sun, 18 Feb 2024 13:34:19 +0100 Subject: [PATCH 12/18] Renamed fx_render_blur_options to fx_render_blur_pass_options --- include/render/pass.h | 6 +++--- render/fx_renderer/fx_pass.c | 14 +++++++------- types/scene/wlr_scene.c | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/render/pass.h b/include/render/pass.h index 3ba951d..60edf29 100644 --- a/include/render/pass.h +++ b/include/render/pass.h @@ -43,7 +43,7 @@ struct fx_render_rect_options { struct fx_render_rect_options fx_render_rect_options_default( const struct wlr_render_rect_options *base); -struct fx_render_blur_options { +struct fx_render_blur_pass_options { struct fx_render_texture_options tex_options; struct wlr_scene_buffer *scene_buffer; struct wlr_output *output; @@ -82,13 +82,13 @@ void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass, * Render blur. */ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, - struct fx_render_blur_options *fx_options); + struct fx_render_blur_pass_options *fx_options); /** * Render optimized blur. */ void fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass, - struct fx_render_blur_options *fx_options); + struct fx_render_blur_pass_options *fx_options); /** * Render from one buffer to another diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index 3e5f097..bed430c 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -442,7 +442,7 @@ void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass, // Renders the blur for each damaged rect and swaps the buffer static void render_blur_segments(struct fx_gles_render_pass *pass, - struct fx_render_blur_options *fx_options, struct blur_shader* shader) { + struct fx_render_blur_pass_options *fx_options, struct blur_shader* shader) { struct fx_render_texture_options *tex_options = &fx_options->tex_options; struct wlr_render_texture_options *options = &tex_options->base; struct fx_renderer *renderer = pass->buffer->renderer; @@ -525,7 +525,7 @@ static void render_blur_segments(struct fx_gles_render_pass *pass, } static void render_blur_effects(struct fx_gles_render_pass *pass, - struct fx_render_blur_options *fx_options) { + struct fx_render_blur_pass_options *fx_options) { struct fx_render_texture_options *tex_options = &fx_options->tex_options; struct wlr_render_texture_options *options = &tex_options->base; @@ -587,7 +587,7 @@ static void render_blur_effects(struct fx_gles_render_pass *pass, // Blurs the main_buffer content and returns the blurred framebuffer static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *pass, - struct fx_render_blur_options *fx_options) { + struct fx_render_blur_pass_options *fx_options) { struct fx_renderer *renderer = pass->buffer->renderer; struct blur_data *blur_data = fx_options->blur_data; @@ -656,7 +656,7 @@ static struct fx_framebuffer *get_main_buffer_blur(struct fx_gles_render_pass *p } void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, - struct fx_render_blur_options *fx_options) { + struct fx_render_blur_pass_options *fx_options) { struct fx_renderer *renderer = pass->buffer->renderer; struct fx_render_texture_options *tex_options = &fx_options->tex_options; const struct wlr_render_texture_options *options = &tex_options->base; @@ -682,7 +682,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, pixman_region32_intersect(&translucent_region, &translucent_region, options->clip); // Render the blur into its own buffer - struct fx_render_blur_options blur_options = *fx_options; + struct fx_render_blur_pass_options blur_options = *fx_options; blur_options.tex_options.base.clip = &translucent_region; blur_options.current_buffer = pass->buffer; buffer = get_main_buffer_blur(pass, &blur_options); @@ -726,7 +726,7 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, } void fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass, - struct fx_render_blur_options *fx_options) { + struct fx_render_blur_pass_options *fx_options) { struct fx_renderer *renderer = pass->buffer->renderer; struct wlr_box monitor_box = fx_options->monitor_box; @@ -734,7 +734,7 @@ void fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass, pixman_region32_init_rect(&fake_damage, 0, 0, monitor_box.width, monitor_box.height); // Render the blur into its own buffer - struct fx_render_blur_options blur_options = *fx_options; + struct fx_render_blur_pass_options blur_options = *fx_options; blur_options.tex_options.base.clip = &fake_damage; blur_options.current_buffer = pass->buffer; struct fx_framebuffer *buffer = get_main_buffer_blur(pass, &blur_options); diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index f4bc94f..d1aef48 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1373,7 +1373,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren wlr_box_transform(&monitor_box, &monitor_box, wlr_output_transform_invert(output->transform), monitor_box.width, monitor_box.height); - struct fx_render_blur_options blur_options = { + struct fx_render_blur_pass_options blur_options = { .tex_options = tex_options, .scene_buffer = scene_buffer, .output = output, From 56d844039021ffdb24246ef2affdcd029bd749af Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sun, 18 Feb 2024 13:35:43 +0100 Subject: [PATCH 13/18] Fixed nits --- include/render/fx_renderer/fx_renderer.h | 1 - include/scenefx/fx_renderer/fx_renderer.h | 1 - types/scene/wlr_scene.c | 1 - 3 files changed, 3 deletions(-) diff --git a/include/render/fx_renderer/fx_renderer.h b/include/render/fx_renderer/fx_renderer.h index 70d746a..3b651b9 100644 --- a/include/render/fx_renderer/fx_renderer.h +++ b/include/render/fx_renderer/fx_renderer.h @@ -13,7 +13,6 @@ #include "render/fx_renderer/shaders.h" #include "render/pass.h" -#include "scenefx/types/fx/shadow_data.h" struct fx_pixel_format { uint32_t drm_format; diff --git a/include/scenefx/fx_renderer/fx_renderer.h b/include/scenefx/fx_renderer/fx_renderer.h index 3578dae..2e64ffb 100644 --- a/include/scenefx/fx_renderer/fx_renderer.h +++ b/include/scenefx/fx_renderer/fx_renderer.h @@ -2,7 +2,6 @@ #define SCENEFX_FX_OPENGL_H #include -#include struct wlr_renderer *fx_renderer_create_with_drm_fd(int drm_fd); struct wlr_renderer *fx_renderer_create(struct wlr_backend *backend); diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index d1aef48..2121a27 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1855,7 +1855,6 @@ struct blur_info { static struct blur_info workspace_get_blur_info(int list_len, struct render_list_entry *list_data, struct wlr_scene_output *scene_output, pixman_region32_t *blur_region) { - // TODO: Check if a check for "is current workspace" is also needed if (!wlr_scene_should_blur(scene_output->scene)) { return (struct blur_info) { .has_blur = false, From 19822f11f14332022db6214a1be3d489c819414d Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sun, 18 Feb 2024 14:10:42 +0100 Subject: [PATCH 14/18] Removed unused fx_framebuffer_bind_wlr_fbo function --- include/render/fx_renderer/fx_renderer.h | 2 -- render/fx_renderer/fx_framebuffer.c | 4 ---- 2 files changed, 6 deletions(-) diff --git a/include/render/fx_renderer/fx_renderer.h b/include/render/fx_renderer/fx_renderer.h index 3b651b9..74066b5 100644 --- a/include/render/fx_renderer/fx_renderer.h +++ b/include/render/fx_renderer/fx_renderer.h @@ -56,8 +56,6 @@ struct fx_framebuffer *fx_framebuffer_get_or_create(struct fx_renderer *renderer void fx_framebuffer_bind(struct fx_framebuffer *buffer); -void fx_framebuffer_bind_wlr_fbo(struct fx_renderer *renderer); - void fx_framebuffer_destroy(struct fx_framebuffer *buffer); /// diff --git a/render/fx_renderer/fx_framebuffer.c b/render/fx_renderer/fx_framebuffer.c index 66b37de..573602c 100644 --- a/render/fx_renderer/fx_framebuffer.c +++ b/render/fx_renderer/fx_framebuffer.c @@ -142,10 +142,6 @@ void fx_framebuffer_bind(struct fx_framebuffer *fx_buffer) { glBindFramebuffer(GL_FRAMEBUFFER, fx_buffer->fbo); } -void fx_framebuffer_bind_wlr_fbo(struct fx_renderer *renderer) { - glBindFramebuffer(GL_FRAMEBUFFER, renderer->current_buffer->fbo); -} - void fx_framebuffer_destroy(struct fx_framebuffer *fx_buffer) { // Release the framebuffer wl_list_remove(&fx_buffer->link); From 013be330da9aafea66d14651a8932a228f4fa7d3 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Mon, 26 Feb 2024 12:49:39 +0100 Subject: [PATCH 15/18] Removed wlr_scene impl. Should be moved into future PR instead --- include/scenefx/types/fx/blur_data.h | 2 - include/scenefx/types/fx/shadow_data.h | 4 +- include/scenefx/types/wlr_scene.h | 39 +--- tinywl/tinywl.c | 78 ++++---- types/fx/blur_data.c | 4 - types/scene/wlr_scene.c | 255 ++----------------------- 6 files changed, 64 insertions(+), 318 deletions(-) diff --git a/include/scenefx/types/fx/blur_data.h b/include/scenefx/types/fx/blur_data.h index 5afda75..e6a7c29 100644 --- a/include/scenefx/types/fx/blur_data.h +++ b/include/scenefx/types/fx/blur_data.h @@ -15,8 +15,6 @@ struct blur_data { struct blur_data blur_data_get_default(void); -bool scene_buffer_should_blur(bool backdrop_blur, struct blur_data *blur_data); - bool blur_data_should_parameters_blur_effects(struct blur_data *blur_data); bool blur_data_cmp(struct blur_data *a, struct blur_data *b); diff --git a/include/scenefx/types/fx/shadow_data.h b/include/scenefx/types/fx/shadow_data.h index 4982078..d96a084 100644 --- a/include/scenefx/types/fx/shadow_data.h +++ b/include/scenefx/types/fx/shadow_data.h @@ -1,5 +1,5 @@ -#ifndef TYPES_FX_SHADOW_DATA_H -#define TYPES_FX_SHADOW_DATA_H +#ifndef TYPES_DECORATION_DATA +#define TYPES_DECORATION_DATA #include #include diff --git a/include/scenefx/types/wlr_scene.h b/include/scenefx/types/wlr_scene.h index 4af8a7f..5925931 100644 --- a/include/scenefx/types/wlr_scene.h +++ b/include/scenefx/types/wlr_scene.h @@ -21,7 +21,6 @@ #include #include "scenefx/types/fx/shadow_data.h" -#include "scenefx/types/fx/blur_data.h" #include #include #include @@ -112,8 +111,6 @@ struct wlr_scene { enum wlr_scene_debug_damage_option debug_damage_option; bool direct_scanout; bool calculate_visibility; - - struct blur_data blur_data; }; /** A scene-graph node displaying a single surface. */ @@ -179,13 +176,10 @@ struct wlr_scene_buffer { */ struct wlr_scene_output *primary_output; + float opacity; int corner_radius; struct shadow_data shadow_data; - bool backdrop_blur; - bool backdrop_blur_optimized; - bool backdrop_blur_ignore_transparent; - float opacity; enum wlr_scale_filter_mode filter_mode; struct wlr_fbox src_box; int dst_width, dst_height; @@ -320,9 +314,6 @@ struct wlr_scene *wlr_scene_create(void); void wlr_scene_set_presentation(struct wlr_scene *scene, struct wlr_presentation *presentation); -/** Sets the global blur parameters */ -void wlr_scene_set_blur_data(struct wlr_scene *scene, struct blur_data blur_data); - /** * Handles linux_dmabuf_v1 feedback for all surfaces in the scene. * @@ -471,34 +462,6 @@ void wlr_scene_buffer_set_corner_radius(struct wlr_scene_buffer *scene_buffer, void wlr_scene_buffer_set_shadow_data(struct wlr_scene_buffer *scene_buffer, struct shadow_data shadow_data); -/** -* Sets the whether or not the buffer should render backdrop blur -*/ -void wlr_scene_buffer_set_backdrop_blur(struct wlr_scene_buffer *scene_buffer, - bool enabled); - -/** -* Sets the whether the backdrop blur should use optimized blur or not -*/ -void wlr_scene_buffer_set_backdrop_blur_optimized(struct wlr_scene_buffer *scene_buffer, - bool enabled); - -/** -* Sets the whether the backdrop blur should not render in fully transparent -* segments. -*/ -void wlr_scene_buffer_set_backdrop_blur_ignore_transparent( - struct wlr_scene_buffer *scene_buffer, bool enabled); - -/** - * Tells the renderer to re-render the optimized blur. Very expensive so should - * only be called when needed. - * - * An example use would be to call this when a "static" node changes, like a - * wallpaper. - */ -void wlr_scene_optimized_blur_mark_dirty(struct wlr_scene *scene); - /** * Calls the buffer's frame_done signal. */ diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 32488f6..994574f 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -557,6 +557,50 @@ static void server_cursor_frame(struct wl_listener *listener, void *data) { wlr_seat_pointer_notify_frame(server->seat); } +static void output_configure_scene(struct wlr_scene_node *node, + struct tinywl_toplevel *toplevel) { + if (!node->enabled) { + return; + } + + struct tinywl_toplevel *_toplevel = node->data; + if (_toplevel) { + toplevel = _toplevel; + } + + if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); + + struct wlr_scene_surface * scene_surface = + wlr_scene_surface_try_from_buffer(buffer); + if (!scene_surface) { + return; + } + + struct wlr_xdg_surface *xdg_surface = + wlr_xdg_surface_try_from_wlr_surface(scene_surface->surface); + + if (toplevel && + xdg_surface && + xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + // TODO: Be able to set whole decoration_data instead of calling + // each individually? + wlr_scene_buffer_set_opacity(buffer, toplevel->opacity); + + if (!wlr_subsurface_try_from_wlr_surface(xdg_surface->surface)) { + wlr_scene_buffer_set_corner_radius(buffer, toplevel->corner_radius); + wlr_scene_buffer_set_shadow_data(buffer, toplevel->shadow_data); + } + } + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *tree = wl_container_of(node, tree, node); + struct wlr_scene_node *node; + wl_list_for_each(node, &tree->children, link) { + output_configure_scene(node, toplevel); + } + } +} + static void output_frame(struct wl_listener *listener, void *data) { /* This function is called every time an output is ready to display a frame, * generally at the output's refresh rate (e.g. 60Hz). */ @@ -566,6 +610,8 @@ static void output_frame(struct wl_listener *listener, void *data) { struct wlr_scene_output *scene_output = wlr_scene_get_scene_output( scene, output->wlr_output); + output_configure_scene(&scene_output->scene->tree.node, NULL); + /* Render the scene if needed and commit the output */ wlr_scene_output_commit(scene_output, NULL); @@ -657,42 +703,10 @@ static void server_new_output(struct wl_listener *listener, void *data) { wlr_scene_output_layout_add_output(server->scene_layout, l_output, scene_output); } -static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int sx, - int sy, void *user_data) { - struct tinywl_toplevel *toplevel = user_data; - - struct wlr_scene_surface * scene_surface = wlr_scene_surface_try_from_buffer(buffer); - if (!scene_surface) { - return; - } - - struct wlr_xdg_surface *xdg_surface = - wlr_xdg_surface_try_from_wlr_surface(scene_surface->surface); - if (toplevel && - xdg_surface && - xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - // TODO: Be able to set whole decoration_data instead of calling - // each individually? - wlr_scene_buffer_set_opacity(buffer, toplevel->opacity); - - if (!wlr_subsurface_try_from_wlr_surface(xdg_surface->surface)) { - wlr_scene_buffer_set_corner_radius(buffer, toplevel->corner_radius); - wlr_scene_buffer_set_shadow_data(buffer, toplevel->shadow_data); - - wlr_scene_buffer_set_backdrop_blur(buffer, true); - wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false); - wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, true); - } - } -} - static void xdg_toplevel_map(struct wl_listener *listener, void *data) { /* Called when the surface is mapped, or ready to display on-screen. */ struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, map); - wlr_scene_node_for_each_buffer(&toplevel->scene_tree->node, - iter_xdg_scene_buffers, toplevel); - wl_list_insert(&toplevel->server->toplevels, &toplevel->link); focus_toplevel(toplevel, toplevel->xdg_toplevel->base->surface); diff --git a/types/fx/blur_data.c b/types/fx/blur_data.c index 0458cea..3aa618b 100644 --- a/types/fx/blur_data.c +++ b/types/fx/blur_data.c @@ -11,10 +11,6 @@ struct blur_data blur_data_get_default(void) { }; } -bool scene_buffer_should_blur(bool backdrop_blur, struct blur_data *blur_data) { - return backdrop_blur && blur_data->radius > 0 && blur_data->num_passes > 0; -} - bool blur_data_should_parameters_blur_effects(struct blur_data *blur_data) { return blur_data->brightness != 1.0f || blur_data->saturation != 1.0f diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 2121a27..0545e70 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -17,8 +17,6 @@ #include #include "render/pass.h" -#include "render/fx_renderer/fx_renderer.h" -#include "scenefx/types/fx/blur_data.h" #include "scenefx/types/fx/shadow_data.h" #include "types/wlr_buffer.h" #include "types/wlr_output.h" @@ -178,8 +176,6 @@ struct wlr_scene *wlr_scene_create(void) { scene->direct_scanout = !env_parse_bool("WLR_SCENE_DISABLE_DIRECT_SCANOUT"); scene->calculate_visibility = !env_parse_bool("WLR_SCENE_DISABLE_VISIBILITY"); - scene->blur_data = blur_data_get_default(); - return scene; } @@ -648,12 +644,8 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, wl_signal_init(&scene_buffer->events.frame_done); pixman_region32_init(&scene_buffer->opaque_region); scene_buffer->opacity = 1; - scene_buffer->corner_radius = 0; scene_buffer->shadow_data = shadow_data_get_default(); - scene_buffer->backdrop_blur = false; - scene_buffer->backdrop_blur_optimized = false; - scene_buffer->backdrop_blur_ignore_transparent = true; scene_node_update(&scene_buffer->node, NULL); @@ -901,45 +893,6 @@ void wlr_scene_buffer_set_shadow_data(struct wlr_scene_buffer *scene_buffer, scene_node_update(&scene_buffer->node, NULL); } -void wlr_scene_buffer_set_backdrop_blur(struct wlr_scene_buffer *scene_buffer, - bool enabled) { - if (scene_buffer->backdrop_blur != enabled) { - scene_buffer->backdrop_blur = enabled; - wlr_scene_optimized_blur_mark_dirty(scene_node_get_root(&scene_buffer->node)); - } -} - -void wlr_scene_buffer_set_backdrop_blur_optimized(struct wlr_scene_buffer *scene_buffer, - bool enabled) { - if (scene_buffer->backdrop_blur_optimized != enabled) { - scene_buffer->backdrop_blur_optimized = enabled; - wlr_scene_optimized_blur_mark_dirty(scene_node_get_root(&scene_buffer->node)); - } -} - -void wlr_scene_buffer_set_backdrop_blur_ignore_transparent( - struct wlr_scene_buffer *scene_buffer, bool enabled) { - if (scene_buffer->backdrop_blur_ignore_transparent != enabled) { - scene_buffer->backdrop_blur_ignore_transparent = enabled; - wlr_scene_optimized_blur_mark_dirty(scene_node_get_root(&scene_buffer->node)); - } -} - -static void output_optimized_blur_mark_dirty(struct wlr_output *output) { - struct fx_renderer *renderer = fx_get_renderer(output->renderer); - renderer->blur_buffer_dirty = true; -} - -void wlr_scene_optimized_blur_mark_dirty(struct wlr_scene *scene) { - // Mark the blur buffers as dirty - struct wlr_scene_output *current_output; - wl_list_for_each(current_output, &scene->outputs, link) { - struct wlr_output *output = current_output->output; - output_optimized_blur_mark_dirty(output); - } - scene_node_update(&scene->tree.node, NULL); -} - static struct wlr_texture *scene_buffer_get_texture( struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) { struct wlr_client_buffer *client_buffer = @@ -1221,8 +1174,7 @@ static void clip_xdg(struct wlr_scene_node *node, // Don't clip if the scene buffer doesn't have any effects if (!scene_buffer || (scene_buffer->corner_radius == 0 && - !scene_buffer_has_shadow(&scene_buffer->shadow_data) && - !scene_buffer->backdrop_blur)) { + !scene_buffer_has_shadow(&scene_buffer->shadow_data))) { return; } @@ -1330,6 +1282,20 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren wlr_output_transform_invert(scene_buffer->transform); transform = wlr_output_transform_compose(transform, data->transform); + // Shadow + if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { + struct fx_render_rect_options shadow_options = { + .base = { + .box = xdg_box, + .clip = &render_region, // Render with the original extended clip region + }, + .scale = data->scale, + }; + fx_render_pass_add_box_shadow(data->render_pass, &shadow_options, + scene_buffer->corner_radius * data->scale, + &scene_buffer->shadow_data); + } + struct fx_render_texture_options tex_options = { .base = (struct wlr_render_texture_options){ .texture = texture, @@ -1345,68 +1311,8 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .scale = data->scale, .clip_box = &xdg_box, .corner_radius = scene_buffer->corner_radius * data->scale, - .discard_transparent = false, }; - // Blur - struct wlr_scene *scene = data->output->scene; - if (scene_buffer_should_blur(scene_buffer->backdrop_blur, &scene->blur_data)) { - pixman_region32_t opaque_region; - pixman_region32_init(&opaque_region); - - bool has_alpha = false; - if (scene_buffer->opacity < 1.0) { - has_alpha = true; - pixman_region32_union_rect(&opaque_region, &opaque_region, 0, 0, 0, 0); - } else { - struct wlr_scene_surface *scene_surface - = wlr_scene_surface_try_from_buffer(scene_buffer); - has_alpha = !scene_surface->surface->opaque; - pixman_region32_copy(&opaque_region, &scene_surface->surface->opaque_region); - } - - if (has_alpha) { - struct wlr_output *output = data->output->output; - int width, height; - wlr_output_transformed_resolution(output, &width, &height); - struct wlr_box monitor_box = { 0, 0, width, height }; - wlr_box_transform(&monitor_box, &monitor_box, - wlr_output_transform_invert(output->transform), - monitor_box.width, monitor_box.height); - struct fx_render_blur_pass_options blur_options = { - .tex_options = tex_options, - .scene_buffer = scene_buffer, - .output = output, - .monitor_box = monitor_box, - .blur_data = &scene->blur_data, - .ignore_transparent = scene_buffer->backdrop_blur_ignore_transparent, - }; - // Re-render the optimized blur buffer when needed - if (data->render_pass->buffer->renderer->blur_buffer_dirty - && scene_buffer->backdrop_blur_optimized) { - fx_render_pass_add_optimized_blur(data->render_pass, &blur_options); - } - // Render the actual blur behind the surface - fx_render_pass_add_blur(data->render_pass, &blur_options); - - } - pixman_region32_fini(&opaque_region); - } - - // Shadow - if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { - struct fx_render_rect_options shadow_options = { - .base = { - .box = xdg_box, - .clip = &render_region, // Render with the original extended clip region - }, - .scale = data->scale, - }; - fx_render_pass_add_box_shadow(data->render_pass, &shadow_options, - scene_buffer->corner_radius * data->scale, - &scene_buffer->shadow_data); - } - fx_render_pass_add_texture(data->render_pass, &tex_options); struct wlr_scene_output_sample_event sample_event = { @@ -1439,22 +1345,6 @@ void wlr_scene_set_presentation(struct wlr_scene *scene, wl_signal_add(&presentation->events.destroy, &scene->presentation_destroy); } -void wlr_scene_set_blur_data(struct wlr_scene *scene, struct blur_data blur_data) { - struct blur_data *buff_data = &scene->blur_data; - if (blur_data_cmp(buff_data, &blur_data)) { - return; - } - - memcpy(&scene->blur_data, &blur_data, - sizeof(struct blur_data)); - - wlr_scene_optimized_blur_mark_dirty(scene); -} - -static bool wlr_scene_should_blur(struct wlr_scene *scene) { - return scene->blur_data.radius > 0 && scene->blur_data.num_passes > 0; -} - static void scene_handle_linux_dmabuf_v1_destroy(struct wl_listener *listener, void *data) { struct wlr_scene *scene = @@ -1503,9 +1393,6 @@ static void scene_output_update_geometry(struct wlr_scene_output *scene_output, wlr_damage_ring_add_whole(&scene_output->damage_ring); wlr_output_schedule_frame(scene_output->output); - // Re-render the optimized blur when the output is changed - output_optimized_blur_mark_dirty(scene_output->output); - scene_node_output_update(&scene_output->scene->tree.node, &scene_output->scene->outputs, NULL, force_update ? scene_output : NULL); } @@ -1847,54 +1734,6 @@ static bool scene_entry_try_direct_scanout(struct render_list_entry *entry, return true; } -struct blur_info { - bool has_blur; - bool has_optimized; -}; - -static struct blur_info workspace_get_blur_info(int list_len, - struct render_list_entry *list_data, struct wlr_scene_output *scene_output, - pixman_region32_t *blur_region) { - if (!wlr_scene_should_blur(scene_output->scene)) { - return (struct blur_info) { - .has_blur = false, - .has_optimized = false, - }; - } - - bool has_optimized = false; - for (int i = list_len - 1; i >= 0; i--) { - struct wlr_scene_node *node = list_data[i].node; - switch (node->type) { - case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_try_from_buffer(scene_buffer); - assert(scene_buffer->buffer); - if (scene_buffer->backdrop_blur && scene_surface && - !scene_surface->surface->opaque) { - int x, y; - wlr_scene_node_coords(node, &x, &y); - pixman_region32_union_rect(blur_region, blur_region, - (x - scene_output->x) * scene_output->output->scale, - (y - scene_output->y) * scene_output->output->scale, - scene_buffer->dst_width * scene_output->output->scale, - scene_buffer->dst_height * scene_output->output->scale); - if (scene_buffer->backdrop_blur_optimized) { - has_optimized = true; - } - } - break; - default: - break; - } - } - return (struct blur_info) { - .has_blur = pixman_region32_not_empty(blur_region), - .has_optimized = has_optimized, - }; -} - bool wlr_scene_output_commit(struct wlr_scene_output *scene_output, const struct wlr_scene_output_state_options *options) { if (!scene_output->output->needs_frame && !pixman_region32_not_empty( @@ -2080,7 +1919,6 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, timer->pre_render_duration = timespec_to_nsec(&duration); } - struct fx_renderer *renderer = fx_get_renderer(output->renderer); struct fx_gles_render_pass *render_pass = fx_renderer_begin_buffer_pass(output->renderer, buffer, output, &(struct wlr_buffer_pass_options) { @@ -2097,61 +1935,6 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring, buffer_age, &render_data.damage); - // Blur artifact prevention - pixman_region32_t *damage = &render_data.damage; - pixman_region32_t blur_region; - pixman_region32_init(&blur_region); - struct blur_info blur_info = - workspace_get_blur_info(list_len, list_data, scene_output, &blur_region); - // Expand the damage to compensate for blur - if (blur_info.has_blur) { - // Skip the blur artifact prevention if damaging the whole viewport - if (renderer->blur_buffer_dirty) { - // Needs to be extended before clearing - pixman_region32_union_rect(&render_data.damage, &render_data.damage, - 0, 0, output->width, output->height); - } else { - // copy the surrounding content where the blur would display artifacts - // and draw it above the artifacts - struct blur_data *blur_data = &scene_output->scene->blur_data; - int output_width, output_height; - wlr_output_transformed_resolution(output, &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); - } else { - // Expand the original damage to compensate for surrounding - // blurred views to avoid sharp edges between damage regions - wlr_region_expand(damage, damage, blur_data_calc_size(blur_data)); - } - - 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, blur_data_calc_size(blur_data)); - // 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_renderer_read_to_buffer(render_pass, &renderer->blur_padding_region, - renderer->blur_saved_pixels_buffer, render_pass->buffer); - } - } - pixman_region32_fini(&blur_region); - pixman_region32_t background; pixman_region32_init(&background); pixman_region32_copy(&background, &render_data.damage); @@ -2214,14 +1997,6 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, } } - // Not needed if we damaged the whole viewport - if (!renderer->blur_buffer_dirty) { - // TODO: Investigate blitting instead - // Render the saved pixels over the blur artifacts - fx_renderer_read_to_buffer(render_pass, &renderer->blur_padding_region, - render_pass->buffer, renderer->blur_saved_pixels_buffer); - } - if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { struct highlight_region *damage; wl_list_for_each(damage, &scene_output->damage_highlight_regions, link) { From 541f4b348f9f9ea3b78fe4861caf811f9a5abec9 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Mon, 26 Feb 2024 12:53:30 +0100 Subject: [PATCH 16/18] Made blur impl independent of wlr_scene --- include/render/pass.h | 3 ++- render/fx_renderer/fx_pass.c | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/render/pass.h b/include/render/pass.h index 60edf29..db33ff6 100644 --- a/include/render/pass.h +++ b/include/render/pass.h @@ -45,11 +45,12 @@ struct fx_render_rect_options fx_render_rect_options_default( struct fx_render_blur_pass_options { struct fx_render_texture_options tex_options; - struct wlr_scene_buffer *scene_buffer; + pixman_region32_t *opaque_region; struct wlr_output *output; struct wlr_box monitor_box; struct fx_framebuffer *current_buffer; struct blur_data *blur_data; + bool use_optimized_blur; bool ignore_transparent; }; diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index bed430c..a0760a4 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -15,7 +15,6 @@ #include "render/pass.h" #include "scenefx/types/fx/blur_data.h" #include "scenefx/types/fx/shadow_data.h" -#include "scenefx/types/wlr_scene.h" #define MAX_QUADS 86 // 4kb @@ -660,7 +659,6 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, struct fx_renderer *renderer = pass->buffer->renderer; struct fx_render_texture_options *tex_options = &fx_options->tex_options; const struct wlr_render_texture_options *options = &tex_options->base; - struct wlr_scene_buffer *scene_buffer = fx_options->scene_buffer; pixman_region32_t translucent_region; pixman_region32_init(&translucent_region); @@ -670,14 +668,14 @@ void fx_render_pass_add_blur(struct fx_gles_render_pass *pass, // Gets the translucent region pixman_box32_t surface_box = { 0, 0, dst_box.width, dst_box.height }; - pixman_region32_copy(&translucent_region, &scene_buffer->opaque_region); + pixman_region32_copy(&translucent_region, fx_options->opaque_region); pixman_region32_inverse(&translucent_region, &translucent_region, &surface_box); if (!pixman_region32_not_empty(&translucent_region)) { goto damage_finish; } struct fx_framebuffer *buffer = renderer->optimized_blur_buffer; - if (!buffer || !scene_buffer->backdrop_blur_optimized) { + if (!buffer || !fx_options->use_optimized_blur) { pixman_region32_translate(&translucent_region, dst_box.x, dst_box.y); pixman_region32_intersect(&translucent_region, &translucent_region, options->clip); From dc89a55772a118725a26239077903953bc2e57cd Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Tue, 27 Feb 2024 10:48:00 +0100 Subject: [PATCH 17/18] Moved shader init back into fx_renderer.c --- include/render/fx_renderer/fx_renderer.h | 12 +++- include/render/fx_renderer/shaders.h | 25 ++++--- render/fx_renderer/fx_renderer.c | 61 ++++++++++++++++ render/fx_renderer/shaders.c | 91 ++++++------------------ 4 files changed, 107 insertions(+), 82 deletions(-) diff --git a/include/render/fx_renderer/fx_renderer.h b/include/render/fx_renderer/fx_renderer.h index 74066b5..9f9da1e 100644 --- a/include/render/fx_renderer/fx_renderer.h +++ b/include/render/fx_renderer/fx_renderer.h @@ -142,7 +142,17 @@ struct fx_renderer { PFNGLGETINTEGER64VEXTPROC glGetInteger64vEXT; } procs; - struct shaders shaders; + struct { + struct quad_shader quad; + struct tex_shader tex_rgba; + struct tex_shader tex_rgbx; + struct tex_shader tex_ext; + struct box_shadow_shader box_shadow; + struct stencil_mask_shader stencil_mask; + struct blur_shader blur1; + struct blur_shader blur2; + struct blur_effects_shader blur_effects; + } shaders; struct wl_list buffers; // fx_framebuffer.link struct wl_list textures; // fx_texture.link diff --git a/include/render/fx_renderer/shaders.h b/include/render/fx_renderer/shaders.h index b1ae247..226dd36 100644 --- a/include/render/fx_renderer/shaders.h +++ b/include/render/fx_renderer/shaders.h @@ -27,6 +27,8 @@ struct quad_shader { GLint pos_attrib; }; +bool link_quad_program(struct quad_shader *shader); + struct tex_shader { GLuint program; GLint proj; @@ -40,6 +42,8 @@ struct tex_shader { GLint discard_transparent; }; +bool link_tex_program(struct tex_shader *shader, enum fx_tex_shader_source source); + struct stencil_mask_shader { GLuint program; GLint proj; @@ -50,6 +54,8 @@ struct stencil_mask_shader { GLint radius; }; +bool link_stencil_mask_program(struct stencil_mask_shader *shader); + struct box_shadow_shader { GLuint program; GLint proj; @@ -61,6 +67,8 @@ struct box_shadow_shader { GLint corner_radius; }; +bool link_box_shadow_program(struct box_shadow_shader *shader); + struct blur_shader { GLuint program; GLint proj; @@ -71,6 +79,9 @@ struct blur_shader { GLint halfpixel; }; +bool link_blur1_program(struct blur_shader *shader); +bool link_blur2_program(struct blur_shader *shader); + struct blur_effects_shader { GLuint program; GLint proj; @@ -83,18 +94,6 @@ struct blur_effects_shader { GLfloat saturation; }; -struct shaders { - struct quad_shader quad; - struct tex_shader tex_rgba; - struct tex_shader tex_rgbx; - struct tex_shader tex_ext; - struct box_shadow_shader box_shadow; - struct stencil_mask_shader stencil_mask; - struct blur_shader blur1; - struct blur_shader blur2; - struct blur_effects_shader blur_effects; -}; - -bool link_shaders(struct fx_renderer *renderer); +bool link_blur_effects_program(struct blur_effects_shader *shader); #endif diff --git a/render/fx_renderer/fx_renderer.c b/render/fx_renderer/fx_renderer.c index 1a41232..0923555 100644 --- a/render/fx_renderer/fx_renderer.c +++ b/render/fx_renderer/fx_renderer.c @@ -632,6 +632,67 @@ struct wlr_renderer *fx_renderer_create(struct wlr_backend *backend) { return renderer_autocreate(backend, -1); } +static bool link_shaders(struct fx_renderer *renderer) { + // quad fragment shader + if (!link_quad_program(&renderer->shaders.quad)) { + wlr_log(WLR_ERROR, "Could not link quad shader"); + goto error; + } + // fragment shaders + if (!link_tex_program(&renderer->shaders.tex_rgba, SHADER_SOURCE_TEXTURE_RGBA)) { + wlr_log(WLR_ERROR, "Could not link tex_RGBA shader"); + goto error; + } + if (!link_tex_program(&renderer->shaders.tex_rgbx, SHADER_SOURCE_TEXTURE_RGBX)) { + wlr_log(WLR_ERROR, "Could not link tex_RGBX shader"); + goto error; + } + if (!link_tex_program(&renderer->shaders.tex_ext, SHADER_SOURCE_TEXTURE_EXTERNAL)) { + wlr_log(WLR_ERROR, "Could not link tex_EXTERNAL shader"); + goto error; + } + + // stencil mask shader + if (!link_stencil_mask_program(&renderer->shaders.stencil_mask)) { + wlr_log(WLR_ERROR, "Could not link stencil mask shader"); + goto error; + } + // box shadow shader + if (!link_box_shadow_program(&renderer->shaders.box_shadow)) { + wlr_log(WLR_ERROR, "Could not link box shadow shader"); + goto error; + } + + // Blur shaders + if (!link_blur1_program(&renderer->shaders.blur1)) { + wlr_log(WLR_ERROR, "Could not link blur1 shader"); + goto error; + } + if (!link_blur2_program(&renderer->shaders.blur2)) { + wlr_log(WLR_ERROR, "Could not link blur2 shader"); + goto error; + } + if (!link_blur_effects_program(&renderer->shaders.blur_effects)) { + wlr_log(WLR_ERROR, "Could not link blur_effects shader"); + goto error; + } + + return true; + +error: + glDeleteProgram(renderer->shaders.quad.program); + glDeleteProgram(renderer->shaders.tex_rgba.program); + glDeleteProgram(renderer->shaders.tex_rgbx.program); + glDeleteProgram(renderer->shaders.tex_ext.program); + glDeleteProgram(renderer->shaders.stencil_mask.program); + glDeleteProgram(renderer->shaders.box_shadow.program); + glDeleteProgram(renderer->shaders.blur1.program); + glDeleteProgram(renderer->shaders.blur2.program); + glDeleteProgram(renderer->shaders.blur_effects.program); + + return false; +} + struct wlr_renderer *fx_renderer_create_egl(struct wlr_egl *egl) { if (!wlr_egl_make_current(egl)) { return NULL; diff --git a/render/fx_renderer/shaders.c b/render/fx_renderer/shaders.c index 8705c6d..cd15eea 100644 --- a/render/fx_renderer/shaders.c +++ b/render/fx_renderer/shaders.c @@ -99,7 +99,7 @@ void load_gl_proc(void *proc_ptr, const char *name) { // Shaders -static bool link_quad_program(struct quad_shader *shader) { +bool link_quad_program(struct quad_shader *shader) { GLuint prog; shader->program = prog = link_program(quad_frag_src); if (!shader->program) { @@ -113,7 +113,7 @@ static bool link_quad_program(struct quad_shader *shader) { return true; } -static bool link_tex_program(struct tex_shader *shader, +bool link_tex_program(struct tex_shader *shader, enum fx_tex_shader_source source) { GLchar frag_src[2048]; snprintf(frag_src, sizeof(frag_src), @@ -138,7 +138,7 @@ static bool link_tex_program(struct tex_shader *shader, return true; } -static bool link_stencil_mask_program(struct stencil_mask_shader *shader) { +bool link_stencil_mask_program(struct stencil_mask_shader *shader) { GLuint prog; shader->program = prog = link_program(stencil_mask_frag_src); if (!shader->program) { @@ -155,7 +155,7 @@ static bool link_stencil_mask_program(struct stencil_mask_shader *shader) { return true; } -static bool link_box_shadow_program(struct box_shadow_shader *shader) { +bool link_box_shadow_program(struct box_shadow_shader *shader) { GLuint prog; shader->program = prog = link_program(box_shadow_frag_src); if (!shader->program) { @@ -172,9 +172,9 @@ static bool link_box_shadow_program(struct box_shadow_shader *shader) { return true; } -static bool link_blur_program(struct blur_shader *shader, const char *shader_program) { +bool link_blur1_program(struct blur_shader *shader) { GLuint prog; - shader->program = prog = link_program(shader_program); + shader->program = prog = link_program(blur1_frag_src); if (!shader->program) { return false; } @@ -188,9 +188,9 @@ static bool link_blur_program(struct blur_shader *shader, const char *shader_pro return true; } -static bool link_blur_effects_program(struct blur_effects_shader *shader) { +bool link_blur2_program(struct blur_shader *shader) { GLuint prog; - shader->program = prog = link_program(blur_effects_frag_src); + shader->program = prog = link_program(blur2_frag_src); if (!shader->program) { return false; } @@ -198,71 +198,26 @@ static bool link_blur_effects_program(struct blur_effects_shader *shader) { shader->tex = glGetUniformLocation(prog, "tex"); shader->pos_attrib = glGetAttribLocation(prog, "pos"); shader->tex_proj = glGetUniformLocation(prog, "tex_proj"); - shader->noise = glGetUniformLocation(prog, "noise"); - shader->brightness = glGetUniformLocation(prog, "brightness"); - shader->contrast = glGetUniformLocation(prog, "contrast"); - shader->saturation = glGetUniformLocation(prog, "saturation"); + shader->radius = glGetUniformLocation(prog, "radius"); + shader->halfpixel = glGetUniformLocation(prog, "halfpixel"); return true; } -bool link_shaders(struct fx_renderer *renderer) { - // quad fragment shader - if (!link_quad_program(&renderer->shaders.quad)) { - wlr_log(WLR_ERROR, "Could not link quad shader"); - goto error; - } - // fragment shaders - if (!link_tex_program(&renderer->shaders.tex_rgba, SHADER_SOURCE_TEXTURE_RGBA)) { - wlr_log(WLR_ERROR, "Could not link tex_RGBA shader"); - goto error; - } - if (!link_tex_program(&renderer->shaders.tex_rgbx, SHADER_SOURCE_TEXTURE_RGBX)) { - wlr_log(WLR_ERROR, "Could not link tex_RGBX shader"); - goto error; - } - if (!link_tex_program(&renderer->shaders.tex_ext, SHADER_SOURCE_TEXTURE_EXTERNAL)) { - wlr_log(WLR_ERROR, "Could not link tex_EXTERNAL shader"); - goto error; - } - - // stencil mask shader - if (!link_stencil_mask_program(&renderer->shaders.stencil_mask)) { - wlr_log(WLR_ERROR, "Could not link stencil mask shader"); - goto error; - } - // box shadow shader - if (!link_box_shadow_program(&renderer->shaders.box_shadow)) { - wlr_log(WLR_ERROR, "Could not link box shadow shader"); - goto error; - } - - // Blur shaders - if (!link_blur_program(&renderer->shaders.blur1, blur1_frag_src)) { - wlr_log(WLR_ERROR, "Could not link blur1 shader"); - goto error; - } - if (!link_blur_program(&renderer->shaders.blur2, blur2_frag_src)) { - wlr_log(WLR_ERROR, "Could not link blur2 shader"); - goto error; - } - if (!link_blur_effects_program(&renderer->shaders.blur_effects)) { - wlr_log(WLR_ERROR, "Could not link blur_effects shader"); - goto error; +bool link_blur_effects_program(struct blur_effects_shader *shader) { + GLuint prog; + shader->program = prog = link_program(blur_effects_frag_src); + if (!shader->program) { + return false; } + shader->proj = glGetUniformLocation(prog, "proj"); + shader->tex = glGetUniformLocation(prog, "tex"); + shader->pos_attrib = glGetAttribLocation(prog, "pos"); + shader->tex_proj = glGetUniformLocation(prog, "tex_proj"); + shader->noise = glGetUniformLocation(prog, "noise"); + shader->brightness = glGetUniformLocation(prog, "brightness"); + shader->contrast = glGetUniformLocation(prog, "contrast"); + shader->saturation = glGetUniformLocation(prog, "saturation"); return true; - -error: - glDeleteProgram(renderer->shaders.quad.program); - glDeleteProgram(renderer->shaders.tex_rgba.program); - glDeleteProgram(renderer->shaders.tex_rgbx.program); - glDeleteProgram(renderer->shaders.tex_ext.program); - glDeleteProgram(renderer->shaders.stencil_mask.program); - glDeleteProgram(renderer->shaders.box_shadow.program); - glDeleteProgram(renderer->shaders.blur1.program); - glDeleteProgram(renderer->shaders.blur2.program); - glDeleteProgram(renderer->shaders.blur_effects.program); - - return false; } From 662ae909441a6754b6032a855e4b1d9bba7bb756 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Tue, 27 Feb 2024 10:48:54 +0100 Subject: [PATCH 18/18] Renamed fx_framebuffer_get_or_create_bufferless to fx_framebuffer_get_or_create_custom --- include/render/fx_renderer/fx_renderer.h | 2 +- render/fx_renderer/fx_framebuffer.c | 2 +- render/fx_renderer/fx_pass.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/render/fx_renderer/fx_renderer.h b/include/render/fx_renderer/fx_renderer.h index 9f9da1e..83ac305 100644 --- a/include/render/fx_renderer/fx_renderer.h +++ b/include/render/fx_renderer/fx_renderer.h @@ -48,7 +48,7 @@ struct fx_framebuffer { }; /** Should only be used with custom fbs */ -void fx_framebuffer_get_or_create_bufferless(struct fx_renderer *fx_renderer, +void fx_framebuffer_get_or_create_custom(struct fx_renderer *fx_renderer, struct wlr_output *output, struct fx_framebuffer **fx_buffer); struct fx_framebuffer *fx_framebuffer_get_or_create(struct fx_renderer *renderer, diff --git a/render/fx_renderer/fx_framebuffer.c b/render/fx_renderer/fx_framebuffer.c index 573602c..0c8e04c 100644 --- a/render/fx_renderer/fx_framebuffer.c +++ b/render/fx_renderer/fx_framebuffer.c @@ -20,7 +20,7 @@ static const struct wlr_addon_interface buffer_addon_impl = { .destroy = handle_buffer_destroy, }; -void fx_framebuffer_get_or_create_bufferless(struct fx_renderer *renderer, +void fx_framebuffer_get_or_create_custom(struct fx_renderer *renderer, struct wlr_output *output, struct fx_framebuffer **fx_framebuffer) { struct wlr_allocator *allocator = output->allocator; struct wlr_swapchain *swapchain = output->swapchain; diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index a0760a4..f12eda5 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -738,7 +738,7 @@ void fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass, struct fx_framebuffer *buffer = get_main_buffer_blur(pass, &blur_options); // Update the optimized blur buffer if invalid - fx_framebuffer_get_or_create_bufferless(renderer, fx_options->output, + fx_framebuffer_get_or_create_custom(renderer, fx_options->output, &renderer->optimized_blur_buffer); // Render the newly blurred content into the blur_buffer @@ -858,9 +858,9 @@ struct fx_gles_render_pass *fx_renderer_begin_buffer_pass( // Update the buffers if needed if (output) { - fx_framebuffer_get_or_create_bufferless(renderer, output, &renderer->blur_saved_pixels_buffer); - fx_framebuffer_get_or_create_bufferless(renderer, output, &renderer->effects_buffer); - fx_framebuffer_get_or_create_bufferless(renderer, output, &renderer->effects_buffer_swapped); + fx_framebuffer_get_or_create_custom(renderer, output, &renderer->blur_saved_pixels_buffer); + fx_framebuffer_get_or_create_custom(renderer, output, &renderer->effects_buffer); + fx_framebuffer_get_or_create_custom(renderer, output, &renderer->effects_buffer_swapped); } pixman_region32_init(&renderer->blur_padding_region);