From patchwork Wed Apr 23 17:04:00 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Matt Roper X-Patchwork-Id: 4043141 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id C9AB79F319 for ; Wed, 23 Apr 2014 17:02:13 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C741C201F7 for ; Wed, 23 Apr 2014 17:02:12 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 5F44E20219 for ; Wed, 23 Apr 2014 17:02:11 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 0C8428A2A1; Wed, 23 Apr 2014 10:02:11 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by gabe.freedesktop.org (Postfix) with ESMTP id 238726EAEB; Wed, 23 Apr 2014 10:02:09 -0700 (PDT) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga102.jf.intel.com with ESMTP; 23 Apr 2014 09:56:30 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.97,912,1389772800"; d="scan'208";a="526354461" Received: from mdroper-hswdev.fm.intel.com (HELO mdroper-hswdev) ([10.1.134.215]) by orsmga002.jf.intel.com with ESMTP; 23 Apr 2014 10:01:16 -0700 Received: from mattrope by mdroper-hswdev with local (Exim 4.82) (envelope-from ) id 1Wd0ak-00019A-LQ; Wed, 23 Apr 2014 10:04:14 -0700 From: Matt Roper To: intel-gfx@lists.freedesktop.org Date: Wed, 23 Apr 2014 10:04:00 -0700 Message-Id: <1398272641-4368-2-git-send-email-matthew.d.roper@intel.com> X-Mailer: git-send-email 1.8.5.1 In-Reply-To: <1398272641-4368-1-git-send-email-matthew.d.roper@intel.com> References: <1398272641-4368-1-git-send-email-matthew.d.roper@intel.com> MIME-Version: 1.0 Cc: dri-devel@lists.freedesktop.org Subject: [Intel-gfx] [PATCH 2/3] drm/plane-helper: Add drm_primary_helper_check_update() X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Pull the parameter checking from drm_primary_helper_update() out into its own function; drivers that provide their own setplane() implementations rather than using the helper may still want to share this parameter checking logic. A few of the checks here were also updated based on suggestions by Ville Syrjälä. Cc: Ville Syrjälä Cc: dri-devel@lists.freedesktop.org Signed-off-by: Matt Roper --- drivers/gpu/drm/drm_plane_helper.c | 148 +++++++++++++++++++++++++++++-------- include/drm/drm_plane_helper.h | 9 +++ 2 files changed, 128 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 65c4a00..9bbbdf2 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -66,6 +66,102 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc, } /** + * drm_primary_helper_check_update() - Check primary plane update for validity + * @plane: plane object to update + * @crtc: owning CRTC of owning plane + * @fb: framebuffer to flip onto plane + * @crtc_x: x offset of primary plane on crtc + * @crtc_y: y offset of primary plane on crtc + * @crtc_w: width of primary plane rectangle on crtc + * @crtc_h: height of primary plane rectangle on crtc + * @src_x: x offset of @fb for panning + * @src_y: y offset of @fb for panning + * @src_w: width of source rectangle in @fb + * @src_h: height of source rectangle in @fb + * @can_scale: is primary plane scaling legal? + * @can_position: is it legal to position the primary plane such that it + * doesn't cover the entire crtc? + * + * Checks that a desired primary plane update is valid. Drivers that provide + * their own primary plane handling may still wish to call this function to + * avoid duplication of error checking code. + * + * RETURNS: + * Zero if update appears valid, error code on failure + */ +int drm_primary_helper_check_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, + bool can_scale, + bool can_position) +{ + struct drm_rect dest = { + .x1 = crtc_x, + .y1 = crtc_y, + .x2 = crtc_x + crtc_w, + .y2 = crtc_y + crtc_h, + }; + struct drm_rect src = { + .x1 = src_x >> 16, + .y1 = src_y >> 16, + .x2 = (src_x + src_w) >> 16, + .y2 = (src_y + src_h) >> 16, + }; + const struct drm_rect clip = { + .x2 = crtc->mode.hdisplay, + .y2 = crtc->mode.vdisplay, + }; + int hscale, vscale; + int visible; + + if (!crtc->enabled) { + DRM_DEBUG_KMS("Cannot update primary plane of a disabled CRTC.\n"); + return -EINVAL; + } + + /* setplane API takes shifted source rectangle values; unshift them */ + src_x >>= 16; + src_y >>= 16; + src_w >>= 16; + src_h >>= 16; + + /* check scaling */ + if (!can_scale && (crtc_w != src_w || crtc_h != src_h)) { + DRM_DEBUG_KMS("Can't scale primary plane\n"); + return -EINVAL; + } + + /* + * Drivers that can scale should perform their own min/max scale + * factor checks. + */ + hscale = drm_rect_calc_hscale(&src, &dest, 0, INT_MAX); + vscale = drm_rect_calc_vscale(&src, &dest, 0, INT_MAX); + visible = drm_rect_clip_scaled(&src, &dest, &clip, hscale, vscale); + if (!visible) + /* + * Primary plane isn't visible; some drivers can handle this + * so we just return success here. Drivers that can't + * (including those that use the primary plane helper's + * update function) will return an error from their + * update_plane handler. + */ + return 0; + + if (!can_position && !drm_rect_equals(&dest, &clip)) { + DRM_DEBUG_KMS("Primary plane must cover entire CRTC\n"); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(drm_primary_helper_check_update); + +/** * drm_primary_helper_update() - Helper for primary plane update * @plane: plane object to update * @crtc: owning CRTC of owning plane @@ -113,6 +209,12 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, .x = src_x >> 16, .y = src_y >> 16, }; + struct drm_rect src = { + .x1 = src_x >> 16, + .y1 = src_y >> 16, + .x2 = (src_x + src_w) >> 16, + .y2 = (src_y + src_h) >> 16, + }; struct drm_rect dest = { .x1 = crtc_x, .y1 = crtc_y, @@ -124,40 +226,28 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, .y2 = crtc->mode.vdisplay, }; struct drm_connector **connector_list; + int visible; + int hscale, vscale; int num_connectors, ret; - if (!crtc->enabled) { - DRM_DEBUG_KMS("Cannot update primary plane of a disabled CRTC.\n"); - return -EINVAL; - } - - /* Disallow subpixel positioning */ - if ((src_x | src_y | src_w | src_h) & SUBPIXEL_MASK) { - DRM_DEBUG_KMS("Primary plane does not support subpixel positioning\n"); - return -EINVAL; - } - - /* Disallow scaling */ - src_w >>= 16; - src_h >>= 16; - if (crtc_w != src_w || crtc_h != src_h) { - DRM_DEBUG_KMS("Can't scale primary plane\n"); - return -EINVAL; - } - - /* Make sure primary plane covers entire CRTC */ - drm_rect_intersect(&dest, &clip); - if (dest.x1 != 0 || dest.y1 != 0 || - dest.x2 != crtc->mode.hdisplay || dest.y2 != crtc->mode.vdisplay) { - DRM_DEBUG_KMS("Primary plane must cover entire CRTC\n"); - return -EINVAL; - } - - /* Framebuffer must be big enough to cover entire plane */ - ret = drm_crtc_check_viewport(crtc, crtc_x, crtc_y, &crtc->mode, fb); + ret = drm_primary_helper_check_update(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h, + false, false); if (ret) return ret; + hscale = drm_rect_calc_hscale(&src, &dest, 0, INT_MAX); + vscale = drm_rect_calc_vscale(&src, &dest, 0, INT_MAX); + visible = drm_rect_clip_scaled(&src, &dest, &clip, hscale, vscale); + if (!visible) + /* + * Primary plane isn't visible. Note that unless a driver + * provides their own disable function, this will just + * wind up returning -EINVAL to userspace. + */ + return plane->funcs->disable_plane(plane); + /* Find current connectors for CRTC */ num_connectors = get_connectors_for_crtc(crtc, NULL, 0); BUG_ON(num_connectors == 0); diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index 09824be..373201a 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -31,6 +31,15 @@ * planes. */ +extern int drm_primary_helper_check_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, + bool can_scale, + bool can_position); extern int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb,