Skip to content

Commit f83d744

Browse files
committed
Simplified the linking of the scene shadow and buffer nodes
1 parent 67d235c commit f83d744

File tree

5 files changed

+144
-42
lines changed

5 files changed

+144
-42
lines changed

include/scenefx/types/wlr_scene.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "scenefx/types/fx/blur_data.h"
3232
#include "scenefx/types/fx/clipped_region.h"
3333
#include "scenefx/types/fx/corner_location.h"
34+
#include "types/linked_nodes.h"
3435

3536
struct wlr_output;
3637
struct wlr_output_layout;
@@ -171,8 +172,8 @@ struct wlr_scene_shadow {
171172

172173
enum wlr_scene_shadow_type type;
173174
struct {
174-
// Used to draw a drop-shadow. If NULL, falls-back to a box-shadow
175-
struct wlr_scene_buffer *reference_buffer;
175+
// Used to draw a drop-shadow
176+
struct linked_node buffer_link;
176177
} WLR_PRIVATE;
177178

178179
struct clipped_region clipped_region;
@@ -256,8 +257,8 @@ struct wlr_scene_buffer {
256257
// as {R, G, B, A} where the max value of each component is UINT32_MAX
257258
uint32_t single_pixel_buffer_color[4];
258259

259-
/** May be NULL. Used to know which shadow's linked to this scene_buffer */
260-
struct wlr_scene_shadow *linked_drop_shadow;
260+
// Used to know which shadow's linked to this scene_buffer
261+
struct linked_node drop_shadow_link;
261262
} WLR_PRIVATE;
262263
};
263264

include/types/linked_nodes.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef TYPES_LINKED_NODES_H
2+
#define TYPES_LINKED_NODES_H
3+
4+
/**
5+
* A node in a link between two objects. Can be used to safely couple two
6+
* objects together.
7+
*/
8+
struct linked_node {
9+
struct link *link;
10+
};
11+
12+
#define linked_node_init() \
13+
((struct linked_node) { \
14+
.link = NULL \
15+
})
16+
17+
void linked_node_init_link(struct linked_node *main_node,
18+
struct linked_node *reference_node);
19+
20+
struct linked_node *linked_nodes_get_sibling(struct linked_node *node);
21+
22+
void linked_node_unlink(struct linked_node *main_node,
23+
struct linked_node *reference_node);
24+
25+
void linked_node_destroy(struct linked_node *node);
26+
27+
#endif

types/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
scenefx_files += files(
22
'scene/wlr_scene.c',
3+
'scene/linked_nodes.c',
34
'output/wlr_output.c',
45
)
56

types/scene/linked_nodes.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include <assert.h>
2+
#include <stdbool.h>
3+
#include <stdlib.h>
4+
#include <wlr/util/log.h>
5+
6+
#include "types/linked_nodes.h"
7+
8+
struct link {
9+
struct linked_node *node_1;
10+
struct linked_node *node_2;
11+
};
12+
13+
static struct link *link_init(struct linked_node *node_1,
14+
struct linked_node *node_2) {
15+
struct link *link = calloc(1, sizeof(*link));
16+
if (!link) {
17+
wlr_log(WLR_ERROR, "Failed to allocate link!");
18+
return NULL;
19+
}
20+
21+
link->node_1 = node_1;
22+
link->node_2 = node_2;
23+
24+
return link;
25+
}
26+
27+
//
28+
// Linked Node
29+
//
30+
31+
static bool linked_nodes_are_linked(struct linked_node *node_1,
32+
struct linked_node *node_2) {
33+
return node_1->link != NULL && node_2->link != NULL
34+
&& node_1->link == node_2->link;
35+
}
36+
37+
void linked_node_init_link(struct linked_node *node_1,
38+
struct linked_node *node_2) {
39+
if (node_1->link || node_2->link) {
40+
assert(linked_nodes_are_linked(node_1, node_2));
41+
linked_node_unlink(node_1, node_2);
42+
}
43+
44+
struct link *link = link_init(node_1, node_2);
45+
node_1->link = link;
46+
node_2->link = link;
47+
}
48+
49+
struct linked_node *linked_nodes_get_sibling(struct linked_node *node) {
50+
if (node->link == NULL) {
51+
return NULL;
52+
}
53+
assert(node == node->link->node_1 || node == node->link->node_2);
54+
55+
struct link *link = node->link;
56+
if (link->node_1 == node) {
57+
return link->node_2;
58+
}
59+
return link->node_1;
60+
}
61+
62+
void linked_node_unlink(struct linked_node *node_1,
63+
struct linked_node *node_2) {
64+
assert(linked_nodes_are_linked(node_1, node_2));
65+
66+
struct link *link = node_1->link;
67+
node_1->link = NULL;
68+
node_2->link = NULL;
69+
free(link);
70+
}
71+
72+
void linked_node_destroy(struct linked_node *node) {
73+
if (node->link == NULL) {
74+
return;
75+
}
76+
assert(node == node->link->node_1 || node == node->link->node_2);
77+
linked_node_unlink(node->link->node_1, node->link->node_2);
78+
}

