backend-drm: Teach drm_property_info_populate() to retrieve range values
authorMarius Vlad <marius.vlad0@gmail.com>
Mon, 11 Nov 2019 15:24:25 +0000 (15:24 +0000)
committerDaniel Stone <daniel@fooishbar.org>
Mon, 11 Nov 2019 15:24:25 +0000 (15:24 +0000)
Useful for zpos range values.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Suggested-by: Daniel Stone <daniel.stone@collabora.com>
libweston/backend-drm/drm-internal.h
libweston/backend-drm/drm.c
libweston/backend-drm/kms.c
libweston/backend-drm/state-helpers.c
libweston/backend-drm/state-propose.c
libweston/compositor.c
libweston/libweston-internal.h

index b55061ab65d7f837f777ac25c3bc77c3dd61a8e1..cf588674f8aacf774b6d07d1b422789000968a44 100644 (file)
 #define GBM_BO_USE_LINEAR (1 << 4)
 #endif
 
+#ifndef DRM_PLANE_ZPOS_INVALID_PLANE
+#define DRM_PLANE_ZPOS_INVALID_PLANE   0xffffffffffffffffULL
+#endif
+
 /**
  * A small wrapper to print information into the 'drm-backend' debug scope.
  *
@@ -144,8 +148,11 @@ struct drm_property_enum_info {
 struct drm_property_info {
        const char *name; /**< name as string (static, not freed) */
        uint32_t prop_id; /**< KMS property object ID */
+       uint32_t flags;
        unsigned int num_enum_values; /**< number of enum values */
        struct drm_property_enum_info *enum_values; /**< array of enum values */
+       unsigned int num_range_values;
+       uint64_t range_values[2];
 };
 
 /**
@@ -166,6 +173,7 @@ enum wdrm_plane_property {
        WDRM_PLANE_IN_FORMATS,
        WDRM_PLANE_IN_FENCE_FD,
        WDRM_PLANE_FB_DAMAGE_CLIPS,
+       WDRM_PLANE_ZPOS,
        WDRM_PLANE__COUNT
 };
 
@@ -361,6 +369,16 @@ struct drm_output_state {
        struct wl_list plane_list;
 };
 
+/**
+ * An instance of this class is created each time we believe we have a plane
+ * suitable to be used by a view as a direct scan-out. The list is initalized
+ * and populated locally.
+ */
+struct drm_plane_zpos {
+       struct drm_plane *plane;
+       struct wl_list link;    /**< :candidate_plane_zpos_list */
+};
+
 /**
  * Plane state holds the dynamic state for a plane: where it is positioned,
  * and which buffer it is currently displaying.
@@ -382,6 +400,8 @@ struct drm_plane_state {
        int32_t dest_x, dest_y;
        uint32_t dest_w, dest_h;
 
+       uint64_t zpos;
+
        bool complete;
 
        /* We don't own the fd, so we shouldn't close it */
@@ -423,6 +443,9 @@ struct drm_plane {
        /* The last state submitted to the kernel for this plane. */
        struct drm_plane_state *state_cur;
 
+       uint64_t zpos_min;
+       uint64_t zpos_max;
+
        struct wl_list link;
 
        struct {
@@ -523,6 +546,22 @@ to_drm_mode(struct weston_mode *base)
        return container_of(base, struct drm_mode, base);
 }
 
+static inline const char *
+drm_output_get_plane_type_name(struct drm_plane *p)
+{
+       switch (p->type) {
+       case WDRM_PLANE_TYPE_PRIMARY:
+               return "primary";
+       case WDRM_PLANE_TYPE_CURSOR:
+               return "cursor";
+       case WDRM_PLANE_TYPE_OVERLAY:
+               return "overlay";
+       default:
+               assert(0);
+               break;
+       }
+}
+
 struct drm_output *
 drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id);
 
@@ -579,6 +618,9 @@ uint64_t
 drm_property_get_value(struct drm_property_info *info,
                       const drmModeObjectProperties *props,
                       uint64_t def);
+uint64_t *
+drm_property_get_range_values(struct drm_property_info *info,
+                             const drmModeObjectProperties *props);
 int
 drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
                           const drmModeObjectProperties *props);
@@ -695,7 +737,7 @@ void
 drm_plane_state_put_back(struct drm_plane_state *state);
 bool
 drm_plane_state_coords_for_view(struct drm_plane_state *state,
-                               struct weston_view *ev);
+                               struct weston_view *ev, uint64_t zpos);
 
 void
 drm_assign_planes(struct weston_output *output_base, void *repaint_data);
index 878d71ec3d6f797f813bafdc0a7d58d3899cb1ca..33ccbeb364f5211140c05e2b7d3b8ccfe843c418 100644 (file)
 
 static const char default_seat[] = "seat0";
 
