boards: cxd56_imageproc.c: Add alpha blend API

Add imageproc_alpha_blend() to blend two images in a specified ratio.

The blended source image is selectable from the following two types:

 - Single color image
 - YUV422 image

The blend ratio is selectable from the following three types:

 - Blend ratio with single value
 - Blend ratio with 1bpp
 - Blend ratio with 8bpp
This commit is contained in:
SPRESENSE 2020-07-27 13:54:26 +09:00 committed by Alin Jerpelea
parent 8fec8cccfc
commit f1f0378d0a
2 changed files with 371 additions and 0 deletions

View File

@ -140,6 +140,10 @@
#define FIXEDSRC (1 << 14)
#define MSBFIRST (1 << 13)
#ifndef MIN
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
/****************************************************************************
* Private Types
****************************************************************************/
@ -217,6 +221,7 @@ struct __attribute__ ((aligned(16))) ge2d_abcmd_s
static sem_t g_rotwait;
static sem_t g_rotexc;
static sem_t g_geexc;
static sem_t g_abexc;
static int g_gfd = -1;
static char g_gcmdbuf[256] __attribute__ ((aligned(16)));
@ -373,6 +378,39 @@ static void *set_rop_cmd(void *cmdbuf,
return (void *)((uintptr_t) cmdbuf + sizeof(struct ge2d_ropcmd_s));
}
static void *set_ab_cmd(void *cmdbuf, void *srcaddr, void *destaddr,
uint16_t srcwidth, uint16_t srcheight,
uint16_t srcpitch, uint16_t destpitch,
void *aaddr, uint16_t apitch,
int options, uint16_t fixedsrc, uint16_t fixedalpha)
{
struct ge2d_abcmd_s *ac = (struct ge2d_abcmd_s *)cmdbuf;
memset(ac, 0, sizeof(struct ge2d_abcmd_s));
ac->cmd = ABCMD | options;
ac->mode = fixedalpha;
ac->srch = srcwidth - 1;
ac->srcv = srcheight - 1;
ac->saddr = (uint32_t)(uintptr_t)srcaddr | MSEL;
ac->daddr = (uint32_t)(uintptr_t)destaddr | MSEL;
ac->spitch = srcpitch - 1;
ac->dpitch = destpitch - 1;
ac->fixedsrc = (uint32_t)fixedsrc;
if (aaddr)
{
ac->aaddr = (uint32_t)(uintptr_t)aaddr | MSEL;
ac->apitch = apitch - 1;
}
else
{
ac->aaddr = (uint32_t)(uintptr_t)destaddr | MSEL;
ac->apitch = destpitch - 1;
}
return (void *)((uintptr_t)cmdbuf + sizeof(struct ge2d_abcmd_s));
}
static void *set_halt_cmd(void *cmdbuf)
{
memset(cmdbuf, 0, 16);
@ -426,6 +464,77 @@ static void imageproc_convert_(int is_yuv2rgb,
ip_semgive(&g_rotexc);
}
static void get_rect_info(imageproc_imginfo_t *imginfo,
int *offset, int *w, int *h)
{
if (imginfo->rect)
{
*offset = (imginfo->rect->y1 * imginfo->w)
+ imginfo->rect->x1;
*w = imginfo->rect->x2 - imginfo->rect->x1 + 1;
*h = imginfo->rect->y2 - imginfo->rect->y1 + 1;
}
else
{
*offset = 0;
*w = imginfo->w;
*h = imginfo->h;
}
return;
}
static int chk_imgsize(imageproc_imginfo_t *imginfo)
{
if (!imginfo)
{
return -EINVAL;
}
if ((imginfo->w > HSIZE_MAX) || (imginfo->w < HSIZE_MIN) ||
(imginfo->h > VSIZE_MAX) || (imginfo->h < VSIZE_MIN))
{
return -EINVAL;
}
if (imginfo->rect)
{
if ((imginfo->rect->x2 <= imginfo->rect->x1) ||
(imginfo->rect->y2 <= imginfo->rect->y1))
{
return -EINVAL;
}
if ((imginfo->rect->x2 >= imginfo->w) ||
(imginfo->rect->y2 >= imginfo->h))
{
return -EINVAL;
}
}
return 0;
}
static void *get_blendarea(imageproc_imginfo_t *imginfo, int offset)
{
switch (imginfo->type)
{
case IMAGEPROC_IMGTYPE_8BPP:
return imginfo->img.p_u8 + offset;
case IMAGEPROC_IMGTYPE_16BPP:
return imginfo->img.p_u16 + offset;
case IMAGEPROC_IMGTYPE_BINARY:
return imginfo->img.binary.p_u8 + offset / 8;
default:
return NULL;
}
return NULL;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -435,6 +544,7 @@ void imageproc_initialize(void)
nxsem_init(&g_rotexc, 0, 1);
nxsem_init(&g_rotwait, 0, 0);
nxsem_init(&g_geexc, 0, 1);
nxsem_init(&g_abexc, 0, 1);
nxsem_set_protocol(&g_rotwait, SEM_PRIO_NONE);
cxd56_ge2dinitialize(GEDEVNAME);
@ -465,6 +575,7 @@ void imageproc_finalize(void)
nxsem_destroy(&g_rotwait);
nxsem_destroy(&g_rotexc);
nxsem_destroy(&g_geexc);
nxsem_destroy(&g_abexc);
}
void imageproc_convert_yuv2rgb(uint8_t * ibuf,
@ -697,3 +808,194 @@ int imageproc_clip_and_resize(uint8_t * ibuf,
return 0;
}
int imageproc_alpha_blend(imageproc_imginfo_t *dst,
int pos_x,
int pos_y,
imageproc_imginfo_t *src,
imageproc_imginfo_t *alpha)
{
int ret;
/* Graphic engine control */
void *cmd = g_gcmdbuf;
size_t len;
/* alpha blend options */
uint16_t fixed_alpha;
uint16_t fixed_src;
int options;
/* blended rectangles information */
void *dst_addr;
void *src_addr;
void *a_addr;
int dst_offset;
int dst_w;
int dst_h;
int src_offset;
int src_w;
int src_h;
int a_offset;
int a_w;
int a_h;
int blendarea_left;
int blendarea_right;
int blendarea_top;
int blendarea_bottom;
/* Parameter range check */
ret = chk_imgsize(dst);
if (ret < 0)
{
return ret;
}
ret = chk_imgsize(src);
if (ret < 0)
{
return ret;
}
ret = chk_imgsize(alpha);
if (ret < 0)
{
return ret;
}
/* Determine alpha blend options */
fixed_src = 0;
fixed_alpha = 0;
options = 0;
switch (alpha->type)
{
case IMAGEPROC_IMGTYPE_SINGLE:
fixed_alpha = 0x0800 | (uint8_t)alpha->img.single;
break;
case IMAGEPROC_IMGTYPE_BINARY:
fixed_alpha = (uint8_t)alpha->img.binary.multiplier;
options |= ALPHA1BPP;
break;
case IMAGEPROC_IMGTYPE_8BPP:
/* In this case, no option */
break;
default:
return -EINVAL;
}
switch (src->type)
{
case IMAGEPROC_IMGTYPE_SINGLE:
options |= FIXEDSRC;
fixed_src = src->img.single;
break;
case IMAGEPROC_IMGTYPE_16BPP:
/* In this case, no option */
break;
default:
return -EINVAL;
}
switch (dst->type)
{
case IMAGEPROC_IMGTYPE_16BPP:
/* In this case, no option */
break;
default:
return -EINVAL;
}
/* Determine offset, width, height of rectangles from IN parameter */
get_rect_info(dst, &dst_offset, &dst_w, &dst_h);
get_rect_info(src, &src_offset, &src_w, &src_h);
get_rect_info(alpha, &a_offset, &a_w, &a_h);
/* Recalculate offset by calculating overlapped area. */
blendarea_left = - MIN(0, pos_x);
blendarea_right = MIN(MIN(a_w, src_w), dst_w - pos_x);
blendarea_top = - MIN(0, pos_y);
blendarea_bottom = MIN(MIN(a_h, src_h), dst_h - pos_y);
if ((blendarea_right <= blendarea_left) ||
(blendarea_bottom <= blendarea_top))
{
return 0; /* Not blend due to no overlapped area */
}
dst_offset += ((blendarea_top + pos_y) * dst->w)
+ (blendarea_left + pos_x);
src_offset += (blendarea_top * src->w) + blendarea_left;
a_offset += (blendarea_top * alpha->w) + blendarea_left;
dst_addr = get_blendarea(dst, dst_offset);
src_addr = get_blendarea(src, src_offset);
a_addr = get_blendarea(alpha, a_offset);
ret = ip_semtake(&g_abexc);
if (ret)
{
return ret; /* -EINTR */
}
/* Create descriptor to graphics engine */
cmd = set_ab_cmd(cmd,
src_addr,
dst_addr,
blendarea_right - blendarea_left, /* width of blended area */
blendarea_bottom - blendarea_top, /* height of blended area */
src->w, /* pitch of src image */
dst->w, /* pitch of dst image */
a_addr,
alpha->w, /* pitch of alpha plane */
options,
fixed_src,
fixed_alpha);
if (cmd == NULL)
{
ip_semgive(&g_abexc);
return -EINVAL;
}
/* Terminate command */
cmd = set_halt_cmd(cmd);
/* Process alpha blending */
len = (uintptr_t)cmd - (uintptr_t)g_gcmdbuf;
ret = write(g_gfd, g_gcmdbuf, len);
if (ret < 0)
{
ip_semgive(&g_abexc);
return -EFAULT;
}
ip_semgive(&g_abexc);
return 0;
}

View File

@ -46,6 +46,10 @@ extern "C"
{
#endif
/****************************************************************************
* Public Types
****************************************************************************/
/* Structure of rectangle coordinates from left top point to
* right bottom point.
*/
@ -59,6 +63,43 @@ extern "C"
};
typedef struct imageproc_rect_s imageproc_rect_t;
/* Enumeration of image type */
enum imageproc_imginfo_e
{
IMAGEPROC_IMGTYPE_SINGLE = 0, /* All pixels have the same value */
IMAGEPROC_IMGTYPE_BINARY = 1, /* Each pixels have 0 or specific non-zero value */
IMAGEPROC_IMGTYPE_8BPP = 2, /* Each pixels have 8bit value */
IMAGEPROC_IMGTYPE_16BPP = 3, /* Each pixels have 16bit value */
};
/* Structure of binary image */
struct imageproc_binary_img_s
{
uint8_t *p_u8; /* 1bpp image */
int multiplier; /* specific non-zero value */
};
typedef struct imageproc_binary_img_s imageproc_binary_img_t;
/* Structure of image information. */
struct imageproc_imginfo_s
{
enum imageproc_imginfo_e type; /* Type of image data */
int w; /* width of total image */
int h; /* height of total image */
imageproc_rect_t *rect; /* clipped rectangle */
union
{
int single; /* type = IMAGEPROC_IMGTYPE_SINGLE */
imageproc_binary_img_t binary; /* type = IMAGEPROC_IMGTYPE_BINARY */
uint8_t *p_u8; /* type = IMAGEPROC_IMGTYPE_8BPP */
uint16_t *p_u16; /* type = IMAGEPROC_IMGTYPE_16BPP */
} img;
};
typedef struct imageproc_imginfo_s imageproc_imginfo_t;
/****************************************************************************
* Public Functions Prototypes
****************************************************************************/
@ -162,6 +203,34 @@ extern "C"
uint16_t ohsize, uint16_t ovsize, int bpp,
imageproc_rect_t * clip_rect);
/* Execute alpha blending
*
* Execute alpha blending.
* dst buffer is overwritten by blended image.
*
* [in,out] dst: Destination image.
* dst->type = IMAGEPROC_IMGTYPE_16BPP.
* [in] pos_x: x-coordinate of blended position.
* Minus value means
* the left of the destination image origin.
* [in] pos_y: y-coordinate of blended position.
* Minus value means
* the upper of the destination image origin.
* [in] src: Source image.
* src->type = IMAGEPROC_IMGTYPE_16BPP or
* IMAGEPROC_IMGTYPE_SINGLE.
* [in] alpha: Alpha plane.
* alpha->type = IMAGEPROC_IMGTYPE_SINGLE,
* IMAGEPROC_IMGTYPE_BINARY,
* or IMAGEPROC_IMGTYPE_8BPP.
*
* return 0 on success, otherwise error code.
*/
int imageproc_alpha_blend(imageproc_imginfo_t *dst, int pos_x, int pos_y,
imageproc_imginfo_t *src,
imageproc_imginfo_t *alpha);
#ifdef __cplusplus
}
#endif