From patchwork Mon Apr 10 00:24:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gustavo Padovan X-Patchwork-Id: 9671847 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 2A378601EA for ; Mon, 10 Apr 2017 00:25:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1AC2027EED for ; Mon, 10 Apr 2017 00:25:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0FAC827FA8; Mon, 10 Apr 2017 00:25:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-3.7 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RCVD_IN_SORBS_SPAM autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 70FD427EED for ; Mon, 10 Apr 2017 00:25:11 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 618036E0E1; Mon, 10 Apr 2017 00:25:01 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-wm0-f67.google.com (mail-wm0-f67.google.com [74.125.82.67]) by gabe.freedesktop.org (Postfix) with ESMTPS id 35C0E89CCB for ; Mon, 10 Apr 2017 00:24:53 +0000 (UTC) Received: by mail-wm0-f67.google.com with SMTP id o81so6999223wmb.0 for ; Sun, 09 Apr 2017 17:24:53 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=xmYYPAJXyea54i+ZOEpeGWi0jX1iFRPjnuoo+NUxu8w=; b=T50IbjHjtZDzydg8GssR4uqr7wguY0QwsiF36E8Tt3wKxc0czWYSw8Zc7fir1u8GIf JbCe5xnbqKh2A6B1wj/4OSU2aDrphqgPwsujNJK2nvffZXAfbjSo+M/9cJ3BNBhMYrf5 tpBhZljqYLpxzhVv8BQxL2eOIynpShhDsxlkVfMcwEQowfrLoLAwyJHlOfJ4S5ZR9urV n0seJ9e01ca66mI/mHaHCcBUS9WBRzcVUU5qmy4f5+E+LHMFDNfshYW/Yrfwy/PDK+mH HdxjmRsbNjpb6CxeJgSqQ0mk/go3UxxoX5k/Gae11lRco0K45eFpQRreOv2ssE7q+qup Sj6Q== X-Gm-Message-State: AN3rC/5b3pNAPJk8S2DNjKfgiL/nqdIiBLNqAva4aqIntHTrEqz7Zb2t3/kI8iH32P6h2w== X-Received: by 10.28.17.70 with SMTP id 67mr2417003wmr.78.1491783891724; Sun, 09 Apr 2017 17:24:51 -0700 (PDT) Received: from localhost.localdomain ([79.143.138.42]) by smtp.gmail.com with ESMTPSA id w10sm8015818wmw.14.2017.04.09.17.24.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 09 Apr 2017 17:24:51 -0700 (PDT) From: Gustavo Padovan To: dri-devel@lists.freedesktop.org Subject: [RFC 1/7] drm/atomic: initial support for asynchronous plane update Date: Mon, 10 Apr 2017 02:24:42 +0200 Message-Id: <20170410002448.12460-2-gustavo@padovan.org> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170410002448.12460-1-gustavo@padovan.org> References: <20170410002448.12460-1-gustavo@padovan.org> Cc: Gustavo Padovan , Daniel Vetter X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Gustavo Padovan In some cases, like cursor updates, it is interesting to update the plane in an asynchronous fashion to avoid big delays. The current queued update could be still waiting for a fence to signal and thus block and subsequent update until its scan out. In cases like this if we update the cursor synchronously it will cause significant delays on some platforms that would be noticed by the final user. This patch creates a fast path to jump ahead the current queued state and do single planes updates without going through all atomic step in drm_atomic_helper_commit(). For now only single plane updates are supported and only if there is no update to that plane in the queued state. We plan to support async PageFlips through this interface as well in the near future. Cc: Daniel Vetter Cc: Rob Clark Cc: Eric Anholt Signed-off-by: Gustavo Padovan --- drivers/gpu/drm/drm_atomic.c | 75 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_atomic_helper.c | 41 +++++++++++++++++ include/drm/drm_atomic.h | 4 ++ include/drm/drm_atomic_helper.h | 2 + include/drm/drm_modeset_helper_vtables.h | 47 ++++++++++++++++++++ 5 files changed, 169 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f32506a..cae0122 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -631,6 +631,79 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc, return 0; } +static bool drm_atomic_async_check(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_crtc_commit *commit; + struct drm_plane *__plane, *plane = NULL; + struct drm_plane_state *__plane_state, *plane_state = NULL; + const struct drm_plane_helper_funcs *funcs; + int i, n_planes = 0; + + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + if (drm_atomic_crtc_needs_modeset(crtc_state)) + return false; + } + + for_each_new_plane_in_state(state, __plane, __plane_state, i) { + n_planes++; + plane = __plane; + plane_state = __plane_state; + } + + if (!plane || n_planes != 1) + return false; + + if (!plane->state->crtc) + return false; + + if (plane_state->fence) + return false; + + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + if (plane->crtc != crtc) + continue; + + spin_lock(&crtc->commit_lock); + commit = list_first_entry_or_null(&crtc->commit_list, + struct drm_crtc_commit, + commit_entry); + if (!commit) { + spin_unlock(&crtc->commit_lock); + continue; + } + spin_unlock(&crtc->commit_lock); + + for_each_plane_in_state(crtc_state->state, __plane, + __plane_state, i) { + if (__plane == plane) { + return false; + } + } + } + + /* Not configuring new scaling in the async path. */ + if (plane->state->crtc_w != plane_state->crtc_w || + plane->state->crtc_h != plane_state->crtc_h || + plane->state->src_w != plane_state->src_w || + plane->state->src_h != plane_state->src_h) { + return false; + } + + funcs = plane->helper_private; + + if (!funcs->atomic_async_update) + return false; + + if (funcs->atomic_async_check) { + if (funcs->atomic_async_check(plane, plane_state) < 0) + return false; + } + + return true; +} + static void drm_atomic_crtc_print_state(struct drm_printer *p, const struct drm_crtc_state *state) { @@ -1591,6 +1664,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) } } + state->async_update = drm_atomic_async_check(state); + return ret; } EXPORT_SYMBOL(drm_atomic_check_only); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 8be9719..a79e06c 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1235,6 +1235,36 @@ static void commit_work(struct work_struct *work) } /** + * drm_atomic_helper_async_commit - commit state asynchronously + * + * This function commits a state asynchronously. It should be used + * on a state only when drm_atomic_async_check() succeds. Async + * commits are not supposed to swap the states like normal sync commits, + * but just do in-place change on the current state. + */ +void drm_atomic_helper_async_commit(struct drm_device *dev, + struct drm_atomic_state *state) +{ + struct drm_plane *plane; + struct drm_plane_state *plane_state; + const struct drm_plane_helper_funcs *funcs; + int i; + + for_each_new_plane_in_state(state, plane, plane_state, i) { + funcs = plane->helper_private; + + plane->state->src_x = plane_state->src_x; + plane->state->src_y = plane_state->src_y; + plane->state->crtc_x = plane_state->crtc_x; + plane->state->crtc_y = plane_state->crtc_y; + + if (funcs && funcs->atomic_async_update) + funcs->atomic_async_update(plane, plane_state); + } +} +EXPORT_SYMBOL(drm_atomic_helper_async_commit); + +/** * drm_atomic_helper_commit - commit validated state object * @dev: DRM device * @state: the driver state object @@ -1258,6 +1288,17 @@ int drm_atomic_helper_commit(struct drm_device *dev, { int ret; + if (state->async_update) { + ret = drm_atomic_helper_prepare_planes(dev, state); + if (ret) + return ret; + + drm_atomic_helper_async_commit(dev, state); + drm_atomic_helper_cleanup_planes(dev, state); + + return 0; + } + ret = drm_atomic_helper_setup_commit(state, nonblock); if (ret) return ret; diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 788daf7..c00c565 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -160,6 +160,8 @@ struct __drm_connnectors_state { * @dev: parent DRM device * @allow_modeset: allow full modeset * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics + * @legacy_set_config: Disable conflicting encoders instead of failing with -EINVAL. + * @async_update: hint for asynchronous plane update * @planes: pointer to array of structures with per-plane data * @crtcs: pointer to array of CRTC pointers * @num_connector: size of the @connectors and @connector_states arrays @@ -172,6 +174,8 @@ struct drm_atomic_state { struct drm_device *dev; bool allow_modeset : 1; bool legacy_cursor_update : 1; + bool legacy_set_config : 1; + bool async_update : 1; struct __drm_planes_state *planes; struct __drm_crtcs_state *crtcs; int num_connector; diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index f0a8678..8571b51 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -44,6 +44,8 @@ void drm_atomic_helper_commit_tail(struct drm_atomic_state *state); int drm_atomic_helper_commit(struct drm_device *dev, struct drm_atomic_state *state, bool nonblock); +void drm_atomic_helper_async_commit(struct drm_device *dev, + struct drm_atomic_state *state); int drm_atomic_helper_wait_for_fences(struct drm_device *dev, struct drm_atomic_state *state, diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index c01c328..3efa4cc 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -1048,6 +1048,53 @@ struct drm_plane_helper_funcs { */ void (*atomic_disable)(struct drm_plane *plane, struct drm_plane_state *old_state); + + /** + * @atomic_async_check: + * + * Drivers should use this function check if the plane state + * can be updated in a async fashion. + * + * This hook is called by drm_atomic_async_check() in the process + * to figure out if an given update can be committed asynchronously, + * that is, if it can jump ahead the state currently queued for + * update. + * + * Check drm_atomic_async_check() to see what is already there + * to discover potential async updates. + * + * RETURNS: + * + * Return 0 on success and -EINVAL if the update can't be async. + * Error return doesn't mean that the update can't be applied, + * it just mean that it can't be an async one. + * + * FIXME: + * - It only works for single plane updates + * - It can't do async update if the plane is already being update + * by the queued state + * - Async Pageflips are not supported yet + */ + int (*atomic_async_check)(struct drm_plane *plane, + struct drm_plane_state *state); + + /** + * @atomic_async_update: + * + * Drivers should use this functions to perform asynchronous + * updates of planes, that is jump ahead the currently queued + * state for and update the plane. + * + * This hook is called by drm_atomic_helper_async_commit(). + * + * Note that differently from the &drm_plane_helper_funcs.atomic_update + * this hook takes the new &drm_plane_state as parameter. When doing + * async_update drivers shouldn't replace the &drm_plane_state but + * just, update the current one with the new plane configurations in + * the new plane_state. + */ + void (*atomic_async_update)(struct drm_plane *plane, + struct drm_plane_state *new_state); }; /**