This set intoduces a bunch of helper functions for help drm plane driver writers deal with scaling and other details. Still work in progress, escpecially the last patch.
Some open questions: - In which file should this kind of stuff be placed?
- How should the functions be named?
- Should the scaling factor helpers also perform pre-decimation, by increasing the stride or skipping pixels. OMAP is the only hardware I've seen that can skip pixels horizontally, but increasing the stride should be possible practically on every hardware.
- User space API for the CSC stuff
There is also a bunch of other stuff missing from the API: - interlaced buffers This should be a fairly simple addition to addfb2. I'll try to propose something next week.
- color keying One question here is whether to expose just plain key values or perhaps min+max, or key+mask, or both depending on what the hardware actually supports. I think for now I'll just ignore the fact that color keying may or may not be plane specific.
- alpha blending Constant alpha and per pixel alpha. I don't recall of the v4l2 fourccs had any alpha channel stuff in them, so we may need extra fourccs, or just some extra per-pixel alpha enable bit in the API.
- zorder What's a nice API for this? A signed int with 0 being reserved for the "CRTC plane". Negative values would place the planes below the "CRTC plane", and positive values above it. Setting a plane to a specific zorder would move the existing stack of planes away from zero to make room for the new plane, any holes in the stack would get squashed. Does that sound reasonable?
- gamma correction I've seen three major variations in hardware; selection from a small fixed set of functions, a single curve with some number of points which may or may not be spaced equally, and a full LUT.
- color adjustment My proposal would be something close to what DirectFB uses. Brightness,contrast,saturation,hue adjustments. Valid values 0x0000-0xffff, where 0x8000 means "no change", smaller values mean decrease and larger values increase. The drivers would then map that to hardware specific values however they see fit. I think a good guideline would be to utilize the full range even if the hardware only supports a few adjustment steps. This would allow the users of the API to remain hardware agnostic.
- VC1 range mapping I left this out of the CSC enums for now. I'm not 100% sure, but I think this simply boils down to two small integers which are used to multiply the luma and chroma values before color space conversion. I also don't know what the range of the resulting luma and chroma values is, ie. is it always full range or not, or can that detail still be specified separately.
If no one beats me to it I'll try to come up with some actual code/structs for these things soon. Feel free to propose something if you think I've left something important out.
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.h | 1 + include/drm/drm_crtc_helper.h | 3 +++ 3 files changed, 37 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 68011bb..db59561 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1011,3 +1011,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 (V4L2_PIX_FMT_*) + * + * See linux/videodev2.h for valid values of @format. + * + * RETURNS: + * The number of planes used by the specified pixel format. + */ +int drm_format_num_planes(uint32_t format) +{ + /* FIXME add all planar formats. */ + + switch (format) { + case V4L2_PIX_FMT_YUV410: + case V4L2_PIX_FMT_YVU410: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV411P: + case V4L2_PIX_FMT_YUV422P: + return 3; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + return 2; + default: + return 1; + } +} +EXPORT_SYMBOL(drm_format_num_planes); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 49dc288..736d68d 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -902,4 +902,5 @@ extern int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_destroy_dumb_ioctl(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 b4abb33..20a43f7 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -146,4 +146,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
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 | 43 +++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 1 + 2 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index db59561..7c5c516 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1044,3 +1044,46 @@ 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 (V4L2_PIX_FMT_*) + * @plane: plane index + * + * See linux/videodev2.h for valid values of @format. + * + * 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 V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + return 2; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + return plane ? 2 : 1; + case V4L2_PIX_FMT_YUV410: + case V4L2_PIX_FMT_YVU410: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV411P: + case V4L2_PIX_FMT_YUV422P: + return 1; + default: + drm_helper_get_fb_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 20a43f7..9996643 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -148,5 +148,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 | 67 +++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 2 + 2 files changed, 69 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 7c5c516..1528068 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1087,3 +1087,70 @@ 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 (V4L2_PIX_FMT_*) + * + * See linux/videodev2.h for valid values of @format. + * + * RETURNS: + * The horizontal chroma subsampling factor for the + * specified pixel format. + */ +int drm_format_horz_chroma_subsampling(uint32_t format) +{ + /* FIXME add all subsampled formats. */ + + switch (format) { + case V4L2_PIX_FMT_Y41P: + case V4L2_PIX_FMT_YUV411P: + case V4L2_PIX_FMT_YUV410: + case V4L2_PIX_FMT_YVU410: + return 4; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + 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 (V4L2_PIX_FMT_*) + * + * See linux/videodev2.h for valid values of @format. + * + * RETURNS: + * The vertical chroma subsampling factor for the + * specified pixel format. + */ +int drm_format_vert_chroma_subsampling(uint32_t format) +{ + /* FIXME add all subsampled formats. */ + + switch (format) { + case V4L2_PIX_FMT_YUV410: + case V4L2_PIX_FMT_YVU410: + return 4; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_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 9996643..25d46b8 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -149,5 +149,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 | 70 +++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 2 + 2 files changed, 72 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 1528068..af5a8f0 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1154,3 +1154,73 @@ 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 + * @size: BO size + * + * RETURNS: + * Zero on success, error code on failure. + */ +int drm_framebuffer_check(const struct drm_mode_fb_cmd2 *r, unsigned int size) +{ + struct { + unsigned int start, end; + } ranges[4]; + unsigned int required_size = 0; + 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 -EINVAL; + + 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 (size < r->pitches[i] || size < height) + return -EINVAL; + + if (min_pitch < width || min_pitch < cpp) + return -EINVAL; + + 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 -EINVAL; + + required_size = max(required_size, ranges[i].end); + } + + if (size < required_size) + return -EINVAL; + + /* Check for overlapping ranges */ + for (i = 0; i < num_planes; i++) { + for (j = i + 1; j < num_planes; j++) { + if (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 25d46b8..4d2a53a 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -151,5 +151,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, + unsigned int size);
#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 af5a8f0..f311c21 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1224,3 +1224,159 @@ int drm_framebuffer_check(const struct drm_mode_fb_cmd2 *r, unsigned int size) 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 4d2a53a..e1295c7 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -154,4 +154,28 @@ extern int drm_format_vert_chroma_subsampling(uint32_t format); extern int drm_framebuffer_check(const struct drm_mode_fb_cmd2 *r, unsigned int size);
+/** + * 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 f311c21..490b7bc 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1380,3 +1380,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 e1295c7..e23aa02 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -177,5 +177,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
Signed-off-by: Ville Syrjälä ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_crtc_helper.c | 48 ++++++++++++++++++++++++++++++++ include/drm/drm_crtc.h | 55 +++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 5 +++ 3 files changed, 108 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 490b7bc..b06465c 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1482,3 +1482,51 @@ int drm_calc_vscale(struct drm_region *src, struct drm_region *dst, return vscale; } EXPORT_SYMBOL(drm_calc_vscale); + +/** + * 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 (@drm_chroma_siting) + * @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, + enum drm_chroma_siting chroma, + bool second_chroma_plane) +{ + *ret_xoff = 0; + *ret_yoff = 0; + + switch (chroma & 0x3) { + case DRM_CHROMA_SITING_HORZ_LEFT: + break; + case DRM_CHROMA_SITING_HORZ_CENTER: + *ret_xoff -= (hsub - 1) * 0x8000 / hsub; + break; + } + + switch (chroma & 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 & DRM_CHROMA_SITING_MISALIGNED_PLANES)) + *ret_yoff -= 0x8000; +} +EXPORT_SYMBOL(drm_chroma_phase_offsets); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 736d68d..55ff998 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -903,4 +903,59 @@ extern int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, extern int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
+/** + * drm_csc_range - indicates the valid range for color values + * @DRM_CSC_RANGE_UNKNOWN: not specified, implementation defined result + * @DRM_CSC_RANGE_MPEG: "MPEG" range (16-235 for Y, 16-240 for Cb/Cr) + * @DRM_CSC_RANGE_JPEG: "JPEG" or full range (0-255 for Y/Cb/Cr) + */ +enum drm_csc_range { + DRM_CSC_RANGE_UNKNOWN = 0x0, + + DRM_CSC_RANGE_MPEG = 0x1, + DRM_CSC_RANGE_JPEG = 0x2, +}; + +/** + * drm_csc_matrix - specifies the color space conversion matrix + * @DRM_CSC_MATRIX_UNKNOWN: not specified, implementation defined result + * @DRM_CSC_MATRIX_BT601: ITU-R BT.601 + * @DRM_CSC_MATRIX_BT709: ITU-R BT.709 + */ +enum drm_csc_matrix { + DRM_CSC_MATRIX_UNKNOWN = 0x0, + + DRM_CSC_MATRIX_BT601 = 0x1, + DRM_CSC_MATRIX_BT709 = 0x2, +}; + +/** + * drm_chroma_siting - chroma siting information + * @DRM_CHROMA_SITING_UNKNOWN: not specified, implementation defined result + * @DRM_CHROMA_SITING_HORZ_LEFT: horizontally co-sited with the left luma sample + * @DRM_CHROMA_SITING_HORZ_CENTER: horizontally interstitially sited with luma samples + * @DRM_CHROMA_SITING_VERT_TOP: vertically co-sited with the top luma sample + * @DRM_CHROMA_SITING_VERT_CENTER: vertically interstitially sited with luma samples + * @DRM_CHROMA_SITING_MISALIGNED_PLANES: chroma planes out of phase with each other by 0.5 lines + * @DRM_CHROMA_SITING_MPEG1: chroma siting convention used in MPEG1 + * @DRM_CHROMA_SITING_MPEG2: chroma siting convention used in MPEG2 + * @DRM_CHROMA_SITING_DV: chroma siting convention used in DV + */ +enum drm_chroma_siting { + DRM_CHROMA_SITING_UNKNOWN = 0x0, + + DRM_CHROMA_SITING_HORZ_LEFT = 0x1, + DRM_CHROMA_SITING_HORZ_CENTER = 0x2, + + DRM_CHROMA_SITING_VERT_TOP = 0x4, + DRM_CHROMA_SITING_VERT_CENTER = 0x8, + + DRM_CHROMA_SITING_MISALIGNED_PLANES = 0x10, + + /* typical configurations */ + DRM_CHROMA_SITING_MPEG1 = DRM_CHROMA_SITING_HORZ_CENTER | DRM_CHROMA_SITING_VERT_CENTER, + DRM_CHROMA_SITING_MPEG2 = DRM_CHROMA_SITING_HORZ_LEFT | DRM_CHROMA_SITING_VERT_CENTER, + DRM_CHROMA_SITING_DV = DRM_CHROMA_SITING_HORZ_LEFT | DRM_CHROMA_SITING_VERT_TOP | DRM_CHROMA_SITING_MISALIGNED_PLANES, +}; + #endif /* __DRM_CRTC_H__ */ diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index e23aa02..7541f96 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -182,4 +182,9 @@ 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_chroma_phase_offsets(int *ret_xoff, int *ret_yoff, + int hsub, int vsub, + enum drm_chroma_siting chroma, + bool second_chroma_plane); + #endif
dri-devel@lists.freedesktop.org