Commit 7daf8d54 authored by Matt Roper's avatar Matt Roper Committed by Daniel Vetter

drm/plane-helper: Add drm_plane_helper_check_update() (v3)

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ä.

v3:
 - s/primary_helper/plane_helper/ --- this checking logic may be useful
   for other types of planes as well.
 - Fix visibility check (need to dereference visibility pointer)
v2:
 - Pass src/dest/clip rects and min/max scaling down to helper to avoid
   duplication of effort between helper and drivers (suggested by
   Ville).
 - Allow caller to specify whether the primary plane should be
   updatable while the crtc is disabled.

Cc: dri-devel@lists.freedesktop.org
Reviewed-by: default avatarChon Ming Lee <chon.ming.lee@intel.com>
Signed-off-by: default avatarMatt Roper <matthew.d.roper@intel.com>
Acked-by: default avatarDave Airlie <airlied@gmail.com>
[danvet: Include header properly and fixup declaration mismatch to
make this compile.]
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 7f994f3f
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_rect.h> #include <drm/drm_rect.h>
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
...@@ -73,6 +74,79 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc, ...@@ -73,6 +74,79 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc,
return count; return count;
} }
/**
* drm_plane_helper_check_update() - Check plane update for validity
* @plane: plane object to update
* @crtc: owning CRTC of owning plane
* @fb: framebuffer to flip onto plane
* @src: source coordinates in 16.16 fixed point
* @dest: integer destination coordinates
* @clip: integer clipping coordinates
* @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
* @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
* @can_position: is it legal to position the plane such that it
* doesn't cover the entire crtc? This will generally
* only be false for primary planes.
* @can_update_disabled: can the plane be updated while the crtc
* is disabled?
* @visible: output parameter indicating whether plane is still visible after
* clipping
*
* Checks that a desired plane update is valid. Drivers that provide
* their own plane handling rather than helper-provided implementations 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_plane_helper_check_update(struct drm_plane *plane,
struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_rect *src,
struct drm_rect *dest,
const struct drm_rect *clip,
int min_scale,
int max_scale,
bool can_position,
bool can_update_disabled,
bool *visible)
{
int hscale, vscale;
if (!crtc->enabled && !can_update_disabled) {
DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n");
return -EINVAL;
}
/* Check scaling */
hscale = drm_rect_calc_hscale(src, dest, min_scale, max_scale);
vscale = drm_rect_calc_vscale(src, dest, min_scale, max_scale);
if (hscale < 0 || vscale < 0) {
DRM_DEBUG_KMS("Invalid scaling of plane\n");
return -ERANGE;
}
*visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale);
if (!*visible)
/*
* 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("Plane must cover entire CRTC\n");
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(drm_plane_helper_check_update);
/** /**
* drm_primary_helper_update() - Helper for primary plane update * drm_primary_helper_update() - Helper for primary plane update
* @plane: plane object to update * @plane: plane object to update
...@@ -121,51 +195,42 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -121,51 +195,42 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
.x = src_x >> 16, .x = src_x >> 16,
.y = src_y >> 16, .y = src_y >> 16,
}; };
struct drm_rect src = {
.x1 = src_x,
.y1 = src_y,
.x2 = src_x + src_w,
.y2 = src_y + src_h,
};
struct drm_rect dest = { struct drm_rect dest = {
.x1 = crtc_x, .x1 = crtc_x,
.y1 = crtc_y, .y1 = crtc_y,
.x2 = crtc_x + crtc_w, .x2 = crtc_x + crtc_w,
.y2 = crtc_y + crtc_h, .y2 = crtc_y + crtc_h,
}; };
struct drm_rect clip = { const struct drm_rect clip = {
.x2 = crtc->mode.hdisplay, .x2 = crtc->mode.hdisplay,
.y2 = crtc->mode.vdisplay, .y2 = crtc->mode.vdisplay,
}; };
struct drm_connector **connector_list; struct drm_connector **connector_list;
int num_connectors, ret; int num_connectors, ret;
bool visible;
if (!crtc->enabled) { ret = drm_plane_helper_check_update(plane, crtc, fb,
DRM_DEBUG_KMS("Cannot update primary plane of a disabled CRTC.\n"); &src, &dest, &clip,
return -EINVAL; DRM_PLANE_HELPER_NO_SCALING,
} DRM_PLANE_HELPER_NO_SCALING,
false, false, &visible);
/* 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);
if (ret) if (ret)
return ret; return ret;
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 */ /* Find current connectors for CRTC */
num_connectors = get_connectors_for_crtc(crtc, NULL, 0); num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
BUG_ON(num_connectors == 0); BUG_ON(num_connectors == 0);
......
...@@ -24,6 +24,17 @@ ...@@ -24,6 +24,17 @@
#ifndef DRM_PLANE_HELPER_H #ifndef DRM_PLANE_HELPER_H
#define DRM_PLANE_HELPER_H #define DRM_PLANE_HELPER_H
#include <drm/drm_rect.h>
/*
* Drivers that don't allow primary plane scaling may pass this macro in place
* of the min/max scale parameters of the update checker function.
*
* Due to src being in 16.16 fixed point and dest being in integer pixels,
* 1<<16 represents no scaling.
*/
#define DRM_PLANE_HELPER_NO_SCALING (1<<16)
/** /**
* DOC: plane helpers * DOC: plane helpers
* *
...@@ -31,6 +42,17 @@ ...@@ -31,6 +42,17 @@
* planes. * planes.
*/ */
extern int drm_plane_helper_check_update(struct drm_plane *plane,
struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_rect *src,
struct drm_rect *dest,
const struct drm_rect *clip,
int min_scale,
int max_scale,
bool can_position,
bool can_update_disabled,
bool *visible);
extern int drm_primary_helper_update(struct drm_plane *plane, extern int drm_primary_helper_update(struct drm_plane *plane,
struct drm_crtc *crtc, struct drm_crtc *crtc,
struct drm_framebuffer *fb, struct drm_framebuffer *fb,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment