libweston: introduce weston_paint_node

This new object is created for every surface-view-output triplet. As
there is always exactly one surface for a view and it does not change
during a view's lifetime, this is really for a view-output pair or a
surface-output pair.

The object is created on-demand as a part of preparing for an output
repaint, so it applies only to surfaces that are going through repaint.
A prerequisite for that is that the surface is mapped, which means it
has a mapped view.

When any one of surface or view gets destroyed or output gets disabled,
all related paint nodes are destroyed.

In future, paint node will be useful for caching surface-output or
view-output pair dependent data:
- damage regions for overlapping outputs
- color transformations
- backend-specific bookkeeping (e.g. DRM KMS plane assigments)
- per-output repaint lists
- surface geometry transformed into output space

Suggested by Daniel Stone in
https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/582#note_899406

PS. The call in weston_view_destroy() to
weston_compositor_build_view_list() might be so that if the view has
sub-surfaces, rebuilding the view list removes those those too and
automagically deletes their views.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
diff --git a/libweston/compositor.c b/libweston/compositor.c
index 3a96dea..cacded7 100644
--- a/libweston/compositor.c
+++ b/libweston/compositor.c
@@ -1,7 +1,7 @@
 /*
  * Copyright © 2010-2011 Intel Corporation
  * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2012-2018 Collabora, Ltd.
+ * Copyright © 2012-2018, 2021 Collabora, Ltd.
  * Copyright © 2017, 2018 General Electric Company
  *
  * Permission is hereby granted, free of charge, to any person obtaining
@@ -93,11 +93,47 @@
 				   uint32_t transform, uint32_t scale);
 
 static void
-weston_compositor_build_view_list(struct weston_compositor *compositor);
+weston_compositor_build_view_list(struct weston_compositor *compositor,
+				  struct weston_output *output);
 
 static char *
 weston_output_create_heads_string(struct weston_output *output);
 
+static struct weston_paint_node *
+weston_paint_node_create(struct weston_surface *surface,
+			 struct weston_view *view,
+			 struct weston_output *output)
+{
+	struct weston_paint_node *pnode;
+
+	assert(view->surface == surface);
+
+	pnode = zalloc(sizeof *pnode);
+	if (!pnode)
+		return NULL;
+
+	pnode->surface = surface;
+	wl_list_insert(&surface->paint_node_list, &pnode->surface_link);
+
+	pnode->view = view;
+	wl_list_insert(&view->paint_node_list, &pnode->view_link);
+
+	pnode->output = output;
+	wl_list_insert(&output->paint_node_list, &pnode->output_link);
+
+	return pnode;
+}
+
+static void
+weston_paint_node_destroy(struct weston_paint_node *pnode)
+{
+	assert(pnode->view->surface == pnode->surface);
+	wl_list_remove(&pnode->surface_link);
+	wl_list_remove(&pnode->view_link);
+	wl_list_remove(&pnode->output_link);
+	free(pnode);
+}
+
 /** Send wl_output events for mode and scale changes
  *
  * \param head Send on all resources bound to this head.
@@ -336,6 +372,7 @@
 	wl_signal_init(&view->destroy_signal);
 	wl_list_init(&view->link);
 	wl_list_init(&view->layer_link.link);
+	wl_list_init(&view->paint_node_list);
 
 	pixman_region32_init(&view->clip);
 
@@ -553,6 +590,7 @@
 	region_init_infinite(&surface->input);
 
 	wl_list_init(&surface->views);
+	wl_list_init(&surface->paint_node_list);
 
 	wl_list_init(&surface->frame_callback_list);
 	wl_list_init(&surface->feedback_list);
@@ -1951,6 +1989,23 @@
 	return true;
 }
 
+/** Find paint node for the given view and output
+ */
+WL_EXPORT struct weston_paint_node *
+weston_view_find_paint_node(struct weston_view *view,
+			    struct weston_output *output)
+{
+	struct weston_paint_node *pnode;
+
+	wl_list_for_each(pnode, &view->paint_node_list, view_link) {
+		assert(pnode->surface == view->surface);
+		if (pnode->output == output)
+			return pnode;
+	}
+
+	return NULL;
+}
+
 /* Check if a surface has a view assigned to it
  *
  * The indicator is set manually when mapping
@@ -2192,15 +2247,21 @@
 WL_EXPORT void
 weston_view_destroy(struct weston_view *view)
 {
+	struct weston_paint_node *pnode, *pntmp;
+
 	wl_signal_emit(&view->destroy_signal, view);
 
 	assert(wl_list_empty(&view->geometry.child_list));
 
 	if (weston_view_is_mapped(view)) {
 		weston_view_unmap(view);
-		weston_compositor_build_view_list(view->surface->compositor);
+		weston_compositor_build_view_list(view->surface->compositor,
+						  NULL);
 	}
 
+	wl_list_for_each_safe(pnode, pntmp, &view->paint_node_list, view_link)
+		weston_paint_node_destroy(pnode);
+
 	wl_list_remove(&view->link);
 	weston_layer_entry_remove(&view->layer_link);
 
@@ -2223,6 +2284,7 @@
 	struct weston_frame_callback *cb, *next;
 	struct weston_view *ev, *nv;
 	struct weston_pointer_constraint *constraint, *next_constraint;
+	struct weston_paint_node *pnode, *pntmp;
 
 	if (--surface->ref_count > 0)
 		return;
@@ -2237,6 +2299,11 @@
 	wl_list_for_each_safe(ev, nv, &surface->views, surface_link)
 		weston_view_destroy(ev);
 
+	wl_list_for_each_safe(pnode, pntmp,
+			      &surface->paint_node_list, surface_link) {
+		weston_paint_node_destroy(pnode);
+	}
+
 	weston_surface_state_fini(&surface->pending);
 
 	weston_buffer_reference(&surface->buffer_ref, NULL);
@@ -2594,10 +2661,26 @@
 	}
 }
 
+static struct weston_paint_node *
+view_ensure_paint_node(struct weston_view *view, struct weston_output *output)
+{
+	struct weston_paint_node *pnode;
+
+	if (!output)
+		return NULL;
+
+	pnode = weston_view_find_paint_node(view, output);
+	if (pnode)
+		return pnode;
+
+	return weston_paint_node_create(view->surface, view, output);
+}
+
 static void
 view_list_add_subsurface_view(struct weston_compositor *compositor,
 			      struct weston_subsurface *sub,
-			      struct weston_view *parent)
+			      struct weston_view *parent,
+			      struct weston_output *output)
 {
 	struct weston_subsurface *child;
 	struct weston_view *view = NULL, *iv;
@@ -2627,6 +2710,7 @@
 	view->parent_view = parent;
 	weston_view_update_transform(view);
 	view->is_mapped = true;
+	view_ensure_paint_node(view, output);
 
 	if (wl_list_empty(&sub->surface->subsurface_list)) {
 		wl_list_insert(compositor->view_list.prev, &view->link);
@@ -2637,7 +2721,7 @@
 		if (child->surface == sub->surface)
 			wl_list_insert(compositor->view_list.prev, &view->link);
 		else
-			view_list_add_subsurface_view(compositor, child, view);
+			view_list_add_subsurface_view(compositor, child, view, output);
 	}
 }
 
@@ -2649,11 +2733,13 @@
  */
 static void
 view_list_add(struct weston_compositor *compositor,
-	      struct weston_view *view)
+	      struct weston_view *view,
+	      struct weston_output *output)
 {
 	struct weston_subsurface *sub;
 
 	weston_view_update_transform(view);
+	view_ensure_paint_node(view, output);
 
 	if (wl_list_empty(&view->surface->subsurface_list)) {
 		wl_list_insert(compositor->view_list.prev, &view->link);
@@ -2664,12 +2750,13 @@
 		if (sub->surface == view->surface)
 			wl_list_insert(compositor->view_list.prev, &view->link);
 		else
-			view_list_add_subsurface_view(compositor, sub, view);
+			view_list_add_subsurface_view(compositor, sub, view, output);
 	}
 }
 
 static void
