diff options
author | Jörgen Nilsson <jorgen.nilsson@stericsson.com> | 2011-10-12 13:52:32 +0200 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@linaro.org> | 2012-03-19 09:00:17 +0100 |
commit | 6ba571ff2b467d5f2776275f5ab24a335b932864 (patch) | |
tree | e4b04e3a36de4851b9827b837e4708f0478d82f8 /drivers/video | |
parent | 0a6f8864f9e38f24c93fa3445604cee4066d3e98 (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>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/b2r2/b2r2_blt_main.c | 184 | ||||
-rw-r--r-- | drivers/video/b2r2/b2r2_input_validation.c | 67 | ||||
-rw-r--r-- | drivers/video/b2r2/b2r2_internal.h | 4 | ||||
-rw-r--r-- | drivers/video/b2r2/b2r2_node_split.c | 238 | ||||
-rw-r--r-- | drivers/video/b2r2/b2r2_utils.c | 7 | ||||
-rw-r--r-- | drivers/video/b2r2/b2r2_utils.h | 2 |
6 files changed, 407 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); |