diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index cf588674..b55061ab 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -72,10 +72,6 @@ #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. * @@ -148,11 +144,8 @@ 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]; }; /** @@ -173,7 +166,6 @@ enum wdrm_plane_property { WDRM_PLANE_IN_FORMATS, WDRM_PLANE_IN_FENCE_FD, WDRM_PLANE_FB_DAMAGE_CLIPS, - WDRM_PLANE_ZPOS, WDRM_PLANE__COUNT }; @@ -369,16 +361,6 @@ 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. @@ -400,8 +382,6 @@ 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 */ @@ -443,9 +423,6 @@ 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 { @@ -546,22 +523,6 @@ 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); @@ -618,9 +579,6 @@ 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); @@ -737,7 +695,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, uint64_t zpos); + struct weston_view *ev); void drm_assign_planes(struct weston_output *output_base, void *repaint_data); diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index 33ccbeb3..878d71ec 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -68,61 +68,6 @@ 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) { @@ -735,7 +680,6 @@ 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) + @@ -767,18 +711,6 @@ 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; @@ -792,8 +724,6 @@ 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) @@ -2911,9 +2841,6 @@ 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) diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c index 5468afb3..4c942a3d 100644 --- a/libweston/backend-drm/kms.c +++ b/libweston/backend-drm/kms.c @@ -77,7 +77,6 @@ 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[] = { @@ -203,42 +202,6 @@ 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 * @@ -331,15 +294,6 @@ 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); @@ -1051,13 +1005,6 @@ 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; diff --git a/libweston/backend-drm/state-helpers.c b/libweston/backend-drm/state-helpers.c index 7b1d9241..3956960c 100644 --- a/libweston/backend-drm/state-helpers.c +++ b/libweston/backend-drm/state-helpers.c @@ -48,7 +48,6 @@ 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 @@ -81,7 +80,6 @@ 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) { @@ -165,7 +163,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, uint64_t zpos) + struct weston_view *ev) { struct drm_output *output = state->output; struct weston_buffer *buffer = ev->surface->buffer_ref.buffer; @@ -245,9 +243,6 @@ 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; } diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c index 779eb9ff..6a01f44b 100644 --- a/libweston/backend-drm/state-propose.c +++ b/libweston/backend-drm/state-propose.c @@ -62,200 +62,155 @@ drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode) 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; } @@ -299,14 +254,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, 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); @@ -323,6 +278,24 @@ 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); @@ -332,20 +305,16 @@ 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, 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; } @@ -371,7 +340,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[%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); } @@ -384,8 +353,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[%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; @@ -396,7 +365,7 @@ err: #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; } @@ -405,14 +374,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, - 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); @@ -420,25 +389,23 @@ 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. */ - 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; } @@ -450,24 +417,16 @@ 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); - - /* 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; @@ -480,252 +439,6 @@ 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, @@ -736,13 +449,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, 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, @@ -792,19 +502,20 @@ drm_output_propose_state(struct weston_output *output_base, (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) { @@ -812,6 +523,7 @@ 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", @@ -834,7 +546,7 @@ drm_output_propose_state(struct weston_output *output_base, 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; @@ -849,9 +561,6 @@ 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 " @@ -871,7 +580,6 @@ 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. @@ -883,18 +591,51 @@ drm_output_propose_state(struct weston_output *output_base, 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 @@ -903,22 +644,10 @@ 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; } @@ -937,24 +666,9 @@ 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 @@ -962,14 +676,6 @@ 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) { @@ -1058,7 +764,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 || - (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)))) diff --git a/libweston/compositor.c b/libweston/compositor.c index 55f43af4..6336c589 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -1852,41 +1852,6 @@ 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 diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h index 2099f3bc..c804120b 100644 --- a/libweston/libweston-internal.h +++ b/libweston/libweston-internal.h @@ -287,12 +287,6 @@ 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);