[PATCH weston 64/68] compositor-drm: Add test-only mode to state application

Daniel Stone daniels at collabora.com
Fri Dec 9 19:58:19 UTC 2016


The atomic API can allow us to test state before we apply it, to see if
it will be valid. Add support for this, which we will later use in
assign_planes to ensure our plane configuration is valid.

Signed-off-by: Daniel Stone <daniels at collabora.com>

Differential Revision: https://phabricator.freedesktop.org/D1533
---
 libweston/compositor-drm.c | 58 +++++++++++++++++++++++++++++++++-------------
 1 file changed, 42 insertions(+), 16 deletions(-)

diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 6b5c7cb..5db0a1a 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -1561,7 +1561,12 @@ drm_output_get_disable_state(struct drm_output *output)
 	return state;
 }
 
-static int drm_output_apply_state(struct drm_output_state *state);
+enum drm_output_apply_state_mode {
+	DRM_OUTPUT_APPLY_STATE_TEST,
+	DRM_OUTPUT_APPLY_STATE_REAL,
+};
+static int drm_output_apply_state(struct drm_output_state *state,
+				  enum drm_output_apply_state_mode mode);
 
 /**
  * Mark a drm_output_state (the output's last state) as complete. This handles
@@ -1590,7 +1595,7 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags,
 		goto out;
 	} else if (output->dpms_off_pending) {
 		os = drm_output_get_disable_state(output);
-		drm_output_apply_state(os);
+		drm_output_apply_state(os, DRM_OUTPUT_APPLY_STATE_REAL);
 	}
 
 	ts.tv_sec = sec;
@@ -1862,7 +1867,8 @@ drm_waitvblank_pipe(struct drm_output *output)
 }
 
 static int
-drm_output_apply_state_legacy(struct drm_output_state *state)
+drm_output_apply_state_legacy(struct drm_output_state *state,
+			      enum drm_output_apply_state_mode mode)
 {
 	struct drm_output *output = state->output;
 	struct drm_backend *backend = to_drm_backend(output->base.compositor);
@@ -1870,9 +1876,14 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
 	struct drm_plane_state *scanout_state;
 	struct drm_plane_state *ps;
 	struct drm_plane *p;
-	struct drm_mode *mode;
+	struct drm_mode *display_mode;
 	int ret = 0;
 
+	/* The legacy DRM API gives us no way to test commits without actually
+	 * applying them. */
+	if (mode == DRM_OUTPUT_APPLY_STATE_TEST)
+		return 0;
+
 	if (state->dpms != WESTON_DPMS_ON) {
 		wl_list_for_each(ps, &state->plane_list, link) {
 			p = ps->plane;
@@ -1922,7 +1933,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
 	assert(scanout_state->src_w == scanout_state->dest_w << 16);
 	assert(scanout_state->src_h == scanout_state->dest_h << 16);
 
-	mode = to_drm_mode(output->base.current_mode);
+	display_mode = to_drm_mode(output->base.current_mode);
 	if (!scanout_plane->state_cur->fb ||
 	    scanout_plane->state_cur->fb->strides[0] !=
 	    scanout_state->fb->strides[0]) {
@@ -1930,7 +1941,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
 				     scanout_state->fb->fb_id,
 				     0, 0,
 				     &output->connector_id, 1,
-				     &mode->mode_info);
+				     &display_mode->mode_info);
 		if (ret) {
 			weston_log("set mode failed: %m\n");
 			goto err;
@@ -2086,14 +2097,15 @@ drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
 }
 
 static int
-drm_output_apply_state_atomic(struct drm_output_state *state)
+drm_output_apply_state_atomic(struct drm_output_state *state,
+			      enum drm_output_apply_state_mode mode)
 {
 	struct drm_output *output = state->output;
 	struct drm_backend *backend = to_drm_backend(output->base.compositor);
 	struct drm_plane_state *plane_state;
 	drmModeAtomicReq *req = drmModeAtomicAlloc();
 	struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
-	uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
+	uint32_t flags = 0;
 	int ret = 0;
 
 	if (!req)
@@ -2154,7 +2166,16 @@ drm_output_apply_state_atomic(struct drm_output_state *state)
 		}
 	}
 
-	if (drmModeAtomicCommit(backend->drm.fd, req, flags, output) != 0) {
+	if (mode == DRM_OUTPUT_APPLY_STATE_TEST)
+		flags |= DRM_MODE_ATOMIC_TEST_ONLY;
+	else
+		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
+
+	ret = drmModeAtomicCommit(backend->drm.fd, req, flags, output);
+	if (mode == DRM_OUTPUT_APPLY_STATE_TEST)
+		return ret;
+
+	if (ret != 0) {
 		weston_log("couldn't commit new state: %m\n");
 		goto err;
 	}
@@ -2171,16 +2192,17 @@ err:
 #endif
 
 static int
-drm_output_apply_state(struct drm_output_state *state)
+drm_output_apply_state(struct drm_output_state *state,
+		       enum drm_output_apply_state_mode mode)
 {
 #ifdef HAVE_DRM_ATOMIC
 	struct drm_backend *b = to_drm_backend(state->output->base.compositor);
 
 	if (b->atomic_modeset)
-		return drm_output_apply_state_atomic(state);
+		return drm_output_apply_state_atomic(state, mode);
 	else
 #endif
-		return drm_output_apply_state_legacy(state);
+		return drm_output_apply_state_legacy(state, mode);
 }
 
 static int
@@ -2206,7 +2228,8 @@ drm_output_repaint(struct weston_output *output_base,
 	if (!scanout_state || !scanout_state->fb)
 		goto err;
 
-	return drm_output_apply_state(output->state_pending);
+	return drm_output_apply_state(output->state_pending,
+				      DRM_OUTPUT_APPLY_STATE_REAL);
 
 err:
 	drm_output_state_free(output->state_pending);
@@ -2280,7 +2303,8 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
 		drm_output_state_duplicate(output->state_cur,
 					   DRM_OUTPUT_STATE_PRESERVE_PLANES);
 
-	ret = drm_output_apply_state(output->state_pending);
+	ret = drm_output_apply_state(output->state_pending,
+				     DRM_OUTPUT_APPLY_STATE_REAL);
 	if (ret != 0) {
 		weston_log("applying repaint-start state failed: %m\n");
 		goto finish_frame;
@@ -3495,7 +3519,8 @@ drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
 	}
 
 	output->state_pending = drm_output_get_disable_state(output);
-	ret = drm_output_apply_state(output->state_pending);
+	ret = drm_output_apply_state(output->state_pending,
+				     DRM_OUTPUT_APPLY_STATE_REAL);
 	if (ret != 0)
 		weston_log("drm_set_dpms: couldn't disable output?\n");
 }
@@ -4304,7 +4329,8 @@ drm_output_disable(struct weston_output *base)
 	output->disable_pending = 0;
 
 	output->state_pending = drm_output_get_disable_state(output);
-	ret = drm_output_apply_state(output->state_pending);
+	ret = drm_output_apply_state(output->state_pending,
+				     DRM_OUTPUT_APPLY_STATE_REAL);
 	if (ret) {
 		weston_log("Couldn't disable output output %s\n",
 			   output->base.name);
-- 
2.9.3



More information about the wayland-devel mailing list