Commit 0d066d3f authored by Tomasz Stanislawski's avatar Tomasz Stanislawski Committed by Mauro Carvalho Chehab

[media] v4l: s5p-tv: mixer: add support for selection API

This patch add support for V4L2 selection API to s5p-tv driver.  Moreover it
removes old API for cropping.  Old applications would still work because the
crop ioctls are emulated using the selection API.
Signed-off-by: default avatarTomasz Stanislawski <t.stanislaws@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 992efeff
...@@ -86,6 +86,17 @@ struct mxr_crop { ...@@ -86,6 +86,17 @@ struct mxr_crop {
unsigned int field; unsigned int field;
}; };
/** stages of geometry operations */
enum mxr_geometry_stage {
MXR_GEOMETRY_SINK,
MXR_GEOMETRY_COMPOSE,
MXR_GEOMETRY_CROP,
MXR_GEOMETRY_SOURCE,
};
/* flag indicating that offset should be 0 */
#define MXR_NO_OFFSET 0x80000000
/** description of transformation from source to destination image */ /** description of transformation from source to destination image */
struct mxr_geometry { struct mxr_geometry {
/** cropping for source image */ /** cropping for source image */
...@@ -133,7 +144,8 @@ struct mxr_layer_ops { ...@@ -133,7 +144,8 @@ struct mxr_layer_ops {
/** streaming stop/start */ /** streaming stop/start */
void (*stream_set)(struct mxr_layer *, int); void (*stream_set)(struct mxr_layer *, int);
/** adjusting geometry */ /** adjusting geometry */
void (*fix_geometry)(struct mxr_layer *); void (*fix_geometry)(struct mxr_layer *,
enum mxr_geometry_stage, unsigned long);
}; };
/** layer instance, a single window and content displayed on output */ /** layer instance, a single window and content displayed on output */
......
...@@ -101,47 +101,132 @@ static void mxr_graph_format_set(struct mxr_layer *layer) ...@@ -101,47 +101,132 @@ static void mxr_graph_format_set(struct mxr_layer *layer)
layer->fmt, &layer->geo); layer->fmt, &layer->geo);
} }
static void mxr_graph_fix_geometry(struct mxr_layer *layer) static inline unsigned int closest(unsigned int x, unsigned int a,
unsigned int b, unsigned long flags)
{
unsigned int mid = (a + b) / 2;
/* choosing closest value with constraints according to table:
* -------------+-----+-----+-----+-------+
* flags | 0 | LE | GE | LE|GE |
* -------------+-----+-----+-----+-------+
* x <= a | a | a | a | a |
* a < x <= mid | a | a | b | a |
* mid < x < b | b | a | b | b |
* b <= x | b | b | b | b |
* -------------+-----+-----+-----+-------+
*/
/* remove all non-constraint flags */
flags &= V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE;
if (x <= a)
return a;
if (x >= b)
return b;
if (flags == V4L2_SEL_FLAG_LE)
return a;
if (flags == V4L2_SEL_FLAG_GE)
return b;
if (x <= mid)
return a;
return b;
}
static inline unsigned int do_center(unsigned int center,
unsigned int size, unsigned int upper, unsigned int flags)
{
unsigned int lower;
if (flags & MXR_NO_OFFSET)
return 0;
lower = center - min(center, size / 2);
return min(lower, upper - size);
}
static void mxr_graph_fix_geometry(struct mxr_layer *layer,
enum mxr_geometry_stage stage, unsigned long flags)
{ {
struct mxr_geometry *geo = &layer->geo; struct mxr_geometry *geo = &layer->geo;
struct mxr_crop *src = &geo->src;
struct mxr_crop *dst = &geo->dst;
unsigned int x_center, y_center;
/* limit to boundary size */ switch (stage) {
geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767);
geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047); case MXR_GEOMETRY_SINK: /* nothing to be fixed here */
geo->src.width = clamp_val(geo->src.width, 1, geo->src.full_width); flags = 0;
geo->src.width = min(geo->src.width, 2047U); /* fall through */
/* not possible to crop of Y axis */
geo->src.y_offset = min(geo->src.y_offset, geo->src.full_height - 1); case MXR_GEOMETRY_COMPOSE:
geo->src.height = geo->src.full_height - geo->src.y_offset; /* remember center of the area */
/* limitting offset */ x_center = dst->x_offset + dst->width / 2;
geo->src.x_offset = min(geo->src.x_offset, y_center = dst->y_offset + dst->height / 2;
geo->src.full_width - geo->src.width); /* round up/down to 2 multiple depending on flags */
if (flags & V4L2_SEL_FLAG_LE) {
/* setting position in output */ dst->width = round_down(dst->width, 2);
geo->dst.width = min(geo->dst.width, geo->dst.full_width); dst->height = round_down(dst->height, 2);
geo->dst.height = min(geo->dst.height, geo->dst.full_height);
/* Mixer supports only 1x and 2x scaling */
if (geo->dst.width >= 2 * geo->src.width) {
geo->x_ratio = 1;
geo->dst.width = 2 * geo->src.width;
} else { } else {
geo->x_ratio = 0; dst->width = round_up(dst->width, 2);
geo->dst.width = geo->src.width; dst->height = round_up(dst->height, 2);
} }
/* assure that compose rect is inside display area */
dst->width = min(dst->width, dst->full_width);
dst->height = min(dst->height, dst->full_height);
if (geo->dst.height >= 2 * geo->src.height) { /* ensure that compose is reachable using 2x scaling */
geo->y_ratio = 1; dst->width = min(dst->width, 2 * src->full_width);
geo->dst.height = 2 * geo->src.height; dst->height = min(dst->height, 2 * src->full_height);
} else {
/* setup offsets */
dst->x_offset = do_center(x_center, dst->width,
dst->full_width, flags);
dst->y_offset = do_center(y_center, dst->height,
dst->full_height, flags);
flags = 0;
/* fall through */
case MXR_GEOMETRY_CROP:
/* remember center of the area */
x_center = src->x_offset + src->width / 2;
y_center = src->y_offset + src->height / 2;
/* ensure that cropping area lies inside the buffer */
if (src->full_width < dst->width)
src->width = dst->width / 2;
else
src->width = closest(src->width, dst->width / 2,
dst->width, flags);
if (src->width == dst->width)
geo->x_ratio = 0;
else
geo->x_ratio = 1;
if (src->full_height < dst->height)
src->height = dst->height / 2;
else
src->height = closest(src->height, dst->height / 2,
dst->height, flags);
if (src->height == dst->height)
geo->y_ratio = 0; geo->y_ratio = 0;
geo->dst.height = geo->src.height; else
} geo->y_ratio = 1;
geo->dst.x_offset = min(geo->dst.x_offset, /* setup offsets */
geo->dst.full_width - geo->dst.width); src->x_offset = do_center(x_center, src->width,
geo->dst.y_offset = min(geo->dst.y_offset, src->full_width, flags);
geo->dst.full_height - geo->dst.height); src->y_offset = do_center(y_center, src->height,
src->full_height, flags);
flags = 0;
/* fall through */
case MXR_GEOMETRY_SOURCE:
src->full_width = clamp_val(src->full_width,
src->width + src->x_offset, 32767);
src->full_height = clamp_val(src->full_height,
src->height + src->y_offset, 2047);
};
} }
/* PUBLIC API */ /* PUBLIC API */
......
This diff is collapsed.
...@@ -127,47 +127,77 @@ static void mxr_vp_format_set(struct mxr_layer *layer) ...@@ -127,47 +127,77 @@ static void mxr_vp_format_set(struct mxr_layer *layer)
mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo); mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
} }
static void mxr_vp_fix_geometry(struct mxr_layer *layer) static inline unsigned int do_center(unsigned int center,
unsigned int size, unsigned int upper, unsigned int flags)
{ {
struct mxr_geometry *geo = &layer->geo; unsigned int lower;
if (flags & MXR_NO_OFFSET)
return 0;
/* align horizontal size to 8 pixels */ lower = center - min(center, size / 2);
geo->src.full_width = ALIGN(geo->src.full_width, 8); return min(lower, upper - size);
/* limit to boundary size */ }
geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192);
geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192); static void mxr_vp_fix_geometry(struct mxr_layer *layer,
geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width); enum mxr_geometry_stage stage, unsigned long flags)
geo->src.width = min(geo->src.width, 2047U); {
geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height); struct mxr_geometry *geo = &layer->geo;
geo->src.height = min(geo->src.height, 2047U); struct mxr_crop *src = &geo->src;
struct mxr_crop *dst = &geo->dst;
/* setting size of output window */ unsigned long x_center, y_center;
geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width);
geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height); switch (stage) {
/* ensure that scaling is in range 1/4x to 16x */ case MXR_GEOMETRY_SINK: /* nothing to be fixed here */
if (geo->src.width >= 4 * geo->dst.width) case MXR_GEOMETRY_COMPOSE:
geo->src.width = 4 * geo->dst.width; /* remember center of the area */
if (geo->dst.width >= 16 * geo->src.width) x_center = dst->x_offset + dst->width / 2;
geo->dst.width = 16 * geo->src.width; y_center = dst->y_offset + dst->height / 2;
if (geo->src.height >= 4 * geo->dst.height)
geo->src.height = 4 * geo->dst.height; /* ensure that compose is reachable using 16x scaling */
if (geo->dst.height >= 16 * geo->src.height) dst->width = clamp(dst->width, 8U, 16 * src->full_width);
geo->dst.height = 16 * geo->src.height; dst->height = clamp(dst->height, 1U, 16 * src->full_height);
/* setup offsets */
dst->x_offset = do_center(x_center, dst->width,
dst->full_width, flags);
dst->y_offset = do_center(y_center, dst->height,
dst->full_height, flags);
flags = 0; /* remove possible MXR_NO_OFFSET flag */
/* fall through */
case MXR_GEOMETRY_CROP:
/* remember center of the area */
x_center = src->x_offset + src->width / 2;
y_center = src->y_offset + src->height / 2;
/* ensure scaling is between 0.25x .. 16x */
src->width = clamp(src->width, round_up(dst->width, 4),
dst->width * 16);
src->height = clamp(src->height, round_up(dst->height, 4),
dst->height * 16);
/* hardware limits */
src->width = clamp(src->width, 32U, 2047U);
src->height = clamp(src->height, 4U, 2047U);
/* setup offsets */
src->x_offset = do_center(x_center, src->width,
src->full_width, flags);
src->y_offset = do_center(y_center, src->height,
src->full_height, flags);
/* setting scaling ratio */ /* setting scaling ratio */
geo->x_ratio = (geo->src.width << 16) / geo->dst.width; geo->x_ratio = (src->width << 16) / dst->width;
geo->y_ratio = (geo->src.height << 16) / geo->dst.height; geo->y_ratio = (src->height << 16) / dst->height;
/* fall through */
/* adjust offsets */
geo->src.x_offset = min(geo->src.x_offset, case MXR_GEOMETRY_SOURCE:
geo->src.full_width - geo->src.width); src->full_width = clamp(src->full_width,
geo->src.y_offset = min(geo->src.y_offset, ALIGN(src->width + src->x_offset, 8), 8192U);
geo->src.full_height - geo->src.height); src->full_height = clamp(src->full_height,
geo->dst.x_offset = min(geo->dst.x_offset, src->height + src->y_offset, 8192U);
geo->dst.full_width - geo->dst.width); };
geo->dst.y_offset = min(geo->dst.y_offset,
geo->dst.full_height - geo->dst.height);
} }
/* PUBLIC API */ /* PUBLIC API */
......
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