+static void
+drm_backend_create_faked_zpos(struct drm_backend *b)
+{
+       struct drm_plane *plane;
+       uint64_t zpos = 0ULL;
+       uint64_t zpos_min_primary;
+       uint64_t zpos_min_overlay;
+       uint64_t zpos_min_cursor;
+
+       zpos_min_primary = zpos;
+       wl_list_for_each(plane, &b->plane_list, link) {
+               /* if the property is there, bail out sooner */
+               if (plane->props[WDRM_PLANE_ZPOS].prop_id != 0)
+                       return;
+
+               if (plane->type != WDRM_PLANE_TYPE_PRIMARY)
+                       continue;
+               zpos++;
+       }
+
+       zpos_min_overlay = zpos;
+       wl_list_for_each(plane, &b->plane_list, link) {
+               if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
+                       continue;
+               zpos++;
+       }
+
+       zpos_min_cursor = zpos;
+       wl_list_for_each(plane, &b->plane_list, link) {
+               if (plane->type != WDRM_PLANE_TYPE_CURSOR)
+                       continue;
+               zpos++;
+       }
+
+       drm_debug(b, "[drm-backend] zpos property not found. "
+                    "Using invented immutable zpos values:\n");
+       /* assume that invented zpos values are immutable */
+       wl_list_for_each(plane, &b->plane_list, link) {
+               if (plane->type == WDRM_PLANE_TYPE_PRIMARY) {
+                       plane->zpos_min = zpos_min_primary;
+                       plane->zpos_max = zpos_min_primary;
+               } else if (plane->type == WDRM_PLANE_TYPE_OVERLAY) {
+                       plane->zpos_min = zpos_min_overlay;
+                       plane->zpos_max = zpos_min_overlay;
+               } else if (plane->type == WDRM_PLANE_TYPE_CURSOR) {
+                       plane->zpos_min = zpos_min_cursor;
+                       plane->zpos_max = zpos_min_cursor;
+               }
+               drm_debug(b, "\t[plane] %s plane %d, zpos_min %"PRIu64", "
+                             "zpos_max %"PRIu64"\n",
+                             drm_output_get_plane_type_name(plane),
+                             plane->plane_id, plane->zpos_min, plane->zpos_max);
+       }
+}
+
 static void
 wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
 {
@@ -680,6 +735,7 @@ drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
 {
        struct drm_plane *plane;
        drmModeObjectProperties *props;
+       uint64_t *zpos_range_values;
        uint32_t num_formats = (kplane) ? kplane->count_formats : 1;
 
        plane = zalloc(sizeof(*plane) +
@@ -711,6 +767,18 @@ drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
                                               props,
                                               WDRM_PLANE_TYPE__COUNT);
 
+               zpos_range_values =
+                       drm_property_get_range_values(&plane->props[WDRM_PLANE_ZPOS], 
+                                                     props);
+
+               if (zpos_range_values) {
+                       plane->zpos_min = zpos_range_values[0];
+                       plane->zpos_max = zpos_range_values[1];
+               } else {
+                       plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
+                       plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
+               }
+
                if (drm_plane_populate_formats(plane, kplane, props) < 0) {
                        drmModeFreeObjectProperties(props);
                        goto err;
@@ -724,6 +792,8 @@ drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
                plane->count_formats = 1;
                plane->formats[0].format = format;
                plane->type = type;
+               plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
+               plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
        }
 
        if (plane->type == WDRM_PLANE_TYPE__COUNT)
@@ -2841,6 +2911,9 @@ drm_backend_create(struct weston_compositor *compositor,
                goto err_udev_input;
        }
 
+       /* 'compute' faked zpos values in case HW doesn't expose any */
+       drm_backend_create_faked_zpos(b);
+
        /* A this point we have some idea of whether or not we have a working
         * cursor plane. */
        if (!b->cursors_are_broken)
index 4c942a3d3b60f60d99c1ac44289c32dddc4685b6..5468afb36a095f12e5e9f7325b6f805bc5941af1 100644 (file)
@@ -77,6 +77,7 @@ const struct drm_property_info plane_props[] = {
        [WDRM_PLANE_IN_FORMATS] = { .name = "IN_FORMATS" },
        [WDRM_PLANE_IN_FENCE_FD] = { .name = "IN_FENCE_FD" },
        [WDRM_PLANE_FB_DAMAGE_CLIPS] = { .name = "FB_DAMAGE_CLIPS" },
+       [WDRM_PLANE_ZPOS] = { .name = "zpos" },
 };
 
 struct drm_property_enum_info dpms_state_enums[] = {
@@ -202,6 +203,42 @@ drm_property_get_value(struct drm_property_info *info,
        return def;
 }
 
+/**
+ * Get the current range values of a KMS property
+ *
+ * Given a drmModeObjectGetProperties return, as well as the drm_property_info
+ * for the target property, return the current range values of that property,
+ *
+ * If the property is not present, or there's no it is not a prop range then
+ * NULL will be returned.
+ *
+ * @param info Internal structure for property to look up
+ * @param props Raw KMS properties for the target object
+ */
+uint64_t *
+drm_property_get_range_values(struct drm_property_info *info,
+                             const drmModeObjectProperties *props)
+{
+       unsigned int i;
+
+       if (info->prop_id == 0)
+               return NULL;
+
+       for (i = 0; i < props->count_props; i++) {
+
+               if (props->props[i] != info->prop_id)
+                       continue;
+
+               if (!(info->flags & DRM_MODE_PROP_RANGE) &&
+                   !(info->flags & DRM_MODE_PROP_SIGNED_RANGE))
+                       continue;
+
+               return info->range_values;
+       }
+
+       return NULL;
+}
+
 /**
  * Cache DRM property values
  *
@@ -294,6 +331,15 @@ drm_property_info_populate(struct drm_backend *b,
                }
 
                info[j].prop_id = props->props[i];
+               info[j].flags = prop->flags;
+
+               if (prop->flags & DRM_MODE_PROP_RANGE ||
+                   prop->flags & DRM_MODE_PROP_SIGNED_RANGE) {
+                       info[j].num_range_values = prop->count_values;
+                       for (int i = 0; i < prop->count_values; i++)
+                               info[j].range_values[i] = prop->values[i];
+               }
+
 
                if (info[j].num_enum_values == 0) {
                        drmModeFreeProperty(prop);
@@ -1005,6 +1051,13 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
                                              plane_state->in_fence_fd);
                }
 
+               /* do note, that 'invented' zpos values are set as immutable */
+               if (plane_state->zpos != DRM_PLANE_ZPOS_INVALID_PLANE &&
+                   plane_state->plane->zpos_min != plane_state->plane->zpos_max)
+                       ret |= plane_add_prop(req, plane,
+                                             WDRM_PLANE_ZPOS,
+                                             plane_state->zpos);
+
                if (ret != 0) {
                        weston_log("couldn't set plane state\n");
                        return ret;
index 3956960c8e11f4ebc07dd3d56975c9b1358337af..7b1d9241d5cefbea330b378173360cfbb494b880 100644 (file)
@@ -48,6 +48,7 @@ drm_plane_state_alloc(struct drm_output_state *state_output,
        state->output_state = state_output;
        state->plane = plane;
        state->in_fence_fd = -1;
+       state->zpos = DRM_PLANE_ZPOS_INVALID_PLANE;
        pixman_region32_init(&state->damage);
 
        /* Here we only add the plane state to the desired link, and not
@@ -80,6 +81,7 @@ drm_plane_state_free(struct drm_plane_state *state, bool force)
        wl_list_init(&state->link);
        state->output_state = NULL;
        state->in_fence_fd = -1;
+       state->zpos = DRM_PLANE_ZPOS_INVALID_PLANE;
        pixman_region32_fini(&state->damage);
 
        if (force || state != state->plane->state_cur) {
@@ -163,7 +165,7 @@ drm_plane_state_put_back(struct drm_plane_state *state)
  */
 bool
 drm_plane_state_coords_for_view(struct drm_plane_state *state,
-                               struct weston_view *ev)
+                               struct weston_view *ev, uint64_t zpos)
 {
        struct drm_output *output = state->output;
        struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
@@ -243,6 +245,9 @@ drm_plane_state_coords_for_view(struct drm_plane_state *state,
        if (state->src_h > (uint32_t) ((buffer->height << 16) - state->src_y))
                state->src_h = (buffer->height << 16) - state->src_y;
 
+       /* apply zpos if available */
+       state->zpos = zpos;
+
        return true;
 }
 
index 6a01f44bd48157a042f4c71dc5420395d79947e8..779eb9ff3eb3eb082399db4d291ac046d9faf29b 100644 (file)
@@ -62,155 +62,200 @@ drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode)
        return drm_output_propose_state_mode_as_string[mode];
 }
 
-static struct drm_plane_state *
-drm_output_prepare_overlay_view(struct drm_output_state *output_state,
-                               struct weston_view *ev,
-                               enum drm_output_propose_state_mode mode)
+static void
+drm_output_add_zpos_plane(struct drm_plane *plane, struct wl_list *planes)
 {
-       struct drm_output *output = output_state->output;
-       struct weston_compositor *ec = output->base.compositor;
-       struct drm_backend *b = to_drm_backend(ec);
-       struct drm_plane *p;
-       struct drm_plane_state *state = NULL;
-       struct drm_fb *fb;
-       unsigned int i;
-       int ret;
-       enum {
-               NO_PLANES,
-               NO_PLANES_WITH_FORMAT,
-               NO_PLANES_ACCEPTED,
-               PLACED_ON_PLANE,
-       } availability = NO_PLANES;
+       struct drm_backend *b = plane->backend;
+       struct drm_plane_zpos *h_plane;
+       struct drm_plane_zpos *plane_zpos;
 
-       assert(!b->sprites_are_broken);
-       assert(b->atomic_modeset);
+       plane_zpos = zalloc(sizeof(*plane_zpos));
+       if (!plane_zpos)
+               return;
 
-       fb = drm_fb_get_from_view(output_state, ev);
-       if (!fb) {
-               drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
-                            " couldn't get fb\n", ev);
-               return NULL;
+       plane_zpos->plane = plane;
+
+       drm_debug(b, "\t\t\t\t[plane] plane %d added to candidate list\n",
+                     plane->plane_id);
+
+       if (wl_list_empty(planes)) {
+               wl_list_insert(planes, &plane_zpos->link);
+               return;
        }
 
-       wl_list_for_each(p, &b->plane_list, link) {
-               if (p->type != WDRM_PLANE_TYPE_OVERLAY)
-                       continue;
+       h_plane = wl_container_of(planes->next, h_plane, link);
+       if (h_plane->plane->zpos_max >= plane->zpos_max) {
+               wl_list_insert(planes->prev, &plane_zpos->link);
+       } else {
+               struct drm_plane_zpos *p_zpos = NULL;
 
-               if (!drm_plane_is_available(p, output))
-                       continue;
+               if (wl_list_length(planes) == 1) {
+                       wl_list_insert(planes->prev, &plane_zpos->link);
+                       return;
+               }
 
-               state = drm_output_state_get_plane(output_state, p);
-               if (state->fb) {
-                       state = NULL;
-                       continue;
+               wl_list_for_each(p_zpos, planes, link) {
+                       if (p_zpos->plane->zpos_max >
+                           plane_zpos->plane->zpos_max)
+                               break;
                }
 
-               if (availability == NO_PLANES)
-                       availability = NO_PLANES_WITH_FORMAT;
+               wl_list_insert(p_zpos->link.prev, &plane_zpos->link);
+       }
+}
+
+static void
+drm_output_destroy_zpos_plane(struct drm_plane_zpos *plane_zpos)
+{
+       wl_list_remove(&plane_zpos->link);
+       free(plane_zpos);
+}
+
+static bool
+drm_output_check_plane_has_view_assigned(struct drm_plane *plane,
+                                        struct drm_output_state *output_state)
+{
+       struct drm_plane_state *ps;
+       wl_list_for_each(ps, &output_state->plane_list, link) {
+               if (ps->plane == plane && ps->fb)
+                       return true;
+       }
+       return false;
+}
 
-               /* Check whether the format is supported */
-               for (i = 0; i < p->count_formats; i++) {
-                       unsigned int j;
+static bool
+drm_output_plane_has_valid_format(struct drm_plane *plane,
+                                 struct drm_output_state *state,
+                                 struct drm_fb *fb)
+{
+       struct drm_backend *b = plane->backend;
+       unsigned int i;
 
-                       if (p->formats[i].format != fb->format->format)
-                               continue;
+       if (!fb)
+               return false;
 
-                       if (fb->modifier == DRM_FORMAT_MOD_INVALID)
-                               break;
+       /* Check whether the format is supported */
+       for (i = 0; i < plane->count_formats; i++) {
+               unsigned int j;
 
-                       for (j = 0; j < p->formats[i].count_modifiers; j++) {
-                               if (p->formats[i].modifiers[j] == fb->modifier)
-                                       break;
-                       }
-                       if (j != p->formats[i].count_modifiers)
-                               break;
-               }
-               if (i == p->count_formats) {
-                       drm_plane_state_put_back(state);
-                       state = NULL;
+               if (plane->formats[i].format != fb->format->format)
                        continue;
-               }
 
-               if (availability == NO_PLANES_WITH_FORMAT)
-                       availability = NO_PLANES_ACCEPTED;
+               if (fb->modifier == DRM_FORMAT_MOD_INVALID)
+                       return true;
 
-               state->ev = ev;
-               state->output = output;
-               if (!drm_plane_state_coords_for_view(state, ev)) {
-                       drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
-                                    "unsuitable transform\n", ev);
-                       drm_plane_state_put_back(state);
-                       state = NULL;
-                       continue;
+               for (j = 0; j < plane->formats[i].count_modifiers; j++) {
+                       if (plane->formats[i].modifiers[j] == fb->modifier)
+                               return true;
                }
+       }
 
-               /* If the surface buffer has an in-fence fd, but the plane
-                * doesn't support fences, we can't place the buffer on this
-                * plane. */
-               if (ev->surface->acquire_fence_fd >= 0 &&
-                    p->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) {
-                       drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
-                                    "no in-fence support\n", ev);
-                       drm_plane_state_put_back(state);
-                       state = NULL;
-                       continue;
-               }
+       drm_debug(b, "\t\t\t\t[%s] not placing view on %s: "
+                 "no free %s planes matching format %s (0x%lx) "
+                 "modifier 0x%llx\n",
+                 drm_output_get_plane_type_name(plane),
+                 drm_output_get_plane_type_name(plane),
+                 drm_output_get_plane_type_name(plane),
+                 fb->format->drm_format_name,
+                 (unsigned long) fb->format,
+                 (unsigned long long) fb->modifier);
+
+       return false;
+}
 
-               /* We hold one reference for the lifetime of this function;
-                * from calling drm_fb_get_from_view, to the out label where
-                * we unconditionally drop the reference. So, we take another
-                * reference here to live within the state. */
-               state->fb = drm_fb_ref(fb);
+static bool
+drm_output_plane_cursor_has_valid_format(struct weston_view *ev)
+{
+       struct wl_shm_buffer *shmbuf =
+               wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
 
-               state->in_fence_fd = ev->surface->acquire_fence_fd;
+       if (shmbuf && wl_shm_buffer_get_format(shmbuf) == WL_SHM_FORMAT_ARGB8888)
+               return true;
 
-               /* In planes-only mode, we don't have an incremental state to
-                * test against, so we just hope it'll work. */
-               if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) {
-                       drm_debug(b, "\t\t\t\t[overlay] provisionally placing "
-                                    "view %p on overlay %lu in planes-only mode\n",
-                                 ev, (unsigned long) p->plane_id);
-                       availability = PLACED_ON_PLANE;
-                       goto out;
-               }
+       return false;
+}
 
-               ret = drm_pending_state_test(output_state->pending_state);
-               if (ret == 0) {
-                       drm_debug(b, "\t\t\t\t[overlay] provisionally placing "
-                                    "view %p on overlay %d in mixed mode\n",
-                                 ev, p->plane_id);
-                       availability = PLACED_ON_PLANE;
-                       goto out;
-               }
+static struct drm_plane_state *
+drm_output_prepare_overlay_view(struct drm_plane *plane,
+                               struct drm_output_state *output_state,
+                               struct weston_view *ev,
+                               enum drm_output_propose_state_mode mode,
+                               struct drm_fb *fb, uint64_t zpos)
+{
+       struct drm_output *output = output_state->output;
+       struct weston_compositor *ec = output->base.compositor;
+       struct drm_backend *b = to_drm_backend(ec);
+       struct drm_plane_state *state = NULL;
+       int ret;
+
+       assert(!b->sprites_are_broken);
+       assert(b->atomic_modeset);
 
-               drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay %lu "
-                            "in mixed mode: kernel test failed\n",
-                         ev, (unsigned long) p->plane_id);
+       if (!fb) {
+               drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
+                            " couldn't get fb\n", ev);
+               return NULL;
+       }
+
+       state = drm_output_state_get_plane(output_state, plane);
+       /* we can't have a 'pending' framebuffer as never set one before reaching here */
+       assert(!state->fb);
 
+       state->ev = ev;
+       state->output = output;
+
+       if (!drm_plane_state_coords_for_view(state, ev, zpos)) {
+               drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
+                            "unsuitable transform\n", ev);
                drm_plane_state_put_back(state);
                state = NULL;
+               goto out;
        }
 
-       switch (availability) {
-       case NO_PLANES:
-               drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
-                            "no free overlay planes\n", ev);
-               break;
-       case NO_PLANES_WITH_FORMAT:
+       /* If the surface buffer has an in-fence fd, but the plane
+        * doesn't support fences, we can't place the buffer on this
+        * plane. */
+       if (ev->surface->acquire_fence_fd >= 0 &&
+            plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) {
                drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
-                            "no free overlay planes matching format %s (0x%lx) "
-                            "modifier 0x%llx\n",
-                         ev, fb->format->drm_format_name,
-                         (unsigned long) fb->format,
-                         (unsigned long long) fb->modifier);
-               break;
-       case NO_PLANES_ACCEPTED:
-       case PLACED_ON_PLANE:
-               break;
+                            "no in-fence support\n", ev);
+               drm_plane_state_put_back(state);
+               state = NULL;
+               goto out;
+       }
+
+       /* We hold one reference for the lifetime of this function; from
+        * calling drm_fb_get_from_view() in drm_output_prepare_plane_view(),
+        * so, we take another reference here to live within the state. */
+       state->fb = drm_fb_ref(fb);
+
+       state->in_fence_fd = ev->surface->acquire_fence_fd;
+
+       /* In planes-only mode, we don't have an incremental state to
+        * test against, so we just hope it'll work. */
+       if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) {
+               drm_debug(b, "\t\t\t[overlay] provisionally placing "
+                            "view %p on overlay %lu in planes-only mode\n",
+                         ev, (unsigned long) plane->plane_id);
+               goto out;
        }
 
