[Intel-gfx] [PATCH v3 2/6] drm/i915: update cursors asynchronously through atomic
Daniel Vetter
daniel at ffwll.ch
Fri Jun 30 07:27:58 UTC 2017
On Wed, Jun 28, 2017 at 05:54:56PM -0300, Gustavo Padovan wrote:
> From: Gustavo Padovan <gustavo.padovan at collabora.com>
>
> Add support to async updates of cursors by using the new atomic
> interface for that. Basically what this commit does is do what
> intel_legacy_cursor_update() did but through atomic.
>
> v3:
> - set correct vma to new state for cleanup
> - move size checks back to drivers (Ville Syrjälä)
>
> v2:
> - move fb setting to core and use new state (Eric Anholt)
>
> Cc: Daniel Vetter <daniel.vetter at intel.com>
> Signed-off-by: Gustavo Padovan <gustavo.padovan at collabora.com>
> ---
> drivers/gpu/drm/i915/intel_atomic_plane.c | 73 +++++++++++++++
> drivers/gpu/drm/i915/intel_display.c | 149 +++++-------------------------
> 2 files changed, 97 insertions(+), 125 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
> index a40c82c..1737b8a 100644
> --- a/drivers/gpu/drm/i915/intel_atomic_plane.c
> +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
> @@ -246,11 +246,84 @@ static void intel_plane_atomic_update(struct drm_plane *plane,
> }
> }
>
> +static int intel_plane_atomic_async_check(struct drm_plane *plane,
> + struct drm_plane_state *state)
> +{
> + struct drm_crtc *crtc = plane->state->crtc;
> + struct drm_crtc_state *crtc_state = crtc->state;
> +
> + if (plane->type != DRM_PLANE_TYPE_CURSOR)
> + return -EINVAL;
> +
> + /*
> + * When crtc is inactive or there is a modeset pending,
> + * wait for it to complete in the slowpath
> + */
> + if (!crtc_state->active || to_intel_crtc_state(crtc_state)->update_pipe)
> + return -EINVAL;
> +
> + /*
> + * If any parameters change that may affect watermarks,
> + * take the slowpath. Only changing fb or position should be
> + * in the fastpath.
> + */
> + if (plane->state->crtc != state->crtc ||
> + plane->state->src_w != state->src_w ||
> + plane->state->src_h != state->src_h ||
> + plane->state->crtc_w != state->crtc_w ||
> + plane->state->crtc_h != state->crtc_h ||
> + !plane->state->fb != !state->fb)
> + return -EINVAL;
If we ever expose async updates as an ATOMIC_IOCTL flag then we need to
improve this check a lot, and make it more robust. Otherwise we'll get
things wrong everytime we add a new property (like rotation).
-Daniel
> +
> + return 0;
> +}
> +
> +static void intel_plane_atomic_async_update(struct drm_plane *plane,
> + struct drm_plane_state *new_state)
> +{
> + struct intel_plane *intel_plane = to_intel_plane(plane);
> + struct drm_crtc *crtc = plane->state->crtc;
> + struct drm_framebuffer *old_fb;
> + struct i915_vma *old_vma;
> +
> + old_vma = to_intel_plane_state(plane->state)->vma;
> + old_fb = plane->state->fb;
> +
> + i915_gem_track_fb(intel_fb_obj(old_fb), intel_fb_obj(new_state->fb),
> + intel_plane->frontbuffer_bit);
> +
> + plane->state->src_x = new_state->src_x;
> + plane->state->src_y = new_state->src_y;
> + plane->state->crtc_x = new_state->crtc_x;
> + plane->state->crtc_y = new_state->crtc_y;
> + plane->state->fb = new_state->fb;
> + *to_intel_plane_state(plane->state) = *to_intel_plane_state(new_state);
> +
> + to_intel_plane_state(new_state)->vma = old_vma;
> + new_state->fb = old_fb;
> +
> + if (plane->state->visible) {
> + trace_intel_update_plane(plane, to_intel_crtc(crtc));
> + intel_plane->update_plane(plane,
> + to_intel_crtc_state(crtc->state),
> + to_intel_plane_state(plane->state));
> + } else {
> + trace_intel_disable_plane(plane, to_intel_crtc(crtc));
> + intel_plane->disable_plane(plane, crtc);
> + }
> +
> + mutex_lock(&plane->dev->struct_mutex);
> + intel_cleanup_plane_fb(plane, new_state);
> + mutex_unlock(&plane->dev->struct_mutex);
> +}
> +
> const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
> .prepare_fb = intel_prepare_plane_fb,
> .cleanup_fb = intel_cleanup_plane_fb,
> .atomic_check = intel_plane_atomic_check,
> .atomic_update = intel_plane_atomic_update,
> + .atomic_async_check = intel_plane_atomic_async_check,
> + .atomic_async_update = intel_plane_atomic_async_update,
> };
>
> /**
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 636c64e..736301d 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -13004,6 +13004,26 @@ static int intel_atomic_commit(struct drm_device *dev,
> struct drm_i915_private *dev_priv = to_i915(dev);
> int ret = 0;
>
> + /*
> + * The atomic async update fast path takes care
> + * of avoiding the vblank waits for simple cursor
> + * movement and flips. For cursor on/off and size changes,
> + * we want to perform the vblank waits so that watermark
> + * updates happen during the correct frames. Gen9+ have
> + * double buffered watermarks and so shouldn't need this.
> + */
> + if (state->async_update) {
> + ret = mutex_lock_interruptible(&dev->struct_mutex);
> + if (ret)
> + return ret;
> +
> + ret = drm_atomic_helper_prepare_planes(dev, state);
> + mutex_unlock(&dev->struct_mutex);
> +
> + drm_atomic_helper_async_commit(dev, state);
> + return 0;
> + }
> +
> ret = drm_atomic_helper_setup_commit(state, nonblock);
> if (ret)
> return ret;
> @@ -13162,6 +13182,9 @@ intel_prepare_plane_fb(struct drm_plane *plane,
> }
> }
>
> + if (new_state->state->async_update)
> + return 0;
> +
> if (!obj && !old_obj)
> return 0;
>
> @@ -13389,132 +13412,8 @@ const struct drm_plane_funcs intel_plane_funcs = {
> .atomic_destroy_state = intel_plane_destroy_state,
> };
>
> -static int
> -intel_legacy_cursor_update(struct drm_plane *plane,
> - struct drm_crtc *crtc,
> - struct drm_framebuffer *fb,
> - int crtc_x, int crtc_y,
> - unsigned int crtc_w, unsigned int crtc_h,
> - uint32_t src_x, uint32_t src_y,
> - uint32_t src_w, uint32_t src_h,
> - struct drm_modeset_acquire_ctx *ctx)
> -{
> - struct drm_i915_private *dev_priv = to_i915(crtc->dev);
> - int ret;
> - struct drm_plane_state *old_plane_state, *new_plane_state;
> - struct intel_plane *intel_plane = to_intel_plane(plane);
> - struct drm_framebuffer *old_fb;
> - struct drm_crtc_state *crtc_state = crtc->state;
> - struct i915_vma *old_vma;
> -
> - /*
> - * When crtc is inactive or there is a modeset pending,
> - * wait for it to complete in the slowpath
> - */
> - if (!crtc_state->active || needs_modeset(crtc_state) ||
> - to_intel_crtc_state(crtc_state)->update_pipe)
> - goto slow;
> -
> - old_plane_state = plane->state;
> -
> - /*
> - * If any parameters change that may affect watermarks,
> - * take the slowpath. Only changing fb or position should be
> - * in the fastpath.
> - */
> - if (old_plane_state->crtc != crtc ||
> - old_plane_state->src_w != src_w ||
> - old_plane_state->src_h != src_h ||
> - old_plane_state->crtc_w != crtc_w ||
> - old_plane_state->crtc_h != crtc_h ||
> - !old_plane_state->fb != !fb)
> - goto slow;
> -
> - new_plane_state = intel_plane_duplicate_state(plane);
> - if (!new_plane_state)
> - return -ENOMEM;
> -
> - drm_atomic_set_fb_for_plane(new_plane_state, fb);
> -
> - new_plane_state->src_x = src_x;
> - new_plane_state->src_y = src_y;
> - new_plane_state->src_w = src_w;
> - new_plane_state->src_h = src_h;
> - new_plane_state->crtc_x = crtc_x;
> - new_plane_state->crtc_y = crtc_y;
> - new_plane_state->crtc_w = crtc_w;
> - new_plane_state->crtc_h = crtc_h;
> -
> - ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state),
> - to_intel_plane_state(new_plane_state));
> - if (ret)
> - goto out_free;
> -
> - ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex);
> - if (ret)
> - goto out_free;
> -
> - if (INTEL_INFO(dev_priv)->cursor_needs_physical) {
> - int align = IS_I830(dev_priv) ? 16 * 1024 : 256;
> -
> - ret = i915_gem_object_attach_phys(intel_fb_obj(fb), align);
> - if (ret) {
> - DRM_DEBUG_KMS("failed to attach phys object\n");
> - goto out_unlock;
> - }
> - } else {
> - struct i915_vma *vma;
> -
> - vma = intel_pin_and_fence_fb_obj(fb, new_plane_state->rotation);
> - if (IS_ERR(vma)) {
> - DRM_DEBUG_KMS("failed to pin object\n");
> -
> - ret = PTR_ERR(vma);
> - goto out_unlock;
> - }
> -
> - to_intel_plane_state(new_plane_state)->vma = vma;
> - }
> -
> - old_fb = old_plane_state->fb;
> - old_vma = to_intel_plane_state(old_plane_state)->vma;
> -
> - i915_gem_track_fb(intel_fb_obj(old_fb), intel_fb_obj(fb),
> - intel_plane->frontbuffer_bit);
> -
> - /* Swap plane state */
> - new_plane_state->fence = old_plane_state->fence;
> - *to_intel_plane_state(old_plane_state) = *to_intel_plane_state(new_plane_state);
> - new_plane_state->fence = NULL;
> - new_plane_state->fb = old_fb;
> - to_intel_plane_state(new_plane_state)->vma = old_vma;
> -
> - if (plane->state->visible) {
> - trace_intel_update_plane(plane, to_intel_crtc(crtc));
> - intel_plane->update_plane(plane,
> - to_intel_crtc_state(crtc->state),
> - to_intel_plane_state(plane->state));
> - } else {
> - trace_intel_disable_plane(plane, to_intel_crtc(crtc));
> - intel_plane->disable_plane(plane, crtc);
> - }
> -
> - intel_cleanup_plane_fb(plane, new_plane_state);
> -
> -out_unlock:
> - mutex_unlock(&dev_priv->drm.struct_mutex);
> -out_free:
> - intel_plane_destroy_state(plane, new_plane_state);
> - return ret;
> -
> -slow:
> - return drm_atomic_helper_update_plane(plane, crtc, fb,
> - crtc_x, crtc_y, crtc_w, crtc_h,
> - src_x, src_y, src_w, src_h, ctx);
> -}
> -
> static const struct drm_plane_funcs intel_cursor_plane_funcs = {
> - .update_plane = intel_legacy_cursor_update,
> + .update_plane = drm_atomic_helper_update_plane,
> .disable_plane = drm_atomic_helper_disable_plane,
> .destroy = intel_plane_destroy,
> .set_property = drm_atomic_helper_plane_set_property,
> --
> 2.9.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
More information about the Intel-gfx
mailing list