msm: display: plane alpha support
Clean up the blending rule to follow blend_op set from hwc.
Use modulate alpha for plane alpha when it is not 0xff.
Keep backward compatibility if blend_op is not set.
Change-Id: I02fd3c3c7b5ace2e6eec22b2db0284161404a0fc
Signed-off-by: Ken Zhang <kenz@codeaurora.org>
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 5bbca5d..a8c3ca4 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -2077,6 +2077,98 @@
}
}
+static void mdp4_set_blend_by_op(struct mdp4_overlay_pipe *s_pipe,
+ struct mdp4_overlay_pipe *d_pipe,
+ int alpha_drop,
+ struct blend_cfg *blend)
+{
+ int d_alpha, s_alpha;
+ u32 op;
+
+ d_alpha = d_pipe->alpha_enable;
+ s_alpha = s_pipe->alpha_enable;
+ /* base on fg's alpha */
+ blend->fg_alpha = s_pipe->alpha;
+ blend->bg_alpha = 0x0ff - s_pipe->alpha;
+ blend->op = MDP4_BLEND_FG_ALPHA_FG_CONST |
+ MDP4_BLEND_BG_ALPHA_BG_CONST;
+ blend->co3_sel = 1; /* use fg alpha */
+ op = s_pipe->blend_op;
+ if (op == BLEND_OP_OPAQUE) {
+ blend->bg_alpha = 0;
+ blend->fg_alpha = 0xff;
+ } else if ((op == BLEND_OP_PREMULTIPLIED) &&
+ (!alpha_drop) && s_alpha) {
+ blend->op = MDP4_BLEND_FG_ALPHA_FG_CONST |
+ MDP4_BLEND_BG_INV_ALPHA |
+ MDP4_BLEND_BG_ALPHA_FG_PIXEL;
+ if (blend->fg_alpha != 0xff) {
+ blend->bg_alpha = blend->fg_alpha;
+ blend->op |= MDP4_BLEND_BG_MOD_ALPHA;
+ }
+ } else if (!alpha_drop && s_alpha) {
+ blend->op = MDP4_BLEND_FG_ALPHA_FG_PIXEL |
+ MDP4_BLEND_BG_INV_ALPHA |
+ MDP4_BLEND_BG_ALPHA_FG_PIXEL;
+ if (blend->fg_alpha != 0xff) {
+ blend->bg_alpha = blend->fg_alpha;
+ blend->op |= MDP4_BLEND_FG_MOD_ALPHA |
+ MDP4_BLEND_BG_MOD_ALPHA;
+ }
+ }
+ if (!s_alpha && d_alpha)
+ blend->co3_sel = 0;
+ pr_debug("%s: op %d bg alpha %d, fg alpha %d blend: %x\n",
+ __func__, op, blend->bg_alpha, blend->fg_alpha, blend->op);
+}
+
+static void mdp4_set_blend_by_fmt(struct mdp4_overlay_pipe *s_pipe,
+ struct mdp4_overlay_pipe *d_pipe,
+ int alpha_drop,
+ struct blend_cfg *blend)
+{
+ int ptype, d_alpha, s_alpha;
+ d_alpha = d_pipe->alpha_enable;
+ s_alpha = s_pipe->alpha_enable;
+ /* base on fg's alpha */
+ blend->bg_alpha = 0x0ff - s_pipe->alpha;
+ blend->fg_alpha = s_pipe->alpha;
+ blend->co3_sel = 1; /* use fg alpha */
+
+ if (s_pipe->is_fg) {
+ if (s_pipe->alpha == 0xff) {
+ blend->solidfill = 1;
+ blend->solidfill_pipe = d_pipe;
+ }
+ } else if (s_alpha) {
+ if (!alpha_drop) {
+ blend->op = MDP4_BLEND_BG_ALPHA_FG_PIXEL;
+ if (!(s_pipe->flags & MDP_BLEND_FG_PREMULT))
+ blend->op |=
+ MDP4_BLEND_FG_ALPHA_FG_PIXEL;
+ } else
+ blend->op = MDP4_BLEND_BG_ALPHA_FG_CONST;
+
+ blend->op |= MDP4_BLEND_BG_INV_ALPHA;
+ } else if (d_alpha) {
+ ptype = mdp4_overlay_format2type(s_pipe->src_format);
+ if (ptype == OVERLAY_TYPE_VIDEO &&
+ (!(s_pipe->flags & MDP_BACKEND_COMPOSITION))) {
+ blend->op = (MDP4_BLEND_FG_ALPHA_BG_PIXEL |
+ MDP4_BLEND_FG_INV_ALPHA);
+ if (!(s_pipe->flags & MDP_BLEND_FG_PREMULT))
+ blend->op |=
+ MDP4_BLEND_BG_ALPHA_BG_PIXEL;
+ blend->co3_sel = 0; /* use bg alpha */
+ } else {
+ /* s_pipe is rgb without alpha */
+ blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
+ MDP4_BLEND_BG_ALPHA_BG_CONST);
+ blend->bg_alpha = 0;
+ }
+ }
+}
+
/*
* D(i+1) = Ks * S + Kd * D(i)
*/
@@ -2085,8 +2177,7 @@
struct mdp4_overlay_pipe *d_pipe;
struct mdp4_overlay_pipe *s_pipe;
struct blend_cfg *blend;
- int i, off, ptype, alpha_drop;
- int d_alpha, s_alpha;
+ int i, off, alpha_drop;
unsigned char *overlay_base;
uint32 c0, c1, c2;
@@ -2106,7 +2197,6 @@
if (s_pipe == NULL) {
blend++;
d_pipe = NULL;
- d_alpha = 0;
continue;
}
alpha_drop = 0; /* per stage */
@@ -2120,51 +2210,17 @@
alpha_drop = 1;
d_pipe = mdp4_background_layer(mixer, s_pipe);
- d_alpha = d_pipe->alpha_enable;
- s_alpha = s_pipe->alpha_enable;
pr_debug("%s: stage=%d: bg: ndx=%d da=%d dalpha=%x "
"fg: ndx=%d sa=%d salpha=%x is_fg=%d alpha_drop=%d\n",
- __func__, i-2, d_pipe->pipe_ndx, d_alpha, d_pipe->alpha,
- s_pipe->pipe_ndx, s_alpha, s_pipe->alpha, s_pipe->is_fg,
- alpha_drop);
-
- /* base on fg's alpha */
- blend->bg_alpha = 0x0ff - s_pipe->alpha;
- blend->fg_alpha = s_pipe->alpha;
- blend->co3_sel = 1; /* use fg alpha */
-
- if (s_pipe->is_fg) {
- if (s_pipe->alpha == 0xff) {
- blend->solidfill = 1;
- blend->solidfill_pipe = d_pipe;
- }
- } else if (s_alpha) {
- if (!alpha_drop) {
- blend->op = MDP4_BLEND_BG_ALPHA_FG_PIXEL;
- if (!(s_pipe->flags & MDP_BLEND_FG_PREMULT))
- blend->op |=
- MDP4_BLEND_FG_ALPHA_FG_PIXEL;
- } else
- blend->op = MDP4_BLEND_BG_ALPHA_FG_CONST;
-
- blend->op |= MDP4_BLEND_BG_INV_ALPHA;
- } else if (d_alpha) {
- ptype = mdp4_overlay_format2type(s_pipe->src_format);
- if (ptype == OVERLAY_TYPE_VIDEO &&
- (!(s_pipe->flags & MDP_BACKEND_COMPOSITION))) {
- blend->op = (MDP4_BLEND_FG_ALPHA_BG_PIXEL |
- MDP4_BLEND_FG_INV_ALPHA);
- if (!(s_pipe->flags & MDP_BLEND_FG_PREMULT))
- blend->op |=
- MDP4_BLEND_BG_ALPHA_BG_PIXEL;
- blend->co3_sel = 0; /* use bg alpha */
- } else {
- /* s_pipe is rgb without alpha */
- blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
- MDP4_BLEND_BG_ALPHA_BG_CONST);
- blend->bg_alpha = 0;
- }
- }
+ __func__, i-2, d_pipe->pipe_ndx, d_pipe->alpha_enable,
+ d_pipe->alpha, s_pipe->pipe_ndx, s_pipe->alpha_enable,
+ s_pipe->alpha, s_pipe->is_fg, alpha_drop);
+ if ((s_pipe->blend_op == BLEND_OP_NOT_DEFINED) ||
+ (s_pipe->blend_op >= BLEND_OP_MAX))
+ mdp4_set_blend_by_fmt(s_pipe, d_pipe,
+ alpha_drop, blend);
+ else
+ mdp4_set_blend_by_op(s_pipe, d_pipe, alpha_drop, blend);
if (s_pipe->transp != MDP_TRANSP_NOP) {
if (s_pipe->is_fg) {
@@ -2602,6 +2658,7 @@
pipe->is_fg = req->is_fg;/* control alpha and color key */
pipe->alpha = req->alpha & 0x0ff;
+ pipe->blend_op = req->blend_op;
pipe->transp = req->transp_mask;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index ff2f38a..394394b 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -350,6 +350,14 @@
struct mdp_sharp_cfg sharp_cfg;
};
+enum {
+ BLEND_OP_NOT_DEFINED = 0,
+ BLEND_OP_OPAQUE,
+ BLEND_OP_PREMULTIPLIED,
+ BLEND_OP_COVERAGE,
+ BLEND_OP_MAX,
+};
+
struct mdp_overlay {
struct msmfb_img src;
struct mdp_rect src_rect;
@@ -358,6 +366,7 @@
uint32_t is_fg; /* control alpha & transp */
uint32_t alpha;
uint32_t transp_mask;
+ uint32_t blend_op;
uint32_t flags;
uint32_t id;
uint32_t user_data[8];