+       ret = drm_pending_state_test(output_state->pending_state);
+       if (ret == 0) {
+               drm_debug(b, "\t\t\t[overlay] provisionally placing "
+                            "view %p on overlay %d in mixed mode\n",
+                         ev, plane->plane_id);
+               goto out;
+       }
+
+       drm_debug(b, "\t\t\t[overlay] not placing view %p on overlay %lu "
+                    "in mixed mode: kernel test failed\n",
+                 ev, (unsigned long) plane->plane_id);
+
+       drm_plane_state_put_back(state);
+       state = NULL;
+
 out:
-       drm_fb_unref(fb);
        return state;
 }
 
@@ -254,14 +299,14 @@ cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
 
 static struct drm_plane_state *
 drm_output_prepare_cursor_view(struct drm_output_state *output_state,
-                              struct weston_view *ev)
+                              struct weston_view *ev, uint64_t zpos)
 {
        struct drm_output *output = output_state->output;
        struct drm_backend *b = to_drm_backend(output->base.compositor);
        struct drm_plane *plane = output->cursor_plane;
        struct drm_plane_state *plane_state;
-       struct wl_shm_buffer *shmbuf;
        bool needs_update = false;
+       const char *p_name = drm_output_get_plane_type_name(plane);
 
        assert(!b->cursors_are_broken);
 
@@ -278,24 +323,6 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
        if (b->gbm == NULL)
                return NULL;
 
-       if (ev->surface->buffer_ref.buffer == NULL) {
-               drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
-                            "(no buffer available)\n", ev);
-               return NULL;
-       }
-       shmbuf = wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
-       if (!shmbuf) {
-               drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
-                            "(buffer isn't SHM)\n", ev);
-               return NULL;
-       }
-       if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888) {
-               drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
-                            "(format 0x%lx unsuitable)\n",
-                         ev, (unsigned long) wl_shm_buffer_get_format(shmbuf));
-               return NULL;
-       }
-
        plane_state =
                drm_output_state_get_plane(output_state, output->cursor_plane);
 