types/scene/wlr_scene.c

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "scenefx/types/fx/blur_data.h"
2525
#include "scenefx/types/fx/clipped_region.h"
2626
#include "scenefx/types/fx/corner_location.h"
27+
#include "types/linked_nodes.h"
2728
#include "types/wlr_output.h"
2829
#include "types/wlr_scene.h"
2930
#include "util/array.h"
@@ -48,7 +49,7 @@
4849
scene_rect->color[3] < 1.0f)
4950
#define SCENE_SHADOW_IS_DROP(scene_shadow) \
5051
(scene_shadow->type == WLR_SCENE_SHADOW_TYPE_DROP \
51-
&& scene_shadow->reference_buffer \
52+
&& scene_shadow->buffer_link.link != NULL \
5253
&& scene_shadow->blur_sigma >= 0)
5354

5455
struct wlr_scene_tree *wlr_scene_tree_from_node(struct wlr_scene_node *node) {
@@ -193,10 +194,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) {
193194
} else if (node->type == WLR_SCENE_NODE_SHADOW) {
194195
// Remove the drop-shadows referenced buffers link to this node
195196
struct wlr_scene_shadow *scene_shadow = wlr_scene_shadow_from_node(node);
196-
if (scene_shadow->reference_buffer
197-
&& scene_shadow->reference_buffer->linked_drop_shadow == scene_shadow) {
198-
scene_shadow->reference_buffer->linked_drop_shadow = NULL;
199-
}
197+
linked_node_destroy(&scene_shadow->buffer_link);
200198
}
201199

202200
assert(wl_list_empty(&node->events.destroy.listener_list));
@@ -999,7 +997,7 @@ struct wlr_scene_shadow *wlr_scene_shadow_create(struct wlr_scene_tree *parent,
999997

1000998
scene_node_update(&scene_shadow->node, NULL);
1001999

1002-
scene_shadow->reference_buffer = NULL;
1000+
scene_shadow->buffer_link = linked_node_init();
10031001
scene_shadow->type = WLR_SCENE_SHADOW_TYPE_BOX;
10041002

10051003
return scene_shadow;
@@ -1051,19 +1049,8 @@ void wlr_scene_shadow_set_reference_buffer(struct wlr_scene_shadow *shadow,
10511049
return;
10521050
}
10531051

1054-
// Unlink the other drop shadow from the reference buffer if it exists
1055-
if (shadow->reference_buffer) {
1056-
shadow->reference_buffer->linked_drop_shadow = NULL;
1057-
}
1058-
if (ref_buffer) {
1059-
ref_buffer->linked_drop_shadow = shadow;
1060-
}
1052+
linked_node_init_link(&shadow->buffer_link, &ref_buffer->drop_shadow_link);
10611053

1062-
if (ref_buffer == shadow->reference_buffer) {
1063-
return;
1064-
}
1065-
1066-
shadow->reference_buffer = ref_buffer;
10671054
scene_node_update(&shadow->node, NULL);
10681055
}
10691056

@@ -1264,7 +1251,7 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
12641251
scene_buffer->backdrop_blur_optimized = false;
12651252
scene_buffer->backdrop_blur_ignore_transparent = true;
12661253
scene_buffer->corners = CORNER_LOCATION_NONE;
1267-
scene_buffer->linked_drop_shadow = NULL;
1254+
scene_buffer->drop_shadow_link = linked_node_init();
12681255

