diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c index 557c01af0..7d180f421 100644 --- a/libweston/backend-drm/state-propose.c +++ b/libweston/backend-drm/state-propose.c @@ -713,7 +713,10 @@ drm_output_propose_state(struct weston_output *output_base, struct drm_output_state *state; struct drm_plane_state *scanout_state = NULL; struct weston_view *ev; - pixman_region32_t surface_overlap, renderer_region, occluded_region; + + pixman_region32_t surface_overlap, renderer_region, planes_region; + pixman_region32_t occluded_region; + bool renderer_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY); int ret; uint64_t current_lowest_zpos = DRM_PLANE_ZPOS_INVALID_PLANE; @@ -766,20 +769,19 @@ drm_output_propose_state(struct weston_output *output_base, (unsigned long) output->base.id); } - /* - * Find a surface for each sprite in the output using some heuristics: - * 1) size - * 2) frequency of update - * 3) opacity (though some hw might support alpha blending) - * 4) clipping (this can be fixed with color keys) - * - * The idea is to save on blitting since this should save power. - * If we can get a large video surface on the sprite for example, - * the main display surface may not need to update at all, and - * the client buffer can be used directly for the sprite surface - * as we do for flipping full screen surfaces. + /* - renderer_region contains the total region which which will be + * covered by the renderer + * - planes_region contains the total region which has been covered by + * hardware planes + * - occluded_region contains the total region which which will be + * covered by the renderer and hardware planes, where the view's + * visible-and-opaque region is added in both cases (the view's + * opaque region accumulates there for each view); it is being used + * to skip the view, if it is completely occluded; includes the + * situation where occluded_region covers entire output's region. */ pixman_region32_init(&renderer_region); + pixman_region32_init(&planes_region); pixman_region32_init(&occluded_region); wl_list_for_each(ev, &output_base->compositor->view_list, link) { @@ -824,6 +826,9 @@ drm_output_propose_state(struct weston_output *output_base, pixman_region32_init(&surface_overlap); pixman_region32_subtract(&surface_overlap, &clipped_view, &occluded_region); + /* if the view is completely occluded then ignore that + * view; includes the case where occluded_region covers + * the entire output */ totally_occluded = !pixman_region32_not_empty(&surface_overlap); if (totally_occluded) { drm_debug(b, "\t\t\t\t[view] ignoring view %p " @@ -875,10 +880,22 @@ drm_output_propose_state(struct weston_output *output_base, * be added to the renderer region nor the occluded * region. */ if (ps->plane->type != WDRM_PLANE_TYPE_CURSOR) { + pixman_region32_union(&planes_region, + &planes_region, + &clipped_view); + + if (!weston_view_is_opaque(ev, &clipped_view)) + pixman_region32_intersect(&clipped_view, + &clipped_view, + &ev->transform.opaque); + /* the visible-and-opaque region of this view + * will occlude views underneath it */ pixman_region32_union(&occluded_region, &occluded_region, &clipped_view); + pixman_region32_fini(&clipped_view); + } continue; } @@ -897,9 +914,21 @@ drm_output_propose_state(struct weston_output *output_base, pixman_region32_union(&renderer_region, &renderer_region, &clipped_view); + + if (!weston_view_is_opaque(ev, &clipped_view)) + pixman_region32_intersect(&clipped_view, + &clipped_view, + &ev->transform.opaque); + + pixman_region32_union(&occluded_region, + &occluded_region, + &clipped_view); + pixman_region32_fini(&clipped_view); } + pixman_region32_fini(&renderer_region); + pixman_region32_fini(&planes_region); pixman_region32_fini(&occluded_region); /* In renderer-only mode, we can't test the state as we don't have a