@@ -305,16 +332,20 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
        /* We can't scale with the legacy API, and we don't try to account for
         * simple cropping/translation in cursor_bo_update. */
        plane_state->output = output;
-       if (!drm_plane_state_coords_for_view(plane_state, ev))
+       if (!drm_plane_state_coords_for_view(plane_state, ev, zpos)) {
+               drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
+                            "unsuitable transform\n", p_name, ev, p_name);
                goto err;
+       }
 
        if (plane_state->src_x != 0 || plane_state->src_y != 0 ||
            plane_state->src_w > (unsigned) b->cursor_width << 16 ||
            plane_state->src_h > (unsigned) b->cursor_height << 16 ||
            plane_state->src_w != plane_state->dest_w << 16 ||
            plane_state->src_h != plane_state->dest_h << 16) {
-               drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
-                            "(positioning requires cropping or scaling)\n", ev);
+               drm_debug(b, "\t\t\t\t[%s] not assigning view %p to %s plane "
+                            "(positioning requires cropping or scaling)\n",
+                            p_name, ev, p_name);
                goto err;
        }
 
@@ -340,7 +371,7 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
                drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
 
        if (needs_update) {
-               drm_debug(b, "\t\t\t\t[cursor] copying new content to cursor BO\n");
+               drm_debug(b, "\t\t\t\t[%s] copying new content to cursor BO\n", p_name);
                cursor_bo_update(plane_state, ev);
        }
 
