From 7cdf231c762602b820a8ab03bae37297fb5df54f Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Wed, 16 Nov 2016 19:40:29 +0000 Subject: [PATCH] compositor-drm: Use plane_state_coords_for_view for scanout Now that we have a helper to fill the plane state co-ordinates from a view, use this for the scanout plane. We now explicitly check that the view fills exactly the fullscreen area and nothing else. We then use the new helper to fill out the plane state values, and do further checks against the filled-in co-ordinates, i.e. that we're not trying to show an offset into the buffer, or to scale the image. This now allows cases where the buffer -> surface -> view -> output transform chain cancels each other out for scaling: previously, we would never consider a buffer for scanout unless its scale matched the output's. We now only look at the final result of the buffer -> output transformation, to check that this does not result in translation or scaling. An audit of the error paths found some places where we would leave a plane state hanging; this makes them all consistent. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen Tested-by: Emre Ucan --- libweston/compositor-drm.c | 62 ++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c index c35fccdde..71f27d1c1 100644 --- a/libweston/compositor-drm.c +++ b/libweston/compositor-drm.c @@ -1670,8 +1670,8 @@ drm_output_prepare_scanout_view(struct drm_output_state *output_state, 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; + pixman_box32_t *extents; /* Don't import buffers which span multiple outputs. */ if (ev->output_mask != (1u << output->base.id)) @@ -1686,21 +1686,13 @@ drm_output_prepare_scanout_view(struct drm_output_state *output_state, if (wl_shm_buffer_get(buffer->resource)) return NULL; - /* Make sure our view is exactly compatible with the output. */ - if (ev->geometry.x != output->base.x || - ev->geometry.y != output->base.y) - return NULL; - if (buffer->width != output->base.current_mode->width || - buffer->height != output->base.current_mode->height) - return NULL; - - if (ev->transform.enabled) - return NULL; - if (ev->geometry.scissor_enabled) - return NULL; - if (viewport->buffer.scale != output->base.current_scale) - return NULL; - if (!drm_view_transform_supported(ev, &output->base)) + /* Check the view spans exactly the output size, calculated in the + * logical co-ordinate space. */ + extents = pixman_region32_extents(&ev->transform.boundingbox); + if (extents->x1 != output->base.x || + extents->y1 != output->base.y || + extents->x2 != output->base.x + output->base.width || + extents->y2 != output->base.y + output->base.height) return NULL; if (ev->alpha != 1.0f) @@ -1715,44 +1707,48 @@ drm_output_prepare_scanout_view(struct drm_output_state *output_state, return NULL; } + state->output = output; + if (!drm_plane_state_coords_for_view(state, ev)) + goto err; + + /* The legacy API does not let us perform cropping or scaling. */ + if (state->src_x != 0 || state->src_y != 0 || + state->src_w != state->dest_w << 16 || + state->src_h != state->dest_h << 16 || + state->dest_x != 0 || state->dest_y != 0 || + state->dest_w != (unsigned) output->base.current_mode->width || + state->dest_h != (unsigned) output->base.current_mode->height) + goto err; + bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER, buffer->resource, GBM_BO_USE_SCANOUT); /* Unable to use the buffer for scanout */ if (!bo) - return NULL; + goto err; state->fb = drm_fb_get_from_bo(bo, b, drm_view_is_opaque(ev), BUFFER_CLIENT); if (!state->fb) { - drm_plane_state_put_back(state); + /* We need to explicitly destroy the BO. */ gbm_bo_destroy(bo); - return NULL; + goto err; } /* Can't change formats with just a pageflip */ if (state->fb->format->format != output->gbm_format) { /* No need to destroy the GBM BO here, as it's now owned * by the FB. */ - drm_plane_state_put_back(state); - return NULL; + goto err; } drm_fb_set_buffer(state->fb, buffer); - state->output = output; - - state->src_x = 0; - state->src_y = 0; - state->src_w = state->fb->width << 16; - state->src_h = state->fb->height << 16; - - state->dest_x = 0; - state->dest_y = 0; - state->dest_w = output->base.current_mode->width; - state->dest_h = output->base.current_mode->height; - return &scanout_plane->base; + +err: + drm_plane_state_put_back(state); + return NULL; } static struct drm_fb *