[PATCH v14 05/41] compositor-drm: Use drm_plane for cursor plane
Daniel Stone
daniels at collabora.com
Wed Dec 20 12:26:22 UTC 2017
Change the type of cursor_plane from a weston_plane (base tracking
structure) to a drm_plane (wrapper containing additional DRM-specific
details), and make it a dynamically-allocated pointer.
Using the standard drm_plane allows us to reuse code which already deals
with drm_planes, e.g. a common cleanup function.
This patch introduces a 'special plane' helper, creating a drm_plane
either from a real KMS plane when using universal planes, or a fake plane
otherwise. Without universal planes, the cursor and primary planes are
hidden from us; this helper allows us to pretend otherwise.
Signed-off-by: Daniel Stone <daniels at collabora.com>
---
libweston/compositor-drm.c | 463 +++++++++++++++++++++++++++++++++++----------
1 file changed, 358 insertions(+), 105 deletions(-)
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 403438398..a600ef40b 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -355,7 +355,7 @@ struct drm_output {
int disable_pending;
struct drm_fb *gbm_cursor_fb[2];
- struct weston_plane cursor_plane;
+ struct drm_plane *cursor_plane;
struct weston_view *cursor_view;
int current_cursor;
@@ -649,7 +649,7 @@ drm_property_info_free(struct drm_property_info *info, int num_props)
}
static void
-drm_output_set_cursor(struct drm_output *output);
+drm_output_set_cursor(struct drm_output_state *output_state);
static void
drm_output_update_msc(struct drm_output *output, unsigned int seq);
@@ -1091,12 +1091,11 @@ drm_plane_state_put_back(struct drm_plane_state *state)
}
/**
- * Return a plane state from a drm_output_state, either existing or
- * freshly allocated.
+ * Return a plane state from a drm_output_state.
*/
static struct drm_plane_state *
-drm_output_state_get_plane(struct drm_output_state *state_output,
- struct drm_plane *plane)
+drm_output_state_get_existing_plane(struct drm_output_state *state_output,
+ struct drm_plane *plane)
{
struct drm_plane_state *ps;
@@ -1105,6 +1104,23 @@ drm_output_state_get_plane(struct drm_output_state *state_output,
return ps;
}
+ return NULL;
+}
+
+/**
+ * Return a plane state from a drm_output_state, either existing or
+ * freshly allocated.
+ */
+static struct drm_plane_state *
+drm_output_state_get_plane(struct drm_output_state *state_output,
+ struct drm_plane *plane)
+{
+ struct drm_plane_state *ps;
+
+ ps = drm_output_state_get_existing_plane(state_output, plane);
+ if (ps)
+ return ps;
+
return drm_plane_state_alloc(state_output, plane);
}
@@ -1631,8 +1647,8 @@ drm_output_repaint(struct weston_output *output_base,
*/
if (output->base.disable_planes) {
output->cursor_view = NULL;
- output->cursor_plane.x = INT32_MIN;
- output->cursor_plane.y = INT32_MIN;
+ output->cursor_plane->base.x = INT32_MIN;
+ output->cursor_plane->base.y = INT32_MIN;
}
drm_output_render(state, damage);
@@ -1673,7 +1689,7 @@ drm_output_repaint(struct weston_output *output_base,
wl_event_source_timer_update(output->pageflip_timer,
backend->pageflip_timeout);
- drm_output_set_cursor(output);
+ drm_output_set_cursor(state);
/*
* Now, update all the sprite surfaces
@@ -2185,20 +2201,66 @@ err:
return NULL;
}
+/**
+ * Update the image for the current cursor surface
+ *
+ * @param b DRM backend structure
+ * @param bo GBM buffer object to write into
+ * @param ev View to use for cursor image
+ */
+static void
+cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
+ struct weston_view *ev)
+{
+ struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
+ uint32_t buf[b->cursor_width * b->cursor_height];
+ int32_t stride;
+ uint8_t *s;
+ int i;
+
+ assert(buffer && buffer->shm_buffer);
+ assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
+ assert(ev->surface->width <= b->cursor_width);
+ assert(ev->surface->height <= b->cursor_height);
+
+ memset(buf, 0, sizeof buf);
+ stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
+ s = wl_shm_buffer_get_data(buffer->shm_buffer);
+
+ wl_shm_buffer_begin_access(buffer->shm_buffer);
+ for (i = 0; i < ev->surface->height; i++)
+ memcpy(buf + i * b->cursor_width,
+ s + i * stride,
+ ev->surface->width * 4);
+ wl_shm_buffer_end_access(buffer->shm_buffer);
+
+ if (gbm_bo_write(bo, buf, sizeof buf) < 0)
+ weston_log("failed update cursor: %m\n");
+}
+
static struct weston_plane *
drm_output_prepare_cursor_view(struct drm_output_state *output_state,
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 weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
struct wl_shm_buffer *shmbuf;
+ bool needs_update = false;
float x, y;
+ if (!plane)
+ return NULL;
+
if (b->cursors_are_broken)
return NULL;
- if (output->cursor_view)
+ if (!plane->state_cur->complete)
+ return NULL;
+
+ if (plane->state_cur->output && plane->state_cur->output != output)
return NULL;
/* Don't import buffers which span multiple outputs. */
@@ -2231,89 +2293,101 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
ev->surface->height > b->cursor_height)
return NULL;
- output->cursor_view = ev;
- weston_view_to_global_float(ev, 0, 0, &x, &y);
- output->cursor_plane.x = x;
- output->cursor_plane.y = y;
-
- return &output->cursor_plane;
-}
+ plane_state =
+ drm_output_state_get_plane(output_state, output->cursor_plane);
-/**
- * Update the image for the current cursor surface
- *
- * @param b DRM backend structure
- * @param bo GBM buffer object to write into
- * @param ev View to use for cursor image
- */
-static void
-cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
- struct weston_view *ev)
-{
- struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
- uint32_t buf[b->cursor_width * b->cursor_height];
- int32_t stride;
- uint8_t *s;
- int i;
-
- assert(buffer && buffer->shm_buffer);
- assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
- assert(ev->surface->width <= b->cursor_width);
- assert(ev->surface->height <= b->cursor_height);
-
- memset(buf, 0, sizeof buf);
- stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
- s = wl_shm_buffer_get_data(buffer->shm_buffer);
+ if (plane_state && plane_state->fb)
+ return NULL;
- wl_shm_buffer_begin_access(buffer->shm_buffer);
- for (i = 0; i < ev->surface->height; i++)
- memcpy(buf + i * b->cursor_width,
- s + i * stride,
- ev->surface->width * 4);
- wl_shm_buffer_end_access(buffer->shm_buffer);
+ /* Since we're setting plane state up front, we need to work out
+ * whether or not we need to upload a new cursor. We can't use the
+ * plane damage, since the planes haven't actually been calculated
+ * yet: instead try to figure it out directly. KMS cursor planes are
+ * pretty unique here, in that they lie partway between a Weston plane
+ * (direct scanout) and a renderer. */
+ if (ev != output->cursor_view ||
+ pixman_region32_not_empty(&ev->surface->damage)) {
+ output->current_cursor++;
+ output->current_cursor =
+ output->current_cursor %
+ ARRAY_LENGTH(output->gbm_cursor_fb);
+ needs_update = true;
+ }
- if (gbm_bo_write(bo, buf, sizeof buf) < 0)
- weston_log("failed update cursor: %m\n");
+ output->cursor_view = ev;
+ weston_view_to_global_float(ev, 0, 0, &x, &y);
+ plane->base.x = x;
+ plane->base.y = y;
+
+ plane_state->fb =
+ drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
+ plane_state->output = output;
+ plane_state->src_x = 0;
+ plane_state->src_y = 0;
+ plane_state->src_w = b->cursor_width << 16;
+ plane_state->src_h = b->cursor_height << 16;
+ plane_state->dest_x = (x - output->base.x) * output->base.current_scale;
+ plane_state->dest_y = (y - output->base.y) * output->base.current_scale;
+ plane_state->dest_w = b->cursor_width;
+ plane_state->dest_h = b->cursor_height;
+
+ if (needs_update)
+ cursor_bo_update(b, plane_state->fb->bo, ev);
+
+ return &plane->base;
}
static void
-drm_output_set_cursor(struct drm_output *output)
+drm_output_set_cursor(struct drm_output_state *output_state)
{
- struct weston_view *ev = output->cursor_view;
+ 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 *state;
EGLint handle;
struct gbm_bo *bo;
- float x, y;
- if (ev == NULL) {
+ if (!plane)
+ return;
+
+ state = drm_output_state_get_existing_plane(output_state, plane);
+ if (!state)
+ return;
+
+ if (!state->fb) {
+ pixman_region32_fini(&plane->base.damage);
+ pixman_region32_init(&plane->base.damage);
drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
return;
}
- if (pixman_region32_not_empty(&output->cursor_plane.damage)) {
- pixman_region32_fini(&output->cursor_plane.damage);
- pixman_region32_init(&output->cursor_plane.damage);
- output->current_cursor ^= 1;
- bo = output->gbm_cursor_fb[output->current_cursor]->bo;
+ assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
+ assert(!plane->state_cur->output || plane->state_cur->output == output);
- cursor_bo_update(b, bo, ev);
+ if (plane->state_cur->fb != state->fb) {
+ bo = state->fb->bo;
handle = gbm_bo_get_handle(bo).s32;
if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
- b->cursor_width, b->cursor_height)) {
+ b->cursor_width, b->cursor_height)) {
weston_log("failed to set cursor: %m\n");
- b->cursors_are_broken = 1;
+ goto err;
}
}
- x = (output->cursor_plane.x - output->base.x) *
- output->base.current_scale;
- y = (output->cursor_plane.y - output->base.y) *
- output->base.current_scale;
+ pixman_region32_fini(&plane->base.damage);
+ pixman_region32_init(&plane->base.damage);
- if (drmModeMoveCursor(b->drm.fd, output->crtc_id, x, y)) {
+ if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
+ state->dest_x, state->dest_y)) {
weston_log("failed to move cursor: %m\n");
- b->cursors_are_broken = 1;
+ goto err;
}
+
+ return;
+
+err:
+ b->cursors_are_broken = 1;
+ drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
}
static void
@@ -2323,6 +2397,7 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
struct drm_pending_state *pending_state = repaint_data;
struct drm_output *output = to_drm_output(output_base);
struct drm_output_state *state;
+ struct drm_plane_state *plane_state;
struct weston_view *ev, *next;
pixman_region32_t overlap, surface_overlap;
struct weston_plane *primary, *next_plane;
@@ -2349,10 +2424,6 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
pixman_region32_init(&overlap);
primary = &output_base->compositor->primary_plane;
- output->cursor_view = NULL;
- output->cursor_plane.x = INT32_MIN;
- output->cursor_plane.y = INT32_MIN;
-
wl_list_for_each_safe(ev, next, &output_base->compositor->view_list, link) {
struct weston_surface *es = ev->surface;
@@ -2405,7 +2476,8 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
&ev->transform.boundingbox);
if (next_plane == primary ||
- next_plane == &output->cursor_plane) {
+ (output->cursor_plane &&
+ next_plane == &output->cursor_plane->base)) {
/* cursor plane involves a copy */
ev->psf_flags = 0;
} else {
@@ -2418,6 +2490,19 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
pixman_region32_fini(&surface_overlap);
}
pixman_region32_fini(&overlap);
+
+ /* We rely on output->cursor_view being both an accurate reflection of
+ * the cursor plane's state, but also being maintained across repaints
+ * to avoid unnecessary damage uploads, per the comment in
+ * drm_output_prepare_cursor_view. In the event that we go from having
+ * a cursor view to not having a cursor view, we need to clear it. */
+ if (output->cursor_view) {
+ plane_state =
+ drm_output_state_get_existing_plane(state,
+ output->cursor_plane);
+ if (!plane_state || !plane_state->fb)
+ output->cursor_view = NULL;
+ }
}
/**
@@ -2685,19 +2770,30 @@ init_pixman(struct drm_backend *b)
* Creates one drm_plane structure for a hardware plane, and initialises its
* properties and formats.
*
+ * In the absence of universal plane support, where KMS does not explicitly
+ * expose the primary and cursor planes to userspace, this may also create
+ * an 'internal' plane for internal management.
+ *
* This function does not add the plane to the list of usable planes in Weston
* itself; the caller is responsible for this.
*
* Call drm_plane_destroy to clean up the plane.
*
+ * @sa drm_output_find_special_plane
* @param b DRM compositor backend
- * @param kplane DRM plane to create
+ * @param kplane DRM plane to create, or NULL if creating internal plane
+ * @param output Output to create internal plane for, or NULL
+ * @param type Type to use when creating internal plane, or invalid
+ * @param format Format to use for internal planes, or 0
*/
static struct drm_plane *
-drm_plane_create(struct drm_backend *b, const drmModePlane *kplane)
+drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
+ struct drm_output *output, enum wdrm_plane_type type,
+ uint32_t format)
{
struct drm_plane *plane;
drmModeObjectProperties *props;
+ int num_formats = (kplane) ? kplane->count_formats : 1;
static struct drm_property_enum_info plane_type_enums[] = {
[WDRM_PLANE_TYPE_PRIMARY] = {
@@ -2718,41 +2814,155 @@ drm_plane_create(struct drm_backend *b, const drmModePlane *kplane)
},
};
- plane = zalloc(sizeof(*plane) + ((sizeof(uint32_t)) *
- kplane->count_formats));
+ plane = zalloc(sizeof(*plane) +
+ (sizeof(uint32_t) * num_formats));
if (!plane) {
weston_log("%s: out of memory\n", __func__);
return NULL;
}
plane->backend = b;
- plane->possible_crtcs = kplane->possible_crtcs;
- plane->plane_id = kplane->plane_id;
- plane->count_formats = kplane->count_formats;
plane->state_cur = drm_plane_state_alloc(NULL, plane);
plane->state_cur->complete = true;
- memcpy(plane->formats, kplane->formats,
- kplane->count_formats * sizeof(kplane->formats[0]));
- props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
- DRM_MODE_OBJECT_PLANE);
- if (!props) {
- weston_log("couldn't get plane properties\n");
- free(plane);
- return NULL;
+ if (kplane) {
+ plane->possible_crtcs = kplane->possible_crtcs;
+ plane->plane_id = kplane->plane_id;
+ plane->count_formats = kplane->count_formats;
+ memcpy(plane->formats, kplane->formats,
+ kplane->count_formats * sizeof(kplane->formats[0]));
+
+ props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
+ DRM_MODE_OBJECT_PLANE);
+ if (!props) {
+ weston_log("couldn't get plane properties\n");
+ goto err;
+ }
+ drm_property_info_populate(b, plane_props, plane->props,
+ WDRM_PLANE__COUNT, props);
+ plane->type =
+ drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
+ props,
+ WDRM_PLANE_TYPE__COUNT);
+ drmModeFreeObjectProperties(props);
+ }
+ else {
+ plane->possible_crtcs = (1 << output->pipe);
+ plane->plane_id = 0;
+ plane->count_formats = 1;
+ plane->formats[0] = format;
+ plane->type = type;
+ }
+
+ if (plane->type == WDRM_PLANE_TYPE__COUNT)
+ goto err_props;
+
+ /* With universal planes, everything is a DRM plane; without
+ * universal planes, the only DRM planes are overlay planes.
+ * Everything else is a fake plane. */
+ if (b->universal_planes) {
+ assert(kplane);
+ } else {
+ if (kplane)
+ assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
+ else
+ assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
+ output);
}
- drm_property_info_populate(b, plane_props, plane->props,
- WDRM_PLANE__COUNT, props);
- plane->type =
- drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
- props,
- WDRM_PLANE_TYPE_OVERLAY);
- drmModeFreeObjectProperties(props);
weston_plane_init(&plane->base, b->compositor, 0, 0);
wl_list_insert(&b->plane_list, &plane->link);
return plane;
+
+err_props:
+ drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
+err:
+ drm_plane_state_free(plane->state_cur, true);
+ free(plane);
+ return NULL;
+}
+
+/**
+ * Find, or create, a special-purpose plane
+ *
+ * Primary and cursor planes are a special case, in that before universal
+ * planes, they are driven by non-plane API calls. Without universal plane
+ * support, the only way to configure a primary plane is via drmModeSetCrtc,
+ * and the only way to configure a cursor plane is drmModeSetCursor2.
+ *
+ * Although they may actually be regular planes in the hardware, without
+ * universal plane support, these planes are not actually exposed to
+ * userspace in the regular plane list.
+ *
+ * However, for ease of internal tracking, we want to manage all planes
+ * through the same drm_plane structures. Therefore, when we are running
+ * without universal plane support, we create fake drm_plane structures
+ * to track these planes.
+ *
+ * @param b DRM backend
+ * @param output Output to use for plane
+ * @param type Type of plane
+ */
+static struct drm_plane *
+drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
+ enum wdrm_plane_type type)
+{
+ struct drm_plane *plane;
+
+ if (!b->universal_planes) {
+ uint32_t format;
+
+ switch (type) {
+ case WDRM_PLANE_TYPE_CURSOR:
+ format = GBM_FORMAT_ARGB8888;
+ break;
+ case WDRM_PLANE_TYPE_PRIMARY:
+ format = output->gbm_format;
+ break;
+ default:
+ assert(!"invalid type in drm_output_find_special_plane");
+ break;
+ }
+
+ return drm_plane_create(b, NULL, output, type, format);
+ }
+
+ wl_list_for_each(plane, &b->plane_list, link) {
+ struct drm_output *tmp;
+ bool found_elsewhere = false;
+
+ if (plane->type != type)
+ continue;
+ if (!drm_plane_is_available(plane, output))
+ continue;
+
+ /* On some platforms, primary/cursor planes can roam
+ * between different CRTCs, so make sure we don't claim the
+ * same plane for two outputs. */
+ wl_list_for_each(tmp, &b->compositor->pending_output_list,
+ base.link) {
+ if (tmp->cursor_plane == plane) {
+ found_elsewhere = true;
+ break;
+ }
+ }
+ wl_list_for_each(tmp, &b->compositor->output_list,
+ base.link) {
+ if (tmp->cursor_plane == plane) {
+ found_elsewhere = true;
+ break;
+ }
+ }
+
+ if (found_elsewhere)
+ continue;
+
+ plane->possible_crtcs = (1 << output->pipe);
+ return plane;
+ }
+
+ return NULL;
}
/**
@@ -2766,8 +2976,9 @@ drm_plane_create(struct drm_backend *b, const drmModePlane *kplane)
static void
drm_plane_destroy(struct drm_plane *plane)
{
- drmModeSetPlane(plane->backend->drm.fd, plane->plane_id, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0);
+ if (plane->plane_id > 0)
+ drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
drm_plane_state_free(plane->state_cur, true);
drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
weston_plane_release(&plane->base);
@@ -2804,7 +3015,8 @@ create_sprites(struct drm_backend *b)
if (!kplane)
continue;
- drm_plane = drm_plane_create(b, kplane);
+ drm_plane = drm_plane_create(b, kplane, NULL,
+ WDRM_PLANE_TYPE__COUNT, 0);
drmModeFreePlane(kplane);
if (!drm_plane)
continue;
@@ -3070,6 +3282,10 @@ drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
{
unsigned int i;
+ /* No point creating cursors if we don't have a plane for them. */
+ if (!output->cursor_plane)
+ return 0;
+
for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
struct gbm_bo *bo;
@@ -3659,11 +3875,15 @@ drm_output_enable(struct weston_output *base)
output->base.gamma_size = output->original_crtc->gamma_size;
output->base.set_gamma = drm_output_set_gamma;
- weston_plane_init(&output->cursor_plane, b->compositor,
- INT32_MIN, INT32_MIN);
weston_plane_init(&output->scanout_plane, b->compositor, 0, 0);
- weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
+ if (output->cursor_plane)
+ weston_compositor_stack_plane(b->compositor,
+ &output->cursor_plane->base,
+ NULL);
+ else
+ b->cursors_are_broken = 1;
+
weston_compositor_stack_plane(b->compositor, &output->scanout_plane,
&b->compositor->primary_plane);
@@ -3706,10 +3926,18 @@ drm_output_deinit(struct weston_output *base)
drm_output_fini_egl(output);
weston_plane_release(&output->scanout_plane);
- weston_plane_release(&output->cursor_plane);
- /* Turn off hardware cursor */
- drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
+ /* Since our planes are no longer in use anywhere, remove their base
+ * weston_plane's link from the plane stacking list, unless we're
+ * shutting down, in which case the plane has already been
+ * destroyed. */
+ if (output->cursor_plane && !b->shutting_down) {
+ wl_list_remove(&output->cursor_plane->base.link);
+ wl_list_init(&output->cursor_plane->base.link);
+
+ /* Turn off hardware cursor */
+ drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
+ }
}
static void
@@ -3729,6 +3957,23 @@ drm_output_destroy(struct weston_output *base)
if (output->base.enabled)
drm_output_deinit(&output->base);
+ if (!b->universal_planes && !b->shutting_down) {
+ /* With universal planes, the 'special' planes are allocated at
+ * startup, freed at shutdown, and live on the plane list in
+ * between. We want the planes to continue to exist and be freed
+ * up for other outputs.
+ *
+ * Without universal planes, our special planes are
+ * pseudo-planes allocated at output creation, freed at output
+ * destruction, and not usable by other outputs.
+ *
+ * On the other hand, if the compositor is already shutting down,
+ * the plane has already been destroyed.
+ */
+ if (output->cursor_plane)
+ drm_plane_destroy(output->cursor_plane);
+ }
+
wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
base.link) {
wl_list_remove(&drm_mode->base.link);
@@ -3889,6 +4134,12 @@ create_output_for_connector(struct drm_backend *b,
}
}
+ /* Failing to find a cursor plane is not fatal, as we'll fall back
+ * to software cursor. */
+ output->cursor_plane =
+ drm_output_find_special_plane(b, output,
+ WDRM_PLANE_TYPE_CURSOR);
+
weston_compositor_add_pending_output(&output->base, b->compositor);
return 0;
@@ -4129,7 +4380,9 @@ session_notify(struct wl_listener *listener, void *data)
wl_list_for_each(output, &compositor->output_list, base.link) {
output->base.repaint_needed = false;
- drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
+ if (output->cursor_plane)
+ drmModeSetCursor(b->drm.fd, output->crtc_id,
+ 0, 0, 0);
}
output = container_of(compositor->output_list.next,
--
2.14.3
More information about the wayland-devel
mailing list