@@ -353,8 +384,8 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
        plane_state->dest_w = b->cursor_width;
        plane_state->dest_h = b->cursor_height;
 
-       drm_debug(b, "\t\t\t\t[cursor] provisionally assigned view %p to cursor\n",
-                 ev);
+       drm_debug(b, "\t\t\t\t[%s] provisionally assigned view %p to cursor\n",
+                 p_name, ev);
 
        return plane_state;
 
@@ -365,7 +396,7 @@ err:
 #else
 static struct drm_plane_state *
 drm_output_prepare_cursor_view(struct drm_output_state *output_state,
-                              struct weston_view *ev)
+                              struct weston_view *ev, uint64_t zpos)
 {
        return NULL;
 }
@@ -374,14 +405,14 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
 static struct drm_plane_state *
 drm_output_prepare_scanout_view(struct drm_output_state *output_state,
                                struct weston_view *ev,
-                               enum drm_output_propose_state_mode mode)
+                               enum drm_output_propose_state_mode mode,
+                               struct drm_fb *fb, uint64_t zpos)
 {
        struct drm_output *output = output_state->output;
        struct drm_backend *b = to_drm_backend(output->base.compositor);
        struct drm_plane *scanout_plane = output->scanout_plane;
        struct drm_plane_state *state;
-       struct drm_fb *fb;
-       pixman_box32_t *extents;
+       const char *p_name = drm_output_get_plane_type_name(scanout_plane);
 
        assert(!b->sprites_are_broken);
        assert(b->atomic_modeset);
@@ -389,23 +420,25 @@ drm_output_prepare_scanout_view(struct drm_output_state *output_state,
 
        /* Check the view spans exactly the output size, calculated in the
         * logical co-ordinate space. */
-       extents = pixman_region32_extents(&ev->transform.boundingbox);
-       if (extents->x1 != output->base.x ||
-           extents->y1 != output->base.y ||
-           extents->x2 != output->base.x + output->base.width ||
-           extents->y2 != output->base.y + output->base.height)
+       if (!weston_view_matches_output_entirely(ev, &output->base)) {
+               drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
+                            " view does not match output entirely\n",
+                            p_name, ev, p_name);
                return NULL;
+       }
 
        /* If the surface buffer has an in-fence fd, but the plane doesn't
         * support fences, we can't place the buffer on this plane. */
        if (ev->surface->acquire_fence_fd >= 0 &&
-           scanout_plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0)
+           scanout_plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) {
+               drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
+                            "no in-fence support\n", p_name, ev, p_name);
                return NULL;
