[PATCH weston v10 26/61] compositor-drm: Use drm_plane for scanout plane

Daniel Stone daniels at collabora.com
Tue Apr 4 16:54:44 UTC 2017


Use a real drm_plane to back the scanout plane, displacing
output->fb_{last,cur,pending} to their plane-tracked equivalents.

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

Differential Revision: https://phabricator.freedesktop.org/D1416

Signed-off-by: Daniel Stone <daniels at collabora.com>
---
 libweston/compositor-drm.c | 156 ++++++++++++++++++++++++++-------------------
 1 file changed, 92 insertions(+), 64 deletions(-)

v10: Free scanout state on disable.

diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 092509f1..c3d0900e 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -364,16 +364,7 @@ struct drm_output {
 	uint32_t gbm_format;
 
 	/* Plane currently being directly displayed by KMS */
-	struct weston_plane scanout_plane;
-
-	/* The last framebuffer submitted to the kernel for this CRTC. */
-	struct drm_fb *fb_current;
-	/* The previously-submitted framebuffer, where the hardware has not
-	 * yet acknowledged display of fb_current. */
-	struct drm_fb *fb_last;
-	/* Framebuffer we are going to submit to the kernel when the current
-	 * repaint is flushed. */
-	struct drm_fb *fb_pending;
+	struct drm_plane *scanout_plane;
 
 	/* The last state submitted to the kernel for this CRTC. */
 	struct drm_output_state *state_cur;
@@ -1384,6 +1375,8 @@ drm_output_assign_state(struct drm_output_state *state,
 
 		if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
 			output->vblank_pending++;
+		else if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
+			output->page_flip_pending = 1;
 	}
 }
 
