drm/imx: IPUv3 image converter fixes and improvements
Fix image converter seam handling for 1024x1024 pixel hardware limitation at the main processing section input, improve error handling, and slightly optimize for 1:1 conversions. Add support for newly defined 32-bit RGB V4L2 pixel formats. -----BEGIN PGP SIGNATURE----- iI0EABYIADUWIQRRO6F6WdpH1R0vGibVhaclGDdiwAUCXV/+phcccC56YWJlbEBw ZW5ndXRyb25peC5kZQAKCRDVhaclGDdiwJk/AP91Z8dTyRq2gaSJqRRYqe+dkyTI SzfUKMA+nJG5ybRq4wD+MhLdbyq5MUEhg4ZDqvDjFKdXm8dO1YpBh4gkbj++gwA= =PVTc -----END PGP SIGNATURE----- Merge tag 'imx-drm-next-2019-08-23' of git://git.pengutronix.de/pza/linux into drm-next drm/imx: IPUv3 image converter fixes and improvements Fix image converter seam handling for 1024x1024 pixel hardware limitation at the main processing section input, improve error handling, and slightly optimize for 1:1 conversions. Add support for newly defined 32-bit RGB V4L2 pixel formats. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Philipp Zabel <p.zabel@pengutronix.de> Link: https://patchwork.freedesktop.org/patch/msgid/1566573659.23587.2.camel@pengutronix.de
This commit is contained in:
commit
2467d946f9
@ -8,5 +8,4 @@ obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
|
|||||||
obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
|
obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
|
||||||
obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
|
obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
|
||||||
|
|
||||||
obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
|
|
||||||
obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
|
obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
|
||||||
|
@ -113,13 +113,17 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
|
|||||||
case V4L2_PIX_FMT_NV16:
|
case V4L2_PIX_FMT_NV16:
|
||||||
case V4L2_PIX_FMT_NV61:
|
case V4L2_PIX_FMT_NV61:
|
||||||
return IPUV3_COLORSPACE_YUV;
|
return IPUV3_COLORSPACE_YUV;
|
||||||
case V4L2_PIX_FMT_XRGB32:
|
|
||||||
case V4L2_PIX_FMT_XBGR32:
|
|
||||||
case V4L2_PIX_FMT_RGB32:
|
|
||||||
case V4L2_PIX_FMT_BGR32:
|
|
||||||
case V4L2_PIX_FMT_RGB24:
|
|
||||||
case V4L2_PIX_FMT_BGR24:
|
|
||||||
case V4L2_PIX_FMT_RGB565:
|
case V4L2_PIX_FMT_RGB565:
|
||||||
|
case V4L2_PIX_FMT_BGR24:
|
||||||
|
case V4L2_PIX_FMT_RGB24:
|
||||||
|
case V4L2_PIX_FMT_ABGR32:
|
||||||
|
case V4L2_PIX_FMT_XBGR32:
|
||||||
|
case V4L2_PIX_FMT_BGRA32:
|
||||||
|
case V4L2_PIX_FMT_BGRX32:
|
||||||
|
case V4L2_PIX_FMT_RGBA32:
|
||||||
|
case V4L2_PIX_FMT_RGBX32:
|
||||||
|
case V4L2_PIX_FMT_ARGB32:
|
||||||
|
case V4L2_PIX_FMT_XRGB32:
|
||||||
return IPUV3_COLORSPACE_RGB;
|
return IPUV3_COLORSPACE_RGB;
|
||||||
default:
|
default:
|
||||||
return IPUV3_COLORSPACE_UNKNOWN;
|
return IPUV3_COLORSPACE_UNKNOWN;
|
||||||
|
@ -182,9 +182,27 @@ static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
|
|||||||
case V4L2_PIX_FMT_RGB32:
|
case V4L2_PIX_FMT_RGB32:
|
||||||
/* R G B A <=> [32:0] A:B:G:R */
|
/* R G B A <=> [32:0] A:B:G:R */
|
||||||
return DRM_FORMAT_XBGR8888;
|
return DRM_FORMAT_XBGR8888;
|
||||||
|
case V4L2_PIX_FMT_ABGR32:
|
||||||
|
/* B G R A <=> [32:0] A:R:G:B */
|
||||||
|
return DRM_FORMAT_ARGB8888;
|
||||||
case V4L2_PIX_FMT_XBGR32:
|
case V4L2_PIX_FMT_XBGR32:
|
||||||
/* B G R X <=> [32:0] X:R:G:B */
|
/* B G R X <=> [32:0] X:R:G:B */
|
||||||
return DRM_FORMAT_XRGB8888;
|
return DRM_FORMAT_XRGB8888;
|
||||||
|
case V4L2_PIX_FMT_BGRA32:
|
||||||
|
/* A B G R <=> [32:0] R:G:B:A */
|
||||||
|
return DRM_FORMAT_RGBA8888;
|
||||||
|
case V4L2_PIX_FMT_BGRX32:
|
||||||
|
/* X B G R <=> [32:0] R:G:B:X */
|
||||||
|
return DRM_FORMAT_RGBX8888;
|
||||||
|
case V4L2_PIX_FMT_RGBA32:
|
||||||
|
/* R G B A <=> [32:0] A:B:G:R */
|
||||||
|
return DRM_FORMAT_ABGR8888;
|
||||||
|
case V4L2_PIX_FMT_RGBX32:
|
||||||
|
/* R G B X <=> [32:0] X:B:G:R */
|
||||||
|
return DRM_FORMAT_XBGR8888;
|
||||||
|
case V4L2_PIX_FMT_ARGB32:
|
||||||
|
/* A R G B <=> [32:0] B:G:R:A */
|
||||||
|
return DRM_FORMAT_BGRA8888;
|
||||||
case V4L2_PIX_FMT_XRGB32:
|
case V4L2_PIX_FMT_XRGB32:
|
||||||
/* X R G B <=> [32:0] B:G:R:X */
|
/* X R G B <=> [32:0] B:G:R:X */
|
||||||
return DRM_FORMAT_BGRX8888;
|
return DRM_FORMAT_BGRX8888;
|
||||||
@ -823,8 +841,14 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
|
|||||||
break;
|
break;
|
||||||
case V4L2_PIX_FMT_RGB32:
|
case V4L2_PIX_FMT_RGB32:
|
||||||
case V4L2_PIX_FMT_BGR32:
|
case V4L2_PIX_FMT_BGR32:
|
||||||
case V4L2_PIX_FMT_XRGB32:
|
case V4L2_PIX_FMT_ABGR32:
|
||||||
case V4L2_PIX_FMT_XBGR32:
|
case V4L2_PIX_FMT_XBGR32:
|
||||||
|
case V4L2_PIX_FMT_BGRA32:
|
||||||
|
case V4L2_PIX_FMT_BGRX32:
|
||||||
|
case V4L2_PIX_FMT_RGBA32:
|
||||||
|
case V4L2_PIX_FMT_RGBX32:
|
||||||
|
case V4L2_PIX_FMT_ARGB32:
|
||||||
|
case V4L2_PIX_FMT_XRGB32:
|
||||||
offset = image->rect.left * 4 +
|
offset = image->rect.left * 4 +
|
||||||
image->rect.top * pix->bytesperline;
|
image->rect.top * pix->bytesperline;
|
||||||
break;
|
break;
|
||||||
|
@ -251,6 +251,12 @@ static const struct ipu_image_pixfmt image_convert_formats[] = {
|
|||||||
}, {
|
}, {
|
||||||
.fourcc = V4L2_PIX_FMT_XBGR32,
|
.fourcc = V4L2_PIX_FMT_XBGR32,
|
||||||
.bpp = 32,
|
.bpp = 32,
|
||||||
|
}, {
|
||||||
|
.fourcc = V4L2_PIX_FMT_BGRX32,
|
||||||
|
.bpp = 32,
|
||||||
|
}, {
|
||||||
|
.fourcc = V4L2_PIX_FMT_RGBX32,
|
||||||
|
.bpp = 32,
|
||||||
}, {
|
}, {
|
||||||
.fourcc = V4L2_PIX_FMT_YUYV,
|
.fourcc = V4L2_PIX_FMT_YUYV,
|
||||||
.bpp = 16,
|
.bpp = 16,
|
||||||
@ -376,8 +382,11 @@ static inline int num_stripes(int dim)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate downsizing coefficients, which are the same for all tiles,
|
* Calculate downsizing coefficients, which are the same for all tiles,
|
||||||
* and bilinear resizing coefficients, which are used to find the best
|
* and initial bilinear resizing coefficients, which are used to find the
|
||||||
* seam positions.
|
* best seam positions.
|
||||||
|
* Also determine the number of tiles necessary to guarantee that no tile
|
||||||
|
* is larger than 1024 pixels in either dimension at the output and between
|
||||||
|
* IC downsizing and main processing sections.
|
||||||
*/
|
*/
|
||||||
static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
|
static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
|
||||||
struct ipu_image *in,
|
struct ipu_image *in,
|
||||||
@ -391,6 +400,8 @@ static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
|
|||||||
u32 resized_height = out->rect.height;
|
u32 resized_height = out->rect.height;
|
||||||
u32 resize_coeff_h;
|
u32 resize_coeff_h;
|
||||||
u32 resize_coeff_v;
|
u32 resize_coeff_v;
|
||||||
|
u32 cols;
|
||||||
|
u32 rows;
|
||||||
|
|
||||||
if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
|
if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
|
||||||
resized_width = out->rect.height;
|
resized_width = out->rect.height;
|
||||||
@ -401,14 +412,12 @@ static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
|
|||||||
if (WARN_ON(resized_width == 0 || resized_height == 0))
|
if (WARN_ON(resized_width == 0 || resized_height == 0))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
while (downsized_width > 1024 ||
|
while (downsized_width >= resized_width * 2) {
|
||||||
downsized_width >= resized_width * 2) {
|
|
||||||
downsized_width >>= 1;
|
downsized_width >>= 1;
|
||||||
downsize_coeff_h++;
|
downsize_coeff_h++;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (downsized_height > 1024 ||
|
while (downsized_height >= resized_height * 2) {
|
||||||
downsized_height >= resized_height * 2) {
|
|
||||||
downsized_height >>= 1;
|
downsized_height >>= 1;
|
||||||
downsize_coeff_v++;
|
downsize_coeff_v++;
|
||||||
}
|
}
|
||||||
@ -422,10 +431,18 @@ static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
|
|||||||
resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
|
resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
|
||||||
resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
|
resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Both the output of the IC downsizing section before being passed to
|
||||||
|
* the IC main processing section and the final output of the IC main
|
||||||
|
* processing section must be <= 1024 pixels in both dimensions.
|
||||||
|
*/
|
||||||
|
cols = num_stripes(max_t(u32, downsized_width, resized_width));
|
||||||
|
rows = num_stripes(max_t(u32, downsized_height, resized_height));
|
||||||
|
|
||||||
dev_dbg(ctx->chan->priv->ipu->dev,
|
dev_dbg(ctx->chan->priv->ipu->dev,
|
||||||
"%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
|
"%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
|
||||||
__func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
|
__func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
|
||||||
resize_coeff_v, ctx->in.num_cols, ctx->in.num_rows);
|
resize_coeff_v, cols, rows);
|
||||||
|
|
||||||
if (downsize_coeff_h > 2 || downsize_coeff_v > 2 ||
|
if (downsize_coeff_h > 2 || downsize_coeff_v > 2 ||
|
||||||
resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
|
resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
|
||||||
@ -435,6 +452,8 @@ static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
|
|||||||
ctx->downsize_coeff_v = downsize_coeff_v;
|
ctx->downsize_coeff_v = downsize_coeff_v;
|
||||||
ctx->image_resize_coeff_h = resize_coeff_h;
|
ctx->image_resize_coeff_h = resize_coeff_h;
|
||||||
ctx->image_resize_coeff_v = resize_coeff_v;
|
ctx->image_resize_coeff_v = resize_coeff_v;
|
||||||
|
ctx->in.num_cols = cols;
|
||||||
|
ctx->in.num_rows = rows;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -442,12 +461,10 @@ static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
|
|||||||
#define round_closest(x, y) round_down((x) + (y)/2, (y))
|
#define round_closest(x, y) round_down((x) + (y)/2, (y))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the best aligned seam position in the inverval [out_start, out_end].
|
* Find the best aligned seam position for the given column / row index.
|
||||||
* Rotation and image offsets are out of scope.
|
* Rotation and image offsets are out of scope.
|
||||||
*
|
*
|
||||||
* @out_start: start of inverval, must be within 1024 pixels / lines
|
* @index: column / row index, used to calculate valid interval
|
||||||
* of out_end
|
|
||||||
* @out_end: end of interval, smaller than or equal to out_edge
|
|
||||||
* @in_edge: input right / bottom edge
|
* @in_edge: input right / bottom edge
|
||||||
* @out_edge: output right / bottom edge
|
* @out_edge: output right / bottom edge
|
||||||
* @in_align: input alignment, either horizontal 8-byte line start address
|
* @in_align: input alignment, either horizontal 8-byte line start address
|
||||||
@ -463,8 +480,7 @@ static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
|
|||||||
* @_out_seam: aligned output seam position return value
|
* @_out_seam: aligned output seam position return value
|
||||||
*/
|
*/
|
||||||
static void find_best_seam(struct ipu_image_convert_ctx *ctx,
|
static void find_best_seam(struct ipu_image_convert_ctx *ctx,
|
||||||
unsigned int out_start,
|
unsigned int index,
|
||||||
unsigned int out_end,
|
|
||||||
unsigned int in_edge,
|
unsigned int in_edge,
|
||||||
unsigned int out_edge,
|
unsigned int out_edge,
|
||||||
unsigned int in_align,
|
unsigned int in_align,
|
||||||
@ -482,6 +498,24 @@ static void find_best_seam(struct ipu_image_convert_ctx *ctx,
|
|||||||
unsigned int out_seam = 0;
|
unsigned int out_seam = 0;
|
||||||
unsigned int in_seam = 0;
|
unsigned int in_seam = 0;
|
||||||
unsigned int min_diff = UINT_MAX;
|
unsigned int min_diff = UINT_MAX;
|
||||||
|
unsigned int out_start;
|
||||||
|
unsigned int out_end;
|
||||||
|
unsigned int in_start;
|
||||||
|
unsigned int in_end;
|
||||||
|
|
||||||
|
/* Start within 1024 pixels of the right / bottom edge */
|
||||||
|
out_start = max_t(int, index * out_align, out_edge - 1024);
|
||||||
|
/* End before having to add more columns to the left / rows above */
|
||||||
|
out_end = min_t(unsigned int, out_edge, index * 1024 + 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limit input seam position to make sure that the downsized input tile
|
||||||
|
* to the right or bottom does not exceed 1024 pixels.
|
||||||
|
*/
|
||||||
|
in_start = max_t(int, index * in_align,
|
||||||
|
in_edge - (1024 << downsize_coeff));
|
||||||
|
in_end = min_t(unsigned int, in_edge,
|
||||||
|
index * (1024 << downsize_coeff) + 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Output tiles must start at a multiple of 8 bytes horizontally and
|
* Output tiles must start at a multiple of 8 bytes horizontally and
|
||||||
@ -492,6 +526,7 @@ static void find_best_seam(struct ipu_image_convert_ctx *ctx,
|
|||||||
for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
|
for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
|
||||||
unsigned int in_pos;
|
unsigned int in_pos;
|
||||||
unsigned int in_pos_aligned;
|
unsigned int in_pos_aligned;
|
||||||
|
unsigned int in_pos_rounded;
|
||||||
unsigned int abs_diff;
|
unsigned int abs_diff;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -512,9 +547,16 @@ static void find_best_seam(struct ipu_image_convert_ctx *ctx,
|
|||||||
* start the input tile at, 19.13 fixed point.
|
* start the input tile at, 19.13 fixed point.
|
||||||
*/
|
*/
|
||||||
in_pos_aligned = round_closest(in_pos, 8192U * in_align);
|
in_pos_aligned = round_closest(in_pos, 8192U * in_align);
|
||||||
|
/* Convert 19.13 fixed point to integer */
|
||||||
|
in_pos_rounded = in_pos_aligned / 8192U;
|
||||||
|
|
||||||
|
if (in_pos_rounded < in_start)
|
||||||
|
continue;
|
||||||
|
if (in_pos_rounded >= in_end)
|
||||||
|
break;
|
||||||
|
|
||||||
if ((in_burst > 1) &&
|
if ((in_burst > 1) &&
|
||||||
(in_edge - in_pos_aligned / 8192U) % in_burst)
|
(in_edge - in_pos_rounded) % in_burst)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (in_pos < in_pos_aligned)
|
if (in_pos < in_pos_aligned)
|
||||||
@ -523,19 +565,18 @@ static void find_best_seam(struct ipu_image_convert_ctx *ctx,
|
|||||||
abs_diff = in_pos - in_pos_aligned;
|
abs_diff = in_pos - in_pos_aligned;
|
||||||
|
|
||||||
if (abs_diff < min_diff) {
|
if (abs_diff < min_diff) {
|
||||||
in_seam = in_pos_aligned;
|
in_seam = in_pos_rounded;
|
||||||
out_seam = out_pos;
|
out_seam = out_pos;
|
||||||
min_diff = abs_diff;
|
min_diff = abs_diff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*_out_seam = out_seam;
|
*_out_seam = out_seam;
|
||||||
/* Convert 19.13 fixed point to integer seam position */
|
*_in_seam = in_seam;
|
||||||
*_in_seam = DIV_ROUND_CLOSEST(in_seam, 8192U);
|
|
||||||
|
|
||||||
dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) diff %u.%03u\n",
|
dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) in [%u, %u] diff %u.%03u\n",
|
||||||
__func__, out_seam, out_align, out_start, out_end,
|
__func__, out_seam, out_align, out_start, out_end,
|
||||||
*_in_seam, in_align, min_diff / 8192,
|
in_seam, in_align, in_start, in_end, min_diff / 8192,
|
||||||
DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
|
DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,8 +753,6 @@ static void find_seams(struct ipu_image_convert_ctx *ctx,
|
|||||||
!(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
|
!(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
|
||||||
bool allow_out_overshoot = (col < in->num_cols - 1) &&
|
bool allow_out_overshoot = (col < in->num_cols - 1) &&
|
||||||
!(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
|
!(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
|
||||||
unsigned int out_start;
|
|
||||||
unsigned int out_end;
|
|
||||||
unsigned int in_left;
|
unsigned int in_left;
|
||||||
unsigned int out_left;
|
unsigned int out_left;
|
||||||
|
|
||||||
@ -722,12 +761,7 @@ static void find_seams(struct ipu_image_convert_ctx *ctx,
|
|||||||
* horizontally.
|
* horizontally.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Start within 1024 pixels of the right edge */
|
find_best_seam(ctx, col,
|
||||||
out_start = max_t(int, 0, out_right - 1024);
|
|
||||||
/* End before having to add more columns to the left */
|
|
||||||
out_end = min_t(unsigned int, out_right, col * 1024);
|
|
||||||
|
|
||||||
find_best_seam(ctx, out_start, out_end,
|
|
||||||
in_right, out_right,
|
in_right, out_right,
|
||||||
in_left_align, out_left_align,
|
in_left_align, out_left_align,
|
||||||
allow_in_overshoot ? 1 : 8 /* burst length */,
|
allow_in_overshoot ? 1 : 8 /* burst length */,
|
||||||
@ -762,17 +796,10 @@ static void find_seams(struct ipu_image_convert_ctx *ctx,
|
|||||||
|
|
||||||
for (row = in->num_rows - 1; row > 0; row--) {
|
for (row = in->num_rows - 1; row > 0; row--) {
|
||||||
bool allow_overshoot = row < in->num_rows - 1;
|
bool allow_overshoot = row < in->num_rows - 1;
|
||||||
unsigned int out_start;
|
|
||||||
unsigned int out_end;
|
|
||||||
unsigned int in_top;
|
unsigned int in_top;
|
||||||
unsigned int out_top;
|
unsigned int out_top;
|
||||||
|
|
||||||
/* Start within 1024 lines of the bottom edge */
|
find_best_seam(ctx, row,
|
||||||
out_start = max_t(int, 0, out_bottom - 1024);
|
|
||||||
/* End before having to add more rows above */
|
|
||||||
out_end = min_t(unsigned int, out_bottom, row * 1024);
|
|
||||||
|
|
||||||
find_best_seam(ctx, out_start, out_end,
|
|
||||||
in_bottom, out_bottom,
|
in_bottom, out_bottom,
|
||||||
in_top_align, out_top_align,
|
in_top_align, out_top_align,
|
||||||
1, allow_overshoot ? 1 : out_height_align,
|
1, allow_overshoot ? 1 : out_height_align,
|
||||||
@ -809,13 +836,21 @@ static void find_seams(struct ipu_image_convert_ctx *ctx,
|
|||||||
in_bottom, flipped_out_top, out_bottom);
|
in_bottom, flipped_out_top, out_bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
|
static int calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
|
||||||
struct ipu_image_convert_image *image)
|
struct ipu_image_convert_image *image)
|
||||||
{
|
{
|
||||||
struct ipu_image_convert_chan *chan = ctx->chan;
|
struct ipu_image_convert_chan *chan = ctx->chan;
|
||||||
struct ipu_image_convert_priv *priv = chan->priv;
|
struct ipu_image_convert_priv *priv = chan->priv;
|
||||||
|
unsigned int max_width = 1024;
|
||||||
|
unsigned int max_height = 1024;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
if (image->type == IMAGE_CONVERT_IN) {
|
||||||
|
/* Up to 4096x4096 input tile size */
|
||||||
|
max_width <<= ctx->downsize_coeff_h;
|
||||||
|
max_height <<= ctx->downsize_coeff_v;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < ctx->num_tiles; i++) {
|
for (i = 0; i < ctx->num_tiles; i++) {
|
||||||
struct ipu_image_tile *tile;
|
struct ipu_image_tile *tile;
|
||||||
const unsigned int row = i / image->num_cols;
|
const unsigned int row = i / image->num_cols;
|
||||||
@ -845,7 +880,17 @@ static void calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
|
|||||||
image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
|
image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
|
||||||
row, col,
|
row, col,
|
||||||
tile->width, tile->height, tile->left, tile->top);
|
tile->width, tile->height, tile->left, tile->top);
|
||||||
|
|
||||||
|
if (!tile->width || tile->width > max_width ||
|
||||||
|
!tile->height || tile->height > max_height) {
|
||||||
|
dev_err(priv->ipu->dev, "invalid %s tile size: %ux%u\n",
|
||||||
|
image->type == IMAGE_CONVERT_IN ? "input" :
|
||||||
|
"output", tile->width, tile->height);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1076,6 +1121,7 @@ static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
|
|||||||
!(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
|
!(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
|
||||||
u32 resized_width;
|
u32 resized_width;
|
||||||
u32 resize_coeff_h;
|
u32 resize_coeff_h;
|
||||||
|
u32 in_width;
|
||||||
|
|
||||||
tile_idx = col;
|
tile_idx = col;
|
||||||
in_tile = &ctx->in.tile[tile_idx];
|
in_tile = &ctx->in.tile[tile_idx];
|
||||||
@ -1093,33 +1139,35 @@ static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
|
|||||||
dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
|
dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
|
||||||
__func__, col, resize_coeff_h);
|
__func__, col, resize_coeff_h);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With the horizontal scaling factor known, round up resized
|
||||||
|
* width (output width or height) to burst size.
|
||||||
|
*/
|
||||||
|
resized_width = round_up(resized_width, 8);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate input width from the last accessed input pixel
|
||||||
|
* given resized width and scaling coefficients. Round up to
|
||||||
|
* burst size.
|
||||||
|
*/
|
||||||
|
last_output = resized_width - 1;
|
||||||
|
if (closest && ((last_output * resize_coeff_h) % 8192))
|
||||||
|
last_output++;
|
||||||
|
in_width = round_up(
|
||||||
|
(DIV_ROUND_UP(last_output * resize_coeff_h, 8192) + 1)
|
||||||
|
<< ctx->downsize_coeff_h, 8);
|
||||||
|
|
||||||
for (row = 0; row < ctx->in.num_rows; row++) {
|
for (row = 0; row < ctx->in.num_rows; row++) {
|
||||||
tile_idx = row * ctx->in.num_cols + col;
|
tile_idx = row * ctx->in.num_cols + col;
|
||||||
in_tile = &ctx->in.tile[tile_idx];
|
in_tile = &ctx->in.tile[tile_idx];
|
||||||
out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
|
out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
|
||||||
|
|
||||||
/*
|
|
||||||
* With the horizontal scaling factor known, round up
|
|
||||||
* resized width (output width or height) to burst size.
|
|
||||||
*/
|
|
||||||
if (ipu_rot_mode_is_irt(ctx->rot_mode))
|
if (ipu_rot_mode_is_irt(ctx->rot_mode))
|
||||||
out_tile->height = round_up(resized_width, 8);
|
out_tile->height = resized_width;
|
||||||
else
|
else
|
||||||
out_tile->width = round_up(resized_width, 8);
|
out_tile->width = resized_width;
|
||||||
|
|
||||||
/*
|
in_tile->width = in_width;
|
||||||
* Calculate input width from the last accessed input
|
|
||||||
* pixel given resized width and scaling coefficients.
|
|
||||||
* Round up to burst size.
|
|
||||||
*/
|
|
||||||
last_output = round_up(resized_width, 8) - 1;
|
|
||||||
if (closest)
|
|
||||||
last_output++;
|
|
||||||
in_tile->width = round_up(
|
|
||||||
(DIV_ROUND_UP(last_output * resize_coeff_h,
|
|
||||||
8192) + 1)
|
|
||||||
<< ctx->downsize_coeff_h, 8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->resize_coeffs_h[col] = resize_coeff_h;
|
ctx->resize_coeffs_h[col] = resize_coeff_h;
|
||||||
@ -1130,6 +1178,7 @@ static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
|
|||||||
!(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
|
!(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
|
||||||
u32 resized_height;
|
u32 resized_height;
|
||||||
u32 resize_coeff_v;
|
u32 resize_coeff_v;
|
||||||
|
u32 in_height;
|
||||||
|
|
||||||
tile_idx = row * ctx->in.num_cols;
|
tile_idx = row * ctx->in.num_cols;
|
||||||
in_tile = &ctx->in.tile[tile_idx];
|
in_tile = &ctx->in.tile[tile_idx];
|
||||||
@ -1147,33 +1196,35 @@ static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
|
|||||||
dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
|
dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
|
||||||
__func__, row, resize_coeff_v);
|
__func__, row, resize_coeff_v);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With the vertical scaling factor known, round up resized
|
||||||
|
* height (output width or height) to IDMAC limitations.
|
||||||
|
*/
|
||||||
|
resized_height = round_up(resized_height, 2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate input width from the last accessed input pixel
|
||||||
|
* given resized height and scaling coefficients. Align to
|
||||||
|
* IDMAC restrictions.
|
||||||
|
*/
|
||||||
|
last_output = resized_height - 1;
|
||||||
|
if (closest && ((last_output * resize_coeff_v) % 8192))
|
||||||
|
last_output++;
|
||||||
|
in_height = round_up(
|
||||||
|
(DIV_ROUND_UP(last_output * resize_coeff_v, 8192) + 1)
|
||||||
|
<< ctx->downsize_coeff_v, 2);
|
||||||
|
|
||||||
for (col = 0; col < ctx->in.num_cols; col++) {
|
for (col = 0; col < ctx->in.num_cols; col++) {
|
||||||
tile_idx = row * ctx->in.num_cols + col;
|
tile_idx = row * ctx->in.num_cols + col;
|
||||||
in_tile = &ctx->in.tile[tile_idx];
|
in_tile = &ctx->in.tile[tile_idx];
|
||||||
out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
|
out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
|
||||||
|
|
||||||
/*
|
|
||||||
* With the vertical scaling factor known, round up
|
|
||||||
* resized height (output width or height) to IDMAC
|
|
||||||
* limitations.
|
|
||||||
*/
|
|
||||||
if (ipu_rot_mode_is_irt(ctx->rot_mode))
|
if (ipu_rot_mode_is_irt(ctx->rot_mode))
|
||||||
out_tile->width = round_up(resized_height, 2);
|
out_tile->width = resized_height;
|
||||||
else
|
else
|
||||||
out_tile->height = round_up(resized_height, 2);
|
out_tile->height = resized_height;
|
||||||
|
|
||||||
/*
|
in_tile->height = in_height;
|
||||||
* Calculate input width from the last accessed input
|
|
||||||
* pixel given resized height and scaling coefficients.
|
|
||||||
* Align to IDMAC restrictions.
|
|
||||||
*/
|
|
||||||
last_output = round_up(resized_height, 2) - 1;
|
|
||||||
if (closest)
|
|
||||||
last_output++;
|
|
||||||
in_tile->height = round_up(
|
|
||||||
(DIV_ROUND_UP(last_output * resize_coeff_v,
|
|
||||||
8192) + 1)
|
|
||||||
<< ctx->downsize_coeff_v, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->resize_coeffs_v[row] = resize_coeff_v;
|
ctx->resize_coeffs_v[row] = resize_coeff_v;
|
||||||
@ -2024,22 +2075,26 @@ ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
|
|||||||
ctx->chan = chan;
|
ctx->chan = chan;
|
||||||
init_completion(&ctx->aborted);
|
init_completion(&ctx->aborted);
|
||||||
|
|
||||||
|
ctx->rot_mode = rot_mode;
|
||||||
|
|
||||||
|
/* Sets ctx->in.num_rows/cols as well */
|
||||||
|
ret = calc_image_resize_coefficients(ctx, in, out);
|
||||||
|
if (ret)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
s_image = &ctx->in;
|
s_image = &ctx->in;
|
||||||
d_image = &ctx->out;
|
d_image = &ctx->out;
|
||||||
|
|
||||||
/* set tiling and rotation */
|
/* set tiling and rotation */
|
||||||
d_image->num_rows = num_stripes(out->pix.height);
|
|
||||||
d_image->num_cols = num_stripes(out->pix.width);
|
|
||||||
if (ipu_rot_mode_is_irt(rot_mode)) {
|
if (ipu_rot_mode_is_irt(rot_mode)) {
|
||||||
s_image->num_rows = d_image->num_cols;
|
d_image->num_rows = s_image->num_cols;
|
||||||
s_image->num_cols = d_image->num_rows;
|
d_image->num_cols = s_image->num_rows;
|
||||||
} else {
|
} else {
|
||||||
s_image->num_rows = d_image->num_rows;
|
d_image->num_rows = s_image->num_rows;
|
||||||
s_image->num_cols = d_image->num_cols;
|
d_image->num_cols = s_image->num_cols;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->num_tiles = d_image->num_cols * d_image->num_rows;
|
ctx->num_tiles = d_image->num_cols * d_image->num_rows;
|
||||||
ctx->rot_mode = rot_mode;
|
|
||||||
|
|
||||||
ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
|
ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -2048,15 +2103,14 @@ ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
ret = calc_image_resize_coefficients(ctx, in, out);
|
|
||||||
if (ret)
|
|
||||||
goto out_free;
|
|
||||||
|
|
||||||
calc_out_tile_map(ctx);
|
calc_out_tile_map(ctx);
|
||||||
|
|
||||||
find_seams(ctx, s_image, d_image);
|
find_seams(ctx, s_image, d_image);
|
||||||
|
|
||||||
calc_tile_dimensions(ctx, s_image);
|
ret = calc_tile_dimensions(ctx, s_image);
|
||||||
|
if (ret)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
ret = calc_tile_offsets(ctx, s_image);
|
ret = calc_tile_offsets(ctx, s_image);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
Loading…
Reference in New Issue
Block a user