+       }
 
-       fb = drm_fb_get_from_view(output_state, ev);
        if (!fb) {
-               drm_debug(b, "\t\t\t\t[scanout] not placing view %p on scanout: "
-                            " couldn't get fb\n", ev);
+               drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
+                            " couldn't get fb\n", p_name, ev, p_name);
                return NULL;
        }
 
@@ -417,16 +450,24 @@ drm_output_prepare_scanout_view(struct drm_output_state *output_state,
         * and in the latter case, the view must have been marked as occluded,
         * meaning we should never have ended up here. */
        assert(!state->fb);
-       state->fb = fb;
+
+       /* take another reference here to live within the state */
+       state->fb = drm_fb_ref(fb);
        state->ev = ev;
        state->output = output;
-       if (!drm_plane_state_coords_for_view(state, ev))
+       if (!drm_plane_state_coords_for_view(state, ev, zpos)) {
+               drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
+                            "unsuitable transform\n", p_name, ev, p_name);
                goto err;
+       }
 
        if (state->dest_x != 0 || state->dest_y != 0 ||
            state->dest_w != (unsigned) output->base.current_mode->width ||
-           state->dest_h != (unsigned) output->base.current_mode->height)
+           state->dest_h != (unsigned) output->base.current_mode->height) {
+               drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
+                            " invalid plane state\n", p_name, ev, p_name);
                goto err;
+       }
 
        state->in_fence_fd = ev->surface->acquire_fence_fd;
 
@@ -439,6 +480,252 @@ err:
        return NULL;
 }
 
