Revert "backend-drm: Teach drm_property_info_populate() to retrieve range values"

Due to an error in driving GitLab, this commit erroneously contained the
entirety of !267 (zpos support in the KMS backend) squashed into one
single commit, pushed into master.

In order to keep the history clean, this is being reverted; a rebased
version of !267 with the clear individual commits which were already
present will be applied in its place.

This reverts commit 95e3b0deae.
dev
Daniel Stone 5 years ago
parent 95e3b0deae
commit 2cb926c558
  1. 44
      libweston/backend-drm/drm-internal.h
  2. 73
      libweston/backend-drm/drm.c
  3. 53
      libweston/backend-drm/kms.c
  4. 7
      libweston/backend-drm/state-helpers.c
  5. 668
      libweston/backend-drm/state-propose.c
  6. 35
      libweston/compositor.c
  7. 6
      libweston/libweston-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);

@ -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)

@ -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;

@ -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;
}

@ -62,171 +62,104 @@ 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;
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;
}
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;
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;
if (wl_list_length(planes) == 1) {
wl_list_insert(planes->prev, &plane_zpos->link);
return;
}
assert(!b->sprites_are_broken);
assert(b->atomic_modeset);
wl_list_for_each(p_zpos, planes, link) {
if (p_zpos->plane->zpos_max >
plane_zpos->plane->zpos_max)
break;
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;
}
wl_list_insert(p_zpos->link.prev, &plane_zpos->link);
}
}
wl_list_for_each(p, &b->plane_list, link) {
if (p->type != WDRM_PLANE_TYPE_OVERLAY)
continue;
static void
drm_output_destroy_zpos_plane(struct drm_plane_zpos *plane_zpos)
{
wl_list_remove(&plane_zpos->link);
free(plane_zpos);
}
if (!drm_plane_is_available(p, output))
continue;
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;
state = drm_output_state_get_plane(output_state, p);
if (state->fb) {
state = NULL;
continue;
}
return false;
}
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 (!fb)
return false;
if (availability == NO_PLANES)
availability = NO_PLANES_WITH_FORMAT;
/* Check whether the format is supported */
for (i = 0; i < plane->count_formats; i++) {
for (i = 0; i < p->count_formats; i++) {
unsigned int j;
if (plane->formats[i].format != fb->format->format)
if (p->formats[i].format != fb->format->format)
continue;
if (fb->modifier == DRM_FORMAT_MOD_INVALID)
return true;
break;
for (j = 0; j < plane->formats[i].count_modifiers; j++) {
if (plane->formats[i].modifiers[j] == fb->modifier)
return true;
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;
}
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 (shmbuf && wl_shm_buffer_get_format(shmbuf) == WL_SHM_FORMAT_ARGB8888)
return true;
return false;
}
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);
if (!fb) {
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
" couldn't get fb\n", ev);
return NULL;
if (i == p->count_formats) {
drm_plane_state_put_back(state);
state = NULL;
continue;
}
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);
if (availability == NO_PLANES_WITH_FORMAT)
availability = NO_PLANES_ACCEPTED;
state->ev = ev;
state->output = output;
if (!drm_plane_state_coords_for_view(state, ev, zpos)) {
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;
goto out;
continue;
}
/* 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) {
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;
goto out;
continue;
}
/* 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. */
/* 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);
state->in_fence_fd = ev->surface->acquire_fence_fd;
@ -234,28 +167,50 @@ drm_output_prepare_overlay_view(struct drm_plane *plane,
/* 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 "
drm_debug(b, "\t\t\t\t[overlay] provisionally placing "
"view %p on overlay %lu in planes-only mode\n",
ev, (unsigned long) plane->plane_id);
ev, (unsigned long) p->plane_id);
availability = PLACED_ON_PLANE;
goto out;
}
ret = drm_pending_state_test(output_state->pending_state);
if (ret == 0) {
drm_debug(b, "\t\t\t[overlay] provisionally placing "
drm_debug(b, "\t\t\t\t[overlay] provisionally placing "
"view %p on overlay %d in mixed mode\n",
ev, plane->plane_id);
ev, p->plane_id);
availability = PLACED_ON_PLANE;
goto out;
}
drm_debug(b, "\t\t\t[overlay] not placing view %p on overlay %lu "
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) plane->plane_id);
ev, (unsigned long) p->plane_id);
drm_plane_state_put_back(state);
state = NULL;
}
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:
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;
}
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);
/* 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;
}
if (ps) {
current_lowest_zpos = ps->zpos;
drm_debug(b, "\t\t\t[plane] next zpos to use %"PRIu64"\n",
current_lowest_zpos);
/* 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))))

@ -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

@ -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);

Loading…
Cancel
Save