libweston: fix paint node color invariant

The invariant is clearly documented in code comments, but the code
failed to ensure it in all cases. Fix it.

There is one very specific protocol sequence triggered by a development
version of the Wine Wayland driver when Chrome (win64 app) is switched
from window to fullscreen and then back by pressing F11 key. The switch
back triggered

weston: ../libweston/color.c:217: weston_paint_node_ensure_color_transform: Assertion 'it->surf_xform_valid == false' failed

For some reason, that specific protocol sequence causes
weston_compositor_build_view_list() to create a transient second view
for a sub-surface. In the Chrome traces, I have seen that happen twice
per run.  The first time it works, the old view gets immediately
destroyed. The second time (during un-fullscreening) a new transient
view is create and then it fails the invariant check.

The fix is in weston_paint_node_create() which is supposed to ensure the
invariant. However, it went through the (new) view's paint node list,
which will not contain paint nodes from other views. In hindsight this
is an obvious bug, but perhaps all views having exactly one associated
surface each somehow confused the author. Since the invariant is about
surface+output, go through the surface's paint node list instead. That
list contains all the relevant paint nodes by definition.

Fixes: https://gitlab.freedesktop.org/wayland/weston/-/issues/568

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
dev
Pekka Paalanen 3 years ago committed by Daniel Stone
parent e948bd4bc9
commit 26b04f0045
  1. 2
      libweston/compositor.c

@ -119,7 +119,7 @@ weston_paint_node_create(struct weston_surface *surface,
* Invariant: all paint nodes with the same surface+output have the * Invariant: all paint nodes with the same surface+output have the
* same surf_xform state. * same surf_xform state.
*/ */
wl_list_for_each(existing_node, &view->paint_node_list, view_link) { wl_list_for_each(existing_node, &surface->paint_node_list, surface_link) {
assert(existing_node->surface == surface); assert(existing_node->surface == surface);
if (existing_node->output != output) if (existing_node->output != output)
continue; continue;

Loading…
Cancel
Save