+static bool
+drm_output_plane_view_has_valid_format(struct drm_plane *plane,
+                                      struct drm_output_state *state,
+                                      struct weston_view *ev,
+                                      struct drm_fb *fb)
+{
+       /* depending on the type of the plane we have different requirements */
+       switch (plane->type) {
+       case WDRM_PLANE_TYPE_CURSOR:
+               return drm_output_plane_cursor_has_valid_format(ev);
+       case WDRM_PLANE_TYPE_OVERLAY:
+               return drm_output_plane_has_valid_format(plane, state, fb);
+       case WDRM_PLANE_TYPE_PRIMARY:
+               return drm_output_plane_has_valid_format(plane, state, fb);
+       default:
+               assert(0);
+               return false;
+       }
+
+       return false;
+}
+
+static struct drm_plane_state *
+drm_output_try_view_on_plane(struct drm_plane *plane,
+                            struct drm_output_state *state,
+                            struct weston_view *ev,
+                            enum drm_output_propose_state_mode mode,
+                            struct drm_fb *fb, uint64_t zpos)
+{
+       struct drm_backend *b = state->pending_state->backend;
+       struct weston_output *wet_output = &state->output->base;
+       bool view_matches_entire_output, scanout_has_view_assigned;
+       struct drm_plane *scanout_plane = state->output->scanout_plane;
+       struct drm_plane_state *ps = NULL;
+       const char *p_name = drm_output_get_plane_type_name(plane);
+       enum {
+               NO_PLANES,      /* generic err-handle */
+               NO_PLANES_ACCEPTED,
+               PLACED_ON_PLANE,
+       } availability = NO_PLANES;
+
+       /* sanity checks in case we over/underflow zpos or pass incorrect
+        * values */
+       assert(zpos <= plane->zpos_max ||
+              zpos != DRM_PLANE_ZPOS_INVALID_PLANE);
+
+       switch (plane->type) {
+       case WDRM_PLANE_TYPE_CURSOR:
+               if (b->cursors_are_broken) {
+                       availability = NO_PLANES_ACCEPTED;
+                       goto out;
+               }
+
+               ps = drm_output_prepare_cursor_view(state, ev, zpos);
+               if (ps)
+                       availability = PLACED_ON_PLANE;
+               break;
+       case WDRM_PLANE_TYPE_OVERLAY:
+               /* do not attempt to place it in the overlay if we don't have
+                * anything in the scanout/primary and the view doesn't cover
+                * the entire output  */
+               view_matches_entire_output =
+                       weston_view_matches_output_entirely(ev, wet_output);
+               scanout_has_view_assigned =
+                       drm_output_check_plane_has_view_assigned(scanout_plane,
+                                                                state);
+
+               if (view_matches_entire_output && !scanout_has_view_assigned) {
+                       availability = NO_PLANES_ACCEPTED;
+                       goto out;
+               }
+
+               ps = drm_output_prepare_overlay_view(plane, state, ev, mode,
+                                                    fb, zpos);
+               if (ps)
+                       availability = PLACED_ON_PLANE;
+               break;
+       case WDRM_PLANE_TYPE_PRIMARY:
+               if (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) {
+                       availability = NO_PLANES_ACCEPTED;
+                       goto out;
+               }
+
+               ps = drm_output_prepare_scanout_view(state, ev, mode,
+                                                    fb, zpos);
+               if (ps)
+                       availability = PLACED_ON_PLANE;
+               break;
+       default:
+               assert(0);
+               break;
+       }
+
+out:
+       switch (availability) {
+       case NO_PLANES:
+               /* set initial to this catch-all case, such that
+                * prepare_cursor/overlay/scanout() should have/contain the
+                * reason for failling */
+               break;
+       case NO_PLANES_ACCEPTED:
+               drm_debug(b, "\t\t\t\t[plane] plane %d refusing to "
+                            "place view %p in %s\n",
+                            plane->plane_id, ev, p_name);
+               break;
+       case PLACED_ON_PLANE:
+               break;
+       }
+
+
+       return ps;
+}
+
+static int
+drm_output_check_zpos_plane_states(struct drm_output_state *state)
+{
+       struct drm_backend *b = state->pending_state->backend;
+       struct drm_plane_state *ps;
+       int ret = 0;
+
+       wl_list_for_each(ps, &state->plane_list, link) {
+               struct wl_list *next_node = ps->link.next;
+               bool found_dup = false;
+
+               /* find another plane with the same zpos value */
+               if (next_node == &state->plane_list)
+                       break;
+
+               while (next_node && next_node != &state->plane_list) {
+                       struct drm_plane_state *ps_next;
+
+                       ps_next = container_of(next_node,
+                                              struct drm_plane_state,
+                                              link);
+
+                       if (ps->zpos == ps_next->zpos) {
+                               found_dup = true;
+                               break;
+                       }
+                       next_node = next_node->next;
+               }
+
+               if (found_dup) {
+                       ret = 1;
+                       drm_debug(b, "\t\t\t[plane] found duplicate zpos values\n");
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static struct drm_plane_state *
+drm_output_prepare_plane_view(struct drm_output_state *state,
+                             struct weston_view *ev,
+                             enum drm_output_propose_state_mode mode,
+                             uint64_t current_lowest_zpos)
+{
+       struct drm_output *output = state->output;
+       struct drm_backend *b = to_drm_backend(output->base.compositor);
+
+       struct drm_plane_state *ps = NULL;
+       struct drm_plane *plane;
+       struct drm_plane_zpos *p_zpos, *p_zpos_next;
+       struct wl_list zpos_candidate_list;
+
+       struct drm_fb *fb;
+
+       wl_list_init(&zpos_candidate_list);
+
+       /* check view for valid buffer, doesn't make sense to even try */
+       if (!weston_view_has_valid_buffer(ev))
+               return ps;
+
+       fb = drm_fb_get_from_view(state, ev);
+
+       /* assemble a list with possible candidates */
+       wl_list_for_each(plane, &b->plane_list, link) {
+               if (!drm_plane_is_available(plane, output))
+                       continue;
+
+               if (drm_output_check_plane_has_view_assigned(plane, state)) {
+                       drm_debug(b, "\t\t\t\t[plane] not adding plane %d to"
+                                    " candidate list: view already assigned "
+                                    "to a plane\n", plane->plane_id);
+                       continue;
+               }
+
+               if (plane->zpos_min >= current_lowest_zpos) {
+                       drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
+                                    "candidate list: minium zpos (%"PRIu64") "
+                                    "plane's above current lowest zpos "
+                                    "(%"PRIu64")\n", plane->plane_id,
+                                    plane->zpos_min, current_lowest_zpos);
+                       continue;
+               }
+
+               if (!drm_output_plane_view_has_valid_format(plane, state, ev, fb)) {
+                       drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
+                                    "candidate list: invalid pixel format\n",
+                                    plane->plane_id);
+                       continue;
+               }
+
+               drm_output_add_zpos_plane(plane, &zpos_candidate_list);
+       }
+
+       /* go over the potential candidate list and try to find a possible
+        * plane suitable for \c ev; start with the highest zpos value of a
+        * plane to maximize our chances, but do note we pass the zpos value
+        * based on current tracked value by \c current_lowest_zpos_in_use */
+       while (!wl_list_empty(&zpos_candidate_list)) {
+               struct drm_plane_zpos *head_p_zpos =
+                       wl_container_of(zpos_candidate_list.next,
+                                       head_p_zpos, link);
+               struct drm_plane *plane = head_p_zpos->plane;
+               const char *p_name = drm_output_get_plane_type_name(plane);
+               uint64_t zpos;
+
+               if (current_lowest_zpos == DRM_PLANE_ZPOS_INVALID_PLANE)
+                       zpos = plane->zpos_max;
+               else
+                       zpos = MIN(current_lowest_zpos - 1, plane->zpos_max);
+
+               drm_debug(b, "\t\t\t\t[plane] plane %d picked "
+                            "from candidate list, type: %s\n",
+                            plane->plane_id, p_name);
+
+               ps = drm_output_try_view_on_plane(plane, state, ev,
+                                                 mode, fb, zpos);
+               drm_output_destroy_zpos_plane(head_p_zpos);
+               if (ps) {
+                       drm_debug(b, "\t\t\t\t[view] view %p has been placed to "
+                                    "%s plane with computed zpos %"PRIu64"\n",
+                                    ev, p_name, zpos);
+                       break;
+               }
+       }
+
+       wl_list_for_each_safe(p_zpos, p_zpos_next, &zpos_candidate_list, link)
+               drm_output_destroy_zpos_plane(p_zpos);
+
+       drm_fb_unref(fb);
+       return ps;
+}
+
 static struct drm_output_state *
 drm_output_propose_state(struct weston_output *output_base,
                         struct drm_pending_state *pending_state,
@@ -449,10 +736,13 @@ 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;
-       bool planes_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY);
+
+       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;
 
        assert(!output->state_last);
        state = drm_output_state_duplicate(output->state_cur,
@@ -502,20 +792,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) {
@@ -523,7 +812,6 @@ drm_output_propose_state(struct weston_output *output_base,
                bool force_renderer = false;
                pixman_region32_t clipped_view;
                bool totally_occluded = false;
-               bool overlay_occluded = false;
 
                drm_debug(b, "\t\t\t[view] evaluating view %p for "
                             "output %s (%lu)\n",
@@ -546,7 +834,7 @@ drm_output_propose_state(struct weston_output *output_base,
                        force_renderer = true;
                }
 
-               if (!ev->surface->buffer_ref.buffer) {
+               if (!weston_view_has_valid_buffer(ev)) {
                        drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
                                     "(no buffer available)\n", ev);
                        force_renderer = true;
@@ -561,6 +849,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 "
@@ -580,6 +871,7 @@ drm_output_propose_state(struct weston_output *output_base,
                                     "(occluded by renderer views)\n", ev);
                        force_renderer = true;
                }
+               pixman_region32_fini(&surface_overlap);
 
                /* In case of enforced mode of content-protection do not
                 * assign planes for a protected surface on an unsecured output.
@@ -591,51 +883,18 @@ drm_output_propose_state(struct weston_output *output_base,
                        force_renderer = true;
                }
 
-               /* We do not control the stacking order of overlay planes;
-                * the scanout plane is strictly stacked bottom and the cursor
-                * plane top, but the ordering of overlay planes with respect
-                * to each other is undefined. Make sure we do not have two
-                * planes overlapping each other. */
-               pixman_region32_intersect(&surface_overlap, &occluded_region,
-                                         &clipped_view);
-               if (pixman_region32_not_empty(&surface_overlap)) {
-                       drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
-                                    "(occluded by other overlay planes)\n", ev);
-                       overlay_occluded = true;
+               if (!force_renderer) {
+                       drm_debug(b, "\t\t\t[plane] started with zpos %"PRIu64"\n",
+                                     current_lowest_zpos);
+                       ps = drm_output_prepare_plane_view(state, ev, mode,
+                                                          current_lowest_zpos);
                }
-               pixman_region32_fini(&surface_overlap);
-
-               /* The cursor plane is 'special' in the sense that we can still
-                * place it in the legacy API, and we gate that with a separate
-                * cursors_are_broken flag. */
-               if (!force_renderer && !overlay_occluded && !b->cursors_are_broken)
-                       ps = drm_output_prepare_cursor_view(state, ev);
-
-               /* If sprites are disabled or the view is not fully opaque, we
-                * must put the view into the renderer - unless it has already
-                * been placed in the cursor plane, which can handle alpha. */
-               if (!ps && !planes_ok) {
-                       drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
-                                    "(precluded by mode)\n", ev);
-                       force_renderer = true;
-               }
-               if (!ps && !weston_view_is_opaque(ev, &clipped_view)) {
-                       drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
-                                    "(view not fully opaque)\n", ev);
-                       force_renderer = true;
-               }
-
-               /* Only try to place scanout surfaces in planes-only mode; in
-                * mixed mode, we have already failed to place a view on the
-                * scanout surface, forcing usage of the renderer on the
-                * scanout plane. */
-               if (!ps && !force_renderer && !renderer_ok)
-                       ps = drm_output_prepare_scanout_view(state, ev, mode);
-
-               if (!ps && !overlay_occluded && !force_renderer)
-                       ps = drm_output_prepare_overlay_view(state, ev, mode);
 
                if (ps) {
+                       current_lowest_zpos = ps->zpos;
+                       drm_debug(b, "\t\t\t[plane] next zpos to use %"PRIu64"\n",
+                                     current_lowest_zpos);
+
                        /* If we have been assigned to an overlay or scanout
                         * plane, add this area to the occluded region, so
                         * other views are known to be behind it. The cursor
@@ -644,10 +903,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;
                }
@@ -666,9 +937,24 @@ 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);
+
+               drm_debug(b, "\t\t\t\t[view] view %p will be placed "
+                            "on the renderer\n", ev);
        }
+
        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
@@ -676,6 +962,14 @@ drm_output_propose_state(struct weston_output *output_base,
        if (mode == DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY)
                return state;
 
+       /* check if we have invalid zpos values, like duplicate(s) */
+       ret = drm_output_check_zpos_plane_states(state);
+       if (ret != 0) {
+               drm_debug(b, "\t\t[view] failing state generation: "
+                            "zpos values are in-consistent\n");
+               goto err;
+       }
+
        /* Check to see if this state will actually work. */
        ret = drm_pending_state_test(state->pending_state);
        if (ret != 0) {
@@ -764,7 +1058,7 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
                 * to the buffer anyway, there is no side effects.
                 */
                if (b->use_pixman ||
-                   (ev->surface->buffer_ref.buffer &&
+                   (weston_view_has_valid_buffer(ev) &&
                    (!wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
                     (ev->surface->width <= b->cursor_width &&
                      ev->surface->height <= b->cursor_height))))
index 6336c58989d869dcb22497f9a623323cd4793ce5..55f43af4fa218db7a5021517c1ddd9d25a6e8a72 100644 (file)
@@ -1852,6 +1852,41 @@ weston_view_is_opaque(struct weston_view *ev, pixman_region32_t *region)
        return ret;
 }
 
+/** Check if the view has a valid buffer available
+ *
+ * @param ev The view to check if it has a valid buffer.
+ *
+ * Returns true if the view has a valid buffer or false otherwise.
+ */
+WL_EXPORT bool
+weston_view_has_valid_buffer(struct weston_view *ev)
+{
+       return ev->surface->buffer_ref.buffer != NULL;
+}
+
+/** Check if the view matches the entire output
+ *
+ * @param ev The view to check.
+ * @param output The output to check against.
+ *
+ * Returns true if the view does indeed matches the entire output.
+ */
+WL_EXPORT bool
+weston_view_matches_output_entirely(struct weston_view *ev,
+                                   struct weston_output *output)
+{
+       pixman_box32_t *extents =
+               pixman_region32_extents(&ev->transform.boundingbox);
+
+       if (extents->x1 != output->x ||
+           extents->y1 != output->y ||
+           extents->x2 != output->x + output->width ||
+           extents->y2 != output->y + output->height)
+               return false;
+
+       return true;
+}
+
 /* Check if a surface has a view assigned to it
  *
  * The indicator is set manually when mapping
index c804120b98c49998a9d7de067b4b203e81e3c350..2099f3bce8d8af55ba6c34f10791c66449c7b584 100644 (file)
@@ -287,6 +287,12 @@ weston_view_from_global_float(struct weston_view *view,
 bool
 weston_view_is_opaque(struct weston_view *ev, pixman_region32_t *region);
 
+bool
+weston_view_has_valid_buffer(struct weston_view *ev);
+
+bool
+weston_view_matches_output_entirely(struct weston_view *ev,
+                                   struct weston_output *output);
 void
 weston_view_move_to_plane(struct weston_view *view,
                          struct weston_plane *plane);