Here are the utility functions again. Rebased and updated slightly.
I adapted drm_framebuffer_check() to handle multiple handles, and I changed some of the error values it returns.
The plane options ioctl is a bit of an open question. I started by adding separate ioctls for some subsets of the fucntionality, but then I was just writing so much duplicated ioctl handling code that I decided it doesn't seem right. I'm not really happy with this monster ioctl either.
I would actually like to replace the whole KMS API with some tag-length-value (TLV) type of thing. Basically you'd just feed the ioctl a KMS object ID and bunch of attribute IDs + values. The ioctl could take multiple such "streams" for any number of KMS objects.
It would be easily extendible simply by adding new types of attributes.
It would also support atomic mode setting changes across an arbitrary set of KMS objects, without having to do some kind begin+set+set+set...+commit multi ioctl sequence with all the state management nightmares that it would entail.
It would also cleanly handle cases where some attributes would be somehow tied together in hardware (eg. you have to set one attribute to a specific value, before another atribute can be set). With a multi ioctl approach you would have to accept invalid intermediate states, and delay error checking until the commit ioctl.
Of course you'd need to parse the "stream" and feed the resulting state to the driver somehow. I'm think the common code would pass the stream to the driver attribute at a time, and the driver would build up the state, possibly doing some early error checking. Finally when the whole state is built up, it would would be passed to the driver for final error checking, and if everything looks good the driver could push the state to the hardware. The driver could then attempt to do its thing in an atomic fashion, if possible.
Well, that's my utopian idea. Would require quite a bit of work though. Anyone else thinking along similar lines?
From: Ville Syrjälä ville.syrjala@linux.intel.com
This function returns the number of planes used by a specific pixel format.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_crtc_helper.c | 33 +++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 3 +++ 2 files changed, 36 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index ccbdc0b..f388708 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -979,3 +979,36 @@ void drm_helper_hpd_irq_event(struct drm_device *dev) queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0); } EXPORT_SYMBOL(drm_helper_hpd_irq_event); + + +/** + * drm_format_num_planes - get the number of planes for format + * @format: pixel format (DRM_FORMAT_*) + * + * RETURNS: + * The number of planes used by the specified pixel format. + */ +int drm_format_num_planes(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YVU444: + return 3; + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + return 2; + default: + return 1; + } +} +EXPORT_SYMBOL(drm_format_num_planes); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index e88b7d7..37515d1 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -144,4 +144,7 @@ extern void drm_helper_hpd_irq_event(struct drm_device *dev);
extern void drm_kms_helper_poll_disable(struct drm_device *dev); extern void drm_kms_helper_poll_enable(struct drm_device *dev); + +extern int drm_format_num_planes(uint32_t format); + #endif
On Mon, Dec 19, 2011 at 4:33 PM, ville.syrjala@linux.intel.com wrote:
From: Ville Syrjälä ville.syrjala@linux.intel.com
This function returns the number of planes used by a specific pixel format.
btw, I end up with a very similar util fxn in omapdrm driver.. would be nice to have this in core to avoid duplicating in every driver supporting multi-planar
Reviewed-by: Rob Clark rob.clark@linaro.org
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com
drivers/gpu/drm/drm_crtc_helper.c | 33 +++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 3 +++ 2 files changed, 36 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index ccbdc0b..f388708 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -979,3 +979,36 @@ void drm_helper_hpd_irq_event(struct drm_device *dev) queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0); } EXPORT_SYMBOL(drm_helper_hpd_irq_event);
+/**
- drm_format_num_planes - get the number of planes for format
- @format: pixel format (DRM_FORMAT_*)
- RETURNS:
- The number of planes used by the specified pixel format.
- */
+int drm_format_num_planes(uint32_t format) +{
- switch (format) {
- case DRM_FORMAT_YUV410:
- case DRM_FORMAT_YVU410:
- case DRM_FORMAT_YUV411:
- case DRM_FORMAT_YVU411:
- case DRM_FORMAT_YUV420:
- case DRM_FORMAT_YVU420:
- case DRM_FORMAT_YUV422:
- case DRM_FORMAT_YVU422:
- case DRM_FORMAT_YUV444:
- case DRM_FORMAT_YVU444:
- return 3;
- case DRM_FORMAT_NV12:
- case DRM_FORMAT_NV21:
- case DRM_FORMAT_NV16:
- case DRM_FORMAT_NV61:
- return 2;
- default:
- return 1;
- }
+} +EXPORT_SYMBOL(drm_format_num_planes); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index e88b7d7..37515d1 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -144,4 +144,7 @@ extern void drm_helper_hpd_irq_event(struct drm_device *dev);
extern void drm_kms_helper_poll_disable(struct drm_device *dev); extern void drm_kms_helper_poll_enable(struct drm_device *dev);
+extern int drm_format_num_planes(uint32_t format);
#endif
1.7.3.4
dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
On Tue, Dec 20, 2011 at 7:55 PM, Rob Clark robdclark@gmail.com wrote:
On Mon, Dec 19, 2011 at 4:33 PM, ville.syrjala@linux.intel.com wrote:
From: Ville Syrjälä ville.syrjala@linux.intel.com
This function returns the number of planes used by a specific pixel format.
btw, I end up with a very similar util fxn in omapdrm driver.. would be nice to have this in core to avoid duplicating in every driver supporting multi-planar
Reviewed-by: Rob Clark rob.clark@linaro.org
Applied to -next.
Dave.
From: Ville Syrjälä ville.syrjala@linux.intel.com
This function returns the bytes per pixel value based on the pixel format and plane index.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_crtc_helper.c | 45 +++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 1 + 2 files changed, 46 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index f388708..507c3fe 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1012,3 +1012,48 @@ int drm_format_num_planes(uint32_t format) } } EXPORT_SYMBOL(drm_format_num_planes); + +/** + * drm_format_plane_cpp - determine the bytes per pixel value + * @format: pixel format (DRM_FORMAT_*) + * @plane: plane index + * + * RETURNS: + * The bytes per pixel value for the specified plane. + */ +int drm_format_plane_cpp(uint32_t format, int plane) +{ + unsigned int depth; + int bpp; + + if (plane >= drm_format_num_planes(format)) + return 0; + + switch (format) { + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + return 2; + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + return plane ? 2 : 1; + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YVU444: + return 1; + default: + drm_fb_get_bpp_depth(format, &depth, &bpp); + return bpp >> 3; + } +} +EXPORT_SYMBOL(drm_format_plane_cpp); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 37515d1..13f6145 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -146,5 +146,6 @@ extern void drm_kms_helper_poll_disable(struct drm_device *dev); extern void drm_kms_helper_poll_enable(struct drm_device *dev);
extern int drm_format_num_planes(uint32_t format); +extern int drm_format_plane_cpp(uint32_t format, int plane);
#endif
From: Ville Syrjälä ville.syrjala@linux.intel.com
These functions return the chroma subsampling factors for the specified pixel format.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_crtc_helper.c | 60 +++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 2 + 2 files changed, 62 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 507c3fe..00d1218 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1057,3 +1057,63 @@ int drm_format_plane_cpp(uint32_t format, int plane) } } EXPORT_SYMBOL(drm_format_plane_cpp); + +/** + * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor + * @format: pixel format (DRM_FORMAT_*) + * + * RETURNS: + * The horizontal chroma subsampling factor for the + * specified pixel format. + */ +int drm_format_horz_chroma_subsampling(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YVU411: + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + return 4; + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + return 2; + default: + return 1; + } +} +EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); + +/** + * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor + * @format: pixel format (DRM_FORMAT_*) + * + * RETURNS: + * The vertical chroma subsampling factor for the + * specified pixel format. + */ +int drm_format_vert_chroma_subsampling(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUV410: + case DRM_FORMAT_YVU410: + return 4; + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + return 2; + default: + return 1; + } +} +EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 13f6145..30a6610 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -147,5 +147,7 @@ extern void drm_kms_helper_poll_enable(struct drm_device *dev);
extern int drm_format_num_planes(uint32_t format); extern int drm_format_plane_cpp(uint32_t format, int plane); +extern int drm_format_horz_chroma_subsampling(uint32_t format); +extern int drm_format_vert_chroma_subsampling(uint32_t format);
#endif
From: Ville Syrjälä ville.syrjala@linux.intel.com
This function performs a battery of sanity checks on the requested framebuffer layout. Drivers can call it from their fb_create hook.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_crtc_helper.c | 85 +++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 2 + 2 files changed, 87 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 00d1218..e87f932 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1117,3 +1117,88 @@ int drm_format_vert_chroma_subsampling(uint32_t format) } } EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); + +/** + * drm_framebuffer_check - check the framebuffer layout + * @r: cmd from ioctl + * @sizes: sizes of the used BOs + * + * For each handle in the handles[] array of @r, the size of the + * corresponding BO must be passed in @sizes using the same index. + * + * RETURNS: + * Zero on success, error code on failure. + */ +int drm_framebuffer_check(const struct drm_mode_fb_cmd2 *r, const uint64_t sizes[4]) +{ + struct { + unsigned int start, end; + } ranges[4]; + unsigned int req_sizes[4] = {}; + int hsub = drm_format_horz_chroma_subsampling(r->pixel_format); + int vsub = drm_format_vert_chroma_subsampling(r->pixel_format); + int num_planes = drm_format_num_planes(r->pixel_format); + int i, j; + + if (r->width == 0 || r->height == 0) + return -EINVAL; + + /* Keep things safe for s15.16 fixed point math. */ + if (r->width > 0x7fff || r->height > 0x7fff) + return -ERANGE; + + if (r->width % hsub || r->height % vsub) + return -EINVAL; + + for (i = 0; i < num_planes; i++) { + unsigned int height = r->height / (i != 0 ? vsub : 1); + unsigned int width = r->width / (i != 0 ? hsub : 1); + unsigned int size = r->pitches[i] * height; + unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); + unsigned int min_pitch = cpp * width; + + if (!r->handles[i]) + return -EINVAL; + + if (size < r->pitches[i] || size < height) + return -ERANGE; + + if (min_pitch < width || min_pitch < cpp) + return -ERANGE; + + if (r->pitches[i] < min_pitch) + return -EINVAL; + + ranges[i].start = r->offsets[i]; + ranges[i].end = ranges[i].start + size; + + if (ranges[i].end < ranges[i].start) + return -ERANGE; + + /* update all indexes of req_sizes that match this handle */ + for (j = 0; j < num_planes; j++) { + if (r->handles[i] == r->handles[j]) + req_sizes[j] = max(req_sizes[j], ranges[i].end); + } + } + + /* Check that the passed BO sizes are sufficient */ + for (i = 0; i < num_planes; i++) { + if (sizes[i] < req_sizes[i]) + return -ENOSPC; + } + + /* Check for overlapping ranges within the same BO */ + /* FIXME what about formats with interleaved planes (eg. IMC2/IMC4)? */ + for (i = 0; i < num_planes; i++) { + for (j = i + 1; j < num_planes; j++) { + if (r->handles[i] == r->handles[j] && + ranges[i].start < ranges[j].end && + ranges[j].start < ranges[i].end) + return -EINVAL; + } + } + + return 0; +} +EXPORT_SYMBOL(drm_framebuffer_check); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 30a6610..81b325f 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -149,5 +149,7 @@ extern int drm_format_num_planes(uint32_t format); extern int drm_format_plane_cpp(uint32_t format, int plane); extern int drm_format_horz_chroma_subsampling(uint32_t format); extern int drm_format_vert_chroma_subsampling(uint32_t format); +extern int drm_framebuffer_check(const struct drm_mode_fb_cmd2 *r, + const uint64_t sizes[4]);
#endif
From: Ville Syrjälä ville.syrjala@linux.intel.com
struct drm_region represents a two dimensional region. The utility functions are there to help driver writers.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_crtc_helper.c | 156 +++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 24 ++++++ 2 files changed, 180 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index e87f932..3a5dac6 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1202,3 +1202,159 @@ int drm_framebuffer_check(const struct drm_mode_fb_cmd2 *r, const uint64_t sizes return 0; } EXPORT_SYMBOL(drm_framebuffer_check); + + +/** + * drm_region_adjust_size - adjust the size of the region + * @r: region to be adjusted + * @x: horizontal adjustment + * @y: vertical adjustment + * + * Change the size of region @r by @x in the horizontal direction, + * and by @y in the vertical direction, while keeping the center + * of @r stationary. + * + * Positive @x and @y increase the size, negative values decrease it. + */ +void drm_region_adjust_size(struct drm_region *r, int x, int y) +{ + r->x1 -= x >> 1; + r->y1 -= y >> 1; + r->x2 += (x + 1) >> 1; + r->y2 += (y + 1) >> 1; +} +EXPORT_SYMBOL(drm_region_adjust_size); + +/** + * drm_region_translate - translate the region + * @r: region to be tranlated + * @x: horizontal translation + * @y: vertical translation + * + * Move region @r by @x in the horizontal direction, + * and by @y in the vertical direction. + */ +void drm_region_translate(struct drm_region *r, int x, int y) +{ + r->x1 += x; + r->y1 += y; + r->x2 += x; + r->y2 += y; +} +EXPORT_SYMBOL(drm_region_translate); + +/** + * drm_region_subsample - subsample a region + * @r: region to be subsampled + * @hsub: horizontal subsampling factor + * @vsub: vertical subsampling factor + * + * Divide the coordinates of region @r by @hsub and @vsub. + */ +void drm_region_subsample(struct drm_region *r, int hsub, int vsub) +{ + r->x1 /= hsub; + r->y1 /= vsub; + r->x2 /= hsub; + r->y2 /= vsub; +} +EXPORT_SYMBOL(drm_region_subsample); + +/** + * drm_region_width - determine the region width + * @r: region whose width is returned + * + * RETURNS: + * The width of the region. + */ +int drm_region_width(const struct drm_region *r) +{ + return r->x2 - r->x1; +} +EXPORT_SYMBOL(drm_region_width); + +/** + * drm_region_height - determine the region height + * @r: region whose height is returned + * + * RETURNS: + * The height of the region. + */ +int drm_region_height(const struct drm_region *r) +{ + return r->y2 - r->y1; +} +EXPORT_SYMBOL(drm_region_height); + +/** + * drm_region_visible - determine if the the region is visible + * @r: region whose visibility is returned + * + * RETURNS: + * @true if the region is visible, @false otherwise. + */ +bool drm_region_visible(const struct drm_region *r) +{ + return drm_region_width(r) > 0 && drm_region_height(r) > 0; +} +EXPORT_SYMBOL(drm_region_visible); + +/** + * drm_region_clip - clip one region by another region + * @r: region to be clipped + * @clip: clip region + * + * Clip region @r by region @clip. + * + * RETURNS: + * @true if the region is still visible after being clipped, + * @false otherwise. + */ +bool drm_region_clip(struct drm_region *r, const struct drm_region *clip) +{ + r->x1 = max(r->x1, clip->x1); + r->y1 = max(r->y1, clip->y1); + r->x2 = min(r->x2, clip->x2); + r->y2 = min(r->y2, clip->y2); + + return drm_region_visible(r); +} +EXPORT_SYMBOL(drm_region_clip); + +/** + * drm_region_clip_scaled - perform a scaled clip operation + * @src: source window region + * @dst: destination window region + * @clip: clip region + * @hscale: horizontal scaling factor + * @vscale: vertical scaling factor + * + * Clip region @dst by region @clip. Clip region @src by the same + * amounts multiplied by @hscale and @vscale. + * + * RETUTRNS: + * @true if region @dst is still visible after being clipped, + * @false otherwise + */ +bool drm_region_clip_scaled(struct drm_region *src, struct drm_region *dst, + const struct drm_region *clip, + int hscale, int vscale) +{ + int diff; + + diff = clip->x1 - dst->x1; + if (diff > 0) + src->x1 += diff * hscale; + diff = clip->y1 - dst->y1; + if (diff > 0) + src->y1 += diff * vscale; + diff = dst->x2 - clip->x2; + if (diff > 0) + src->x2 -= diff * hscale; + diff = dst->y2 - clip->y2; + if (diff > 0) + src->y2 -= diff * vscale; + + return drm_region_clip(dst, clip); +} +EXPORT_SYMBOL(drm_region_clip_scaled); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 81b325f..591102f 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -152,4 +152,28 @@ extern int drm_format_vert_chroma_subsampling(uint32_t format); extern int drm_framebuffer_check(const struct drm_mode_fb_cmd2 *r, const uint64_t sizes[4]);
+/** + * drm_region - two dimensional region + * @x1: horizontal starting coordinate (inclusive) + * @x2: horizontal ending coordinate (exclusive) + * @y1: vertical starting coordinate (inclusive) + * @y2: vertical ending coordinate (exclusive) + */ +struct drm_region { + int x1, y1, x2, y2; +}; + +extern void drm_region_adjust_size(struct drm_region *r, int x, int y); +extern void drm_region_translate(struct drm_region *r, int x, int y); +extern void drm_region_subsample(struct drm_region *r, int hsub, int vsub); +extern int drm_region_width(const struct drm_region *r); +extern int drm_region_height(const struct drm_region *r); +extern bool drm_region_visible(const struct drm_region *r); +extern bool drm_region_clip(struct drm_region *r, + const struct drm_region *clip); +extern bool drm_region_clip_scaled(struct drm_region *src, + struct drm_region *dst, + const struct drm_region *clip, + int hscale, int vscale); + #endif
From: Ville Syrjälä ville.syrjala@linux.intel.com
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_crtc_helper.c | 102 +++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 4 ++ 2 files changed, 106 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 3a5dac6..5e0b94c 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1358,3 +1358,105 @@ bool drm_region_clip_scaled(struct drm_region *src, struct drm_region *dst, return drm_region_clip(dst, clip); } EXPORT_SYMBOL(drm_region_clip_scaled); + +/** + * drm_calc_hscale - calculate the horizontal scaling factor + * @src: source window region + * @dst: destination window region + * @min_hscale: minimum allowed horizontal scaling factor + * @max_hscale: maximum allowed horizontal scaling factor + * + * Calculate the horizontal scaling factor as + * (@src width) / (@dst width). + * + * If the calculated scaling factor is below @min_hscale, + * decrease the width of region @dst to compensate. + * + * If the calculcated scaling factor is above @max_hscale, + * decrease the width of region @src to compensate. + * + * RETURNS: + * The horizontal scaling factor. + */ +int drm_calc_hscale(struct drm_region *src, struct drm_region *dst, + int min_hscale, int max_hscale) +{ + int src_w = drm_region_width(src); + int dst_w = drm_region_width(dst); + int hscale; + + if (dst_w <= 0) + return 0; + + hscale = src_w / dst_w; + + if (hscale < min_hscale) { + int max_dst_w = src_w / min_hscale; + + drm_region_adjust_size(dst, max_dst_w - dst_w, 0); + + return min_hscale; + } + + if (hscale > max_hscale) { + int max_src_w = dst_w * max_hscale; + + drm_region_adjust_size(src, max_src_w - src_w, 0); + + return max_hscale; + } + + return hscale; +} +EXPORT_SYMBOL(drm_calc_hscale); + +/** + * drm_calc_vscale - calculate the vertical scaling factor + * @src: source window region + * @dst: destination window region + * @min_vscale: minimum allowed vertical scaling factor + * @max_vscale: maximum allowed vertical scaling factor + * + * Calculate the vertical scaling factor as + * (@src height) / (@dst height). + * + * If the calculated scaling factor is below @min_vscale, + * decrease the height of region @dst to compensate. + * + * If the calculcated scaling factor is above @max_vscale, + * decrease the height of region @src to compensate. + * + * RETURNS: + * The vertical scaling factor. + */ +int drm_calc_vscale(struct drm_region *src, struct drm_region *dst, + int min_vscale, int max_vscale) +{ + int src_h = drm_region_height(src); + int dst_h = drm_region_height(dst); + int vscale; + + if (dst_h <= 0) + return 0; + + vscale = src_h / dst_h; + + if (vscale < min_vscale) { + int max_dst_h = src_h / min_vscale; + + drm_region_adjust_size(dst, 0, max_dst_h - dst_h); + + return min_vscale; + } + + if (vscale > max_vscale) { + int max_src_h = dst_h * max_vscale; + + drm_region_adjust_size(src, 0, max_src_h - src_h); + + return max_vscale; + } + + return vscale; +} +EXPORT_SYMBOL(drm_calc_vscale); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 591102f..78e77af 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -175,5 +175,9 @@ extern bool drm_region_clip_scaled(struct drm_region *src, struct drm_region *dst, const struct drm_region *clip, int hscale, int vscale); +extern int drm_calc_hscale(struct drm_region *src, struct drm_region *dst, + int min_hscale, int max_hscale); +extern int drm_calc_vscale(struct drm_region *src, struct drm_region *dst, + int min_vscale, int max_vscale);
#endif
From: Ville Syrjälä ville.syrjala@linux.intel.com
Add a new ioctl DRM_IOCTL_MODE_PLANE_OPTS which is used to configure various settings for the plane.
I left out gamma correction thinking that it could be added using a separate ioctl, since there's already a gamma ioctl for CRTCs.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_crtc.c | 168 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc_helper.c | 19 ++++ drivers/gpu/drm/drm_drv.c | 3 +- include/drm/drm.h | 2 + include/drm/drm_crtc.h | 60 +++++++++++++ include/drm/drm_crtc_helper.h | 1 + include/drm/drm_mode.h | 111 ++++++++++++++++++++++++ 7 files changed, 363 insertions(+), 1 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 0d1faa7..9cec7f0 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1772,6 +1772,174 @@ out: }
/** + * drm_mode_plane_opts - set and get plane options + * @dev: DRM device + * @data: ioctl data* + * @file_prive: DRM file info + * + */ +int drm_mode_plane_opts(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_plane_opts_cmd *req = data; + struct drm_mode_object *obj; + struct drm_plane *plane; + int ret = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + mutex_lock(&dev->mode_config.mutex); + + /* + * First, find the plane object. If not available, + * we don't bother to call the driver. + */ + obj = drm_mode_object_find(dev, req->plane_id, + DRM_MODE_OBJECT_PLANE); + if (!obj) { + DRM_DEBUG_KMS("Unknown plane ID %d\n", + req->plane_id); + ret = -ENOENT; + goto out; + } + plane = obj_to_plane(obj); + + if (req->flags & ~plane->opts_flags) { + ret = -ENOTSUPP; + goto out; + } + + if (req->flags) { + /* Start with the current values. */ + struct drm_plane_opts opts = plane->opts; + uint32_t flags = 0; + + /* Overwrite with user provided values. */ + if (req->flags & DRM_MODE_PLANE_BRIGHTNESS && + opts.brightness != req->brightness) { + flags |= DRM_MODE_PLANE_BRIGHTNESS; + opts.brightness = req->brightness; + } + if (req->flags & DRM_MODE_PLANE_CONTRAST && + opts.contrast != req->contrast) { + flags |= DRM_MODE_PLANE_CONTRAST; + opts.contrast = req->contrast; + } + if (req->flags & DRM_MODE_PLANE_HUE && + opts.hue != req->hue) { + flags |= DRM_MODE_PLANE_HUE; + opts.hue = req->hue; + } + if (req->flags & DRM_MODE_PLANE_SATURATION && + opts.saturation != req->saturation) { + flags |= DRM_MODE_PLANE_SATURATION; + opts.saturation = req->saturation; + } + if (req->flags & DRM_MODE_PLANE_SRC_KEY && + (opts.src_key_low != req->src_key_low || + opts.src_key_high != req->src_key_high)) { + flags |= DRM_MODE_PLANE_SRC_KEY; + opts.src_key_low = req->src_key_low; + opts.src_key_high = req->src_key_high; + } + if (req->flags & DRM_MODE_PLANE_DST_KEY && + (opts.dst_key_value != req->dst_key_value || + opts.dst_key_mask != req->dst_key_mask)) { + flags |= DRM_MODE_PLANE_DST_KEY; + opts.dst_key_value = req->dst_key_value; + opts.dst_key_mask = req->dst_key_mask; + } + if (req->flags & DRM_MODE_PLANE_CONST_ALPHA && + opts.const_alpha != req->const_alpha) { + flags |= DRM_MODE_PLANE_CONST_ALPHA; + opts.const_alpha = req->const_alpha; + } + if (req->flags & DRM_MODE_PLANE_ZORDER && + opts.zorder != req->zorder) { + if (req->zorder == 0) { + ret = -EINVAL; + goto out; + } + flags |= DRM_MODE_PLANE_ZORDER; + opts.zorder = req->zorder; + } + if (req->flags & DRM_MODE_PLANE_CSC_MATRIX && + opts.csc_matrix != req->csc_matrix) { + flags |= DRM_MODE_PLANE_CSC_MATRIX; + opts.csc_matrix = req->csc_matrix; + } + if (req->flags & DRM_MODE_PLANE_CSC_RANGE && + opts.csc_range != req->csc_range) { + flags |= DRM_MODE_PLANE_CSC_RANGE; + opts.csc_range = req->csc_range; + } + if (req->flags & DRM_MODE_PLANE_CHROMA_SITING && + opts.chroma_siting != req->chroma_siting) { + flags |= DRM_MODE_PLANE_CHROMA_SITING; + opts.chroma_siting = req->chroma_siting; + } + if (req->flags & DRM_MODE_PLANE_VC1_RANGE_MAPY && + opts.vc1_range_mapy != req->vc1_range_mapy) { + flags |= DRM_MODE_PLANE_VC1_RANGE_MAPY; + opts.vc1_range_mapy = req->vc1_range_mapy; + } + if (req->flags & DRM_MODE_PLANE_VC1_RANGE_MAPUV && + opts.vc1_range_mapuv != req->vc1_range_mapuv) { + flags |= DRM_MODE_PLANE_VC1_RANGE_MAPUV; + opts.vc1_range_mapuv = req->vc1_range_mapuv; + } + + if (flags) { + ret = plane->funcs->set_plane_opts(plane, flags, &opts); + if (ret) + goto out; + + plane->opts = opts; + } + } + + /* Copy the current values back to the user. */ + req->flags = plane->opts_flags; + + if (req->flags & DRM_MODE_PLANE_BRIGHTNESS) + req->brightness = plane->opts.brightness; + if (req->flags & DRM_MODE_PLANE_CONTRAST) + req->contrast = plane->opts.contrast; + if (req->flags & DRM_MODE_PLANE_HUE) + req->hue = plane->opts.hue; + if (req->flags & DRM_MODE_PLANE_SATURATION) + req->saturation = plane->opts.saturation; + if (req->flags & DRM_MODE_PLANE_SRC_KEY) { + req->src_key_low = plane->opts.src_key_low; + req->src_key_high = plane->opts.src_key_high; + } + if (req->flags & DRM_MODE_PLANE_DST_KEY) { + req->dst_key_value = plane->opts.dst_key_value; + req->dst_key_mask = plane->opts.dst_key_mask; + } + if (req->flags & DRM_MODE_PLANE_CONST_ALPHA) + req->const_alpha = plane->opts.const_alpha; + if (req->flags & DRM_MODE_PLANE_ZORDER) + req->zorder = plane->opts.zorder; + if (req->flags & DRM_MODE_PLANE_CSC_MATRIX) + req->csc_matrix = plane->opts.csc_matrix; + if (req->flags & DRM_MODE_PLANE_CSC_RANGE) + req->csc_range = plane->opts.csc_range; + if (req->flags & DRM_MODE_PLANE_CHROMA_SITING) + req->chroma_siting = plane->opts.chroma_siting; + if (req->flags & DRM_MODE_PLANE_VC1_RANGE_MAPY) + req->vc1_range_mapy = plane->opts.vc1_range_mapy; + if (req->flags & DRM_MODE_PLANE_VC1_RANGE_MAPUV) + req->vc1_range_mapuv = plane->opts.vc1_range_mapuv; + + out: + mutex_unlock(&dev->mode_config.mutex); + + return ret; +} + +/** * drm_mode_setcrtc - set CRTC configuration * @inode: inode from the ioctl * @filp: file * from the ioctl diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 5e0b94c..0153187 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1460,3 +1460,22 @@ int drm_calc_vscale(struct drm_region *src, struct drm_region *dst, return vscale; } EXPORT_SYMBOL(drm_calc_vscale); + +/** + * drm_plane_opts_defaults - fill the plane opts with default values + */ +void drm_plane_opts_defaults(struct drm_plane_opts *opts) +{ + memset(opts, 0, sizeof *opts); + + opts->brightness = 0x8000; + opts->contrast = 0x8000; + opts->hue = 0x8000; + opts->saturation = 0x8000; + + /* disable source color keying */ + opts->src_key_low = ~0ULL; + + opts->const_alpha = 0xffff; +} +EXPORT_SYMBOL(drm_plane_opts_defaults); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index eaf25ff..5759baa 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -159,7 +159,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED) + DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_PLANE_OPTS, drm_mode_plane_opts, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), };
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/include/drm/drm.h b/include/drm/drm.h index 49d94ed..e59ec20 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -718,6 +718,8 @@ struct drm_get_cap { #define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xB6, struct drm_mode_get_plane) #define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct drm_mode_set_plane) #define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xB8, struct drm_mode_fb_cmd2) +#define DRM_IOCTL_MODE_PLANE_OPTS DRM_IOWR(0xB9, struct drm_mode_plane_opts_cmd) +
/** * Device specific ioctls should only be in their respective headers diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 2deb6f9..cf99643 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -277,6 +277,56 @@ struct drm_property { struct list_head enum_blob_list; };
+/** + * drm_plane_opts - plane options + * @brightness: brightness value + * @contrast: contrast value + * @hue: hue value + * @saturation: saturation value + * @src_key_low: minimum source color key value + * @src_key_high: maximum source color key value + * @dst_key_value: destination color key value + * @dst_key_mask: destination color key mask + * @const_alpha: constant alpha blending factor + * @zorder: plane Z order + * @csc_matrix: transfer matrix + * @csc_range: Y/Cb/Cb range information + * @chroma_siting: chroma siting information + * @vc1_range_mapy: VC-1 range mapping for Y + * @vc1_range_mapuv: VC-1 range mapping for Cb/Cr + * + * @brightness, @contrast, @hue and @saturation have a range of 0x0000 to + * 0xffff. Values of 0x0000 to 0x7fff indicate a decrease, a value of + * 0x8000 indicates a default level, and values from 0x8001 to 0xffff + * indicate an increase. + * + * The actual change in the level per a change in the value is implementation + * defined, as is the exact meaning of the default level. The only strict + * requirement is that the mapping between the value and the actual level is + * a monotonically non-decreasing function. + * + * It is recommended that the full range of values be utilized eg. by + * using coarsers step size, piecewise functions, etc. This helps to + * isolate the user from the hardware details as much as possible. + */ +struct drm_plane_opts { + uint16_t brightness; + uint16_t contrast; + uint16_t hue; + uint16_t saturation; + uint64_t src_key_low; + uint64_t src_key_high; + uint64_t dst_key_value; + uint64_t dst_key_mask; + uint16_t const_alpha; + int8_t zorder; + uint8_t csc_matrix; + uint8_t csc_range; + uint8_t chroma_siting; + uint8_t vc1_range_mapy; + uint8_t vc1_range_mapuv; +}; + struct drm_crtc; struct drm_connector; struct drm_encoder; @@ -595,6 +645,7 @@ struct drm_connector { * @update_plane: update the plane configuration * @disable_plane: shut down the plane * @destroy: clean up plane resources + * @set_plane_opts: set plane options */ struct drm_plane_funcs { int (*update_plane)(struct drm_plane *plane, @@ -605,6 +656,8 @@ struct drm_plane_funcs { uint32_t src_w, uint32_t src_h); int (*disable_plane)(struct drm_plane *plane); void (*destroy)(struct drm_plane *plane); + int (*set_plane_opts)(struct drm_plane *plane, uint32_t flags, + struct drm_plane_opts *opts); };
/** @@ -644,6 +697,9 @@ struct drm_plane {
const struct drm_plane_funcs *funcs; void *helper_private; + + uint32_t opts_flags; + struct drm_plane_opts opts; };
/** @@ -1007,4 +1063,8 @@ extern int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp); + +extern int drm_mode_plane_opts(struct drm_device *dev, void *data, + struct drm_file *file_priv); + #endif /* __DRM_CRTC_H__ */ diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 78e77af..e4946a5 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -179,5 +179,6 @@ extern int drm_calc_hscale(struct drm_region *src, struct drm_region *dst, int min_hscale, int max_hscale); extern int drm_calc_vscale(struct drm_region *src, struct drm_region *dst, int min_vscale, int max_vscale); +extern void drm_plane_opts_defaults(struct drm_plane_opts *opts);
#endif diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index 966fe7d..be8a9fd 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -157,6 +157,117 @@ struct drm_mode_get_plane_res { __u32 count_planes; };
+/* Valid YCbCr range */ +#define DRM_CSC_RANGE_UNKNOWN 0x0 /* not specified, implementation defined result */ +#define DRM_CSC_RANGE_MPEG 0x1 /* "MPEG" range (16-235 for Y, 16-240 for Cb/Cr) */ +#define DRM_CSC_RANGE_JPEG 0x2 /* "JPEG" or full range (0-255 for Y/Cb/Cr) */ + +/* Color space conversion transfer matrix */ +#define DRM_CSC_MATRIX_UNKNOWN 0x0 /* not specified, implementation defined result */ +#define DRM_CSC_MATRIX_BT601 0x1 /* ITU-R BT.601 */ +#define DRM_CSC_MATRIX_BT709 0x2 /* ITU-R BT.709 */ + +/* Chroma siting information */ +#define DRM_CHROMA_SITING_UNKNOWN 0x0 /* not specified, implementation defined result */ +#define DRM_CHROMA_SITING_HORZ_LEFT 0x1 /* horizontally co-sited with the first luma sample */ +#define DRM_CHROMA_SITING_HORZ_CENTER 0x2 /* horizontally interstitially sited with luma samples */ +#define DRM_CHROMA_SITING_VERT_TOP 0x4 /* vertically co-sited with the first luma sample */ +#define DRM_CHROMA_SITING_VERT_CENTER 0x8 /* vertically interstitially sited with luma samples */ +#define DRM_CHROMA_SITING_MISALIGNED_PLANES 0x10 /* chroma planes out of phase with each other by 0.5 lines */ +/* Typical chroma siting configurations */ +#define DRM_CHROMA_SITING_MPEG1 (DRM_CHROMA_SITING_HORZ_CENTER |\ + DRM_CHROMA_SITING_VERT_CENTER) +#define DRM_CHROMA_SITING_MPEG2 (DRM_CHROMA_SITING_HORZ_LEFT |\ + DRM_CHROMA_SITING_VERT_CENTER) +#define DRM_CHROMA_SITING_DV (DRM_CHROMA_SITING_HORZ_LEFT |\ + DRM_CHROMA_SITING_VERT_TOP |\ + DRM_CHROMA_SITING_MISALIGNED_PLANES) + +/* + * Plane option flags. + * If a flag is set the corresponding value is valid + */ +#define DRM_MODE_PLANE_BRIGHTNESS (1<<0) +#define DRM_MODE_PLANE_CONTRAST (1<<1) +#define DRM_MODE_PLANE_HUE (1<<2) +#define DRM_MODE_PLANE_SATURATION (1<<3) +#define DRM_MODE_PLANE_SRC_KEY (1<<4) +#define DRM_MODE_PLANE_DST_KEY (1<<5) +#define DRM_MODE_PLANE_CONST_ALPHA (1<<6) +#define DRM_MODE_PLANE_ZORDER (1<<7) +#define DRM_MODE_PLANE_CSC_MATRIX (1<<8) +#define DRM_MODE_PLANE_CSC_RANGE (1<<9) +#define DRM_MODE_PLANE_CHROMA_SITING (1<<10) +#define DRM_MODE_PLANE_VC1_RANGE_MAPY (1<<11) +#define DRM_MODE_PLANE_VC1_RANGE_MAPUV (1<<12) + +struct drm_mode_plane_opts_cmd { + __u32 plane_id; + + __u32 flags; + + /* + * 0x0000 - 0x7fff = decrease + * 0x8000 = no change + * 0x8001 - 0xffff = increase + */ + __u16 brightness; + __u16 contrast; + __u16 hue; + __u16 saturation; + + /* + * [47:32] R [31:16] G [15:0] B or [47:32] Y [31:16] Cb [15:0] Cr + * The size and color space of the components depends on the + * used pixel format. If the actual component size is less than + * 16 bits, the most significat bits of of each component are + * used. + * The plane is invisible when the following equation evaluates + * to true (for each component): + * src_pixel >= src_key_low && src_pixel <= src_key_high + * + * To disable source color keying set src_key_high < src_key_low + * for each compnent. + */ + __u64 src_key_low; + __u64 src_key_high; + + /* See src_key_low/src_key_high */ + __u64 dst_key_value; + /* + * Layout matches that of dst_key_value. The plane is visible + * if the following equation evaluates to true: + * (dst_pixel & dst_key_mask) == (dst_key_value & dst_key_mask) + * + * To disable destination color keying set dst_key_mask to 0. + */ + __u64 dst_key_mask; + + /* If the hardware uses less bits, the most significat bits are used. */ + __u16 const_alpha; + + /* + * CRTC is at 0, < 0 is below it, > 0 is above it + * If two planes are configured with the same zorder + * on the same CRTC, the plane with the lower plane_id + * will be stacked closer to the CRTC. + */ + __s8 zorder; + + /* DRM_CSC_MATRIX_* */ + __u8 csc_matrix; + + /* DRM_CSC_RANGE_* */ + __u8 csc_range; + + /* DRM_CHROMA_SITING_* */ + __u8 chroma_siting; + + /* as defined by VC-1 */ + __u8 vc1_range_mapy; + __u8 vc1_range_mapuv; +}; + #define DRM_MODE_ENCODER_NONE 0 #define DRM_MODE_ENCODER_DAC 1 #define DRM_MODE_ENCODER_TMDS 2
From: Ville Syrjälä ville.syrjala@linux.intel.com
This function is is there to help driver writers.
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_crtc_helper.c | 47 +++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 3 ++ 2 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 0153187..341f05c 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1479,3 +1479,50 @@ void drm_plane_opts_defaults(struct drm_plane_opts *opts) opts->const_alpha = 0xffff; } EXPORT_SYMBOL(drm_plane_opts_defaults); + +/** + * drm_chroma_phase_offsets - calculate the chroma phase offsets + * @ret_xoff: returned horizontal offset (16.16) + * @ret_yoff: returned vertical offset (16.16) + * @hsub: horizontal chroma subsampling factor + * @vsub: vertical chroma subsampling factor + * @chroma: chroma siting information + * @second_chroma_plane: first or second chroma plane? + * + * Calculates the phase offset between chroma and luma pixel centers, + * based on infromation provided in @chroma, @hsub, @vsub, and + * @second_chroma_plane. + * + * RETURNS: + * The chroma phase offsets in 16.16 format. The returned + * phase offsets are in chroma (ie. subsampled) coordinate space. + */ +void drm_chroma_phase_offsets(int *ret_xoff, int *ret_yoff, + int hsub, int vsub, uint8_t chroma_siting, + bool second_chroma_plane) +{ + *ret_xoff = 0; + *ret_yoff = 0; + + switch (chroma_siting & 0x3) { + case DRM_CHROMA_SITING_HORZ_LEFT: + break; + case DRM_CHROMA_SITING_HORZ_CENTER: + *ret_xoff -= (hsub - 1) * 0x8000 / hsub; + break; + } + + switch (chroma_siting & 0xc0) { + case DRM_CHROMA_SITING_VERT_TOP: + break; + case DRM_CHROMA_SITING_VERT_CENTER: + *ret_yoff -= (vsub - 1) * 0x8000 / vsub; + break; + } + + /* Chroma planes out of phase by 0.5 chroma lines? */ + if (second_chroma_plane && + (chroma_siting & DRM_CHROMA_SITING_MISALIGNED_PLANES)) + *ret_yoff -= 0x8000; +} +EXPORT_SYMBOL(drm_chroma_phase_offsets); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index e4946a5..58881f6 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -180,5 +180,8 @@ extern int drm_calc_hscale(struct drm_region *src, struct drm_region *dst, extern int drm_calc_vscale(struct drm_region *src, struct drm_region *dst, int min_vscale, int max_vscale); extern void drm_plane_opts_defaults(struct drm_plane_opts *opts); +extern void drm_chroma_phase_offsets(int *ret_xoff, int *ret_yoff, + int hsub, int vsub, uint8_t chroma_siting, + bool second_chroma_plane);
#endif
dri-devel@lists.freedesktop.org