-weston_compositor_build_view_list(struct weston_compositor *compositor)
+weston_compositor_build_view_list(struct weston_compositor *compositor,
+				  struct weston_output *output)
 {
 	struct weston_view *view, *tmp;
 	struct weston_layer *layer;
@@ -2684,7 +2771,7 @@
 
 	wl_list_for_each(layer, &compositor->layer_list, link) {
 		wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
-			view_list_add(compositor, view);
+			view_list_add(compositor, view, output);
 		}
 	}
 
@@ -2737,7 +2824,7 @@
 	TL_POINT(ec, "core_repaint_begin", TLP_OUTPUT(output), TLP_END);
 
 	/* Rebuild the surface list and update surface transforms up front. */
-	weston_compositor_build_view_list(ec);
+	weston_compositor_build_view_list(ec, output);
 
 	/* Find the highest protection desired for an output */
 	wl_list_for_each(ev, &ec->view_list, link) {
@@ -6102,6 +6189,8 @@
  *
  * The following happens:
  *
+ * - Destroys all paint nodes related to the output.
+ *
  * - The output assignments of all views in the current scenegraph are
  *   recomputed.
  *
@@ -6127,12 +6216,18 @@
 weston_compositor_remove_output(struct weston_output *output)
 {
 	struct weston_compositor *compositor = output->compositor;
+	struct weston_paint_node *pnode, *pntmp;
 	struct weston_view *view;
 	struct weston_head *head;
 
 	assert(output->destroying);
 	assert(output->enabled);
 
+	wl_list_for_each_safe(pnode, pntmp,
+			      &output->paint_node_list, output_link) {
+		weston_paint_node_destroy(pnode);
+	}
+
 	wl_list_for_each(view, &compositor->view_list, link) {
 		if (view->output_mask & (1u << output->id))
 			weston_view_assign_output(view);
@@ -6483,6 +6578,7 @@
 
 	wl_list_init(&output->animation_list);
 	wl_list_init(&output->feedback_list);
+	wl_list_init(&output->paint_node_list);
 
 	/* Enable the output (set up the crtc or create a
 	 * window representing the output, set up the
@@ -6645,6 +6741,8 @@
 	if (output->enabled)
 		weston_compositor_remove_output(output);
 
+	assert(wl_list_empty(&output->paint_node_list));
+
 	pixman_region32_fini(&output->region);
 	wl_list_remove(&output->link);