From: Gustavo Padovan gustavo.padovan@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.
v4: - call drm_atomic_helper_async_check() from the check hook
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@intel.com Cc: intel-gfx@lists.freedesktop.org Signed-off-by: Gustavo Padovan gustavo.padovan@collabora.com --- drivers/gpu/drm/i915/intel_atomic_plane.c | 73 ++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 160 +++++------------------------- 2 files changed, 100 insertions(+), 133 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index ee76fab7bb6f..e5d64a206e75 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -245,11 +245,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; + + 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(intel_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(intel_plane, to_intel_crtc(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 3f505682963f..8399f04a8ad2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12765,6 +12765,9 @@ static int intel_atomic_check(struct drm_device *dev, if (ret) return ret;
+ if (state->legacy_cursor_update) + state->async_update = !drm_atomic_helper_async_check(dev, state); + intel_fbc_choose_crtc(dev_priv, state); return calc_watermark_data(state); } @@ -13167,6 +13170,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; @@ -13295,6 +13318,9 @@ intel_prepare_plane_fb(struct drm_plane *plane, } }
+ if (new_state->state->async_update) + return 0; + if (!obj && !old_obj) return 0;
@@ -13521,140 +13547,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; - /* - * Don't do an async update if there is an outstanding commit modifying - * the plane. This prevents our async update's changes from getting - * overridden by a previous synchronous update's state. - */ - if (old_plane_state->commit && - !try_wait_for_completion(&old_plane_state->commit->hw_done)) - goto slow; - - /* - * 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 = intel_cursor_alignment(dev_priv); - - 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; - - i915_gem_track_fb(intel_fb_obj(old_fb), intel_fb_obj(fb), - intel_plane->frontbuffer_bit); - - /* Swap plane state */ - plane->state = new_plane_state; - - if (plane->state->visible) { - trace_intel_update_plane(plane, to_intel_crtc(crtc)); - intel_plane->update_plane(intel_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(intel_plane, to_intel_crtc(crtc)); - } - - old_vma = fetch_and_zero(&to_intel_plane_state(old_plane_state)->vma); - if (old_vma) - intel_unpin_fb_vma(old_vma); - -out_unlock: - mutex_unlock(&dev_priv->drm.struct_mutex); -out_free: - if (ret) - intel_plane_destroy_state(plane, new_plane_state); - else - intel_plane_destroy_state(plane, old_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, .atomic_get_property = intel_plane_atomic_get_property,
From: Gustavo Padovan gustavo.padovan@collabora.com
After converting legacy cursor updates to atomic async commits intel_cursor_plane_funcs just duplicates intel_plane_funcs now.
Cc: Daniel Vetter daniel.vetter@intel.com Cc: intel-gfx@lists.freedesktop.org Signed-off-by: Gustavo Padovan gustavo.padovan@collabora.com --- drivers/gpu/drm/i915/intel_display.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8399f04a8ad2..6af01d611b01 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13547,16 +13547,6 @@ const struct drm_plane_funcs intel_plane_funcs = { .atomic_destroy_state = intel_plane_destroy_state, };
-static const struct drm_plane_funcs intel_cursor_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = intel_plane_destroy, - .atomic_get_property = intel_plane_atomic_get_property, - .atomic_set_property = intel_plane_atomic_set_property, - .atomic_duplicate_state = intel_plane_duplicate_state, - .atomic_destroy_state = intel_plane_destroy_state, -}; - static struct intel_plane * intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) { @@ -13721,7 +13711,7 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv, cursor->cursor.size = ~0;
ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base, - 0, &intel_cursor_plane_funcs, + 0, &intel_plane_funcs, intel_cursor_formats, ARRAY_SIZE(intel_cursor_formats), NULL, DRM_PLANE_TYPE_CURSOR,
From: Gustavo Padovan gustavo.padovan@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 mdp5_update_cursor_plane_legacy() did but through atomic.
v5: call drm_atomic_helper_async_check() from the check hook
v4: add missing atomic async commit call to msm_atomic_commit(Archit Taneja)
v3: move size checks back to drivers (Ville Syrjälä)
v2: move fb setting to core and use new state (Eric Anholt)
Cc: Rob Clark robdclark@gmail.com Cc: Archit Taneja architt@codeaurora.org Signed-off-by: Gustavo Padovan gustavo.padovan@collabora.com Tested-by: Archit Taneja architt@codeaurora.org (v4) --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 151 +++++++++++++----------------- drivers/gpu/drm/msm/msm_atomic.c | 9 ++ 2 files changed, 72 insertions(+), 88 deletions(-)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 4b22ac3413a1..83200bbf91f8 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -31,15 +31,6 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_rect *src, struct drm_rect *dest);
-static int mdp5_update_cursor_plane_legacy(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); - static struct mdp5_kms *get_kms(struct drm_plane *plane) { struct msm_drm_private *priv = plane->dev->dev_private; @@ -255,7 +246,7 @@ static const struct drm_plane_funcs mdp5_plane_funcs = { };
static const struct drm_plane_funcs mdp5_cursor_plane_funcs = { - .update_plane = mdp5_update_cursor_plane_legacy, + .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, .destroy = mdp5_plane_destroy, .atomic_set_property = mdp5_plane_atomic_set_property, @@ -487,11 +478,73 @@ static void mdp5_plane_atomic_update(struct drm_plane *plane, } }
+static int mdp5_plane_atomic_async_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state); + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_existing_crtc_state(state->state, + state->crtc); + if (WARN_ON(!crtc_state)) + return -EINVAL; + + if (!crtc_state->active) + return -EINVAL; + + mdp5_state = to_mdp5_plane_state(state); + + /* don't use fast path if we don't have a hwpipe allocated yet */ + if (!mdp5_state->hwpipe) + return -EINVAL; + + /* only allow changing of position(crtc x/y or src x/y) in fast path */ + 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 || + plane->state->fb != state->fb) + return -EINVAL; + + return 0; +} + +static void mdp5_plane_atomic_async_update(struct drm_plane *plane, + struct drm_plane_state *new_state) +{ + 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; + + if (plane_enabled(new_state)) { + struct mdp5_ctl *ctl; + struct mdp5_pipeline *pipeline = + mdp5_crtc_get_pipeline(plane->crtc); + int ret; + + ret = mdp5_plane_mode_set(plane, new_state->crtc, new_state->fb, + &new_state->src, &new_state->dst); + WARN_ON(ret < 0); + + ctl = mdp5_crtc_get_ctl(new_state->crtc); + + mdp5_ctl_commit(ctl, pipeline, mdp5_plane_get_flush(plane)); + } + + *to_mdp5_plane_state(plane->state) = + *to_mdp5_plane_state(new_state); +} + static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = { .prepare_fb = mdp5_plane_prepare_fb, .cleanup_fb = mdp5_plane_cleanup_fb, .atomic_check = mdp5_plane_atomic_check, .atomic_update = mdp5_plane_atomic_update, + .atomic_async_check = mdp5_plane_atomic_async_check, + .atomic_async_update = mdp5_plane_atomic_async_update, };
static void set_scanout_locked(struct mdp5_kms *mdp5_kms, @@ -996,84 +1049,6 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, return ret; }
-static int mdp5_update_cursor_plane_legacy(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_plane_state *plane_state, *new_plane_state; - struct mdp5_plane_state *mdp5_pstate; - struct drm_crtc_state *crtc_state = crtc->state; - int ret; - - if (!crtc_state->active || drm_atomic_crtc_needs_modeset(crtc_state)) - goto slow; - - plane_state = plane->state; - mdp5_pstate = to_mdp5_plane_state(plane_state); - - /* don't use fast path if we don't have a hwpipe allocated yet */ - if (!mdp5_pstate->hwpipe) - goto slow; - - /* only allow changing of position(crtc x/y or src x/y) in fast path */ - if (plane_state->crtc != crtc || - plane_state->src_w != src_w || - plane_state->src_h != src_h || - plane_state->crtc_w != crtc_w || - plane_state->crtc_h != crtc_h || - !plane_state->fb || - plane_state->fb != fb) - goto slow; - - new_plane_state = mdp5_plane_duplicate_state(plane); - if (!new_plane_state) - return -ENOMEM; - - 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 = mdp5_plane_atomic_check_with_state(crtc_state, new_plane_state); - if (ret) - goto slow_free; - - if (new_plane_state->visible) { - struct mdp5_ctl *ctl; - struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(crtc); - - ret = mdp5_plane_mode_set(plane, crtc, fb, - &new_plane_state->src, - &new_plane_state->dst); - WARN_ON(ret < 0); - - ctl = mdp5_crtc_get_ctl(crtc); - - mdp5_ctl_commit(ctl, pipeline, mdp5_plane_get_flush(plane)); - } - - *to_mdp5_plane_state(plane_state) = - *to_mdp5_plane_state(new_plane_state); - - mdp5_plane_destroy_state(plane, new_plane_state); - - return 0; -slow_free: - mdp5_plane_destroy_state(plane, new_plane_state); -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); -} - /* * Use this func and the one below only after the atomic state has been * successfully swapped diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 025d454163b0..24066a432e0b 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -172,6 +172,9 @@ int msm_atomic_check(struct drm_device *dev, if (ret) return ret;
+ if (state->legacy_cursor_update) + state->async_update = !drm_atomic_helper_async_check(dev, state); + return ret; }
@@ -202,6 +205,12 @@ int msm_atomic_commit(struct drm_device *dev, if (ret) return ret;
+ if (state->async_update) { + drm_atomic_helper_async_commit(dev, state); + drm_atomic_helper_cleanup_planes(dev, state); + return 0; + } + c = commit_init(state); if (!c) { ret = -ENOMEM;
From: Gustavo Padovan gustavo.padovan@collabora.com
After converting legacy cursor updates to atomic async commits mdp5_cursor_plane_funcs just duplicates mdp5_plane_funcs now.
Cc: Rob Clark robdclark@gmail.com Cc: Archit Taneja architt@codeaurora.org Signed-off-by: Gustavo Padovan gustavo.padovan@collabora.com Tested-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 83200bbf91f8..1eee8c730665 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -245,18 +245,6 @@ static const struct drm_plane_funcs mdp5_plane_funcs = { .atomic_print_state = mdp5_plane_atomic_print_state, };
-static const struct drm_plane_funcs mdp5_cursor_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = mdp5_plane_destroy, - .atomic_set_property = mdp5_plane_atomic_set_property, - .atomic_get_property = mdp5_plane_atomic_get_property, - .reset = mdp5_plane_reset, - .atomic_duplicate_state = mdp5_plane_duplicate_state, - .atomic_destroy_state = mdp5_plane_destroy_state, - .atomic_print_state = mdp5_plane_atomic_print_state, -}; - static int mdp5_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state) { @@ -1108,16 +1096,10 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev, mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats, ARRAY_SIZE(mdp5_plane->formats), false);
- if (type == DRM_PLANE_TYPE_CURSOR) - ret = drm_universal_plane_init(dev, plane, 0xff, - &mdp5_cursor_plane_funcs, - mdp5_plane->formats, mdp5_plane->nformats, - NULL, type, NULL); - else - ret = drm_universal_plane_init(dev, plane, 0xff, - &mdp5_plane_funcs, - mdp5_plane->formats, mdp5_plane->nformats, - NULL, type, NULL); + ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs, + mdp5_plane->formats, + mdp5_plane->nformats, + NULL, type, NULL); if (ret) goto fail;
From: Gustavo Padovan gustavo.padovan@collabora.com
Add support for async updates of cursors by using the new atomic interface for that. Basically what this commit does is do what vc4_update_plane() did but through atomic.
v5: add missing call to vc4_plane_atomic_check() (Eric Anholt)
v4: add drm_atomic_helper_async() commit (Eric Anholt)
v3: move size checks back to drivers (Ville Syrjälä)
v2: move fb setting to core and use new state (Eric Anholt)
Cc: Eric Anholt eric@anholt.net Signed-off-by: Gustavo Padovan gustavo.padovan@collabora.com Reviewed-by: Eric Anholt eric@anholt.net Signed-off-by: Eric Anholt eric@anholt.net --- drivers/gpu/drm/vc4/vc4_kms.c | 20 +++++++ drivers/gpu/drm/vc4/vc4_plane.c | 128 ++++++++++++++++------------------------ 2 files changed, 71 insertions(+), 77 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 50c4959b5bd3..e006b4849f73 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -96,6 +96,26 @@ static int vc4_atomic_commit(struct drm_device *dev, struct vc4_dev *vc4 = to_vc4_dev(dev); int ret;
+ if (state->async_update) { + ret = down_interruptible(&vc4->async_modeset); + if (ret) + return ret; + + ret = drm_atomic_helper_prepare_planes(dev, state); + if (ret) { + up(&vc4->async_modeset); + return ret; + } + + drm_atomic_helper_async_commit(dev, state); + + drm_atomic_helper_cleanup_planes(dev, state); + + up(&vc4->async_modeset); + + return 0; + } + ret = drm_atomic_helper_setup_commit(state, nonblock); if (ret) return ret; diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 2968b3ebb895..36d41b172919 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -759,87 +759,41 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) vc4_state->dlist[vc4_state->ptr0_offset] = addr; }
-static int vc4_prepare_fb(struct drm_plane *plane, - struct drm_plane_state *state) +static int vc4_plane_atomic_async_check(struct drm_plane *plane, + struct drm_plane_state *state) { - struct vc4_bo *bo; - struct dma_fence *fence; + if (plane != state->crtc->cursor) + return -EINVAL;
- if ((plane->state->fb == state->fb) || !state->fb) - return 0; + if (!plane->state) + return -EINVAL;
- bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base); - fence = reservation_object_get_excl_rcu(bo->resv); - drm_atomic_set_fence_for_plane(state, fence); + /* No configuring new scaling in the fast path. */ + if (state->crtc_w != plane->state->crtc_w || + state->crtc_h != plane->state->crtc_h || + state->src_w != plane->state->src_w || + state->src_h != plane->state->src_h) { + return -EINVAL; + }
return 0; }
-static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { - .atomic_check = vc4_plane_atomic_check, - .atomic_update = vc4_plane_atomic_update, - .prepare_fb = vc4_prepare_fb, -}; - -static void vc4_plane_destroy(struct drm_plane *plane) -{ - drm_plane_helper_disable(plane); - drm_plane_cleanup(plane); -} - -/* Implements immediate (non-vblank-synced) updates of the cursor - * position, or falls back to the atomic helper otherwise. - */ -static int -vc4_update_plane(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) +static void vc4_plane_atomic_async_update(struct drm_plane *plane, + struct drm_plane_state *new_state) { - struct drm_plane_state *plane_state; - struct vc4_plane_state *vc4_state; - - if (plane != crtc->cursor) - goto out; - - plane_state = plane->state; - vc4_state = to_vc4_plane_state(plane_state); - - if (!plane_state) - goto out; - - /* No configuring new scaling in the fast path. */ - if (crtc_w != plane_state->crtc_w || - crtc_h != plane_state->crtc_h || - src_w != plane_state->src_w || - src_h != plane_state->src_h) { - goto out; - } - - if (fb != plane_state->fb) { - drm_atomic_set_fb_for_plane(plane->state, fb); - vc4_plane_async_set_fb(plane, fb); - } + struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
- /* Set the cursor's position on the screen. This is the - * expected change from the drm_mode_cursor_universal() - * helper. - */ - plane_state->crtc_x = crtc_x; - plane_state->crtc_y = crtc_y; + 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;
- /* Allow changing the start position within the cursor BO, if - * that matters. - */ - plane_state->src_x = src_x; - plane_state->src_y = src_y; + if (plane->state->fb != new_state->fb) + vc4_plane_async_set_fb(plane, new_state->fb);
/* Update the display list based on the new crtc_x/y. */ - vc4_plane_atomic_check(plane, plane_state); + vc4_plane_atomic_check(plane, plane->state);
/* Note that we can't just call vc4_plane_write_dlist() * because that would smash the context data that the HVS is @@ -851,20 +805,40 @@ vc4_update_plane(struct drm_plane *plane, &vc4_state->hw_dlist[vc4_state->pos2_offset]); writel(vc4_state->dlist[vc4_state->ptr0_offset], &vc4_state->hw_dlist[vc4_state->ptr0_offset]); +} + +static int vc4_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct vc4_bo *bo; + struct dma_fence *fence; + + if ((plane->state->fb == state->fb) || !state->fb) + return 0; + + bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base); + fence = reservation_object_get_excl_rcu(bo->resv); + drm_atomic_set_fence_for_plane(state, fence);
return 0; +} + +static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { + .atomic_check = vc4_plane_atomic_check, + .atomic_update = vc4_plane_atomic_update, + .atomic_async_check = vc4_plane_atomic_async_check, + .atomic_async_update = vc4_plane_atomic_async_update, + .prepare_fb = vc4_prepare_fb, +};
-out: - 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 void vc4_plane_destroy(struct drm_plane *plane) +{ + drm_plane_helper_disable(plane); + drm_plane_cleanup(plane); }
static const struct drm_plane_funcs vc4_plane_funcs = { - .update_plane = vc4_update_plane, + .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, .destroy = vc4_plane_destroy, .set_property = NULL,
Quoting Gustavo Padovan (2017-09-08 20:24:15)
@@ -13167,6 +13170,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;
This deadlock should be found by the test suite, or else we are missing tests!
ret = drm_atomic_helper_prepare_planes(dev, state);
And that will make adding the missing if (ret) return ret; easier.
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;
2017-09-08 Chris Wilson chris@chris-wilson.co.uk:
Quoting Gustavo Padovan (2017-09-08 20:24:15)
@@ -13167,6 +13170,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;
This deadlock should be found by the test suite, or else we are missing tests!
It seems that I missed the fact that the driver changed when I rebased and resent. I'll investigate this further and come back with another patch.
Gustavo
dri-devel@lists.freedesktop.org