libweston: Track damage on paint nodes instead of planes
Remove plane->damage and instead accumulate damage on paint nodes. This is a step towards allowing multiple overlapping outputs. Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
This commit is contained in:
parent
fe2b5db01e
commit
820346a372
@ -1267,7 +1267,6 @@ struct weston_layer {
|
||||
|
||||
struct weston_plane {
|
||||
struct weston_compositor *compositor;
|
||||
pixman_region32_t damage; /**< in global coords */
|
||||
pixman_region32_t clip;
|
||||
int32_t x, y;
|
||||
struct wl_list link;
|
||||
|
@ -708,8 +708,6 @@ drm_output_set_cursor(struct drm_output_state *output_state)
|
||||
return;
|
||||
|
||||
if (!state->fb) {
|
||||
pixman_region32_fini(&plane->base.damage);
|
||||
pixman_region32_init(&plane->base.damage);
|
||||
drmModeSetCursor(device->drm.fd, crtc->crtc_id, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
@ -727,9 +725,6 @@ drm_output_set_cursor(struct drm_output_state *output_state)
|
||||
}
|
||||
}
|
||||
|
||||
pixman_region32_fini(&plane->base.damage);
|
||||
pixman_region32_init(&plane->base.damage);
|
||||
|
||||
if (drmModeMoveCursor(device->drm.fd, crtc->crtc_id,
|
||||
state->dest_x, state->dest_y)) {
|
||||
weston_log("failed to move cursor: %s\n", strerror(errno));
|
||||
|
@ -149,6 +149,25 @@ weston_output_dirty_paint_nodes(struct weston_output *output)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
paint_node_damage_below(struct weston_paint_node *pnode)
|
||||
{
|
||||
struct weston_paint_node *lower_node;
|
||||
|
||||
if (!pnode->plane)
|
||||
return;
|
||||
|
||||
wl_list_for_each(lower_node, &pnode->z_order_link,
|
||||
z_order_link) {
|
||||
|
||||
if (lower_node->plane != pnode->plane)
|
||||
continue;
|
||||
|
||||
pixman_region32_union(&lower_node->damage, &lower_node->damage,
|
||||
&pnode->visible);
|
||||
}
|
||||
}
|
||||
|
||||
/* Paint nodes contain filter and transform information that needs to be
|
||||
* up to date before assign_planes() is called. But there are also
|
||||
* damage related bits that must be updated after assign_planes()
|
||||
@ -181,8 +200,20 @@ paint_node_update_early(struct weston_paint_node *pnode)
|
||||
static void
|
||||
paint_node_update_late(struct weston_paint_node *pnode)
|
||||
{
|
||||
bool vis_dirty = pnode->status & PAINT_NODE_VISIBILITY_DIRTY;
|
||||
bool plane_dirty = pnode->status & PAINT_NODE_PLANE_DIRTY;
|
||||
|
||||
/* The geoemtry may be shrinking, so we shouldn't just
|
||||
* add the old visible region to our damage region, because
|
||||
* our damage region shouldn't contain anything outside of
|
||||
* our geometry.
|
||||
*
|
||||
* On a plane change, we need to damage below now before
|
||||
* we update visibility.
|
||||
*/
|
||||
if (vis_dirty || plane_dirty)
|
||||
paint_node_damage_below(pnode);
|
||||
|
||||
/* Even if our geometry didn't change, our visible region may
|
||||
* have been updated by some other node changing. Keep the
|
||||
* visible region up to date.
|
||||
@ -191,6 +222,15 @@ paint_node_update_late(struct weston_paint_node *pnode)
|
||||
&pnode->view->visible,
|
||||
&pnode->output->region);
|
||||
|
||||
/* If our visible region was dirty, we should damage the entire
|
||||
* new visible region to ensure a redraw of our content.
|
||||
*
|
||||
* If we chanaged planes, we need full visible region damage
|
||||
* on the new plane now that visibility is updated.
|
||||
*/
|
||||
if (pnode->plane && (vis_dirty || plane_dirty))
|
||||
pixman_region32_copy(&pnode->damage, &pnode->visible);
|
||||
|
||||
if (plane_dirty) {
|
||||
assert(pnode->plane_next);
|
||||
|
||||
@ -247,6 +287,7 @@ weston_paint_node_create(struct weston_surface *surface,
|
||||
|
||||
wl_list_init(&pnode->z_order_link);
|
||||
|
||||
pixman_region32_init(&pnode->damage);
|
||||
pixman_region32_init(&pnode->visible);
|
||||
pixman_region32_copy(&pnode->visible, &view->visible);
|
||||
|
||||
@ -262,12 +303,16 @@ static void
|
||||
weston_paint_node_destroy(struct weston_paint_node *pnode)
|
||||
{
|
||||
assert(pnode->view->surface == pnode->surface);
|
||||
|
||||
paint_node_damage_below(pnode);
|
||||
|
||||
wl_list_remove(&pnode->surface_link);
|
||||
wl_list_remove(&pnode->view_link);
|
||||
wl_list_remove(&pnode->output_link);
|
||||
wl_list_remove(&pnode->z_order_link);
|
||||
assert(pnode->surf_xform_valid || !pnode->surf_xform.transform);
|
||||
weston_surface_color_transform_fini(&pnode->surf_xform);
|
||||
pixman_region32_fini(&pnode->damage);
|
||||
pixman_region32_fini(&pnode->visible);
|
||||
free(pnode);
|
||||
}
|
||||
@ -1004,46 +1049,15 @@ weston_paint_node_move_to_plane(struct weston_paint_node *pnode,
|
||||
if (pnode->plane == plane)
|
||||
return;
|
||||
|
||||
weston_view_damage_below(pnode->view);
|
||||
pnode->plane_next = plane;
|
||||
weston_surface_damage(pnode->view->surface);
|
||||
|
||||
pnode->status |= PAINT_NODE_PLANE_DIRTY |
|
||||
PAINT_NODE_VISIBILITY_DIRTY;
|
||||
}
|
||||
|
||||
/** Inflict damage on the plane where the view is visible.
|
||||
*
|
||||
* \param view The view that causes the damage.
|
||||
*
|
||||
* If the view is currently on a plane (including the primary plane),
|
||||
* take the view's boundingbox, subtract all the opaque views that cover it,
|
||||
* and add the remaining region as damage to the plane. This corresponds
|
||||
* to the damage inflicted to the plane if this view disappeared.
|
||||
*
|
||||
* A repaint is scheduled for this view.
|
||||
*
|
||||
* The region of all opaque views covering this view is stored in
|
||||
* weston_view::clip and updated by output_update_visibility() during
|
||||
* weston_output_repaint(). Specifically, that region matches the
|
||||
* scenegraph as it was last painted.
|
||||
*/
|
||||
WL_EXPORT void
|
||||
weston_view_damage_below(struct weston_view *view)
|
||||
{
|
||||
struct weston_paint_node *pnode;
|
||||
pixman_region32_t damage;
|
||||
|
||||
pixman_region32_init(&damage);
|
||||
pixman_region32_subtract(&damage, &view->transform.boundingbox,
|
||||
&view->clip);
|
||||
wl_list_for_each(pnode, &view->paint_node_list, view_link) {
|
||||
assert(pnode->plane);
|
||||
|
||||
pixman_region32_union(&pnode->plane->damage,
|
||||
&pnode->plane->damage, &damage);
|
||||
}
|
||||
pixman_region32_fini(&damage);
|
||||
weston_view_schedule_repaint(view);
|
||||
}
|
||||
|
||||
@ -2930,39 +2944,10 @@ weston_output_damage(struct weston_output *output)
|
||||
weston_output_schedule_repaint(output);
|
||||
}
|
||||
|
||||
/* FIXME: note that we don't flush any damage when the core wants us to
|
||||
* do so as it will sometimes ask for a flush not necessarily at the
|
||||
* right time.
|
||||
*
|
||||
* A (more) proper way is to handle correctly damage whenever there's
|
||||
* compositor side damage. See the comment for weston_surface_damage().
|
||||
*/
|
||||
static bool
|
||||
buffer_can_be_accessed_BANDAID_XXX(struct weston_buffer_reference buffer_ref)
|
||||
{
|
||||
return buffer_ref.type == BUFFER_MAY_BE_ACCESSED;
|
||||
}
|
||||
|
||||
static void
|
||||
surface_flush_damage(struct weston_surface *surface, struct weston_output *output)
|
||||
paint_node_add_damage(struct weston_paint_node *node)
|
||||
{
|
||||
struct weston_buffer *buffer = surface->buffer_ref.buffer;
|
||||
|
||||
if (buffer->type == WESTON_BUFFER_SHM &&
|
||||
buffer_can_be_accessed_BANDAID_XXX(surface->buffer_ref))
|
||||
surface->compositor->renderer->flush_damage(surface, buffer);
|
||||
|
||||
if (pixman_region32_not_empty(&surface->damage))
|
||||
TL_POINT(surface->compositor, "core_flush_damage",
|
||||
TLP_SURFACE(surface), TLP_OUTPUT(output), TLP_END);
|
||||
|
||||
pixman_region32_clear(&surface->damage);
|
||||
}
|
||||
|
||||
static void
|
||||
view_accumulate_damage(struct weston_view *view)
|
||||
{
|
||||
struct weston_paint_node *pnode;
|
||||
struct weston_view *view = node->view;
|
||||
pixman_region32_t damage;
|
||||
|
||||
assert(!view->transform.dirty);
|
||||
@ -2980,15 +2965,48 @@ view_accumulate_damage(struct weston_view *view)
|
||||
view->geometry.pos_offset.y);
|
||||
}
|
||||
|
||||
pixman_region32_intersect(&damage, &damage, &view->visible);
|
||||
|
||||
wl_list_for_each(pnode, &view->paint_node_list, view_link) {
|
||||
pixman_region32_union(&pnode->plane->damage,
|
||||
&pnode->plane->damage, &damage);
|
||||
}
|
||||
pixman_region32_intersect(&damage, &damage, &node->visible);
|
||||
pixman_region32_union(&node->damage, &node->damage, &damage);
|
||||
pixman_region32_fini(&damage);
|
||||
}
|
||||
|
||||
/* FIXME: note that we don't flush any damage when the core wants us to
|
||||
* do so as it will sometimes ask for a flush not necessarily at the
|
||||
* right time.
|
||||
*
|
||||
* A (more) proper way is to handle correctly damage whenever there's
|
||||
* compositor side damage. See the comment for weston_surface_damage().
|
||||
*/
|
||||
static bool
|
||||
buffer_can_be_accessed_BANDAID_XXX(struct weston_buffer_reference buffer_ref)
|
||||
{
|
||||
return buffer_ref.type == BUFFER_MAY_BE_ACCESSED;
|
||||
}
|
||||
|
||||
static void
|
||||
surface_flush_damage(struct weston_surface *surface, struct weston_output *output)
|
||||
{
|
||||
struct weston_buffer *buffer = surface->buffer_ref.buffer;
|
||||
struct weston_paint_node *node;
|
||||
|
||||
if (buffer->type == WESTON_BUFFER_SHM &&
|
||||
buffer_can_be_accessed_BANDAID_XXX(surface->buffer_ref))
|
||||
surface->compositor->renderer->flush_damage(surface, buffer);
|
||||
|
||||
if (!pixman_region32_not_empty(&surface->damage))
|
||||
return;
|
||||
|
||||
TL_POINT(surface->compositor, "core_flush_damage",
|
||||
TLP_SURFACE(surface), TLP_OUTPUT(output), TLP_END);
|
||||
|
||||
wl_list_for_each(node, &surface->paint_node_list, surface_link) {
|
||||
assert(node->surface == surface);
|
||||
|
||||
paint_node_add_damage(node);
|
||||
}
|
||||
pixman_region32_clear(&surface->damage);
|
||||
}
|
||||
|
||||
static void
|
||||
view_update_clip_and_visible(struct weston_view *view,
|
||||
pixman_region32_t *opaque)
|
||||
@ -3035,20 +3053,8 @@ output_update_visibility(struct weston_output *output)
|
||||
static void
|
||||
output_accumulate_damage(struct weston_output *output)
|
||||
{
|
||||
struct weston_compositor *ec = output->compositor;
|
||||
struct weston_plane *plane;
|
||||
struct weston_paint_node *pnode;
|
||||
|
||||
wl_list_for_each(plane, &ec->plane_list, link) {
|
||||
wl_list_for_each(pnode, &output->paint_node_z_order_list,
|
||||
z_order_link) {
|
||||
if (pnode->plane != plane)
|
||||
continue;
|
||||
|
||||
view_accumulate_damage(pnode->view);
|
||||
}
|
||||
}
|
||||
|
||||
wl_list_for_each(pnode, &output->paint_node_z_order_list,
|
||||
z_order_link) {
|
||||
pnode->surface->touched = false;
|
||||
@ -3133,15 +3139,6 @@ view_list_add_subsurface_view(struct weston_compositor *compositor,
|
||||
|
||||
assert(view);
|
||||
|
||||
/* We used to mysteriously depend on the view->plane transition
|
||||
* from NULL to primary to generate damage when a view that was
|
||||
* unmapped became remapped. Forcing damage here is a little
|
||||
* more obvious.
|
||||
*
|
||||
* We can't use weston_view_damage_below() because the clip region
|
||||
* isn't correct until after we render, and by then it's too late.
|
||||
*/
|
||||
weston_surface_damage(view->surface);
|
||||
weston_view_update_transform(view);
|
||||
view->is_mapped = true;
|
||||
|
||||
@ -3272,6 +3269,28 @@ weston_output_take_feedback_list(struct weston_output *output,
|
||||
wl_list_init(&surface->feedback_list);
|
||||
}
|
||||
|
||||
static bool
|
||||
weston_output_flush_damage_for_plane(struct weston_output *output,
|
||||
struct weston_plane *plane,
|
||||
pixman_region32_t *damage)
|
||||
{
|
||||
struct weston_paint_node *pnode;
|
||||
bool changed = false;
|
||||
|
||||
wl_list_for_each(pnode, &output->paint_node_z_order_list,
|
||||
z_order_link) {
|
||||
if (pnode->plane != plane)
|
||||
continue;
|
||||
changed = true;
|
||||
|
||||
pixman_region32_union(damage, damage, &pnode->damage);
|
||||
pixman_region32_clear(&pnode->damage);
|
||||
}
|
||||
pixman_region32_intersect(damage, damage, &output->region);
|
||||
pixman_region32_subtract(damage, damage, &plane->clip);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int
|
||||
weston_output_repaint(struct weston_output *output)
|
||||
{
|
||||
@ -3353,10 +3372,9 @@ weston_output_repaint(struct weston_output *output)
|
||||
output_accumulate_damage(output);
|
||||
|
||||
pixman_region32_init(&output_damage);
|
||||
pixman_region32_intersect(&output_damage,
|
||||
&ec->primary_plane.damage, &output->region);
|
||||
pixman_region32_subtract(&output_damage,
|
||||
&output_damage, &ec->primary_plane.clip);
|
||||
|
||||
weston_output_flush_damage_for_plane(output, &ec->primary_plane,
|
||||
&output_damage);
|
||||
|
||||
if (output->full_repaint_needed) {
|
||||
pixman_region32_copy(&output_damage, &output->region);
|
||||
@ -3365,9 +3383,6 @@ weston_output_repaint(struct weston_output *output)
|
||||
|
||||
r = output->repaint(output, &output_damage);
|
||||
|
||||
pixman_region32_subtract(&ec->primary_plane.damage,
|
||||
&ec->primary_plane.damage, &output_damage);
|
||||
|
||||
pixman_region32_fini(&output_damage);
|
||||
|
||||
output->repaint_needed = false;
|
||||
@ -5668,7 +5683,6 @@ idle_handler(void *data)
|
||||
WL_EXPORT void
|
||||
weston_plane_init(struct weston_plane *plane, struct weston_compositor *ec)
|
||||
{
|
||||
pixman_region32_init(&plane->damage);
|
||||
pixman_region32_init(&plane->clip);
|
||||
plane->x = 0;
|
||||
plane->y = 0;
|
||||
@ -5684,7 +5698,6 @@ weston_plane_release(struct weston_plane *plane)
|
||||
{
|
||||
struct weston_output *output;
|
||||
|
||||
pixman_region32_fini(&plane->damage);
|
||||
pixman_region32_fini(&plane->clip);
|
||||
|
||||
wl_list_for_each(output, &plane->compositor->output_list, link) {
|
||||
|
@ -547,6 +547,7 @@ struct weston_paint_node {
|
||||
struct wl_list z_order_link;
|
||||
|
||||
pixman_region32_t visible;
|
||||
pixman_region32_t damage; /* In global coordinates */
|
||||
struct weston_plane *plane;
|
||||
struct weston_plane *plane_next;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user