@@ -1431,6 +1424,8 @@ drm_output_prepare_scanout_view(struct drm_output_state *output_state,
 {
 	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;
 	struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
 	struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
 	struct gbm_bo *bo;
@@ -1484,15 +1479,29 @@ drm_output_prepare_scanout_view(struct drm_output_state *output_state,
 		return NULL;
 	}
 
-	output->fb_pending = drm_fb_get_from_bo(bo, b, format, BUFFER_CLIENT);
-	if (!output->fb_pending) {
+	state = drm_output_state_get_plane(output_state, scanout_plane);
+	state->fb = drm_fb_get_from_bo(bo, b, format, BUFFER_CLIENT);
+	if (!state->fb) {
+		drm_plane_state_put_back(state);
 		gbm_bo_destroy(bo);
 		return NULL;
 	}
 
-	drm_fb_set_buffer(output->fb_pending, buffer);
+	drm_fb_set_buffer(state->fb, buffer);
+
+	state->output = output;
+
+	state->src_x = 0;
+	state->src_y = 0;
+	state->src_w = ev->surface->width << 16;
+	state->src_h = ev->surface->height << 16;
+
+	state->dest_x = 0;
+	state->dest_y = 0;
+	state->dest_w = output->base.width;
+	state->dest_h = output->base.height;
 
-	return &output->scanout_plane;
+	return &scanout_plane->base;
 }
 
 static struct drm_fb *
@@ -1557,12 +1566,15 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
 {
 	struct drm_output *output = state->output;
 	struct weston_compositor *c = output->base.compositor;
+	struct drm_plane_state *scanout_state;
 	struct drm_backend *b = to_drm_backend(c);
 	struct drm_fb *fb;
 
 	/* If we already have a client buffer promoted to scanout, then we don't
 	 * want to render. */
-	if (output->fb_pending)
+	scanout_state = drm_output_state_get_plane(state,
+						   output->scanout_plane);
+	if (scanout_state->fb)
 		return;
 
 	if (b->use_pixman)
@@ -1570,9 +1582,24 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
 	else
 		fb = drm_output_render_gl(state, damage);
 
-	if (!fb)
+	if (!fb) {
+		drm_plane_state_put_back(scanout_state);
 		return;
-	output->fb_pending = fb;
+	}
+
+	scanout_state->fb = fb;
+	scanout_state->output = output;
+
+	scanout_state->src_x = 0;
+	scanout_state->src_y = 0;
+	scanout_state->src_w = output->base.current_mode->width << 16;
+	scanout_state->src_h = output->base.current_mode->height << 16;
+
+	scanout_state->dest_x = 0;
+	scanout_state->dest_y = 0;
+	scanout_state->dest_w = scanout_state->src_w >> 16;
+	scanout_state->dest_h = scanout_state->src_h >> 16;
+
 
 	pixman_region32_subtract(&c->primary_plane.damage,
 				 &c->primary_plane.damage, damage);
@@ -1635,6 +1662,8 @@ drm_output_repaint(struct weston_output *output_base,
 	struct drm_output *output = to_drm_output(output_base);
 	struct drm_backend *backend =
 		to_drm_backend(output->base.compositor);
+	struct drm_plane *scanout_plane = output->scanout_plane;
+	struct drm_plane_state *scanout_state;
 	struct drm_plane_state *ps;
 	struct drm_plane *p;
 	struct drm_mode *mode;
@@ -1654,17 +1683,31 @@ drm_output_repaint(struct weston_output *output_base,
 						   pending_state,
 						   DRM_OUTPUT_STATE_CLEAR_PLANES);
 
-	assert(!output->fb_last);
 
 	drm_output_render(state, damage);
-	if (!output->fb_pending)
+	scanout_state = drm_output_state_get_plane(state, scanout_plane);
+	if (!scanout_state || !scanout_state->fb)
 		goto err;
 
+	/* The legacy SetCrtc API doesn't allow us to do scaling, and the
+	 * legacy PageFlip API doesn't allow us to do clipping either. */
+	assert(scanout_state->src_x == 0);
+	assert(scanout_state->src_y == 0);
+	assert(scanout_state->src_w ==
+		(unsigned) (output->base.current_mode->width << 16));
+	assert(scanout_state->src_h ==
+		(unsigned) (output->base.current_mode->height << 16));
+	assert(scanout_state->dest_x == 0);
+	assert(scanout_state->dest_y == 0);
+	assert(scanout_state->src_w == scanout_state->dest_w << 16);
+	assert(scanout_state->src_h == scanout_state->dest_h << 16);
+
 	mode = container_of(output->base.current_mode, struct drm_mode, base);
-	if (!output->fb_current ||
-	    output->fb_current->stride != output->fb_pending->stride) {
+	if (!scanout_plane->state_cur->fb ||
+	    scanout_plane->state_cur->fb->stride != scanout_state->fb->stride) {
 		ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
-				     output->fb_pending->fb_id, 0, 0,
+				     scanout_state->fb->fb_id,
+				     0, 0,
 				     &output->connector_id, 1,
 				     &mode->mode_info);
 		if (ret) {
@@ -1675,18 +1718,13 @@ drm_output_repaint(struct weston_output *output_base,
 	}
 
 	if (drmModePageFlip(backend->drm.fd, output->crtc_id,
-			    output->fb_pending->fb_id,
+			    scanout_state->fb->fb_id,
 			    DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
 		weston_log("queueing pageflip failed: %m\n");
 		goto err;
 	}
 
-	output->fb_last = output->fb_current;
-	output->fb_current = output->fb_pending;
-	output->fb_pending = NULL;
-
 	assert(!output->page_flip_pending);
-	output->page_flip_pending = 1;
 
 	if (output->pageflip_timer)
 		wl_event_source_timer_update(output->pageflip_timer,
@@ -1746,10 +1784,7 @@ drm_output_repaint(struct weston_output *output_base,
 
 err:
 	output->cursor_view = NULL;
-	if (output->fb_pending) {
-		drm_fb_unref(output->fb_pending);
-		output->fb_pending = NULL;
-	}
+
 	drm_output_state_free(state);
 
 	return -1;
@@ -1762,6 +1797,7 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
 	struct drm_pending_state *pending_state;
 	struct drm_output_state *state;
 	struct drm_plane_state *plane_state;
+	struct drm_plane *scanout_plane = output->scanout_plane;
 	struct drm_backend *backend =
 		to_drm_backend(output_base->compositor);
 	uint32_t fb_id;
@@ -1778,11 +1814,13 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
 	if (output->disable_pending || output->destroy_pending)
 		return;
 
-	if (!output->fb_current) {
+	if (!output->scanout_plane->state_cur->fb) {
 		/* We can't page flip if there's no mode set */
 		goto finish_frame;
 	}
 
+	assert(scanout_plane->state_cur->output == output);
+
 	/* Try to get current msc and timestamp via instant query */
 	vbl.request.type |= drm_waitvblank_pipe(output);
 	ret = drmWaitVBlank(backend->drm.fd, &vbl);
@@ -1812,10 +1850,9 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
 	/* Immediate query didn't provide valid timestamp.
 	 * Use pageflip fallback.
 	 */
-	fb_id = output->fb_current->fb_id;
+	fb_id = scanout_plane->state_cur->fb->fb_id;
 
 	assert(!output->page_flip_pending);
-	assert(!output->fb_last);
 	assert(!output->state_last);
 
 	pending_state = drm_pending_state_alloc(backend);
@@ -1833,9 +1870,6 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
 		wl_event_source_timer_update(output->pageflip_timer,
 		                             backend->pageflip_timeout);
 
-	output->fb_last = drm_fb_ref(output->fb_current);
-	output->page_flip_pending = 1;
-
 	wl_list_for_each(plane_state, &state->plane_list, link) {
 		if (plane_state->plane->type != WDRM_PLANE_TYPE_OVERLAY)
 			continue;
@@ -1908,9 +1942,6 @@ page_flip_handler(int fd, unsigned int frame,
 	assert(output->page_flip_pending);
 	output->page_flip_pending = 0;
 
-	drm_fb_unref(output->fb_last);
-	output->fb_last = NULL;
-
 	if (output->vblank_pending)
 		return;
 
@@ -2586,10 +2617,6 @@ drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mo
 	 *      sledgehammer modeswitch first, and only later showing new
 	 *      content.
 	 */
-	drm_fb_unref(output->fb_current);
-	assert(!output->fb_last);
-	assert(!output->fb_pending);
-	output->fb_last = output->fb_current = NULL;
 
 	if (b->use_pixman) {
 		drm_output_fini_pixman(output);
@@ -2901,14 +2928,16 @@ drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
 		 * same plane for two outputs. */
 		wl_list_for_each(tmp, &b->compositor->pending_output_list,
 				 base.link) {
-			if (tmp->cursor_plane == plane) {
+			if (tmp->cursor_plane == plane ||
+			    tmp->scanout_plane == plane) {
 				found_elsewhere = true;
 				break;
 			}
 		}
 		wl_list_for_each(tmp, &b->compositor->output_list,
 				 base.link) {
-			if (tmp->cursor_plane == plane) {
+			if (tmp->cursor_plane == plane ||
+			    tmp->scanout_plane == plane) {
 				found_elsewhere = true;
 				break;
 			}
@@ -3810,6 +3839,15 @@ drm_output_enable(struct weston_output *base)
 	if (b->pageflip_timeout)
 		drm_output_pageflip_timer_create(output);
 
+	output->scanout_plane =
+		drm_output_find_special_plane(b, output,
+					      WDRM_PLANE_TYPE_PRIMARY);
+	if (!output->scanout_plane) {
+		weston_log("Failed to find primary plane for output %s\n",
+			   output->base.name);
+		goto err;
+	}
+
 	/* Failing to find a cursor plane is not fatal, as we'll fall back
 	 * to software cursor. */
 	output->cursor_plane =
@@ -3850,8 +3888,6 @@ drm_output_enable(struct weston_output *base)
 	    output->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
 		output->base.connection_internal = 1;
 
-	weston_plane_init(&output->scanout_plane, b->compositor, 0, 0);
-
 	if (output->cursor_plane)
 		weston_compositor_stack_plane(b->compositor,
 					      &output->cursor_plane->base,
@@ -3859,7 +3895,8 @@ drm_output_enable(struct weston_output *base)
 	else
 		b->cursors_are_broken = 1;
 
-	weston_compositor_stack_plane(b->compositor, &output->scanout_plane,
+	weston_compositor_stack_plane(b->compositor,
+				      &output->scanout_plane->base,
 				      &b->compositor->primary_plane);
 
 	weston_log("Output %s, (connector %d, crtc %d)\n",
@@ -3886,20 +3923,14 @@ drm_output_deinit(struct weston_output *base)
 	struct drm_output *output = to_drm_output(base);
 	struct drm_backend *b = to_drm_backend(base->compositor);
 
-	/* output->fb_last and output->fb_pending must not be set here;
-	 * destroy_pending/disable_pending exist to guarantee exactly this. */
-	assert(!output->fb_last);
-	assert(!output->fb_pending);
-	drm_fb_unref(output->fb_current);
-	output->fb_current = NULL;
+	drm_plane_state_free(output->scanout_plane->state_cur, true);
+	output->scanout_plane->state_cur = NULL;
 
 	if (b->use_pixman)
 		drm_output_fini_pixman(output);
 	else
 		drm_output_fini_egl(output);
 
-	weston_plane_release(&output->scanout_plane);
-
 	if (output->cursor_plane) {
 		/* Turn off hardware cursor */
 		drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
@@ -3967,10 +3998,6 @@ drm_output_disable(struct weston_output *base)
 	if (output->base.enabled)
 		drm_output_deinit(&output->base);
 
-	assert(!output->fb_last);
-	assert(!output->fb_current);
-	assert(!output->fb_pending);
-
 	output->disable_pending = 0;
 
 	weston_log("Disabling output %s\n", output->base.name);
@@ -4539,7 +4566,8 @@ recorder_frame_notify(struct wl_listener *listener, void *data)
 	if (!output->recorder)
 		return;
 
-	ret = drmPrimeHandleToFD(b->drm.fd, output->fb_current->handle,
+	ret = drmPrimeHandleToFD(b->drm.fd,
+				 output->scanout_plane->state_cur->fb->handle,
 				 DRM_CLOEXEC, &fd);
 	if (ret) {
 		weston_log("[libva recorder] "
@@ -4548,7 +4576,7 @@ recorder_frame_notify(struct wl_listener *listener, void *data)
 	}
 
 	ret = vaapi_recorder_frame(output->recorder, fd,
-				   output->fb_current->stride);
+				   output->scanout_plane->state_cur->fb->stride);
 	if (ret < 0) {
 		weston_log("[libva recorder] aborted: %m\n");
 		recorder_destroy(output);
-- 
2.12.2



More information about the wayland-devel mailing list