summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörgen Nilsson <jorgen.nilsson@stericsson.com>2011-10-12 13:52:32 +0200
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:04:18 +0200
commit532bdc7382928cb92b22cfcb7cbeeb462d3974ba (patch)
treedeaf8bcefe1f918ac3cc7da86002651587c1e7c6
parent327b242535599f8b6b41db91e2d68e43b2515a01 (diff)
b2r2: Add support for blending on background image
Instead of blending only on the destination there is now a possibility to blend on a supplied background using standard blending flags. The background blending option is enabled through setting a flag in the request. When background blending is enabled the destination blending is omitted and the destination buffer is simply overwritten. ST-Ericsson Linux next: NA Depends-On: I85ba9d0006e7480167f72f2a6b5c9d8fff272813, Ia34f98cfb20e2f0486049e82581dcea28b465ed4, I5cbeb4525a98a5b9884c3464154182810ee7449b ST-Ericsson ID: 350337 ST-Ericsson FOSS-OUT ID: Trivial Introduce non-backward compatible changes to exposed interfaces Signed-off-by: Jörgen Nilsson <jorgen.nilsson@stericsson.com> Change-Id: Ifeb8eb66c2fed97c541b09715a17251a81e493ab Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/34023 Tested-by: Jorgen NILSSON <jorgen.nilsson@stericsson.com> Reviewed-by: Maciej SOCHA <maciej.socha@stericsson.com> Reviewed-by: Linus WALLEIJ <linus.walleij@stericsson.com>
-rw-r--r--drivers/video/b2r2/b2r2_blt_main.c184
-rw-r--r--drivers/video/b2r2/b2r2_input_validation.c67
-rw-r--r--drivers/video/b2r2/b2r2_internal.h4
-rw-r--r--drivers/video/b2r2/b2r2_node_split.c238
-rw-r--r--drivers/video/b2r2/b2r2_utils.c7
-rw-r--r--drivers/video/b2r2/b2r2_utils.h2
-rw-r--r--include/video/b2r2_blt.h21
7 files changed, 428 insertions, 95 deletions
diff --git a/drivers/video/b2r2/b2r2_blt_main.c b/drivers/video/b2r2/b2r2_blt_main.c
index 5d1d58c53cc..51087e4b437 100644
--- a/drivers/video/b2r2/b2r2_blt_main.c
+++ b/drivers/video/b2r2/b2r2_blt_main.c
@@ -480,6 +480,14 @@ static long b2r2_blt_ioctl(struct file *file,
/* Fall back to generic path if operation was not supported */
if (ret == -ENOSYS) {
struct b2r2_blt_request *request_gen;
+
+ if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) {
+ /* No support for BG BLEND in generic implementation yet */
+ b2r2_log_warn("%s: Unsupported: Background blend in b2r2_generic_blt \n",
+ __func__);
+ return ret;
+ }
+
b2r2_log_info("b2r2_blt=%d Going generic.\n", ret);
request_gen = kmalloc(sizeof(*request_gen), GFP_KERNEL);
if (!request_gen) {
@@ -594,7 +602,7 @@ static long b2r2_blt_ioctl(struct file *file,
b2r2_log_err(
"%s: Unknown cmd %d\n", __func__, cmd);
ret = -EINVAL;
- break;
+ break;
}
@@ -795,6 +803,23 @@ static int b2r2_blt(struct b2r2_blt_instance *instance,
request->user_req.src_rect.y,
request->user_req.src_rect.width,
request->user_req.src_rect.height);
+
+ if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) {
+ b2r2_log_info(
+ "bg.fmt=%#010x bg.buf={%d,%d,%d} "
+ "bg.w,h={%d,%d} bg.rect={%d,%d,%d,%d}\n",
+ request->user_req.bg_img.fmt,
+ request->user_req.bg_img.buf.type,
+ request->user_req.bg_img.buf.fd,
+ request->user_req.bg_img.buf.offset,
+ request->user_req.bg_img.width,
+ request->user_req.bg_img.height,
+ request->user_req.bg_rect.x,
+ request->user_req.bg_rect.y,
+ request->user_req.bg_rect.width,
+ request->user_req.bg_rect.height);
+ }
+
b2r2_log_info(
"dst.fmt=%#010x dst.buf={%d,%d,%d} "
"dst.w,h={%d,%d} dst.rect={%d,%d,%d,%d}\n",
@@ -838,6 +863,19 @@ static int b2r2_blt(struct b2r2_blt_instance *instance,
goto resolve_src_buf_failed;
}
+ /* Background buffer */
+ if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) {
+ ret = resolve_buf(&request->user_req.bg_img,
+ &request->user_req.bg_rect, false, &request->bg_resolved);
+ if (ret < 0) {
+ b2r2_log_warn(
+ "%s: Resolve bg buf failed, %d\n",
+ __func__, ret);
+ ret = -EAGAIN;
+ goto resolve_bg_buf_failed;
+ }
+ }
+
/* Source mask buffer */
ret = resolve_buf(&request->user_req.src_mask,
&request->user_req.src_rect, false,
@@ -872,6 +910,17 @@ static int b2r2_blt(struct b2r2_blt_instance *instance,
request->src_resolved.file_virtual_start,
request->src_resolved.file_len);
+ if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) {
+ b2r2_log_info("bg.rbuf={%X,%p,%d} {%p,%X,%X,%d}\n",
+ request->bg_resolved.physical_address,
+ request->bg_resolved.virtual_address,
+ request->bg_resolved.is_pmem,
+ request->bg_resolved.filep,
+ request->bg_resolved.file_physical_start,
+ request->bg_resolved.file_virtual_start,
+ request->bg_resolved.file_len);
+ }
+
b2r2_log_info("dst.rbuf={%X,%p,%d} {%p,%X,%X,%d}\n",
request->dst_resolved.physical_address,
request->dst_resolved.virtual_address,
@@ -979,6 +1028,20 @@ static int b2r2_blt(struct b2r2_blt_instance *instance,
false, /*is_dst*/
&request->user_req.src_rect);
+ /* Background buffer */
+ if ((request->user_req.flags &
+ B2R2_BLT_FLAG_BG_BLEND) &&
+ !(request->user_req.flags &
+ B2R2_BLT_FLAG_BG_NO_CACHE_FLUSH) &&
+ (request->user_req.bg_img.buf.type !=
+ B2R2_BLT_PTR_PHYSICAL) &&
+ !b2r2_is_mb_fmt(request->user_req.bg_img.fmt))
+ /* MB formats are never touched by SW */
+ sync_buf(&request->user_req.bg_img,
+ &request->bg_resolved,
+ false, /*is_dst*/
+ &request->user_req.bg_rect);
+
/* Source mask buffer */
if (!(request->user_req.flags &
B2R2_BLT_FLAG_SRC_MASK_NO_CACHE_FLUSH) &&
@@ -1080,6 +1143,11 @@ resolve_dst_buf_failed:
unresolve_buf(&request->user_req.src_mask.buf,
&request->src_mask_resolved);
resolve_src_mask_buf_failed:
+ if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) {
+ unresolve_buf(&request->user_req.bg_img.buf,
+ &request->bg_resolved);
+ }
+resolve_bg_buf_failed:
unresolve_buf(&request->user_req.src_img.buf,
&request->src_resolved);
resolve_src_buf_failed:
@@ -1118,6 +1186,10 @@ static void job_callback(struct b2r2_core_job *job)
&request->src_mask_resolved);
unresolve_buf(&request->user_req.dst_img.buf,
&request->dst_resolved);
+ if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) {
+ unresolve_buf(&request->user_req.bg_img.buf,
+ &request->bg_resolved);
+ }
/* Move to report list if the job shall be reported */
/* FIXME: Use a smaller struct? */
@@ -2333,7 +2405,9 @@ static int resolve_hwmem(struct b2r2_blt_img *img,
if (resolved_buf->file_len <
img->buf.offset + (__u32)b2r2_get_img_size(img)) {
- b2r2_log_info("%s: Hwmem buffer too small.\n", __func__);
+ b2r2_log_info("%s: Hwmem buffer too small. (%d < %d) \n", __func__,
+ resolved_buf->file_len,
+ img->buf.offset + (__u32)b2r2_get_img_size(img));
return_value = -EINVAL;
goto size_check_failed;
}
@@ -2400,6 +2474,48 @@ static void unresolve_buf(struct b2r2_blt_buf *buf,
}
/**
+ * get_fb_info() - Fill buf with framebuffer info
+ *
+ * @file: The framebuffer file
+ * @buf: Gathered information about the buffer
+ * @img_offset: Image offset info frame buffer
+ *
+ * Returns 0 if OK else negative error code
+ */
+static int get_fb_info(struct file *file,
+ struct b2r2_resolved_buf *buf,
+ __u32 img_offset)
+{
+#ifdef CONFIG_FB
+ if (file && buf &&
+ MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
+ int i;
+ /*
+ * (OK to do it like this, no locking???)
+ */
+ for (i = 0; i < num_registered_fb; i++) {
+ struct fb_info *info = registered_fb[i];
+
+ if (info && info->dev &&
+ MINOR(info->dev->devt) ==
+ MINOR(file->f_dentry->d_inode->i_rdev)) {
+ buf->file_physical_start = info->fix.smem_start;
+ buf->file_virtual_start = (u32)info->screen_base;
+ buf->file_len = info->fix.smem_len;
+ buf->physical_address = buf->file_physical_start +
+ img_offset;
+ buf->virtual_address =
+ (void *) (buf->file_virtual_start +
+ img_offset);
+ return 0;
+ }
+ }
+ }
+#endif
+ return -EINVAL;
+}
+
+/**
* resolve_buf() - Returns the physical & virtual addresses of a B2R2 blt buffer
*
* @img: The image specification as supplied from user space
@@ -2433,17 +2549,13 @@ static int resolve_buf(struct b2r2_blt_img *img,
* TODO: Do we need to check if the process is allowed to
* read/write (depending on if it's dst or src) to the file?
*/
- struct file *file;
- int put_needed;
- int i;
-
#ifdef CONFIG_ANDROID_PMEM
if (!get_pmem_file(
- img->buf.fd,
- (unsigned long *) &resolved->file_physical_start,
- (unsigned long *) &resolved->file_virtual_start,
- (unsigned long *) &resolved->file_len,
- &resolved->filep)) {
+ img->buf.fd,
+ (unsigned long *) &resolved->file_physical_start,
+ (unsigned long *) &resolved->file_virtual_start,
+ (unsigned long *) &resolved->file_len,
+ &resolved->filep)) {
resolved->physical_address =
resolved->file_physical_start +
img->buf.offset;
@@ -2454,54 +2566,22 @@ static int resolve_buf(struct b2r2_blt_img *img,
} else
#endif
{
- /* Will be set to 0 if a matching dev is found */
- ret = -EINVAL;
+ int fput_needed;
+ struct file *file;
- file = fget_light(img->buf.fd, &put_needed);
+ file = fget_light(img->buf.fd, &fput_needed);
if (file == NULL)
return -EINVAL;
-#ifdef CONFIG_FB
- if (MAJOR(file->f_dentry->d_inode->i_rdev) ==
- FB_MAJOR) {
- /*
- * This is a frame buffer device, find fb_info
- * (OK to do it like this, no locking???)
- */
-
- for (i = 0; i < num_registered_fb; i++) {
- struct fb_info *info = registered_fb[i];
-
- if (info && info->dev &&
- MINOR(info->dev->devt) ==
- MINOR(file->f_dentry->
- d_inode->i_rdev)) {
- resolved->file_physical_start =
- info->fix.smem_start;
- resolved->file_virtual_start =
- (u32)info->screen_base;
- resolved->file_len =
- info->fix.smem_len;
-
- resolved->physical_address =
- resolved->file_physical_start +
- img->buf.offset;
- resolved->virtual_address =
- (void *) (resolved->
- file_virtual_start +
- img->buf.offset);
-
- ret = 0;
- break;
- }
- }
- }
-#endif
- fput_light(file, put_needed);
+ ret = get_fb_info(file, resolved,
+ img->buf.offset);
+ fput_light(file, fput_needed);
+ if (ret < 0)
+ return ret;
}
/* Check bounds */
- if (ret >= 0 && img->buf.offset + img->buf.len >
+ if (img->buf.offset + img->buf.len >
resolved->file_len) {
ret = -ESPIPE;
unresolve_buf(&img->buf, resolved);
diff --git a/drivers/video/b2r2/b2r2_input_validation.c b/drivers/video/b2r2/b2r2_input_validation.c
index 0de714f1161..602041c9294 100644
--- a/drivers/video/b2r2/b2r2_input_validation.c
+++ b/drivers/video/b2r2/b2r2_input_validation.c
@@ -30,6 +30,7 @@
static bool is_valid_format(enum b2r2_blt_fmt fmt);
+static bool is_valid_bg_format(enum b2r2_blt_fmt fmt);
static bool is_valid_pitch_for_fmt(u32 pitch, s32 width,
enum b2r2_blt_fmt fmt);
@@ -79,6 +80,26 @@ static bool is_valid_format(enum b2r2_blt_fmt fmt)
}
}
+static bool is_valid_bg_format(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YVU420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YVU422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ return false;
+ default:
+ return true;
+ }
+}
+
static bool is_valid_pitch_for_fmt(u32 pitch, s32 width, enum b2r2_blt_fmt fmt)
{
@@ -336,6 +357,7 @@ static bool validate_rect(struct b2r2_blt_rect *rect)
bool b2r2_validate_user_req(struct b2r2_blt_req *req)
{
bool is_src_img_used;
+ bool is_bg_img_used;
bool is_src_mask_used;
bool is_dst_clip_rect_used;
@@ -347,6 +369,7 @@ bool b2r2_validate_user_req(struct b2r2_blt_req *req)
is_src_img_used = !(req->flags & B2R2_BLT_FLAG_SOURCE_FILL ||
req->flags & B2R2_BLT_FLAG_SOURCE_FILL_RAW);
+ is_bg_img_used = (req->flags & B2R2_BLT_FLAG_BG_BLEND);
is_src_mask_used = req->flags & B2R2_BLT_FLAG_SOURCE_MASK;
is_dst_clip_rect_used = req->flags & B2R2_BLT_FLAG_DESTINATION_CLIP;
@@ -364,6 +387,14 @@ bool b2r2_validate_user_req(struct b2r2_blt_req *req)
return false;
}
+ if (is_bg_img_used) {
+ if (!validate_rect(&req->bg_rect)) {
+ b2r2_log_info("Validation Error: "
+ "!validate_rect(&req->bg_rect)\n");
+ return false;
+ }
+ }
+
if (is_dst_clip_rect_used) {
if (!validate_rect(&req->dst_clip_rect)) {
b2r2_log_info("Validation Error: "
@@ -392,6 +423,32 @@ bool b2r2_validate_user_req(struct b2r2_blt_req *req)
}
}
+ if (is_bg_img_used) {
+ struct b2r2_blt_rect bg_img_bounding_rect;
+
+ if (!validate_img(&req->bg_img)) {
+ b2r2_log_info("Validation Error: "
+ "!validate_img(&req->bg_img)\n");
+ return false;
+ }
+
+ if (!is_valid_bg_format(req->bg_img.fmt)) {
+ b2r2_log_info("Validation Error: "
+ "!is_valid_bg_format(req->bg_img->fmt)\n");
+ return false;
+ }
+
+ b2r2_get_img_bounding_rect(&req->bg_img,
+ &bg_img_bounding_rect);
+ if (!b2r2_is_rect_inside_rect(&req->bg_rect,
+ &bg_img_bounding_rect)) {
+ b2r2_log_info("Validation Error: "
+ "!b2r2_is_rect_inside_rect(&req->bg_rect, "
+ "&bg_img_bounding_rect)\n");
+ return false;
+ }
+ }
+
if (is_src_mask_used) {
struct b2r2_blt_rect src_mask_bounding_rect;
@@ -418,5 +475,15 @@ bool b2r2_validate_user_req(struct b2r2_blt_req *req)
return false;
}
+ if (is_bg_img_used) {
+ if (!b2r2_is_rect_gte_rect(&req->bg_rect,
+ &req->dst_rect)) {
+ b2r2_log_info("Validation Error: "
+ "!b2r2_is_rect_gte_rect(&req->bg_rect, "
+ "&req->dst_rect)\n");
+ return false;
+ }
+ }
+
return true;
}
diff --git a/drivers/video/b2r2/b2r2_internal.h b/drivers/video/b2r2/b2r2_internal.h
index 18556e7193a..718d1ad40c9 100644
--- a/drivers/video/b2r2/b2r2_internal.h
+++ b/drivers/video/b2r2/b2r2_internal.h
@@ -234,6 +234,7 @@ struct b2r2_node_split_buf {
* @vert_rescale - determines if vertical rescale is enabled
* @vert_sf - the vertical scale factor
* @src - the incoming source buffer
+ * @bg - the incoming background buffer
* @dst - the outgoing destination buffer
* @work_bufs - work buffer specifications
* @tmp_bufs - temporary buffers
@@ -268,6 +269,7 @@ struct b2r2_node_split_job {
u16 v_rsf;
struct b2r2_node_split_buf src;
+ struct b2r2_node_split_buf bg;
struct b2r2_node_split_buf dst;
struct b2r2_work_buf work_bufs[MAX_TMP_BUFS_NEEDED];
@@ -292,6 +294,7 @@ struct b2r2_node_split_job {
* @node_split_handle: Handle of the node split
* @src_resolved: Calculated info about the source buffer
* @src_mask_resolved: Calculated info about the source mask buffer
+ * @bg_resolved: Calculated info about the background buffer
* @dst_resolved: Calculated info about the destination buffer
* @profile: True if the blit shall be profiled, false otherwise
*/
@@ -307,6 +310,7 @@ struct b2r2_blt_request {
/* Resolved buffer addresses */
struct b2r2_resolved_buf src_resolved;
struct b2r2_resolved_buf src_mask_resolved;
+ struct b2r2_resolved_buf bg_resolved;
struct b2r2_resolved_buf dst_resolved;
/* TBD: Info about SRAM usage & needs */
diff --git a/drivers/video/b2r2/b2r2_node_split.c b/drivers/video/b2r2/b2r2_node_split.c
index 556e5f69e07..5faca17c197 100644
--- a/drivers/video/b2r2/b2r2_node_split.c
+++ b/drivers/video/b2r2/b2r2_node_split.c
@@ -179,11 +179,12 @@ static int analyze_scale_factors(struct b2r2_node_split_job *this);
static void configure_src(struct b2r2_node *node,
struct b2r2_node_split_buf *src, const u32 *ivmx);
+static void configure_bg(struct b2r2_node *node,
+ struct b2r2_node_split_buf *bg, bool swap_fg_bg);
static int configure_dst(struct b2r2_node *node,
struct b2r2_node_split_buf *dst, const u32 *ivmx,
struct b2r2_node **next);
-static void configure_blend(struct b2r2_node *node, u32 flags, u32 global_alpha,
- bool swap_fg_bg);
+static void configure_blend(struct b2r2_node *node, u32 flags, u32 global_alpha);
static void configure_clip(struct b2r2_node *node,
struct b2r2_blt_rect *clip_rect);
@@ -263,6 +264,8 @@ static void set_ivmx(struct b2r2_node *node, const u32 *vmx_values);
static void reset_nodes(struct b2r2_node *node);
+static bool bg_format_require_ivmx(enum b2r2_blt_fmt bg_fmt, enum b2r2_blt_fmt dst_fmt);
+
/*
* Public functions
*/
@@ -324,6 +327,22 @@ int b2r2_node_split_analyze(const struct b2r2_blt_request *req,
break;
}
+ /* Unsupported formats on bg */
+ if (this->flags & B2R2_BLT_FLAG_BG_BLEND) {
+ /*
+ * There are no ivmx on source 1, so check that there is no such requirement
+ * on the background to destination format conversion. This check is sufficient
+ * since the node splitter currently does not support destination ivmx. That
+ * fact also removes the source format as a parameter when checking the
+ * background format.
+ */
+ if (bg_format_require_ivmx(req->user_req.bg_img.fmt,
+ req->user_req.dst_img.fmt)) {
+ ret = -ENOSYS;
+ goto unsupported;
+ }
+ }
+
if ((this->flags & B2R2_BLT_FLAG_SOURCE_COLOR_KEY) &&
(is_yuv_fmt(req->user_req.src_img.fmt) ||
req->user_req.src_img.fmt == B2R2_BLT_FMT_1_BIT_A1 ||
@@ -361,16 +380,24 @@ int b2r2_node_split_analyze(const struct b2r2_blt_request *req,
&req->user_req.src_img, &req->user_req.src_rect,
color_fill, req->user_req.src_color);
+ if (this->flags & B2R2_BLT_FLAG_BG_BLEND) {
+ set_buf(&this->bg, req->bg_resolved.physical_address,
+ &req->user_req.bg_img, &req->user_req.bg_rect,
+ false, 0);
+ }
+
set_buf(&this->dst, req->dst_resolved.physical_address,
&req->user_req.dst_img, &req->user_req.dst_rect, false,
0);
b2r2_log_info("%s:\n"
"\t\tsrc.rect=(%4d, %4d, %4d, %4d)\t"
+ "bg.rect=(%4d, %4d, %4d, %4d)\t"
"dst.rect=(%4d, %4d, %4d, %4d)\n", __func__, this->src.rect.x,
this->src.rect.y, this->src.rect.width, this->src.rect.height,
- this->dst.rect.x, this->dst.rect.y, this->dst.rect.width,
- this->dst.rect.height);
+ this->bg.rect.x, this->bg.rect.y, this->bg.rect.width,
+ this->bg.rect.height, this->dst.rect.x, this->dst.rect.y,
+ this->dst.rect.width, this->dst.rect.height);
if (this->flags & B2R2_BLT_FLAG_DITHER)
this->dst.dither = B2R2_TTY_RGB_ROUND_DITHER;
@@ -385,6 +412,8 @@ int b2r2_node_split_analyze(const struct b2r2_blt_request *req,
else if (this->flags & B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND)
this->blend = (color_fill && fmt_has_alpha(this->dst.fmt)) ||
fmt_has_alpha(this->src.fmt);
+ else if (this->flags & B2R2_BLT_FLAG_BG_BLEND)
+ this->blend = true;
if (this->blend && this->src.type == B2R2_FMT_TYPE_PLANAR) {
b2r2_log_warn("%s: Unsupported: blend with planar source\n",
@@ -438,6 +467,14 @@ int b2r2_node_split_analyze(const struct b2r2_blt_request *req,
goto error;
}
+ /* Validate the background source */
+ if (this->flags & B2R2_BLT_FLAG_BG_BLEND) {
+ ret = check_rect(&req->user_req.bg_img,
+ &req->user_req.bg_rect, NULL);
+ if (ret < 0)
+ goto error;
+ }
+
/* Do the analysis depending on the type of operation */
if (color_fill) {
ret = analyze_color_fill(this, req, &this->node_count);
@@ -714,6 +751,87 @@ error:
}
/**
+ * bg_format_require_ivmx()
+ *
+ * Check if there are any color space conversion needed for the
+ * background to the destination format.
+ */
+static bool bg_format_require_ivmx(enum b2r2_blt_fmt bg_fmt, enum b2r2_blt_fmt dst_fmt)
+{
+ if (is_rgb_fmt(bg_fmt)) {
+ if (is_yvu_fmt(dst_fmt))
+ return true;
+ else if (dst_fmt == B2R2_BLT_FMT_24_BIT_YUV888 ||
+ dst_fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 ||
+ dst_fmt == B2R2_BLT_FMT_24_BIT_VUY888 ||
+ dst_fmt == B2R2_BLT_FMT_32_BIT_VUYA8888)
+ return true;
+ else if (is_yuv_fmt(dst_fmt))
+ return true;
+ else if (is_bgr_fmt(dst_fmt))
+ return true;
+ } else if (is_yvu_fmt(bg_fmt)) {
+ if (is_rgb_fmt(dst_fmt))
+ return true;
+ else if (is_bgr_fmt(dst_fmt))
+ return true;
+ else if (dst_fmt == B2R2_BLT_FMT_24_BIT_YUV888 ||
+ dst_fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 ||
+ dst_fmt == B2R2_BLT_FMT_24_BIT_VUY888 ||
+ dst_fmt == B2R2_BLT_FMT_32_BIT_VUYA8888)
+ return true;
+ else if (is_yuv_fmt(dst_fmt) &&
+ !is_yvu_fmt(dst_fmt))
+ return true;
+ } else if (bg_fmt == B2R2_BLT_FMT_24_BIT_YUV888 ||
+ bg_fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 ||
+ bg_fmt == B2R2_BLT_FMT_24_BIT_VUY888 ||
+ bg_fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) {
+ if (is_rgb_fmt(dst_fmt)) {
+ return true;
+ } else if (is_yvu_fmt(dst_fmt)) {
+ return true;
+ } else if (is_yuv_fmt(dst_fmt)) {
+ switch (dst_fmt) {
+ case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ case B2R2_BLT_FMT_24_BIT_VUY888:
+ case B2R2_BLT_FMT_32_BIT_VUYA8888:
+ break;
+ default:
+ return true;
+ }
+ }
+ } else if (is_yuv_fmt(bg_fmt)) {
+ if (is_rgb_fmt(dst_fmt))
+ return true;
+ else if (is_bgr_fmt(dst_fmt))
+ return true;
+ else if (dst_fmt == B2R2_BLT_FMT_24_BIT_YUV888 ||
+ dst_fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 ||
+ dst_fmt == B2R2_BLT_FMT_24_BIT_VUY888 ||
+ dst_fmt == B2R2_BLT_FMT_32_BIT_VUYA8888)
+ return true;
+ else if (is_yvu_fmt(dst_fmt))
+ return true;
+ } else if (is_bgr_fmt(bg_fmt)) {
+ if (is_rgb_fmt(dst_fmt))
+ return true;
+ else if (is_yvu_fmt(dst_fmt))
+ return true;
+ else if (dst_fmt == B2R2_BLT_FMT_24_BIT_YUV888 ||
+ dst_fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 ||
+ dst_fmt == B2R2_BLT_FMT_24_BIT_VUY888 ||
+ dst_fmt == B2R2_BLT_FMT_32_BIT_VUYA8888)
+ return true;
+ else if (is_yuv_fmt(dst_fmt))
+ return true;
+ }
+
+ return false;
+}
+
+/**
* analyze_fmt_conv() - analyze the format conversions needed for a job
*/
static int analyze_fmt_conv(struct b2r2_node_split_buf *src,
@@ -888,7 +1006,7 @@ static int analyze_color_fill(struct b2r2_node_split_job *this,
this->global_alpha = (u8)new_global;
/* Set the pixel alpha to full opaque so we don't get
- any nasty suprises */
+ any nasty surprises */
this->src.color = set_alpha(this->src.fmt, 0xFF,
this->src.color);
}
@@ -1424,9 +1542,11 @@ static int configure_tile(struct b2r2_node_split_job *this,
struct b2r2_node *last;
struct b2r2_node_split_buf *src = &this->src;
struct b2r2_node_split_buf *dst = &this->dst;
+ struct b2r2_node_split_buf *bg = &this->bg;
struct b2r2_blt_rect dst_norm;
struct b2r2_blt_rect src_norm;
+ struct b2r2_blt_rect bg_norm;
/* Normalize the dest coords to the dest rect coordinate space */
dst_norm.x = dst->win.x - dst->rect.x;
@@ -1462,6 +1582,20 @@ static int configure_tile(struct b2r2_node_split_job *this,
src->win.width = src_norm.width;
src->win.height = src_norm.height;
+ /* Set bg norm */
+ bg_norm.x = dst->win.x - dst->rect.x;
+ bg_norm.y = dst->win.y - dst->rect.y;
+ bg_norm.width = dst->win.width;
+ bg_norm.height = dst->win.height;
+
+ /* Convert to bg coordinate space */
+ bg->win.x = bg_norm.x + bg->rect.x;
+ bg->win.y = bg_norm.y + bg->rect.y;
+ bg->win.width = bg_norm.width;
+ bg->win.height = bg_norm.height;
+ bg->vso = dst->vso;
+ bg->hso = dst->hso;
+
/* Do the configuration depending on operation type */
switch (this->type) {
case B2R2_DIRECT_FILL:
@@ -1545,10 +1679,14 @@ static int configure_tile(struct b2r2_node_split_job *this,
goto error;
}
- if (this->blend)
+ if (this->blend) {
+ if (this->flags & B2R2_BLT_FLAG_BG_BLEND)
+ configure_bg(node, bg, this->swap_fg_bg);
+ else
+ configure_bg(node, dst, this->swap_fg_bg);
configure_blend(node, this->flags,
- this->global_alpha,
- this->swap_fg_bg);
+ this->global_alpha);
+ }
if (this->clip)
configure_clip(node, &this->clip_rect);
@@ -2367,6 +2505,51 @@ static void configure_src(struct b2r2_node *node,
}
/**
+ * configure_bg() - configures a background for the given node
+ *
+ * @node - the node to configure
+ * @bg - the background buffer
+ * @swap_fg_bg - if true, fg will be on s1 instead of s2
+ *
+ * This operation will not consume any nodes.
+ *
+ * NOTE: This method should be called _AFTER_ the destination has been
+ * configured.
+ *
+ * WARNING: Take care when using this with semi-planar or planar sources since
+ * either S1 or S2 will be overwritten!
+ */
+static void configure_bg(struct b2r2_node *node,
+ struct b2r2_node_split_buf *bg, bool swap_fg_bg)
+{
+ b2r2_log_info("%s: bg.win=(%d, %d, %d, %d)\n", __func__,
+ bg->win.x, bg->win.y, bg->win.width,
+ bg->win.height);
+
+ /* Configure S1 */
+ switch (bg->type) {
+ case B2R2_FMT_TYPE_RASTER:
+ if (swap_fg_bg) {
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_2_FETCH_FROM_MEM;
+ node->node.GROUP0.B2R2_ACK |= B2R2_ACK_SWAP_FG_BG;
+
+ set_src(&node->node.GROUP4, bg->addr, bg);
+ } else {
+ node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_1;
+ node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_1_FETCH_FROM_MEM;
+
+ set_src(&node->node.GROUP3, bg->addr, bg);
+ }
+ break;
+ default:
+ /* Should never, ever happen */
+ BUG_ON(1);
+ break;
+ }
+}
+
+/**
* configure_dst() - configures the destination registers of the given node
*
* @node - the node to configure
@@ -2513,7 +2696,6 @@ error:
* @node - the node to configure
* @flags - the flags passed in the blt_request
* @global_alpha - the global alpha to use (if enabled in flags)
- * @swap_fg_bg - if true, fg will be on s1 instead of s2
*
* This operation will not consume any nodes.
*
@@ -2523,8 +2705,7 @@ error:
* WARNING: Take care when using this with semi-planar or planar sources since
* either S1 or S2 will be overwritten!
*/
-static void configure_blend(struct b2r2_node *node, u32 flags, u32 global_alpha,
- bool swap_fg_bg)
+static void configure_blend(struct b2r2_node *node, u32 flags, u32 global_alpha)
{
node->node.GROUP0.B2R2_ACK &= ~(B2R2_ACK_MODE_BYPASS_S2_S3);
@@ -2534,9 +2715,8 @@ static void configure_blend(struct b2r2_node *node, u32 flags, u32 global_alpha,
else
node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BLEND_PREMULT;
-
/* Check if global alpha blend should be enabled */
- if ((flags & B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND) != 0) {
+ if (flags & B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND) {
/* B2R2 expects the global alpha to be in 0...128 range */
global_alpha = (global_alpha*128)/255;
@@ -2547,34 +2727,6 @@ static void configure_blend(struct b2r2_node *node, u32 flags, u32 global_alpha,
node->node.GROUP0.B2R2_ACK |=
(128 << B2R2_ACK_GALPHA_ROPID_SHIFT);
}
-
- /* Copy the destination config to the appropriate source and clear any
- clashing flags */
- if (swap_fg_bg) {
- /* S1 will be foreground, S2 background */
- node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2;
- node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_2_FETCH_FROM_MEM;
- node->node.GROUP0.B2R2_ACK |= B2R2_ACK_SWAP_FG_BG;
-
- node->node.GROUP4.B2R2_SBA = node->node.GROUP1.B2R2_TBA;
- node->node.GROUP4.B2R2_STY = node->node.GROUP1.B2R2_TTY;
- node->node.GROUP4.B2R2_SXY = node->node.GROUP1.B2R2_TXY;
- node->node.GROUP4.B2R2_SSZ = node->node.GROUP1.B2R2_TSZ;
-
- node->node.GROUP4.B2R2_STY &= ~(B2R2_S2TY_A1_SUBST_KEY_MODE |
- B2R2_S2TY_CHROMA_LEFT_EXT_AVERAGE);
- } else {
- /* S1 will be background, S2 foreground */
- node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_1;
- node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_1_FETCH_FROM_MEM;
-
- node->node.GROUP3.B2R2_SBA = node->node.GROUP1.B2R2_TBA;
- node->node.GROUP3.B2R2_STY |= node->node.GROUP1.B2R2_TTY;
- node->node.GROUP3.B2R2_SXY = node->node.GROUP1.B2R2_TXY;
-
- node->node.GROUP3.B2R2_STY &= ~(B2R2_S1TY_A1_SUBST_KEY_MODE);
-
- }
}
/**
@@ -3060,13 +3212,13 @@ static int fmt_byte_pitch(enum b2r2_blt_fmt fmt, u32 width)
case B2R2_BLT_FMT_24_BIT_RGB888: /* Fall through */
case B2R2_BLT_FMT_24_BIT_ARGB8565: /* Fall through */
- case B2R2_BLT_FMT_24_BIT_YUV888:
+ case B2R2_BLT_FMT_24_BIT_YUV888: /* Fall through */
case B2R2_BLT_FMT_24_BIT_VUY888:
return width * 3;
case B2R2_BLT_FMT_32_BIT_ARGB8888: /* Fall through */
case B2R2_BLT_FMT_32_BIT_ABGR8888: /* Fall through */
- case B2R2_BLT_FMT_32_BIT_AYUV8888:
+ case B2R2_BLT_FMT_32_BIT_AYUV8888: /* Fall through */
case B2R2_BLT_FMT_32_BIT_VUYA8888:
return width << 2;
diff --git a/drivers/video/b2r2/b2r2_utils.c b/drivers/video/b2r2/b2r2_utils.c
index ad0e7a42fa1..8bb61afdd41 100644
--- a/drivers/video/b2r2/b2r2_utils.c
+++ b/drivers/video/b2r2/b2r2_utils.c
@@ -45,6 +45,13 @@ bool b2r2_is_rect_inside_rect(struct b2r2_blt_rect *rect1,
rect1->y + rect1->height <= rect2->y + rect2->height;
}
+bool b2r2_is_rect_gte_rect(struct b2r2_blt_rect *rect1,
+ struct b2r2_blt_rect *rect2)
+{
+ return rect1->width >= rect2->width &&
+ rect1->height >= rect2->height;
+}
+
void b2r2_intersect_rects(struct b2r2_blt_rect *rect1,
struct b2r2_blt_rect *rect2, struct b2r2_blt_rect *intersection)
{
diff --git a/drivers/video/b2r2/b2r2_utils.h b/drivers/video/b2r2/b2r2_utils.h
index 745d71c0126..5db7868e255 100644
--- a/drivers/video/b2r2/b2r2_utils.h
+++ b/drivers/video/b2r2/b2r2_utils.h
@@ -21,6 +21,8 @@ void b2r2_get_img_bounding_rect(struct b2r2_blt_img *img,
bool b2r2_is_zero_area_rect(struct b2r2_blt_rect *rect);
bool b2r2_is_rect_inside_rect(struct b2r2_blt_rect *rect1,
struct b2r2_blt_rect *rect2);
+bool b2r2_is_rect_gte_rect(struct b2r2_blt_rect *rect1,
+ struct b2r2_blt_rect *rect2);
void b2r2_intersect_rects(struct b2r2_blt_rect *rect1,
struct b2r2_blt_rect *rect2, struct b2r2_blt_rect *intersection);
diff --git a/include/video/b2r2_blt.h b/include/video/b2r2_blt.h
index a992155f0da..26748d4f212 100644
--- a/include/video/b2r2_blt.h
+++ b/include/video/b2r2_blt.h
@@ -302,6 +302,21 @@ enum b2r2_blt_transform {
* Enable destination clip rectangle
* @B2R2_BLT_FLAG_INHERIT_PRIO
* Inherit process priority
+ * @B2R2_BLT_FLAG_SRC_NO_CACHE_FLUSH
+ * Skip cache flush of source image buffer
+ * @B2R2_BLT_FLAG_SRC_MASK_NO_CACHE_FLUSH
+ * Skip cache flush of source mask buffer
+ * @B2R2_BLT_FLAG_DST_NO_CACHE_FLUSH
+ * Skip cache flush of destination image buffer
+ * @B2R2_BLT_FLAG_BG_BLEND
+ * Indicate that a background buffer is supplied
+ * to the blit operation. B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND,
+ * B2R2_BLT_FLAG_SRC_IS_NOT_PREMULT, and
+ * B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND will control the blend operation.
+ * The destination blending is in this case disabled and the destination
+ * buffer will be overwritten with the source and background blend result.
+ * @B2R2_BLT_FLAG_BG_NO_CACHE_FLUSH
+ * Skip cache flush of background image buffer
* @B2R2_BLT_FLAG_REPORT_WHEN_DONE
* Report through b2r2_blt file when done. A b2r2_blt_report structure is
* read. Use poll() or select() if anything to read. (i.e. to help user space
@@ -355,6 +370,8 @@ enum b2r2_blt_flag {
B2R2_BLT_FLAG_SRC_NO_CACHE_FLUSH = BIT(14),/*0x4000*/
B2R2_BLT_FLAG_SRC_MASK_NO_CACHE_FLUSH = BIT(15),/*0x8000*/
B2R2_BLT_FLAG_DST_NO_CACHE_FLUSH = BIT(16),/*0x10000*/
+ B2R2_BLT_FLAG_BG_BLEND = BIT(17),/*0x20000*/
+ B2R2_BLT_FLAG_BG_NO_CACHE_FLUSH = BIT(18),/*0x40000*/
B2R2_BLT_FLAG_REPORT_WHEN_DONE = BIT(29),/*0x20000000*/
B2R2_BLT_FLAG_REPORT_PERFORMANCE = BIT(30),/*0x40000000*/
B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION = BIT(31),/*0x80000000*/
@@ -375,6 +392,8 @@ enum b2r2_blt_flag {
* @src_mask: Source mask. Not used if source fill.
* @src_rect: Source area to be blitted.
* @src_color: Source fill color or color key
+ * @bg_img: Background image.
+ * @bg_rect: Background area to blend with.
* @dst_img: Destination image.
* @dst_rect: Destination area to be blitted to.
* @dst_color: Destination color key
@@ -396,6 +415,8 @@ struct b2r2_blt_req {
struct b2r2_blt_img src_mask;
struct b2r2_blt_rect src_rect;
__u32 src_color;
+ struct b2r2_blt_img bg_img;
+ struct b2r2_blt_rect bg_rect;
struct b2r2_blt_img dst_img;
struct b2r2_blt_rect dst_rect;
struct b2r2_blt_rect dst_clip_rect;