Commit 9991deff authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] vivid-tpg: add helper functions to simplify common calculations

Add helper functions to handle horizontal downscaling and horizontal
scaling.
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent 51f30968
...@@ -183,6 +183,9 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) ...@@ -183,6 +183,9 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
tpg->recalc_colors = true; tpg->recalc_colors = true;
tpg->vdownsampling[0] = 1; tpg->vdownsampling[0] = 1;
tpg->hdownsampling[0] = 1; tpg->hdownsampling[0] = 1;
tpg->hmask[0] = ~0;
tpg->hmask[1] = ~0;
tpg->hmask[2] = ~0;
switch (fourcc) { switch (fourcc) {
case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565:
...@@ -231,6 +234,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) ...@@ -231,6 +234,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV61:
tpg->vdownsampling[1] = 1; tpg->vdownsampling[1] = 1;
tpg->hdownsampling[1] = 1; tpg->hdownsampling[1] = 1;
tpg->hmask[1] = ~1;
tpg->planes = 2; tpg->planes = 2;
tpg->is_yuv = true; tpg->is_yuv = true;
break; break;
...@@ -242,6 +246,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) ...@@ -242,6 +246,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV21:
tpg->vdownsampling[1] = 2; tpg->vdownsampling[1] = 2;
tpg->hdownsampling[1] = 1; tpg->hdownsampling[1] = 1;
tpg->hmask[1] = ~1;
tpg->planes = 2; tpg->planes = 2;
tpg->is_yuv = true; tpg->is_yuv = true;
break; break;
...@@ -249,6 +254,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) ...@@ -249,6 +254,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_VYUY:
tpg->hmask[0] = ~1;
tpg->is_yuv = true; tpg->is_yuv = true;
break; break;
default: default:
...@@ -1116,6 +1122,7 @@ static void tpg_calculate_square_border(struct tpg_data *tpg) ...@@ -1116,6 +1122,7 @@ static void tpg_calculate_square_border(struct tpg_data *tpg)
static void tpg_precalculate_line(struct tpg_data *tpg) static void tpg_precalculate_line(struct tpg_data *tpg)
{ {
enum tpg_color contrast; enum tpg_color contrast;
u8 pix[TPG_MAX_PLANES][8];
unsigned pat; unsigned pat;
unsigned p; unsigned p;
unsigned x; unsigned x;
...@@ -1142,7 +1149,6 @@ static void tpg_precalculate_line(struct tpg_data *tpg) ...@@ -1142,7 +1149,6 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
for (x = 0; x < tpg->scaled_width * 2; x += 2) { for (x = 0; x < tpg->scaled_width * 2; x += 2) {
unsigned real_x = src_x; unsigned real_x = src_x;
enum tpg_color color1, color2; enum tpg_color color1, color2;
u8 pix[TPG_MAX_PLANES][8];
real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x; real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
color1 = tpg_get_color(tpg, pat, real_x); color1 = tpg_get_color(tpg, pat, real_x);
...@@ -1170,8 +1176,7 @@ static void tpg_precalculate_line(struct tpg_data *tpg) ...@@ -1170,8 +1176,7 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
for (p = 0; p < tpg->planes; p++) { for (p = 0; p < tpg->planes; p++) {
unsigned twopixsize = tpg->twopixelsize[p]; unsigned twopixsize = tpg->twopixelsize[p];
unsigned hdiv = tpg->hdownsampling[p]; unsigned hdiv = tpg->hdownsampling[p];
u8 *pos = tpg->lines[pat][p] + u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
(x / hdiv) * twopixsize / 2;
memcpy(pos, pix[p], twopixsize / hdiv); memcpy(pos, pix[p], twopixsize / hdiv);
} }
...@@ -1185,50 +1190,38 @@ static void tpg_precalculate_line(struct tpg_data *tpg) ...@@ -1185,50 +1190,38 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
unsigned next_pat = (pat + 1) % pat_lines; unsigned next_pat = (pat + 1) % pat_lines;
for (p = 1; p < tpg->planes; p++) { for (p = 1; p < tpg->planes; p++) {
unsigned twopixsize = tpg->twopixelsize[p]; unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
unsigned hdiv = tpg->hdownsampling[p]; u8 *pos1 = tpg->lines[pat][p];
u8 *pos2 = tpg->lines[next_pat][p];
for (x = 0; x < tpg->scaled_width * 2; x += 2) { u8 *dest = tpg->downsampled_lines[pat][p];
unsigned offset = (x / hdiv) * twopixsize / 2;
u8 *pos1 = tpg->lines[pat][p] + offset;
u8 *pos2 = tpg->lines[next_pat][p] + offset;
u8 *dest = tpg->downsampled_lines[pat][p] + offset;
unsigned i;
for (i = 0; i < twopixsize / hdiv; i++, dest++, pos1++, pos2++) for (x = 0; x < w; x++, pos1++, pos2++, dest++)
*dest = ((u16)*pos1 + (u16)*pos2) / 2; *dest = ((u16)*pos1 + (u16)*pos2) / 2;
}
} }
} }
} }
for (x = 0; x < tpg->scaled_width; x += 2) { gen_twopix(tpg, pix, contrast, 0);
u8 pix[TPG_MAX_PLANES][8]; gen_twopix(tpg, pix, contrast, 1);
for (p = 0; p < tpg->planes; p++) {
gen_twopix(tpg, pix, contrast, 0); unsigned twopixsize = tpg->twopixelsize[p];
gen_twopix(tpg, pix, contrast, 1); u8 *pos = tpg->contrast_line[p];
for (p = 0; p < tpg->planes; p++) {
unsigned twopixsize = tpg->twopixelsize[p];
u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2;
for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
memcpy(pos, pix[p], twopixsize); memcpy(pos, pix[p], twopixsize);
}
} }
for (x = 0; x < tpg->scaled_width; x += 2) {
u8 pix[TPG_MAX_PLANES][8];
gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0); gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1); gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
for (p = 0; p < tpg->planes; p++) { for (p = 0; p < tpg->planes; p++) {
unsigned twopixsize = tpg->twopixelsize[p]; unsigned twopixsize = tpg->twopixelsize[p];
u8 *pos = tpg->black_line[p] + x * twopixsize / 2; u8 *pos = tpg->black_line[p];
for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
memcpy(pos, pix[p], twopixsize); memcpy(pos, pix[p], twopixsize);
}
} }
for (x = 0; x < tpg->scaled_width * 2; x += 2) {
u8 pix[TPG_MAX_PLANES][8];
for (x = 0; x < tpg->scaled_width * 2; x += 2) {
gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0); gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1); gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
for (p = 0; p < tpg->planes; p++) { for (p = 0; p < tpg->planes; p++) {
...@@ -1238,6 +1231,7 @@ static void tpg_precalculate_line(struct tpg_data *tpg) ...@@ -1238,6 +1231,7 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
memcpy(pos, pix[p], twopixsize); memcpy(pos, pix[p], twopixsize);
} }
} }
gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0); gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1); gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0); gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
...@@ -1533,9 +1527,8 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 ...@@ -1533,9 +1527,8 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8
int hmax = (tpg->compose.height * tpg->perc_fill) / 100; int hmax = (tpg->compose.height * tpg->perc_fill) / 100;
int h; int h;
unsigned twopixsize = tpg->twopixelsize[p]; unsigned twopixsize = tpg->twopixelsize[p];
unsigned hdiv = tpg->hdownsampling[p];
unsigned vdiv = tpg->vdownsampling[p]; unsigned vdiv = tpg->vdownsampling[p];
unsigned img_width = (tpg->compose.width / hdiv) * twopixsize / 2; unsigned img_width = tpg_hdiv(tpg, p, tpg->compose.width);
unsigned line_offset; unsigned line_offset;
unsigned left_pillar_width = 0; unsigned left_pillar_width = 0;
unsigned right_pillar_start = img_width; unsigned right_pillar_start = img_width;
...@@ -1551,28 +1544,25 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 ...@@ -1551,28 +1544,25 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8
tpg_recalc(tpg); tpg_recalc(tpg);
mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1; mv_hor_old = tpg_hscale_div(tpg, p, mv_hor_old);
mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1; mv_hor_new = tpg_hscale_div(tpg, p, mv_hor_new);
wss_width = tpg->crop.left < tpg->src_width / 2 ? wss_width = tpg->crop.left < tpg->src_width / 2 ?
tpg->src_width / 2 - tpg->crop.left : 0; tpg->src_width / 2 - tpg->crop.left : 0;
if (wss_width > tpg->crop.width) if (wss_width > tpg->crop.width)
wss_width = tpg->crop.width; wss_width = tpg->crop.width;
wss_width = wss_width * tpg->scaled_width / tpg->src_width; wss_width = tpg_hscale_div(tpg, p, wss_width);
vbuf += tpg->compose.left * twopixsize / 2; vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width; line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
line_offset = ((line_offset & ~1) / hdiv) * twopixsize / 2;
if (tpg->crop.left < tpg->border.left) { if (tpg->crop.left < tpg->border.left) {
left_pillar_width = tpg->border.left - tpg->crop.left; left_pillar_width = tpg->border.left - tpg->crop.left;
if (left_pillar_width > tpg->crop.width) if (left_pillar_width > tpg->crop.width)
left_pillar_width = tpg->crop.width; left_pillar_width = tpg->crop.width;
left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width; left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
left_pillar_width = ((left_pillar_width & ~1) / hdiv) * twopixsize / 2;
} }
if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) { if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left; right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width; right_pillar_start = tpg_hscale_div(tpg, p, right_pillar_start);
right_pillar_start = ((right_pillar_start & ~1) / hdiv) * twopixsize / 2;
if (right_pillar_start > img_width) if (right_pillar_start > img_width)
right_pillar_start = img_width; right_pillar_start = img_width;
} }
...@@ -1655,10 +1645,8 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 ...@@ -1655,10 +1645,8 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8
pat_line_old = tpg_get_pat_line(tpg, frame_line_old); pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
pat_line_new = tpg_get_pat_line(tpg, frame_line_new); pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
linestart_older = tpg->lines[pat_line_old][p] + linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
(mv_hor_old / hdiv) * twopixsize / 2; linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
linestart_newer = tpg->lines[pat_line_new][p] +
(mv_hor_new / hdiv) * twopixsize / 2;
if (vdiv > 1) { if (vdiv > 1) {
unsigned frame_line_next; unsigned frame_line_next;
...@@ -1683,8 +1671,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 ...@@ -1683,8 +1671,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8
avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new); avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
if (avg_pat < 0) if (avg_pat < 0)
break; break;
linestart_older = tpg->downsampled_lines[avg_pat][p] + linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
(mv_hor_old / hdiv) * twopixsize / 2;
linestart_newer = linestart_older; linestart_newer = linestart_older;
break; break;
case V4L2_FIELD_NONE: case V4L2_FIELD_NONE:
...@@ -1695,11 +1682,11 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 ...@@ -1695,11 +1682,11 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8
avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old); avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
if (avg_pat >= 0) if (avg_pat >= 0)
linestart_older = tpg->downsampled_lines[avg_pat][p] + linestart_older = tpg->downsampled_lines[avg_pat][p] +
(mv_hor_old / hdiv) * twopixsize / 2; mv_hor_old;
avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new); avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
if (avg_pat >= 0) if (avg_pat >= 0)
linestart_newer = tpg->downsampled_lines[avg_pat][p] + linestart_newer = tpg->downsampled_lines[avg_pat][p] +
(mv_hor_new / hdiv) * twopixsize / 2; mv_hor_new;
break; break;
} }
} }
...@@ -1743,22 +1730,10 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 ...@@ -1743,22 +1730,10 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8
memcpy(vbuf + buf_line * stride, linestart_older, img_width); memcpy(vbuf + buf_line * stride, linestart_older, img_width);
break; break;
} }
if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
/*
* Replace the first half of the top line of a 50 Hz frame
* with random data to simulate a WSS signal.
*/
u8 *wss = tpg->random_line[p] +
twopixsize * prandom_u32_max(tpg->src_width / 2);
memcpy(vbuf + buf_line * stride, wss,
(wss_width / hdiv) * twopixsize / 2);
}
} }
vbuf = orig_vbuf; vbuf = orig_vbuf;
vbuf += (tpg->compose.left / hdiv) * twopixsize / 2; vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
src_y = 0; src_y = 0;
error = 0; error = 0;
for (h = 0; h < tpg->compose.height; h++) { for (h = 0; h < tpg->compose.height; h++) {
...@@ -1781,6 +1756,17 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 ...@@ -1781,6 +1756,17 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8
buf_line /= vdiv; buf_line /= vdiv;
} }
if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
/*
* Replace the first half of the top line of a 50 Hz frame
* with random data to simulate a WSS signal.
*/
u8 *wss = tpg->random_line[p] +
twopixsize * prandom_u32_max(tpg->src_width / 2);
memcpy(vbuf + buf_line * stride, wss, wss_width);
}
if (tpg->show_border && frame_line >= b->top && if (tpg->show_border && frame_line >= b->top &&
frame_line < b->top + b->height) { frame_line < b->top + b->height) {
unsigned bottom = b->top + b->height - 1; unsigned bottom = b->top + b->height - 1;
...@@ -1822,14 +1808,12 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 ...@@ -1822,14 +1808,12 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8
if (c->left + c->width < left + width) if (c->left + c->width < left + width)
width -= left + width - c->left - c->width; width -= left + width - c->left - c->width;
left -= c->left; left -= c->left;
left = (left * tpg->scaled_width) / tpg->src_width; left = tpg_hscale_div(tpg, p, left);
left = ((left & ~1) / hdiv) * twopixsize / 2; width = tpg_hscale_div(tpg, p, width);
width = (width * tpg->scaled_width) / tpg->src_width;
width = ((width & ~1) / hdiv) * twopixsize / 2;
memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width); memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
} }
if (tpg->insert_sav) { if (tpg->insert_sav) {
unsigned offset = (tpg->compose.width / (6 * hdiv)) * twopixsize; unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
u8 *p = vbuf + buf_line * stride + offset; u8 *p = vbuf + buf_line * stride + offset;
unsigned vact = 0, hact = 0; unsigned vact = 0, hact = 0;
...@@ -1843,7 +1827,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 ...@@ -1843,7 +1827,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8
(hact ^ vact ^ f); (hact ^ vact ^ f);
} }
if (tpg->insert_eav) { if (tpg->insert_eav) {
unsigned offset = (tpg->compose.width / (6 * hdiv)) * 2 * twopixsize; unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
u8 *p = vbuf + buf_line * stride + offset; u8 *p = vbuf + buf_line * stride + offset;
unsigned vact = 0, hact = 1; unsigned vact = 0, hact = 1;
......
...@@ -142,6 +142,11 @@ struct tpg_data { ...@@ -142,6 +142,11 @@ struct tpg_data {
unsigned planes; unsigned planes;
u8 vdownsampling[TPG_MAX_PLANES]; u8 vdownsampling[TPG_MAX_PLANES];
u8 hdownsampling[TPG_MAX_PLANES]; u8 hdownsampling[TPG_MAX_PLANES];
/*
* horizontal positions must be ANDed with this value to enforce
* correct boundaries for packed YUYV values.
*/
unsigned hmask[TPG_MAX_PLANES];
/* Used to store the colors in native format, either RGB or YUV */ /* Used to store the colors in native format, either RGB or YUV */
u8 colors[TPG_COLOR_MAX][3]; u8 colors[TPG_COLOR_MAX][3];
u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8]; u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8];
...@@ -347,6 +352,24 @@ static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned p ...@@ -347,6 +352,24 @@ static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned p
return tpg->twopixelsize[plane]; return tpg->twopixelsize[plane];
} }
static inline unsigned tpg_hdiv(const struct tpg_data *tpg,
unsigned plane, unsigned x)
{
return ((x / tpg->hdownsampling[plane]) & tpg->hmask[plane]) *
tpg->twopixelsize[plane] / 2;
}
static inline unsigned tpg_hscale(const struct tpg_data *tpg, unsigned x)
{
return (x * tpg->scaled_width) / tpg->src_width;
}
static inline unsigned tpg_hscale_div(const struct tpg_data *tpg,
unsigned plane, unsigned x)
{
return tpg_hdiv(tpg, plane, tpg_hscale(tpg, x));
}
static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane) static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane)
{ {
return tpg->bytesperline[plane]; return tpg->bytesperline[plane];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment