Track the view a plane is currently displaying, so we can avoid needlessly recreating buffers.
Signed-off-by: Daniel Stone <dani...@collabora.com> --- src/compositor-drm.c | 123 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 19 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index b3053c0..bb909b9 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -284,6 +284,9 @@ struct drm_plane { enum wdrm_plane_type type; + struct weston_view *view; + struct wl_listener view_destroy; + struct drm_fb *current, *next; struct drm_output *output; struct drm_compositor *compositor; @@ -1220,6 +1223,17 @@ drm_output_check_scanout_format(struct drm_output *output, return 0; } +/** + * Try to use the primary DRM plane to directly display a full-screen view + * + * If a surface covers an entire output and is unoccluded, attempt to directly + * pageflip the primary DRM plane (not to be confused with the primary Weston + * plane) to the buffer. In legacy DRM usage, this will use drmModePageFlip; + * in atomic, this is just another plane. + * + * @param output Output to target + * @param ev View to prospectively use the primary plane + */ static struct weston_plane * drm_output_prepare_scanout_view(struct drm_output *output, struct weston_view *ev) @@ -1920,6 +1934,7 @@ drm_output_prepare_overlay_view(struct drm_output *output, struct drm_compositor *c = (struct drm_compositor *)ec; struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport; struct drm_plane *p; + struct drm_plane *cur = NULL; int found = 0; struct gbm_bo *bo; pixman_region32_t dest_rect, src_rect; @@ -1954,42 +1969,87 @@ drm_output_prepare_overlay_view(struct drm_output *output, if (!drm_view_transform_supported(ev)) return NULL; + /* Find the current view this plane is assigned to, if any. */ + wl_list_for_each(p, &c->plane_list, link) { + if (p->view != ev || p->output != output) + continue; + + cur = p; + break; + } + + bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER, + ev->surface->buffer_ref.buffer->resource, + GBM_BO_USE_SCANOUT); + wl_list_for_each(p, &c->plane_list, link) { + if (!bo) + continue; + if (!drm_plane_crtc_supported(output, p->possible_crtcs)) continue; if (p->type != WDRM_PLANE_TYPE_OVERLAY) continue; - if (!p->next) { + format = drm_output_check_plane_format(p, ev, bo); + if (format == 0) + continue; + + /* XXX: At this point, we need two runs through assign_planes; + * one to prepare any necessary views, and see if there + * are any currently-unused planes. This process may + * actually free up some planes for other views to use; + * if any planes have been freed up, we should do another + * pass to see if any planeless views can use any planes + * which have just been freed. But we want to cache what + * we can, so we're not, e.g., calling gbm_bo_import + * twice. */ + if (!p->current && !p->next && !p->view) { found = 1; + assert(p->output == NULL); break; } - } - - /* No sprites available */ - if (!found) - return NULL; - bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER, - ev->surface->buffer_ref.buffer->resource, - GBM_BO_USE_SCANOUT); - if (!bo) - return NULL; + /* XXX: Factor out all the above to see if we can just use the + * current plane still. */ + if (p == cur) { + found = 1; + break; + } + } - format = drm_output_check_plane_format(p, ev, bo); - if (format == 0) { - gbm_bo_destroy(bo); - return NULL; + /* If this buffer (view) was previously on a plane, but is being moved + * off, then get rid of it. */ + if (cur && (!found || cur != p)) { + assert(cur->next == NULL); + cur->output = NULL; + wl_list_remove(&cur->view_destroy.link); + cur->view = NULL; + cur = NULL; } - p->next = drm_fb_get_from_bo(bo, c, format); - if (!p->next) { - gbm_bo_destroy(bo); + /* No planes available. */ + if (!found) { + if (bo) + gbm_bo_destroy(bo); return NULL; } - drm_fb_set_buffer(p->next, ev->surface->buffer_ref.buffer); + if (cur && cur->current && + cur->current->buffer_ref.buffer == ev->surface->buffer_ref.buffer) { + p->next = p->current; + } else { + p->next = drm_fb_get_from_bo(bo, c, format); + if (!p->next) { + gbm_bo_destroy(bo); + return NULL; + } + drm_fb_set_buffer(p->next, ev->surface->buffer_ref.buffer); + } + p->output = output; + p->view = ev; + wl_signal_add(&ev->destroy_signal, &p->view_destroy); box = pixman_region32_extents(&ev->transform.boundingbox); p->base.x = box->x1; @@ -2273,6 +2333,8 @@ drm_assign_planes(struct weston_output *output_base) plane->next = NULL; } plane->output = NULL; + plane->view = NULL; + wl_list_remove(&plane->view_destroy.link); next_plane = NULL; } } @@ -3675,6 +3737,27 @@ err_free: } /** + * Handle destruction of a view active on a KMS plane + * + * Called when the weston_view currently being displayed on a KMS + * plane has been destroyed. The very act of destroying a view on + * an active plane will cause a repaint to be scheduled, but we + * still need to disable the plane itself. + * + * @param listener view_destroy listener struct from the plane + * @param data The view being destroyed + */ +static void +drm_plane_view_destroyed(struct wl_listener *listener, void *data) +{ + struct drm_plane *plane = + container_of(listener, struct drm_plane, view_destroy); + + assert(plane->view == data); + plane->view = NULL; +} + +/** * Create a drm_plane for a hardware plane * * Creates one drm_plane structure for a hardware plane, and initialises its @@ -3700,6 +3783,7 @@ drm_plane_create(struct drm_compositor *ec, const drmModePlane *kplane) return NULL; } + weston_plane_init(&plane->base, &ec->base, 0, 0); plane->possible_crtcs = kplane->possible_crtcs; plane->plane_id = kplane->plane_id; plane->current = NULL; @@ -3707,6 +3791,7 @@ drm_plane_create(struct drm_compositor *ec, const drmModePlane *kplane) plane->output = NULL; plane->compositor = ec; plane->count_formats = kplane->count_formats; + plane->view_destroy.notify = drm_plane_view_destroyed; memcpy(plane->formats, kplane->formats, kplane->count_formats * sizeof(kplane->formats[0])); -- 2.4.3 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel