Skip to content

Commit

Permalink
surface-damage: add a helper to track surface damage
Browse files Browse the repository at this point in the history
One remaining major pain point when implementing damage tracking is tracking
damage from surfaces and all of their children. Compositors need to add
new listeners for each view child type, with the appropriate new data
structures.

This commit adds a new helper to ease damage tracking: wlr_surface_damage. It
tracks damage from a surface and all its children and reports it via a "damage"
event in surface-local coordinates. This way, compositors just need to add one
listener for the whole view. There is one function per shell to create a
wlr_surface_damage, just like other helpers like wlr_surface_for_each_surface.

Additional functions are provided to allow compositors to manually damage
surfaces. wlr_surface_damage_add_whole will damage the whole surface and all
its children, this is useful when moving a view.

Of course, this helper is optional, and damage tracking done entirely in the
compositor will still work.

Fixes swaywm#1543
  • Loading branch information
emersion committed Feb 16, 2019
1 parent 2d2c79e commit 9308304
Show file tree
Hide file tree
Showing 12 changed files with 482 additions and 74 deletions.
2 changes: 2 additions & 0 deletions include/rootston/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ struct roots_drag_icon;
void output_damage_whole(struct roots_output *output);
void output_damage_whole_view(struct roots_output *output,
struct roots_view *view);
void output_damage(struct roots_output *output,
int ox, int oy, pixman_region32_t *damage);
void output_damage_from_view(struct roots_output *output,
struct roots_view *view);
void output_damage_whole_drag_icon(struct roots_output *output,
Expand Down
13 changes: 4 additions & 9 deletions include/rootston/view.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <wlr/config.h>
#include <wlr/types/wlr_box.h>
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#include <wlr/types/wlr_surface_damage.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_shell_v6.h>
Expand Down Expand Up @@ -140,15 +141,15 @@ struct roots_view {
};

struct wlr_surface *wlr_surface;
struct wlr_surface_damage *surface_damage;
struct wl_list children; // roots_view_child::link

struct wlr_foreign_toplevel_handle_v1 *toplevel_handle;

struct wl_listener damage;
struct wl_listener toplevel_handle_request_maximize;
struct wl_listener toplevel_handle_request_activate;
struct wl_listener toplevel_handle_request_close;

struct wl_listener new_subsurface;

struct {
struct wl_signal unmap;
struct wl_signal destroy;
Expand Down Expand Up @@ -177,12 +178,6 @@ struct roots_view_child {
void (*destroy)(struct roots_view_child *child);
};

struct roots_subsurface {
struct roots_view_child view_child;
struct wlr_subsurface *wlr_subsurface;
struct wl_listener destroy;
};

struct roots_wl_shell_popup {
struct roots_view_child view_child;
struct wlr_wl_shell_surface *wlr_wl_shell_surface;
Expand Down
1 change: 1 addition & 0 deletions include/wlr/types/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ install_headers(
'wlr_screenshooter.h',
'wlr_seat.h',
'wlr_server_decoration.h',
'wlr_surface_damage.h',
'wlr_surface.h',
'wlr_switch.h',
'wlr_tablet_pad.h',
Expand Down
2 changes: 1 addition & 1 deletion include/wlr/types/wlr_surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ struct wlr_surface {

struct {
struct wl_signal commit;
struct wl_signal new_subsurface;
struct wl_signal new_subsurface; // wlr_subsurface
struct wl_signal destroy;
} events;

Expand Down
69 changes: 69 additions & 0 deletions include/wlr/types/wlr_surface_damage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif

#ifndef WLR_TYPES_WLR_SURFACE_DAMAGE_H
#define WLR_TYPES_WLR_SURFACE_DAMAGE_H

#include <pixman.h>
#include <wayland-server.h>
#include <wlr/types/wlr_surface.h>

struct wlr_surface_damage;

struct wlr_surface_damage_interface {
void (*destroy)(struct wlr_surface_damage *surface_damage);
void (*add_children)(struct wlr_surface_damage *surface_damage);
};

void wlr_surface_damage_init(struct wlr_surface_damage *surface_damage,
struct wlr_surface *surface,
const struct wlr_surface_damage_interface *impl);
void wlr_surface_damage_add(struct wlr_surface_damage *surface_damage,
int32_t sx, int32_t sy, pixman_region32_t *damage);

/**
* Tracks damage coming from a surface and its children.
*
* When a surface maps, unmaps or commits, the `damage` event will be emitted.
*/
struct wlr_surface_damage {
struct wlr_surface *surface;
const struct wlr_surface_damage_interface *impl;

struct {
struct wl_signal destroy;
struct wl_signal damage; // wlr_surface_damage_event
} events;

struct wl_list subsurfaces;

struct wl_listener surface_destroy;
struct wl_listener surface_commit;
struct wl_listener surface_new_subsurface;

void *data;
};

struct wlr_surface_damage_event {
struct wlr_surface_damage *surface_damage;
int32_t sx, sy;
pixman_region32_t *damage;
};

/**
* Tracks damage from a surface and its children subsurfaces.
*/
struct wlr_surface_damage *wlr_surface_damage_create(
struct wlr_surface *surface);
void wlr_surface_damage_destroy(struct wlr_surface_damage *surface_damage);
/**
* Damage the whole surface and all its children.
*/
void wlr_surface_damage_add_whole(struct wlr_surface_damage *surface_damage);

#endif
11 changes: 11 additions & 0 deletions include/wlr/types/wlr_xdg_shell.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,4 +391,15 @@ uint32_t wlr_xdg_surface_schedule_configure(struct wlr_xdg_surface *surface);
void wlr_xdg_surface_for_each_popup(struct wlr_xdg_surface *surface,
wlr_surface_iterator_func_t iterator, void *user_data);

struct wlr_surface_damage;

/**
* Tracks damage from a surface and its children subsurfaces and popups.
*/
struct wlr_surface_damage *wlr_xdg_surface_damage_create(
struct wlr_xdg_surface *xdg_surface);
struct wlr_surface_damage *wlr_xdg_popup_damage_create(
struct wlr_xdg_popup *popup, struct wlr_surface_damage *parent,
struct wl_list *list);

#endif
89 changes: 27 additions & 62 deletions rootston/desktop.c
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,6 @@ void view_child_finish(struct roots_view_child *child) {
view_damage_whole(child->view);
wl_list_remove(&child->link);
wl_list_remove(&child->commit.link);
wl_list_remove(&child->new_subsurface.link);
}

static void view_child_handle_commit(struct wl_listener *listener,
Expand All @@ -393,60 +392,16 @@ static void view_child_handle_commit(struct wl_listener *listener,
view_apply_damage(child->view);
}

static void view_child_handle_new_subsurface(struct wl_listener *listener,
void *data) {
struct roots_view_child *child =
wl_container_of(listener, child, new_subsurface);
struct wlr_subsurface *wlr_subsurface = data;
subsurface_create(child->view, wlr_subsurface);
}

void view_child_init(struct roots_view_child *child, struct roots_view *view,
struct wlr_surface *wlr_surface) {
assert(child->destroy);
child->view = view;
child->wlr_surface = wlr_surface;
child->commit.notify = view_child_handle_commit;
wl_signal_add(&wlr_surface->events.commit, &child->commit);
child->new_subsurface.notify = view_child_handle_new_subsurface;
wl_signal_add(&wlr_surface->events.new_subsurface, &child->new_subsurface);
wl_list_insert(&view->children, &child->link);
}

static void subsurface_destroy(struct roots_view_child *child) {
assert(child->destroy == subsurface_destroy);
struct roots_subsurface *subsurface = (struct roots_subsurface *)child;
if (subsurface == NULL) {
return;
}
wl_list_remove(&subsurface->destroy.link);
view_child_finish(&subsurface->view_child);
free(subsurface);
}

static void subsurface_handle_destroy(struct wl_listener *listener,
void *data) {
struct roots_subsurface *subsurface =
wl_container_of(listener, subsurface, destroy);
subsurface_destroy((struct roots_view_child *)subsurface);
}

struct roots_subsurface *subsurface_create(struct roots_view *view,
struct wlr_subsurface *wlr_subsurface) {
struct roots_subsurface *subsurface =
calloc(1, sizeof(struct roots_subsurface));
if (subsurface == NULL) {
return NULL;
}
subsurface->wlr_subsurface = wlr_subsurface;
subsurface->view_child.destroy = subsurface_destroy;
view_child_init(&subsurface->view_child, view, wlr_subsurface->surface);
subsurface->destroy.notify = subsurface_handle_destroy;
wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
input_update_cursor_focus(view->desktop->server->input);
return subsurface;
}

void view_destroy(struct roots_view *view) {
if (view == NULL) {
return;
Expand All @@ -470,30 +425,42 @@ void view_destroy(struct roots_view *view) {
free(view);
}

static void view_handle_new_subsurface(struct wl_listener *listener,
void *data) {
struct roots_view *view = wl_container_of(listener, view, new_subsurface);
struct wlr_subsurface *wlr_subsurface = data;
subsurface_create(view, wlr_subsurface);
static void view_handle_damage(struct wl_listener *listener, void *data) {
struct roots_view *view = wl_container_of(listener, view, damage);
struct wlr_surface_damage_event *event = data;

// TODO: rotation
// wlr_region_rotated_bounds(&damage, &damage, rotation, center_x, center_y);

int lx = view->box.x + event->sx;
int ly = view->box.y + event->sy;

struct roots_output *output;
wl_list_for_each(output, &view->desktop->outputs, link) {
double ox = lx, oy = ly;
wlr_output_layout_output_coords(output->desktop->layout,
output->wlr_output, &ox, &oy);
output_damage(output, ox, oy, event->damage);
}

struct wlr_surface_damage_event {
struct wlr_surface_damage *surface_damage;
int32_t sx, sy;
pixman_region32_t *damage;
};
}

void view_map(struct roots_view *view, struct wlr_surface *surface) {
assert(view->wlr_surface == NULL);

view->wlr_surface = surface;
view->surface_damage = wlr_surface_damage_create(surface);

struct wlr_subsurface *subsurface;
wl_list_for_each(subsurface, &view->wlr_surface->subsurfaces,
parent_link) {
subsurface_create(view, subsurface);
}

view->new_subsurface.notify = view_handle_new_subsurface;
wl_signal_add(&view->wlr_surface->events.new_subsurface,
&view->new_subsurface);
wl_signal_add(&view->surface_damage->events.damage, &view->damage);
view->damage.notify = view_handle_damage;

wl_list_insert(&view->desktop->views, &view->link);
view_damage_whole(view);
wlr_surface_damage_add_whole(view->surface_damage);
input_update_cursor_focus(view->desktop->server->input);
}

Expand All @@ -505,8 +472,6 @@ void view_unmap(struct roots_view *view) {
view_damage_whole(view);
wl_list_remove(&view->link);

wl_list_remove(&view->new_subsurface.link);

struct roots_view_child *child, *tmp;
wl_list_for_each_safe(child, tmp, &view->children, link) {
child->destroy(child);
Expand Down
10 changes: 10 additions & 0 deletions rootston/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,16 @@ void output_damage_from_view(struct roots_output *output,
view_for_each_surface(view, &data.layout, damage_from_surface, &data);
}

void output_damage(struct roots_output *output,
int ox, int oy, pixman_region32_t *damage) {
pixman_region32_t output_damage;
pixman_region32_init(&output_damage);
pixman_region32_copy(&output_damage, damage);
pixman_region32_translate(&output_damage, ox, oy);
wlr_output_damage_add(output->damage, &output_damage);
pixman_region32_fini(&output_damage);
}

static void set_mode(struct wlr_output *output,
struct roots_output_config *oc) {
int mhz = (int)(oc->mode.refresh_rate * 1000);
Expand Down
3 changes: 1 addition & 2 deletions rootston/xdg_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,12 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) {

static void popup_handle_map(struct wl_listener *listener, void *data) {
struct roots_xdg_popup *popup = wl_container_of(listener, popup, map);
view_damage_whole(popup->view_child.view);
input_update_cursor_focus(popup->view_child.view->desktop->server->input);
}

static void popup_handle_unmap(struct wl_listener *listener, void *data) {
struct roots_xdg_popup *popup = wl_container_of(listener, popup, unmap);
view_damage_whole(popup->view_child.view);
input_update_cursor_focus(popup->view_child.view->desktop->server->input);
}

static struct roots_xdg_popup *popup_create(struct roots_view *view,
Expand Down
1 change: 1 addition & 0 deletions types/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ lib_wlr_types = static_library(
'wlr_screencopy_v1.c',
'wlr_screenshooter.c',
'wlr_server_decoration.c',
'wlr_surface_damage.c',
'wlr_surface.c',
'wlr_switch.c',
'wlr_tablet_pad.c',
Expand Down
Loading

0 comments on commit 9308304

Please sign in to comment.