From cea0ab55efba819631632354700941be428c0dc2 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Tue, 2 Jun 2026 16:03:33 +0300 Subject: [PATCH 1/4] backend-drm: Rename lower_views_to_background Small re-write how we handle pnodes/views to the background region. No functional change just make it easier to reason with. Signed-off-by: Marius Vlad --- libweston/backend-drm/state-propose.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c index b0be56289..f973b4609 100644 --- a/libweston/backend-drm/state-propose.c +++ b/libweston/backend-drm/state-propose.c @@ -907,10 +907,9 @@ is_paint_node_solid_opaque_untransformed(struct weston_paint_node *pnode) } static bool -lower_solid_views_to_background_region(struct drm_output *output, - struct wl_array *visible_pnodes, - struct weston_paint_node **last_visible_pnode, - pixman_region32_t *background_region) +try_solid_pnodes_to_background(struct drm_output *output, struct wl_array *visible_pnodes, + struct weston_paint_node **last_visible_pnode, + pixman_region32_t *background_region) { struct drm_device *device = output->device; struct drm_backend *b = device->backend; @@ -1341,7 +1340,7 @@ drm_output_propose_state(struct weston_output *output_base, pixman_region32_init(&obscured_region); /* background_region contains the area that is covered by opaque - * solid views. If they are black this area can be fully ignored in + * solid paint nodes. If they are black this area can be fully ignored in * PLANES_ONLY mode according to the DRM spec: * * "Unless explicitly specified (via CRTC property or otherwise), the @@ -1355,16 +1354,17 @@ drm_output_propose_state(struct weston_output *output_base, * For other colors the same applies if the BACKGROUND_COLOR DRM * property is supported. * - * All said views can thus be ignored during plane assignment. + * All said paint nodes can thus be ignored during plane assignment. */ pixman_region32_init(&background_region); - if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY && - !lower_solid_views_to_background_region(output, - &visible_pnodes, - &last_visible_pnode, - &background_region)) - goto err_region; + if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) { + bool solid_pnodes_to_bg = + try_solid_pnodes_to_background(output, &visible_pnodes, + &last_visible_pnode, &background_region); + if (!solid_pnodes_to_bg) + goto err_region; + } /* Assign paint nodes to planes. */ wl_array_for_each(visible_pnode, &visible_pnodes) { From 5855fb659704571d9c99d39fee82df63d3fe2e91 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Tue, 2 Jun 2026 16:35:42 +0300 Subject: [PATCH 2/4] backend-drm: Add a helper to walk the paint nodes This doesn't change the functionality but would give us the possibly to pass custom paint nodes arrays and we would need that in future changes. Signed-off-by: Marius Vlad --- libweston/backend-drm/state-propose.c | 314 ++++++++++++++------------ 1 file changed, 171 insertions(+), 143 deletions(-) diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c index f973b4609..6c8c24268 100644 --- a/libweston/backend-drm/state-propose.c +++ b/libweston/backend-drm/state-propose.c @@ -1194,6 +1194,166 @@ drm_output_propose_state_try_reuse(struct weston_output *output_base, return state; } +static int +walk_paint_nodes(pixman_region32_t *renderer_region, + pixman_region32_t *obscured_region, + pixman_region32_t *background_region, + struct drm_plane_state *scanout_state, + struct drm_output_state *state, + enum drm_output_propose_state_mode mode, + uint64_t current_lowest_zpos_underlay, + uint64_t current_lowest_zpos_overlay, + struct drm_output *output, + struct wl_array *pnodes, + struct weston_paint_node *last_visible_pnode) +{ + struct drm_device *device = output->device; + struct drm_backend *b = device->backend; + struct weston_paint_node **visible_pnode; + + /* Assign paint nodes to planes. */ + wl_array_for_each(visible_pnode, pnodes) { + struct weston_paint_node *pnode = *visible_pnode; + struct drm_plane_state *ps = NULL; + bool need_underlay = false; + pixman_region32_t tmp; + bool renderer_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY); + + drm_debug(b, "\t\t\t[paint node] evaluating paint node %s for plane " + "assignment on output %s (%lu)\n", + pnode->internal_name, output->base.name, + (unsigned long) output->base.id); + + if (!b->gbm) + pnode->try_view_on_plane_failure_reasons |= + FAILURE_REASONS_NO_GBM; + + if (!weston_paint_node_has_valid_buffer(pnode)) + pnode->try_view_on_plane_failure_reasons |= + FAILURE_REASONS_NO_BUFFER; + + if (pnode->draw_solid) + pnode->try_view_on_plane_failure_reasons |= + FAILURE_REASONS_SOLID_SURFACE; + + if (pnode->output->color_effect) + pnode->try_view_on_plane_failure_reasons |= + FAILURE_REASONS_OUTPUT_COLOR_EFFECT; + + if (pnode->surf_xform.transform && (!device->color_pipeline_supported || + !pnode->output->from_blend_to_output_by_backend)) + pnode->try_view_on_plane_failure_reasons |= + FAILURE_REASONS_NO_COLOR_TRANSFORM; + + /* Since we process views from top to bottom, we know that if + * the view intersects the calculated renderer region, it must + * be part of, or occluded by, it, and cannot go on an overlay + * plane. */ + pixman_region32_init(&tmp); + pixman_region32_intersect(&tmp, renderer_region, &pnode->clipped_view); + if (pixman_region32_not_empty(&tmp)) { + if (output->has_underlay) { + need_underlay = true; + } else { + pnode->try_view_on_plane_failure_reasons |= + FAILURE_REASONS_OCCLUDED_BY_RENDERER; + drm_debug(b, "\t\t\t\t[paint node] not assigning paint node %s to a " + "plane (occluded by renderer views), current lowest " + "zpos change to %"PRIu64"\n", pnode->internal_name, + current_lowest_zpos_underlay); + } + } + pixman_region32_fini(&tmp); + + /* If need_underlay, but view contains alpha, then it needs to + * be rendered. Only fully-opaque views can go on an underlay. + */ + if (need_underlay && !pnode->is_fully_opaque) + pnode->try_view_on_plane_failure_reasons |= + FAILURE_REASONS_OCCLUDED_BY_RENDERER; + + /* In case of enforced mode of content-protection do not + * assign planes for a protected surface on an unsecured output. + */ + if (pnode->censored) + pnode->try_view_on_plane_failure_reasons |= + FAILURE_REASONS_INADEQUATE_CONTENT_PROTECTION; + + if (pnode->surface->tear_control) + state->tear &= pnode->surface->tear_control->may_tear; + else + state->tear = 0; + + /* Now try to place it on a plane if we can. */ + if (!pnode->try_view_on_plane_failure_reasons) { + pixman_region32_t obscured_or_background_region; + + drm_debug(b, "\t\t\t[plane] started with zpos %"PRIu64"\n", + need_underlay ? current_lowest_zpos_underlay : + current_lowest_zpos_overlay); + + pixman_region32_init(&obscured_or_background_region); + if (pnode == last_visible_pnode) { + pixman_region32_union(&obscured_or_background_region, + background_region, + obscured_region); + if (pixman_region32_not_empty(&obscured_or_background_region)) + drm_debug(b, "\t\t\t[plane] adding background region\n"); + } + + ps = drm_output_find_plane_for_paint_node(state, pnode, mode, + scanout_state, + &obscured_or_background_region, + current_lowest_zpos_overlay, + current_lowest_zpos_underlay, + need_underlay); + + pixman_region32_fini(&obscured_or_background_region); + } + + if (ps) { + if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY && + ps->plane->type == WDRM_PLANE_TYPE_OVERLAY) { + pixman_region32_union(obscured_region, + obscured_region, + weston_paint_node_get_opaque_region (pnode)); + } + + if (drm_mixed_mode_check_underlay(mode, scanout_state, ps->zpos)) + current_lowest_zpos_underlay = ps->zpos; + else + current_lowest_zpos_overlay = ps->zpos; + drm_debug(b, "\t\t\t[plane] next overlay zpos to use %"PRIu64"," + " next underlay zpos to use %"PRIu64"\n", + current_lowest_zpos_overlay, + current_lowest_zpos_underlay); + } else if (!ps && !renderer_ok) { + drm_debug(b, "\t\t[paint node] failing state generation: " + "placing paint node %s to renderer not allowed\n", + pnode->internal_name); + return -1; + } else if (!ps) { + FILE *dbg = weston_log_scope_stream(b->debug); + + if (dbg) { + fprintf(dbg, "\t\t\t\t[paint node] paint node %s will be placed on the renderer: ", + pnode->internal_name); + bits_to_str_stream(pnode->try_view_on_plane_failure_reasons, + weston_plane_failure_reasons_to_str, dbg); + fputs("\n", dbg); + } + } + + if (!ps || drm_mixed_mode_check_underlay(mode, scanout_state, ps->zpos)) { + /* visible contains the area that's going to be visible + * on screen; add this to the renderer region */ + pixman_region32_union(renderer_region, renderer_region, &pnode->visible); + } + } + + return 0; +} + static struct drm_output_state * drm_output_propose_state(struct weston_output *output_base, struct drm_pending_state *pending_state, @@ -1214,7 +1374,7 @@ drm_output_propose_state(struct weston_output *output_base, pixman_region32_t background_region; pixman_region32_t obscured_region; - int ret; + int ret = 0; /* Record the current lowest zpos of the overlay planes */ uint64_t current_lowest_zpos_overlay = DRM_PLANE_ZPOS_INVALID_PLANE; /* Record the current lowest zpos of the underlay plane */ @@ -1366,148 +1526,16 @@ drm_output_propose_state(struct weston_output *output_base, goto err_region; } - /* Assign paint nodes to planes. */ - wl_array_for_each(visible_pnode, &visible_pnodes) { - struct weston_paint_node *pnode = *visible_pnode; - struct drm_plane_state *ps = NULL; - bool need_underlay = false; - pixman_region32_t tmp; - bool renderer_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY); - - drm_debug(b, "\t\t\t[paint node] evaluating paint node %s for plane " - "assignment on output %s (%lu)\n", - pnode->internal_name, output->base.name, - (unsigned long) output->base.id); - - if (!b->gbm) - pnode->try_view_on_plane_failure_reasons |= - FAILURE_REASONS_NO_GBM; - - if (!weston_paint_node_has_valid_buffer(pnode)) - pnode->try_view_on_plane_failure_reasons |= - FAILURE_REASONS_NO_BUFFER; - - if (pnode->draw_solid) - pnode->try_view_on_plane_failure_reasons |= - FAILURE_REASONS_SOLID_SURFACE; - - if (pnode->output->color_effect) - pnode->try_view_on_plane_failure_reasons |= - FAILURE_REASONS_OUTPUT_COLOR_EFFECT; - - if (pnode->surf_xform.transform && (!device->color_pipeline_supported || - !pnode->output->from_blend_to_output_by_backend)) - pnode->try_view_on_plane_failure_reasons |= - FAILURE_REASONS_NO_COLOR_TRANSFORM; - - /* Since we process views from top to bottom, we know that if - * the view intersects the calculated renderer region, it must - * be part of, or occluded by, it, and cannot go on an overlay - * plane. */ - pixman_region32_init(&tmp); - pixman_region32_intersect(&tmp, &renderer_region, - &pnode->clipped_view); - if (pixman_region32_not_empty(&tmp)) { - if (output->has_underlay) { - need_underlay = true; - } else { - pnode->try_view_on_plane_failure_reasons |= - FAILURE_REASONS_OCCLUDED_BY_RENDERER; - drm_debug(b, "\t\t\t\t[paint node] not assigning paint node %s to a " - "plane (occluded by renderer views), current lowest " - "zpos change to %"PRIu64"\n", pnode->internal_name, - current_lowest_zpos_underlay); - } - } - pixman_region32_fini(&tmp); - - /* If need_underlay, but view contains alpha, then it needs to - * be rendered. Only fully-opaque views can go on an underlay. - */ - if (need_underlay && !pnode->is_fully_opaque) - pnode->try_view_on_plane_failure_reasons |= - FAILURE_REASONS_OCCLUDED_BY_RENDERER; - - /* In case of enforced mode of content-protection do not - * assign planes for a protected surface on an unsecured output. - */ - if (pnode->censored) - pnode->try_view_on_plane_failure_reasons |= - FAILURE_REASONS_INADEQUATE_CONTENT_PROTECTION; - - if (pnode->surface->tear_control) - state->tear &= pnode->surface->tear_control->may_tear; - else - state->tear = 0; - - /* Now try to place it on a plane if we can. */ - if (!pnode->try_view_on_plane_failure_reasons) { - pixman_region32_t obscured_or_background_region; - - drm_debug(b, "\t\t\t[plane] started with zpos %"PRIu64"\n", - need_underlay ? current_lowest_zpos_underlay : - current_lowest_zpos_overlay); - - pixman_region32_init(&obscured_or_background_region); - if (pnode == last_visible_pnode) { - pixman_region32_union(&obscured_or_background_region, - &background_region, - &obscured_region); - if (pixman_region32_not_empty (&obscured_or_background_region)) - drm_debug(b, "\t\t\t[plane] adding background region\n"); - } - - ps = drm_output_find_plane_for_paint_node(state, pnode, mode, - scanout_state, - &obscured_or_background_region, - current_lowest_zpos_overlay, - current_lowest_zpos_underlay, - need_underlay); - - pixman_region32_fini(&obscured_or_background_region); - } - - if (ps) { - if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY && - ps->plane->type == WDRM_PLANE_TYPE_OVERLAY) { - pixman_region32_union(&obscured_region, - &obscured_region, - weston_paint_node_get_opaque_region (pnode)); - } - - if (drm_mixed_mode_check_underlay(mode, scanout_state, ps->zpos)) - current_lowest_zpos_underlay = ps->zpos; - else - current_lowest_zpos_overlay = ps->zpos; - drm_debug(b, "\t\t\t[plane] next overlay zpos to use %"PRIu64"," - " next underlay zpos to use %"PRIu64"\n", - current_lowest_zpos_overlay, - current_lowest_zpos_underlay); - } else if (!ps && !renderer_ok) { - drm_debug(b, "\t\t[paint node] failing state generation: " - "placing paint node %s to renderer not allowed\n", - pnode->internal_name); - goto err_region; - } else if (!ps) { - FILE *dbg = weston_log_scope_stream(b->debug); - - if (dbg) { - fprintf(dbg, "\t\t\t\t[paint node] paint node %s will be placed on the renderer: ", - pnode->internal_name); - bits_to_str_stream(pnode->try_view_on_plane_failure_reasons, - weston_plane_failure_reasons_to_str, dbg); - fputs("\n", dbg); - } - } - - if (!ps || drm_mixed_mode_check_underlay(mode, scanout_state, ps->zpos)) { - /* visible contains the area that's going to be visible - * on screen; add this to the renderer region */ - pixman_region32_union(&renderer_region, - &renderer_region, - &pnode->visible); - } - } + drm_debug(b, "\t\t\t[paint node] walking visible paint node list\n"); + ret = walk_paint_nodes(&renderer_region, &obscured_region, + &background_region, scanout_state, state, + mode, + current_lowest_zpos_underlay, + current_lowest_zpos_overlay, output, + &visible_pnodes, + last_visible_pnode); + if (ret) + goto err_region; pixman_region32_fini(&renderer_region); pixman_region32_fini(&obscured_region); From b2a0aa997487414438e63275de43c10d9ea1c471 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Fri, 5 Jun 2026 14:06:03 +0300 Subject: [PATCH 3/4] backend-drm: Prioritize direct-display paint nodes This re-works a bit how we handle paint nodes with direct-display buffers to give them a better chance of making into a HW plane. Signed-off-by: Marius Vlad --- libweston/backend-drm/state-propose.c | 97 +++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c index 6c8c24268..8037ca5e2 100644 --- a/libweston/backend-drm/state-propose.c +++ b/libweston/backend-drm/state-propose.c @@ -1194,6 +1194,52 @@ drm_output_propose_state_try_reuse(struct weston_output *output_base, return state; } +static bool +paint_node_has_direct_display_buffer(struct weston_paint_node *pnode) +{ + struct weston_buffer *buffer = pnode->surface->buffer_ref.buffer; + + if (buffer->type == WESTON_BUFFER_DMABUF) { + if (buffer->direct_display) + return true; + } + + return false; +} + + +static void +filter_pnodes_with_direct_display(struct drm_output *output, + struct wl_array *visible_pnodes, + struct wl_array *pnodes_with_direct_display, + struct wl_array *pnodes_remaining) +{ + struct weston_paint_node **pnode; + + wl_array_for_each(pnode, visible_pnodes) { + if (paint_node_has_direct_display_buffer(*pnode)) { + struct weston_paint_node **pnode_new = + wl_array_add(pnodes_with_direct_display, sizeof(*pnode)); + *pnode_new = *pnode; + } else { + struct weston_paint_node **pnode_new = + wl_array_add(pnodes_remaining, sizeof(*pnode)); + *pnode_new = *pnode; + } + } +} + +static void +paint_node_print_array(struct drm_backend *b, struct wl_array *array) +{ + struct weston_paint_node **pn; + + wl_array_for_each(pn, array) { + struct weston_paint_node *p = *pn; + drm_debug(b, "\t\t\t\t[paint node] paint node %s\n", p->internal_name); + } +} + static int walk_paint_nodes(pixman_region32_t *renderer_region, pixman_region32_t *obscured_region, @@ -1526,6 +1572,57 @@ drm_output_propose_state(struct weston_output *output_base, goto err_region; } + if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) { + struct wl_array pnodes_with_direct_display; + struct wl_array pnodes_remaining; + + unsigned int count_pnodes_dd = 0; + + wl_array_init(&pnodes_with_direct_display); + wl_array_init(&pnodes_remaining); + + filter_pnodes_with_direct_display(output, &visible_pnodes, + &pnodes_with_direct_display, + &pnodes_remaining); + + count_pnodes_dd = pnodes_with_direct_display.size / + sizeof(struct weston_paint_node *); + + drm_debug(b, "\t\t\t[paint node] visible paint nodes\n"); + paint_node_print_array(b, &visible_pnodes); + + if (count_pnodes_dd) { + drm_debug(b, "\t\t\t[paint node] pnodes direct display\n"); + paint_node_print_array(b, &pnodes_with_direct_display); + + drm_debug(b, "\t\t\t[paint node] walking direct display " + "paint node list\n"); + + ret = walk_paint_nodes(&renderer_region, &obscured_region, + &background_region, scanout_state, + state, mode, + current_lowest_zpos_underlay, + current_lowest_zpos_overlay, + output, + &pnodes_with_direct_display, + last_visible_pnode); + if (ret) { + wl_array_release(&pnodes_with_direct_display); + wl_array_release(&pnodes_remaining); + goto err_region; + } + + /* replace with paint nodes not with direct display */ + wl_array_copy(&visible_pnodes, &pnodes_remaining); + + drm_debug(b, "\t\t\t[paint node] remaining visible paint nodes\n"); + paint_node_print_array(b, &visible_pnodes); + } + + wl_array_release(&pnodes_with_direct_display); + wl_array_release(&pnodes_remaining); + } + drm_debug(b, "\t\t\t[paint node] walking visible paint node list\n"); ret = walk_paint_nodes(&renderer_region, &obscured_region, &background_region, scanout_state, state, From 2625f5d52c57ae19325bb8210b79d1c1d34ab9a8 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Fri, 5 Jun 2026 14:21:29 +0300 Subject: [PATCH 4/4] backend-drm: Prioritize paint nodes above direct display Paint nodes above direct display should also be priortized when getting the chance to avoid the direct display ones being promoted to the renderer instead. This filters all the paint nodes above into a distinct array and tries to prioritize those. Signed-off-by: Marius Vlad --- libweston/backend-drm/state-propose.c | 124 +++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c index 8037ca5e2..ce972b513 100644 --- a/libweston/backend-drm/state-propose.c +++ b/libweston/backend-drm/state-propose.c @@ -1229,6 +1229,85 @@ filter_pnodes_with_direct_display(struct drm_output *output, } } +static void +find_pnodes_above_direct_display(struct drm_output *output, + struct weston_paint_node *pnode_dd, + struct wl_array *result) +{ + struct weston_paint_node *pnode; + + /* all the paint nodes until pnode_dd being stacked on top should be + * above pnode_dd; we just need to test for occlusion */ + wl_list_for_each(pnode, &output->base.paint_node_z_order_list, + z_order_link) { + bool pnode_above = false; + + if (pnode == pnode_dd) + break; + + pixman_region32_t overlap; + pixman_region32_init(&overlap); + + if (pnode->is_fully_opaque) + pixman_region32_intersect(&overlap, + weston_paint_node_get_opaque_region(pnode), + weston_paint_node_get_opaque_region(pnode_dd)); + else + pixman_region32_intersect(&overlap, &pnode->visible, &pnode_dd->visible); + + if (pixman_region32_not_empty(&overlap)) + pnode_above = true; + + if (pnode_above) { + struct weston_paint_node **node_above = + wl_array_add(result, sizeof(*node_above)); + *node_above = pnode; + } + + pixman_region32_fini(&overlap); + } +} + +static void +filter_pnodes_above_direct_display(struct drm_output *output, struct wl_array *visible_pnodes, + struct wl_array *pnodes_with_direct_display, struct wl_array *result) +{ + struct weston_paint_node **pn; + + wl_array_for_each(pn, pnodes_with_direct_display) + find_pnodes_above_direct_display(output, *pn, result); +} + +static void +filter_pnodes_duplicates(struct drm_output *output, struct wl_array *a, struct wl_array *b) +{ + struct weston_paint_node **pa; + struct wl_array tmp_dup; + + wl_array_init(&tmp_dup); + + wl_array_for_each(pa, a) { + struct weston_paint_node **pb; + bool found_dup = false; + + wl_array_for_each(pb, b) { + if (*pa == *pb) { + found_dup = true; + break; + } + } + + if (!found_dup) { + struct weston_paint_node **n = + wl_array_add(&tmp_dup, sizeof(*n)); + *n = *pa; + } + } + + wl_array_copy(a, &tmp_dup); + wl_array_release(&tmp_dup); +} + static void paint_node_print_array(struct drm_backend *b, struct wl_array *array) { @@ -1575,18 +1654,35 @@ drm_output_propose_state(struct weston_output *output_base, if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) { struct wl_array pnodes_with_direct_display; struct wl_array pnodes_remaining; + struct wl_array pnodes_above_direct_display; unsigned int count_pnodes_dd = 0; + unsigned int count_pnodes_above_dd = 0; wl_array_init(&pnodes_with_direct_display); wl_array_init(&pnodes_remaining); + wl_array_init(&pnodes_above_direct_display); filter_pnodes_with_direct_display(output, &visible_pnodes, &pnodes_with_direct_display, &pnodes_remaining); + filter_pnodes_above_direct_display(output, &visible_pnodes, + &pnodes_with_direct_display, + &pnodes_above_direct_display); + + /* we might have the same paint nodes in + * pnodes_above_direct_display and in pnodes_remaining as we + * are searching for paint nodes above the direct display ones + * in all visible_pnodes so a paint node above direct-display + * would might also be in pnodes_remaining */ + filter_pnodes_duplicates(output, &pnodes_remaining, + &pnodes_above_direct_display); + count_pnodes_dd = pnodes_with_direct_display.size / sizeof(struct weston_paint_node *); + count_pnodes_above_dd = pnodes_above_direct_display.size / + sizeof(struct weston_paint_node *); drm_debug(b, "\t\t\t[paint node] visible paint nodes\n"); paint_node_print_array(b, &visible_pnodes); @@ -1595,6 +1691,29 @@ drm_output_propose_state(struct weston_output *output_base, drm_debug(b, "\t\t\t[paint node] pnodes direct display\n"); paint_node_print_array(b, &pnodes_with_direct_display); + if (count_pnodes_above_dd && !output->has_underlay) { + drm_debug(b, "\t\t\t[paint node] pnodes above " + "direct display\n"); + paint_node_print_array(b, &pnodes_above_direct_display); + + drm_debug(b, "\t\t\t[paint node] walking above " + "direct display paint node list\n"); + ret = walk_paint_nodes(&renderer_region, &obscured_region, + &background_region, scanout_state, + state, mode, + current_lowest_zpos_underlay, + current_lowest_zpos_overlay, + output, + &pnodes_above_direct_display, + last_visible_pnode); + if (ret) { + wl_array_release(&pnodes_with_direct_display); + wl_array_release(&pnodes_above_direct_display); + wl_array_release(&pnodes_remaining); + goto err_region; + } + } + drm_debug(b, "\t\t\t[paint node] walking direct display " "paint node list\n"); @@ -1608,11 +1727,13 @@ drm_output_propose_state(struct weston_output *output_base, last_visible_pnode); if (ret) { wl_array_release(&pnodes_with_direct_display); + wl_array_release(&pnodes_above_direct_display); wl_array_release(&pnodes_remaining); goto err_region; } - /* replace with paint nodes not with direct display */ + /* replace visible pnodes with remaining pnodes to + * avoid going over them again */ wl_array_copy(&visible_pnodes, &pnodes_remaining); drm_debug(b, "\t\t\t[paint node] remaining visible paint nodes\n"); @@ -1620,6 +1741,7 @@ drm_output_propose_state(struct weston_output *output_base, } wl_array_release(&pnodes_with_direct_display); + wl_array_release(&pnodes_above_direct_display); wl_array_release(&pnodes_remaining); }