From 8cd15af6653a5f7e2dae850a0beff15025d8f375 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 22 Nov 2018 14:01:41 -0500 Subject: [PATCH] drm/amd/display: Add fast path for legacy cursor plane updates [Why] Legacy cursor plane updates from drm helpers go through the full atomic codepath. A high volume of cursor updates through this slow code path can subsequent page-flips to skip a vblank interval for some clients that try to update on every interval. This is particularly noticeable for the compton compositor. [How] There's support for this usecase as part of DRM with asynchronous plane updates but it doesn't do the required locking needed for our usecase. The fast path introduced for cursor updates in this patch is inspired by a similar problem/solution that i915 has previously had. It updates the cursor plane directly. Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 102 +++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index fe21bb86b66a..337d5c5b5f26 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -3472,8 +3473,107 @@ void dm_drm_plane_destroy_state(struct drm_plane *plane, drm_atomic_helper_plane_destroy_state(plane, state); } +static void handle_cursor_update(struct drm_plane *plane, + struct drm_plane_state *old_plane_state); + +static int dm_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state); + +static int dm_plane_helper_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state); + +static int +dm_drm_plane_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) +{ + struct drm_crtc_state *crtc_state = crtc->state; + struct drm_plane_state *old_plane_state, *new_plane_state; + int ret; + + /* Only support fast updates on cursor planes. */ + if (plane->type != DRM_PLANE_TYPE_CURSOR) + goto slow; + + /* + * If the CRTC isn't active or the configuration has changed + * then we can't do a fast update. + */ + if (!crtc_state->active || + drm_atomic_crtc_needs_modeset(crtc_state)) + goto slow; + + /* + * Wait for any commits trying to modify the plane to complete + * before performing the plane update. + */ + old_plane_state = plane->state; + + if (old_plane_state->commit && + !try_wait_for_completion(&old_plane_state->commit->hw_done)) + goto slow; + + /* + * If the basic plane configuration has changed then a fast update + * can't be performed. + */ + 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 = dm_drm_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 = dm_plane_atomic_check(plane, new_plane_state); + if (ret) + goto cleanup; + + ret = dm_plane_helper_prepare_fb(plane, new_plane_state); + if (ret) + goto cleanup; + + /* Swap state. */ + plane->state = new_plane_state; + + handle_cursor_update(plane, old_plane_state); + +cleanup: + if (ret) + dm_drm_plane_destroy_state(plane, new_plane_state); + else + dm_drm_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 dm_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, + .update_plane = dm_drm_plane_update_plane, .disable_plane = drm_atomic_helper_disable_plane, .destroy = drm_primary_helper_destroy, .reset = dm_drm_plane_reset, -- 2.19.1