return drm_output_propose_state_mode_as_string[mode];
}
-static void
-drm_output_add_zpos_plane(struct drm_plane *plane, struct wl_list *planes)
+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)
{
- struct drm_backend *b = plane->backend;
- struct drm_plane_zpos *h_plane;
- struct drm_plane_zpos *plane_zpos;
-
- plane_zpos = zalloc(sizeof(*plane_zpos));
- if (!plane_zpos)
- return;
-
- plane_zpos->plane = plane;
+ 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;
- drm_debug(b, "\t\t\t\t[plane] plane %d added to candidate list\n",
- plane->plane_id);
+ assert(!b->sprites_are_broken);
+ assert(b->atomic_modeset);
- if (wl_list_empty(planes)) {
- wl_list_insert(planes, &plane_zpos->link);
- 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;
}
- 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;
+ wl_list_for_each(p, &b->plane_list, link) {
+ if (p->type != WDRM_PLANE_TYPE_OVERLAY)
+ continue;
- if (wl_list_length(planes) == 1) {
- wl_list_insert(planes->prev, &plane_zpos->link);
- return;
- }
+ if (!drm_plane_is_available(p, output))
+ continue;
- wl_list_for_each(p_zpos, planes, link) {
- if (p_zpos->plane->zpos_max >
- plane_zpos->plane->zpos_max)
- break;
+ state = drm_output_state_get_plane(output_state, p);
+ if (state->fb) {
+ state = NULL;
+ continue;
}
- 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;
-}
+ if (availability == NO_PLANES)
+ availability = NO_PLANES_WITH_FORMAT;
-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;
+ /* Check whether the format is supported */
+ for (i = 0; i < p->count_formats; i++) {
+ unsigned int j;
- if (!fb)
- return false;
+ if (p->formats[i].format != fb->format->format)
+ continue;
- /* Check whether the format is supported */
- for (i = 0; i < plane->count_formats; i++) {
- unsigned int j;
+ if (fb->modifier == DRM_FORMAT_MOD_INVALID)
+ break;
- if (plane->formats[i].format != fb->format->format)
+ 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;
continue;
-
- if (fb->modifier == DRM_FORMAT_MOD_INVALID)
- return true;
-
- for (j = 0; j < plane->formats[i].count_modifiers; j++) {
- if (plane->formats[i].modifiers[j] == fb->modifier)
- return true;
}
- }
- 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;
-}
-
-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);
+ if (availability == NO_PLANES_WITH_FORMAT)
+ availability = NO_PLANES_ACCEPTED;
- if (shmbuf && wl_shm_buffer_get_format(shmbuf) == WL_SHM_FORMAT_ARGB8888)
- 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;
+ }
- return false;
-}
+ /* 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;
+ }
-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;
+ /* 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);
- assert(!b->sprites_are_broken);
- assert(b->atomic_modeset);
+ state->in_fence_fd = ev->surface->acquire_fence_fd;
- if (!fb) {
- drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
- " couldn't get fb\n", ev);
- return NULL;
- }
+ /* 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;
+ }
- 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);
+ 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;
+ }
- state->ev = ev;
- state->output = output;
+ 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 (!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;
}
- /* 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) {
+ switch (availability) {
+ case NO_PLANES:
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;
- 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;
+ "no free overlay planes\n", ev);
+ break;
+ case NO_PLANES_WITH_FORMAT:
+ 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;
}
- 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;
}
static struct drm_plane_state *
drm_output_prepare_cursor_view(struct drm_output_state *output_state,
- struct weston_view *ev, uint64_t zpos)
+ struct weston_view *ev)
{
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);
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);
/* 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, zpos)) {
- drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
- "unsuitable transform\n", p_name, ev, p_name);
+ if (!drm_plane_state_coords_for_view(plane_state, ev))
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[%s] not assigning view %p to %s plane "
- "(positioning requires cropping or scaling)\n",
- p_name, ev, p_name);
+ drm_debug(b, "\t\t\t\t[cursor] not assigning view %p to cursor plane "
+ "(positioning requires cropping or scaling)\n", ev);
goto err;
}
drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
if (needs_update) {
- drm_debug(b, "\t\t\t\t[%s] copying new content to cursor BO\n", p_name);
+ drm_debug(b, "\t\t\t\t[cursor] copying new content to cursor BO\n");
cursor_bo_update(plane_state, ev);
}
plane_state->dest_w = b->cursor_width;
plane_state->dest_h = b->cursor_height;
- drm_debug(b, "\t\t\t\t[%s] provisionally assigned view %p to cursor\n",
- p_name, ev);
+ drm_debug(b, "\t\t\t\t[cursor] provisionally assigned view %p to cursor\n",
+ ev);
return plane_state;
#else
static struct drm_plane_state *
drm_output_prepare_cursor_view(struct drm_output_state *output_state,
- struct weston_view *ev, uint64_t zpos)
+ struct weston_view *ev)
{
return NULL;
}
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,
- struct drm_fb *fb, uint64_t zpos)
+ enum drm_output_propose_state_mode mode)
{
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;
- const char *p_name = drm_output_get_plane_type_name(scanout_plane);
+ struct drm_fb *fb;
+ pixman_box32_t *extents;
assert(!b->sprites_are_broken);
assert(b->atomic_modeset);
/* Check the view spans exactly the output size, calculated in the
* logical co-ordinate space. */
- 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);
+ 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)
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) {
- drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
- "no in-fence support\n", p_name, ev, p_name);
+ scanout_plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0)
return NULL;
- }
+ fb = drm_fb_get_from_view(output_state, ev);
if (!fb) {
- drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
- " couldn't get fb\n", p_name, ev, p_name);
+ drm_debug(b, "\t\t\t\t[scanout] not placing view %p on scanout: "
+ " couldn't get fb\n", ev);
return NULL;
}
* and in the latter case, the view must have been marked as occluded,
* meaning we should never have ended up here. */
assert(!state->fb);
-
- /* take another reference here to live within the state */
- state->fb = drm_fb_ref(fb);
+ state->fb = fb;
state->ev = ev;
state->output = output;
- 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);
+ if (!drm_plane_state_coords_for_view(state, ev))
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) {
- drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
- " invalid plane state\n", p_name, ev, p_name);
+ state->dest_h != (unsigned) output->base.current_mode->height)
goto err;
- }
state->in_fence_fd = ev->surface->acquire_fence_fd;
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,
struct drm_output_state *state;
struct drm_plane_state *scanout_state = NULL;
struct weston_view *ev;
-
- pixman_region32_t surface_overlap, renderer_region, planes_region;
- pixman_region32_t occluded_region;
-
+ pixman_region32_t surface_overlap, renderer_region, occluded_region;
+ bool planes_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY);
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,
(unsigned long) output->base.id);
}
- /* - 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.
+ /*
+ * 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.
*/
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) {
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",
force_renderer = true;
}
- if (!weston_view_has_valid_buffer(ev)) {
+ if (!ev->surface->buffer_ref.buffer) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
"(no buffer available)\n", ev);
force_renderer = true;
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 "
"(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.
force_renderer = 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);
+ /* 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;
}
+ pixman_region32_fini(&surface_overlap);
- if (ps) {
- current_lowest_zpos = ps->zpos;
- drm_debug(b, "\t\t\t[plane] next zpos to use %"PRIu64"\n",
- current_lowest_zpos);
+ /* 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) {
/* 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
* 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;
}
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
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) {
* to the buffer anyway, there is no side effects.
*/
if (b->use_pixman ||
- (weston_view_has_valid_buffer(ev) &&
+ (ev->surface->buffer_ref.buffer &&
(!wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
(ev->surface->width <= b->cursor_width &&
ev->surface->height <= b->cursor_height))))