Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WLR Scene] Add blur #33

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ca66ef7
Add wlr_scene blur impl
ErikReider Feb 27, 2024
4e4efec
Added initial implementation of per output optimized blur
ErikReider Mar 6, 2024
de4ec10
Added ability to only re-render optimized blur on a specific output
ErikReider Mar 6, 2024
7634dbf
Merge branch 'main' into wlr_scene_blur
ErikReider Apr 15, 2024
2f9505a
Fixed segfault if scene_buffer doesn't contain a scene_surface
ErikReider Apr 15, 2024
3bccfb1
Merge branch 'main' into wlr_scene_blur
ErikReider May 7, 2024
29b42d0
Merge branch 'main' into wlr_scene_blur
ErikReider Sep 11, 2024
d94b758
Added support for wlr_scene_subsurface_tree_set_clip. Fixes blur not …
ErikReider Sep 11, 2024
0f25708
Added optimized blur example to tinywl
ErikReider Sep 11, 2024
d65b325
Merge branch 'main' into wlr_scene_blur
ErikReider Oct 19, 2024
59cf510
Fixed blur opaque region not being correct for non scene_surfaces
ErikReider Oct 19, 2024
3b0466b
Renamed wlr_scene_blur to wlr_scene_optimized_blur
ErikReider Oct 19, 2024
80371f6
Fixed optimized blur not being clipped
ErikReider Oct 19, 2024
a2f499e
Renamed enum WLR_SCENE_NODE_BLUR -> WLR_SCENE_NODE_OPTIMIZED_BLUR
ErikReider Oct 20, 2024
734af9c
Fixed silly bug where setting num_passes to the default value wouldn'…
ErikReider Oct 20, 2024
02136a7
Translate toplevel opaque_region to compensate for GTK CSD
ErikReider Oct 20, 2024
d61758f
Merge branch 'main' into wlr_scene_blur
ErikReider Oct 25, 2024
8697426
Set optimized blur node to always visible
ErikReider Oct 25, 2024
1946043
Fixed not optimized blur being restricted to damage
ErikReider Oct 25, 2024
7d61581
Merge branch 'main' into wlr_scene_blur
ErikReider Nov 2, 2024
1f7a977
Fixed blur corner rounding not matching scene_buffer
ErikReider Nov 3, 2024
049255c
Renamed should_blur -> scene_buffer_is_blur_enabled
ErikReider Nov 8, 2024
1286ed5
Simplified method of getting buffer opaque region
ErikReider Nov 8, 2024
808833e
Don't always update the optimized blur when setting buffer blur state
ErikReider Nov 8, 2024
cea3a7d
Skip re-rendering optimized blur when the blur node is disabled
ErikReider Nov 10, 2024
264ceb1
Fixed blur detection only working for wlr_scene_surface nodes
ErikReider Nov 10, 2024
bcdeb0b
Use transformed output size when extending blur damage
ErikReider Nov 10, 2024
3f4047c
Don't update the scene node twice when updating optimized size
ErikReider Nov 10, 2024
698373b
TinyWL: skip commit on initial_commit
ErikReider Nov 10, 2024
398761e
Rebase: wlroots 0.18.1 (#55)
ErikReider Nov 12, 2024
ff18aa8
Merge remote-tracking branch 'origin/main' into wlr_scene_blur
WillPower3309 Nov 13, 2024
decd7e2
updated flake for wlroots 0.18
WillPower3309 Nov 13, 2024
9b18eef
Merge remote-tracking branch 'origin/main' into wlr_scene_blur
WillPower3309 Nov 13, 2024
7e1b317
rebase: wlroots 0.18.1 (#55)
ErikReider Nov 12, 2024
12ab399
Merge remote-tracking branch 'origin/main' into wlr_scene_blur
WillPower3309 Nov 14, 2024
b3d9795
Merge remote-tracking branch 'origin/main' into wlr_scene_blur
WillPower3309 Nov 14, 2024
7b0711b
rebase fix
WillPower3309 Nov 14, 2024
2328527
fix2
WillPower3309 Nov 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/scenefx/types/fx/blur_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ struct blur_data {

struct blur_data blur_data_get_default(void);

bool scene_buffer_is_blur_enabled(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);
Expand Down
73 changes: 72 additions & 1 deletion include/scenefx/types/wlr_scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <wlr/util/addon.h>
#include <wlr/util/box.h>

#include "scenefx/types/fx/blur_data.h"
#include "scenefx/types/fx/corner_location.h"

struct wlr_output;
Expand Down Expand Up @@ -57,6 +58,7 @@ enum wlr_scene_node_type {
WLR_SCENE_NODE_RECT,
WLR_SCENE_NODE_SHADOW,
WLR_SCENE_NODE_BUFFER,
WLR_SCENE_NODE_OPTIMIZED_BLUR,
};

/** A node is an object in the scene. */
Expand Down Expand Up @@ -112,6 +114,8 @@ struct wlr_scene {
bool direct_scanout;
bool calculate_visibility;
bool highlight_transparent_region;

struct blur_data blur_data;
WillPower3309 marked this conversation as resolved.
Show resolved Hide resolved
};

/** A scene-graph node displaying a single surface. */
Expand Down Expand Up @@ -151,6 +155,12 @@ struct wlr_scene_shadow {
float blur_sigma;
};

/** A scene-graph node telling SceneFX to render the optimized blur */
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should maybe write that it doesn't actually render anything onto the tree

struct wlr_scene_optimized_blur {
struct wlr_scene_node node;
int width, height;
};

struct wlr_scene_outputs_update_event {
struct wlr_scene_output **active;
size_t size;
Expand Down Expand Up @@ -187,10 +197,13 @@ struct wlr_scene_buffer {
*/
struct wlr_scene_output *primary_output;

float opacity;
int corner_radius;
bool backdrop_blur;
bool backdrop_blur_optimized;
bool backdrop_blur_ignore_transparent;
enum corner_location corners;

float opacity;
enum wlr_scale_filter_mode filter_mode;
struct wlr_fbox src_box;
int dst_width, dst_height;
Expand Down Expand Up @@ -325,6 +338,10 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
*/
struct wlr_scene *wlr_scene_create(void);


/** Sets the global blur parameters */
void wlr_scene_set_blur_data(struct wlr_scene *scene, struct blur_data blur_data);
WillPower3309 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Handles linux_dmabuf_v1 feedback for all surfaces in the scene.
*
Expand Down Expand Up @@ -431,6 +448,30 @@ void wlr_scene_shadow_set_blur_sigma(struct wlr_scene_shadow *shadow, float blur
*/
void wlr_scene_shadow_set_color(struct wlr_scene_shadow *shadow, const float color[static 4]);

/**
* If this node represents a wlr_scene_optimized_blur node, that node will
* be returned. It is not legal to feed a node that does not represent
* a wlr_scene_optimized_blur.
*/
struct wlr_scene_optimized_blur *wlr_scene_optimized_blur_from_node(
struct wlr_scene_node *node);

/**
* Add a node indicating to the renderer to render optimized blur to the scene-graph.
* NOTE: Has to be positioned where to draw the optimized blur. This allows
* for unique effects like only blurring half of the output.
*/
struct wlr_scene_optimized_blur *wlr_scene_optimized_blur_create(struct wlr_scene_tree *parent,
int width, int height);

/**
* Change the width and height of an existing blur node.
* This calls `wlr_scene_optimized_blur_mark_dirty` as well
*/
void wlr_scene_optimized_blur_set_size(struct wlr_scene_optimized_blur *blur_node,
int width, int height);


/**
* Add a node displaying a buffer to the scene-graph.
*
Expand Down Expand Up @@ -506,6 +547,36 @@ void wlr_scene_buffer_set_filter_mode(struct wlr_scene_buffer *scene_buffer,
void wlr_scene_buffer_set_corner_radius(struct wlr_scene_buffer *scene_buffer,
int radii, enum corner_location corners);

/**
* 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 for the specified output.
* A NULL output will re-render the optimized blur on every output.
* This is 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,
struct wlr_scene_optimized_blur *blur_node, struct wlr_output *output);

/**
* Calls the buffer's frame_done signal.
*/
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
project(
'scenefx',
'c',
version: '0.1',
version: '0.2',
license: 'MIT',
meson_version: '>=0.59.0',
default_options: [
Expand Down
13 changes: 7 additions & 6 deletions render/fx_renderer/fx_pass.c
Original file line number Diff line number Diff line change
Expand Up @@ -1000,26 +1000,27 @@ void fx_render_pass_add_optimized_blur(struct fx_gles_render_pass *pass,
return;
}
struct fx_renderer *renderer = pass->buffer->renderer;
struct wlr_box monitor_box = get_monitor_box(pass->output);
struct wlr_box dst_box = fx_options->tex_options.base.dst_box;

pixman_region32_t fake_damage;
pixman_region32_init_rect(&fake_damage, 0, 0, monitor_box.width, monitor_box.height);
pixman_region32_t clip;
pixman_region32_init_rect(&clip,
dst_box.x, dst_box.y, dst_box.width, dst_box.height);

// Render the blur into its own buffer
struct fx_render_blur_pass_options blur_options = *fx_options;
blur_options.tex_options.base.clip = &fake_damage;
blur_options.current_buffer = pass->buffer;
blur_options.tex_options.base.clip = &clip;
struct fx_framebuffer *buffer = get_main_buffer_blur(pass, &blur_options);

// Update the optimized blur buffer if invalid
fx_framebuffer_get_or_create_custom(renderer, pass->output,
&pass->fx_effect_framebuffers->optimized_blur_buffer);

// Render the newly blurred content into the blur_buffer
fx_renderer_read_to_buffer(pass, &fake_damage,
fx_renderer_read_to_buffer(pass, &clip,
pass->fx_effect_framebuffers->optimized_blur_buffer, buffer, false);

pixman_region32_fini(&fake_damage);
pixman_region32_fini(&clip);

pass->fx_effect_framebuffers->blur_buffer_dirty = false;
}
Expand Down
84 changes: 83 additions & 1 deletion tinywl/tinywl.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <stdio.h>
#include <time.h>
#include <scenefx/render/fx_renderer/fx_renderer.h>
#include <scenefx/types/fx/blur_data.h>
#include <scenefx/types/fx/corner_location.h>
#include <scenefx/types/wlr_scene.h>
#include <unistd.h>
Expand Down Expand Up @@ -44,6 +45,12 @@ struct tinywl_server {
struct wlr_allocator *allocator;
struct wlr_scene *scene;
struct wlr_scene_output_layout *scene_layout;
struct {
struct wlr_scene_tree *bottom_layer;
/** Used for optimized blur. Everything exclusively below gets blurred */
struct wlr_scene_optimized_blur *blur_layer;
struct wlr_scene_tree *toplevel_layer;
} layers;

struct wlr_xdg_shell *xdg_shell;
struct wl_listener new_xdg_toplevel;
Expand Down Expand Up @@ -446,6 +453,15 @@ static void process_cursor_resize(struct tinywl_server *server, uint32_t time) {
int new_width = new_right - new_left;
int new_height = new_bottom - new_top;
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, new_width, new_height);

// Clip to geometry
struct wlr_box clip = {
.width = new_width,
.height = new_height,
.x = geo_box.x,
.y = geo_box.y,
};
wlr_scene_subsurface_tree_set_clip(&toplevel->scene_tree->node, &clip);
}

static void process_cursor_motion(struct tinywl_server *server, uint32_t time) {
Expand Down Expand Up @@ -663,6 +679,14 @@ static void output_request_state(struct wl_listener *listener, void *data) {
struct tinywl_output *output = wl_container_of(listener, output, request_state);
const struct wlr_output_event_request_state *event = data;
wlr_output_commit_state(output->wlr_output, event->state);

/*
* Sets the blur node size to the outputs size. Assumes there's only one
* output. More advanced compositors should either implement per output blur
* nodes or set it to the size of all outputs.
*/
wlr_scene_optimized_blur_set_size(output->server->layers.blur_layer,
output->wlr_output->width, output->wlr_output->height);
}

static void output_destroy(struct wl_listener *listener, void *data) {
Expand Down Expand Up @@ -737,6 +761,43 @@ static void server_new_output(struct wl_listener *listener, void *data) {
wlr_output);
struct wlr_scene_output *scene_output = wlr_scene_output_create(server->scene, wlr_output);
wlr_scene_output_layout_add_output(server->scene_layout, l_output, scene_output);

/*
* Sets the blur node size to the outputs size. Assumes there's only one
* output. More advanced compositors should either implement per output blur
* nodes or set it to the size of all outputs.
*/
wlr_scene_optimized_blur_set_size(output->server->layers.blur_layer,
output->wlr_output->width, output->wlr_output->height);
}

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,
CORNER_LOCATION_BOTTOM);

wlr_scene_buffer_set_backdrop_blur(buffer, true);
wlr_scene_buffer_set_backdrop_blur_optimized(buffer, true);
wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, true);
}
}
}

static void xdg_toplevel_map(struct wl_listener *listener, void *data) {
Expand All @@ -745,6 +806,9 @@ static void xdg_toplevel_map(struct wl_listener *listener, void *data) {

wlr_scene_node_set_enabled(&toplevel->scene_tree->node, true);

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);
Expand Down Expand Up @@ -878,7 +942,7 @@ static void server_new_xdg_toplevel(struct wl_listener *listener, void *data) {
struct tinywl_toplevel *toplevel = calloc(1, sizeof(*toplevel));
toplevel->server = server;
toplevel->xdg_toplevel = xdg_toplevel;
toplevel->scene_tree = wlr_scene_tree_create(&toplevel->server->scene->tree);
toplevel->scene_tree = wlr_scene_tree_create(toplevel->server->layers.toplevel_layer);
toplevel->xdg_scene_tree = wlr_scene_xdg_surface_create(
toplevel->scene_tree, xdg_toplevel->base);
toplevel->scene_tree->node.data = toplevel;
Expand Down Expand Up @@ -1060,6 +1124,24 @@ int main(int argc, char *argv[]) {
server.scene = wlr_scene_create();
server.scene_layout = wlr_scene_attach_output_layout(server.scene, server.output_layout);

/* Create all of the basic scene layers */
server.layers.bottom_layer = wlr_scene_tree_create(&server.scene->tree);
/* Add a bottom rect to demonstrate optimized blur */
float bottom_rect_color[4] = { 1, 1, 1, 1 };
wlr_scene_rect_create(server.layers.bottom_layer, 200, 200, bottom_rect_color);
/* Set the size later */
server.layers.blur_layer = wlr_scene_optimized_blur_create(&server.scene->tree, 0, 0);
server.layers.toplevel_layer = wlr_scene_tree_create(&server.scene->tree);
/* Add a top rect that won't get blurred by optimized */
float top_rect_color[4] = { 1, 0, 0, 1 };
struct wlr_scene_rect *rect = wlr_scene_rect_create(server.layers.toplevel_layer,
200, 200, top_rect_color);
wlr_scene_node_set_position(&rect->node, 200, 200);

// blur
struct blur_data blur_data = blur_data_get_default();
wlr_scene_set_blur_data(server.scene, blur_data);

/* Set up xdg-shell version 3. The xdg-shell is a Wayland protocol which is
* used for application windows. For more detail on shells, refer to
* https://drewdevault.com/2018/07/29/Wayland-shells.html.
Expand Down
6 changes: 5 additions & 1 deletion types/fx/blur_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ struct blur_data blur_data_get_default(void) {
};
}

bool scene_buffer_is_blur_enabled(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
Expand All @@ -20,7 +24,7 @@ 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->num_passes == b->num_passes &&
a->noise == b->noise &&
a->brightness == b->brightness &&
a->contrast == b->contrast &&
Expand Down
Loading