summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stone <daniels@collabora.com>2016-11-08 17:46:10 +0000
committerDaniel Stone <daniels@collabora.com>2017-02-07 19:16:32 +0000
commit8f949cd240d059c94819a48cde1c2f68112ecead (patch)
tree3d2317945fd9b028ece149b9b187c81a2bdc4bf0
parent43483a004375104a330f62aec62c49195d15c985 (diff)
compositor-drm: Move DPMS into output state
Extend drm_output_state to also cover DPMS, so we can use it to enable and disable outputs, and always keep a coherent state. Differential Revision: https://phabricator.freedesktop.org/D1501 Signed-off-by: Daniel Stone <daniels@collabora.com>
-rw-r--r--libweston/compositor-drm.c139
1 files changed, 114 insertions, 25 deletions
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 172bea29..a2f3e9c5 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -230,6 +230,7 @@ struct drm_edid {
struct drm_output_state {
struct drm_output *output;
+ enum dpms_enum dpms;
struct wl_list plane_list;
};
@@ -300,12 +301,11 @@ struct drm_output {
drmModePropertyPtr dpms_prop;
uint32_t gbm_format;
- enum dpms_enum dpms;
-
int vblank_pending;
int page_flip_pending;
int destroy_pending;
int disable_pending;
+ int dpms_off_pending;
struct gbm_surface *gbm_surface;
struct drm_fb *gbm_cursor_fb[2];
@@ -1106,6 +1106,7 @@ drm_output_state_alloc(struct drm_output *output)
struct drm_output_state *state = calloc(1, sizeof(*state));
state->output = output;
+ state->dpms = WESTON_DPMS_OFF;
wl_list_init(&state->plane_list);
return state;
@@ -1162,6 +1163,23 @@ drm_output_state_free(struct drm_output_state *state)
free(state);
}
+static struct drm_output_state *
+drm_output_get_disable_state(struct drm_output *output)
+{
+ struct drm_output_state *state;
+
+ if (!output->state_cur)
+ state = drm_output_state_alloc(output);
+ else
+ state = drm_output_state_duplicate(output->state_cur,
+ DRM_OUTPUT_STATE_CLEAR_PLANES);
+ state->dpms = WESTON_DPMS_OFF;
+
+ return state;
+}
+
+static int drm_output_apply_state(struct drm_output_state *state);
+
/**
* Mark a drm_output_state (the output's last state) as complete. This handles
* any post-completion actions such as updating the repaint timer, disabling the
@@ -1172,6 +1190,7 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags,
unsigned int sec, unsigned int usec)
{
struct drm_plane_state *ps;
+ struct drm_output_state *os;
struct timespec ts;
wl_list_for_each(ps, &output->state_cur->plane_list, link)
@@ -1186,6 +1205,9 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags,
} else if (output->disable_pending) {
weston_output_disable(&output->base);
goto out;
+ } else if (output->dpms_off_pending) {
+ os = drm_output_get_disable_state(output);
+ drm_output_apply_state(os);
}
ts.tv_sec = sec;
@@ -1200,6 +1222,7 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags,
out:
output->destroy_pending = 0;
output->disable_pending = 0;
+ output->dpms_off_pending = 0;
}
/**
@@ -1246,7 +1269,6 @@ drm_output_assign_state(struct drm_output_state *state,
}
}
-
static int
drm_view_transform_supported(struct weston_view *ev)
{
@@ -1537,7 +1559,41 @@ drm_output_apply_state(struct drm_output_state *state)
struct drm_mode *mode;
int ret = 0;
- scanout_state = drm_output_state_get_plane(state, scanout_plane);
+ if (state->dpms != WESTON_DPMS_ON) {
+ wl_list_for_each(ps, &state->plane_list, link) {
+ p = ps->plane;
+ assert(ps->fb == NULL);
+ assert(ps->output == NULL);
+
+ if (p->type != WDRM_PLANE_TYPE_OVERLAY)
+ continue;
+
+ ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ if (ret)
+ weston_log("drmModeSetPlane failed disable: %m\n");
+ }
+
+ if (output->cursor_plane) {
+ ret = drmModeSetCursor(backend->drm.fd, output->crtc_id,
+ 0, 0, 0);
+ if (ret)
+ weston_log("drmModeSetCursor failed disable: %m\n");
+ }
+
+ ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
+ &output->connector_id, 0, NULL);
+ if (ret)
+ weston_log("drmModeSetCrtc failed disabling: %m\n");
+
+ drm_output_assign_state(state,
+ DRM_OUTPUT_STATE_UPDATE_SYNCHRONOUS);
+
+ return 0;
+ }
+
+ scanout_state =
+ drm_output_state_get_existing_plane(state, scanout_plane);
/* The legacy SetCrtc API doesn't allow us to do scaling, and the
* legacy PageFlip API doesn't allow us to do clipping either. */
@@ -1564,7 +1620,6 @@ drm_output_apply_state(struct drm_output_state *state)
weston_log("set mode failed: %m\n");
goto err;
}
- output->base.set_dpms(&output->base, WESTON_DPMS_ON);
}
if (drmModePageFlip(backend->drm.fd, output->crtc_id,
@@ -1626,6 +1681,18 @@ drm_output_apply_state(struct drm_output_state *state)
}
}
+ if (output->dpms_prop &&
+ output->state_cur->dpms != output->state_pending->dpms) {
+ ret = drmModeConnectorSetProperty(backend->drm.fd,
+ output->connector_id,
+ output->dpms_prop->prop_id,
+ output->state_pending->dpms);
+ if (ret) {
+ weston_log("DRM: DPMS: failed property set for %s\n",
+ output->base.name);
+ }
+ }
+
drm_output_assign_state(output->state_pending,
DRM_OUTPUT_STATE_UPDATE_ASYNCHRONOUS);
@@ -1655,6 +1722,7 @@ drm_output_repaint(struct weston_output *output_base,
output->state_pending =
drm_output_state_duplicate(output->state_cur,
DRM_OUTPUT_STATE_CLEAR_PLANES);
+ output->state_pending->dpms = WESTON_DPMS_ON;
drm_output_render(output, damage);
scanout_state = drm_output_state_get_plane(output->state_pending,
@@ -1781,6 +1849,9 @@ drm_output_update_msc(struct drm_output *output, unsigned int seq)
}
static void
+drm_output_destroy(struct weston_output *base);
+
+static void
vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
void *data)
{
@@ -1803,9 +1874,6 @@ vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
}
static void
-drm_output_destroy(struct weston_output *base);
-
-static void
page_flip_handler(int fd, unsigned int frame,
unsigned int sec, unsigned int usec, void *data)
{
@@ -2749,8 +2817,6 @@ drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
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);
drm_plane_state_free(plane->state_cur, true);
weston_plane_release(&plane->base);
wl_list_remove(&plane->link);
@@ -2944,22 +3010,42 @@ static void
drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
{
struct drm_output *output = to_drm_output(output_base);
- struct weston_compositor *ec = output_base->compositor;
- struct drm_backend *b = to_drm_backend(ec);
int ret;
- if (!output->dpms_prop)
+
+ /* As we throw everything away when disabling, just send us back through
+ * a repaint cycle. */
+ if (level == WESTON_DPMS_ON) {
+ if (output->dpms_off_pending) {
+ output->dpms_off_pending = 0;
+ assert(!output->state_cur ||
+ output->state_cur->dpms != level);
+ }
+
+ if (output->state_cur && output->state_cur->dpms == level)
+ return;
+
+ weston_log("asked for DPMS on; scheduling repaint\n");
+ weston_output_schedule_repaint(output_base);
return;
+ }
- ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
- output->dpms_prop->prop_id, level);
- if (ret) {
- weston_log("DRM: DPMS: failed property set for %s\n",
- output->base.name);
+ if (!output->state_cur || output->state_cur->dpms == WESTON_DPMS_OFF)
+ return;
+
+ /* If we've already got a request in the pipeline (common when we've
+ * just finished a repaint cycle, and it's the animation destroy
+ * callback which is asking us to disable), then we need to park our
+ * DPMS request until that request has quiesced. */
+ if (output->state_last) {
+ output->dpms_off_pending = 1;
return;
}
- output->dpms = level;
+ output->state_pending = drm_output_get_disable_state(output);
+ ret = drm_output_apply_state(output->state_pending);
+ if (ret != 0)
+ weston_log("drm_set_dpms: couldn't disable output?\n");
}
static const char * const connector_type_names[] = {
@@ -3773,7 +3859,7 @@ static int
drm_output_disable(struct weston_output *base)
{
struct drm_output *output = to_drm_output(base);
- struct drm_backend *b = to_drm_backend(base->compositor);
+ int ret;
if (output->page_flip_pending || output->vblank_pending) {
output->disable_pending = 1;
@@ -3785,11 +3871,12 @@ drm_output_disable(struct weston_output *base)
output->disable_pending = 0;
- weston_log("Disabling output %s\n", output->base.name);
- drmModeSetCrtc(b->drm.fd, output->crtc_id,
- 0, 0, 0, 0, 0, NULL);
- drm_output_state_free(output->state_cur);
- output->state_cur = NULL;
+ output->state_pending = drm_output_get_disable_state(output);
+ ret = drm_output_apply_state(output->state_pending);
+ if (ret) {
+ weston_log("Couldn't disable output output %s\n",
+ output->base.name);
+ }
return 0;
}
@@ -4094,6 +4181,8 @@ session_notify(struct wl_listener *listener, void *data)
output->crtc_id, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0);
}
+
+ /* XXX: invalidate state_cur everywhere */
}
}