[PATCH weston v9 27/62] compositor-drm: Use drm_plane for scanout plane
Daniel Stone
daniels at collabora.com
Fri Mar 3 23:05:38 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 | 130 ++++++++++++++++++++++++++++++---------------
1 file changed, 86 insertions(+), 44 deletions(-)
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 911413b..72b696a 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -362,8 +362,7 @@ struct drm_output {
uint32_t gbm_format;
/* Plane currently being directly displayed by KMS */
- struct weston_plane scanout_plane;
- struct drm_fb *fb_current, *fb_pending, *fb_last;
+ struct drm_plane *scanout_plane;
struct drm_output_state *state_last;
struct drm_output_state *state_cur;
@@ -1326,6 +1325,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;
}
}
@@ -1373,6 +1374,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;
@@ -1426,15 +1429,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 *
@@ -1499,12 +1516,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)
@@ -1512,9 +1532,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);
@@ -1577,6 +1612,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;
@@ -1596,17 +1633,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) {
@@ -1617,18 +1668,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;
drm_output_set_cursor(state);
@@ -1684,10 +1730,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;
@@ -1700,6 +1743,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;
@@ -1716,11 +1760,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);
@@ -1750,10 +1796,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);
@@ -1767,9 +1812,6 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
goto finish_frame;
}
- 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;
@@ -1842,9 +1884,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;
@@ -2520,10 +2559,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);
@@ -3717,6 +3752,15 @@ drm_output_enable(struct weston_output *base)
struct drm_backend *b = to_drm_backend(base->compositor);
struct weston_mode *m;
+ 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 =
@@ -3757,8 +3801,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,
@@ -3766,7 +3808,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",
@@ -3798,8 +3841,6 @@ drm_output_deinit(struct weston_output *base)
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);
@@ -4429,7 +4470,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] "
@@ -4438,7 +4480,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.9.3
More information about the wayland-devel
mailing list