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 <dani...@collabora.com>

Differential Revision: https://phabricator.freedesktop.org/D1416
---
 libweston/compositor-drm.c | 131 +++++++++++++++++++++++++++++----------------
 1 file changed, 85 insertions(+), 46 deletions(-)

diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 30dd402..4342a3d 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -311,8 +311,8 @@ struct drm_output {
        int current_cursor;
 
        /* 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 backlight *backlight;
 
        struct drm_output_state *state_last;
@@ -1217,6 +1217,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;
        }
 }
 
@@ -1264,6 +1266,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;
@@ -1317,16 +1321,30 @@ drm_output_prepare_scanout_view(struct drm_output_state 
*output_state,
                return NULL;
        }
 
-       output->fb_pending = drm_fb_get_from_bo(bo, b, format);
-       if (!output->fb_pending) {
+       state = drm_output_state_get_plane(output_state, scanout_plane);
+       state->fb = drm_fb_get_from_bo(bo, b, format);
+       if (!state->fb) {
+               drm_plane_state_put_back(state);
                gbm_bo_destroy(bo);
                return NULL;
        }
 
-       output->fb_pending->type = BUFFER_CLIENT;
-       drm_fb_set_buffer(output->fb_pending, buffer);
+       state->fb->type = BUFFER_CLIENT;
+       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 *
@@ -1387,12 +1405,15 @@ static void
 drm_output_render(struct drm_output *output, pixman_region32_t *damage)
 {
        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(output->state_pending,
+                                                  output->scanout_plane);
+       if (scanout_state->fb)
                return;
 
        if (b->use_pixman)
@@ -1400,9 +1421,23 @@ drm_output_render(struct drm_output *output, 
pixman_region32_t *damage)
        else
                fb = drm_output_render_gl(output, 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.width << 16;
+       scanout_state->src_h = output->base.height << 16;
+
+       scanout_state->dest_x = 0;
+       scanout_state->dest_y = 0;
+       scanout_state->dest_w = output->base.width;
+       scanout_state->dest_h = output->base.height;
 
        pixman_region32_subtract(&c->primary_plane.damage,
                                 &c->primary_plane.damage, damage);
@@ -1462,6 +1497,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;
@@ -1476,17 +1513,29 @@ drm_output_repaint(struct weston_output *output_base,
                        drm_output_state_duplicate(output->state_cur,
                                                   
DRM_OUTPUT_STATE_CLEAR_PLANES);
 
-       assert(!output->fb_last);
-
        drm_output_render(output, damage);
-       if (!output->fb_pending)
+       scanout_state = drm_output_state_get_plane(output->state_pending,
+                                                  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 int) output->base.width << 16);
+       assert(scanout_state->src_h == (unsigned int) output->base.height << 
16);
+       assert(scanout_state->dest_x == 0);
+       assert(scanout_state->dest_y == 0);
+       assert(scanout_state->dest_w == (unsigned int) output->base.width);
+       assert(scanout_state->dest_h == (unsigned int) output->base.height);
+
        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) {
@@ -1497,18 +1546,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(output->state_pending);
 
@@ -1567,10 +1611,6 @@ 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(output->state_pending);
        output->state_pending = NULL;
 
@@ -1583,6 +1623,7 @@ drm_output_start_repaint_loop(struct weston_output 
*output_base)
        struct drm_output *output = to_drm_output(output_base);
        struct drm_output_state *output_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;
@@ -1599,11 +1640,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);
@@ -1633,10 +1676,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);
        assert(!output->state_pending);
 
@@ -1651,9 +1693,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, &output_state->plane_list, link) {
                if (plane_state->plane->type != WDRM_PLANE_TYPE_OVERLAY)
                        continue;
@@ -1727,9 +1766,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;
 
@@ -2333,10 +2369,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);
@@ -3547,6 +3579,15 @@ drm_output_enable(struct weston_output *base)
 
        output->dpms_prop = drm_get_prop(b->drm.fd, output->connector, "DPMS");
 
+       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_free;
+       }
+
        /* Failing to find a cursor plane is not fatal, as we'll fall back
         * to software cursor. */
        output->cursor_plane =
@@ -3587,8 +3628,6 @@ drm_output_enable(struct weston_output *base)
        if (output->connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
                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,
@@ -3596,7 +3635,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",
@@ -3630,8 +3670,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);
@@ -4102,7 +4140,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] "
@@ -4111,7 +4150,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

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to