12691256
scene_buffer_set_buffer(scene_buffer, buffer);
12701257
scene_node_update(&scene_buffer->node, NULL);
@@ -1414,24 +1401,27 @@ void wlr_scene_buffer_set_buffer_with_options(struct wlr_scene_buffer *scene_buf
14141401
pixman_region32_fini(&cull_region);
14151402

14161403
// Also damage the linked drop-shadow
1417-
struct wlr_scene_shadow *scene_shadow = scene_buffer->linked_drop_shadow;
1418-
if (scene_shadow && SCENE_SHADOW_IS_DROP(scene_shadow)) {
1419-
int shadow_lx, shadow_ly;
1420-
if (wlr_scene_node_coords(&scene_shadow->node, &shadow_lx, &shadow_ly)) {
1421-
const int shadow_size = drop_shadow_calc_size(scene_shadow->blur_sigma);
1422-
1423-
// Copy the damaged region, translate it to the shadow nodes
1424-
// position, and add it to the original damage
1425-
pixman_region32_t shadow_damage;
1426-
pixman_region32_init(&shadow_damage);
1427-
pixman_region32_copy(&shadow_damage, &output_damage);
1428-
pixman_region32_translate(&shadow_damage,
1429-
((shadow_lx + shadow_size) - lx) * output_scale,
1430-
((shadow_ly + shadow_size) - ly) * output_scale);
1431-
wlr_region_expand(&shadow_damage, &shadow_damage,
1432-
drop_shadow_calc_size(scene_shadow->blur_sigma));
1433-
1434-
pixman_region32_union(&output_damage, &output_damage, &shadow_damage);
1404+
struct linked_node *shadow_link = linked_nodes_get_sibling(&scene_buffer->drop_shadow_link);
1405+
if (shadow_link != NULL) {
1406+
struct wlr_scene_shadow *scene_shadow = wl_container_of(shadow_link, scene_shadow, buffer_link);
1407+
if (scene_shadow && SCENE_SHADOW_IS_DROP(scene_shadow)) {
1408+
int shadow_lx, shadow_ly;
1409+
if (wlr_scene_node_coords(&scene_shadow->node, &shadow_lx, &shadow_ly)) {
1410+
const int shadow_size = drop_shadow_calc_size(scene_shadow->blur_sigma);
1411+
1412+
// Copy the damaged region, translate it to the shadow nodes
1413+
// position, and add it to the original damage
1414+
pixman_region32_t shadow_damage;
1415+
pixman_region32_init(&shadow_damage);
1416+
pixman_region32_copy(&shadow_damage, &output_damage);
1417+
pixman_region32_translate(&shadow_damage,
1418+
((shadow_lx + shadow_size) - lx) * output_scale,
1419+
((shadow_ly + shadow_size) - ly) * output_scale);
1420+
wlr_region_expand(&shadow_damage, &shadow_damage,
1421+
drop_shadow_calc_size(scene_shadow->blur_sigma));
1422+
1423+
pixman_region32_union(&output_damage, &output_damage, &shadow_damage);
1424+
}
14351425
}
14361426
}
14371427

@@ -2044,7 +2034,12 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
20442034

20452035
// Drop Shadow
20462036
if (scene_shadow->type == WLR_SCENE_SHADOW_TYPE_DROP) {
2047-
struct wlr_scene_buffer *scene_buffer = scene_shadow->reference_buffer;
2037+
struct linked_node *buffer_link = linked_nodes_get_sibling(&scene_shadow->buffer_link);
2038+
struct wlr_scene_buffer *scene_buffer = NULL;
2039+
if (buffer_link != NULL) {
2040+
scene_buffer = wl_container_of(buffer_link, scene_buffer, drop_shadow_link);
2041+
}
2042+
20482043
if (!scene_buffer) {
20492044
wlr_log(WLR_ERROR, "Trying to render drop-shadow with NULL reference_buffer."
20502045
" Please set the buffer before rendering. Rendering as a box-shadow...");

0 commit comments

Comments
 (0)