diff options
author | Francis Hart <fhart@nvidia.com> | 2011-03-23 12:30:15 +0200 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-04-15 18:34:31 -0700 |
commit | 063b3c474383cb38a515e4460196bd8ed3946306 (patch) | |
tree | d48663027048d7886153e6207fb8b436a8181b86 /drivers | |
parent | f9dce2202b259c240cf5867654b5340ff8e0c3ab (diff) |
tegra dc: fix premult dst alpha blending
Register assignments were wrong for incoming overlay blend
parameters. DisplayManagerLite policy sets src combine mode
to premult to signal dst premult aplha blending. But the DC
expects premult set for the dst window for this mode.
Bug 796009
Change-Id: I5929bc4cd362ac60c7a9f14bb4ae83da04b857ab
Reviewed-on: http://git-master/r/26835
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/tegra/dc/overlay.c | 66 |
1 files changed, 63 insertions, 3 deletions
diff --git a/drivers/video/tegra/dc/overlay.c b/drivers/video/tegra/dc/overlay.c index b76d87ced011..c915c2d78b63 100644 --- a/drivers/video/tegra/dc/overlay.c +++ b/drivers/video/tegra/dc/overlay.c @@ -59,6 +59,8 @@ struct tegra_overlay_info { struct tegra_dc *dc; + struct tegra_dc_blend blend; + struct workqueue_struct *flip_wq; /* Big enough for tegra_dc%u when %u < 10 */ @@ -83,6 +85,7 @@ struct tegra_overlay_flip_data { struct tegra_overlay_info *overlay; struct tegra_overlay_flip_win win[TEGRA_FB_FLIP_N_WINDOWS]; u32 syncpt_max; + u32 flags; }; /* Overlay window manipulation */ @@ -181,10 +184,54 @@ static int tegra_overlay_set_windowattr(struct tegra_overlay_info *overlay, msecs_to_jiffies(500)); } + /* Store the blend state incase we need to reorder later */ + overlay->blend.z[win->idx] = win->z; + overlay->blend.flags[win->idx] = win->flags & TEGRA_WIN_BLEND_FLAGS_MASK; return 0; } +/* overlay policy for premult is dst alpha, which needs reassignment */ +/* of blend settings for the DC */ +static void tegra_overlay_blend_reorder(struct tegra_dc_blend *blend, + struct tegra_dc_win *windows[]) +{ + int idx, below; + + /* Copy across the original blend state to each window */ + for (idx = 0; idx < DC_N_WINDOWS; idx++) { + windows[idx]->z = blend->z[idx]; + windows[idx]->flags &= ~TEGRA_WIN_BLEND_FLAGS_MASK; + windows[idx]->flags |= blend->flags[idx]; + } + + /* Find a window with PreMult */ + for (idx = 0; idx < DC_N_WINDOWS; idx++) { + if (blend->flags[idx] == TEGRA_WIN_FLAG_BLEND_PREMULT) + break; + } + if (idx == DC_N_WINDOWS) + return; + + /* Find the window directly below it */ + for (below = 0; below < DC_N_WINDOWS; below++) { + if (below == idx) + continue; + if (blend->z[below] > blend->z[idx]) + break; + } + if (below == DC_N_WINDOWS) + return; + + /* Switch the flags and the ordering */ + windows[idx]->z = blend->z[below]; + windows[idx]->flags &= ~TEGRA_WIN_BLEND_FLAGS_MASK; + windows[idx]->flags |= blend->flags[below]; + windows[below]->z = blend->z[idx]; + windows[below]->flags &= ~TEGRA_WIN_BLEND_FLAGS_MASK; + windows[below]->flags |= blend->flags[idx]; +} + static void tegra_overlay_flip_worker(struct work_struct *work) { struct tegra_overlay_flip_data *data = @@ -230,9 +277,20 @@ static void tegra_overlay_flip_worker(struct work_struct *work) #endif } - tegra_dc_update_windows(wins, nr_win); - /* TODO: implement swapinterval here */ - tegra_dc_sync_windows(wins, nr_win); + if (data->flags & TEGRA_OVERLAY_FLIP_FLAG_BLEND_REORDER) { + struct tegra_dc_win *dcwins[DC_N_WINDOWS]; + + for (i = 0; i < DC_N_WINDOWS; i++) + dcwins[i] = tegra_dc_get_window(overlay->dc, i); + + tegra_overlay_blend_reorder(&overlay->blend, dcwins); + tegra_dc_update_windows(dcwins, DC_N_WINDOWS); + tegra_dc_sync_windows(dcwins, DC_N_WINDOWS); + } else { + tegra_dc_update_windows(wins, nr_win); + /* TODO: implement swapinterval here */ + tegra_dc_sync_windows(wins, nr_win); + } tegra_dc_incr_syncpt_min(overlay->dc, data->syncpt_max); @@ -266,6 +324,7 @@ static int tegra_overlay_flip(struct tegra_overlay_info *overlay, INIT_WORK(&data->work, tegra_overlay_flip_worker); data->overlay = overlay; + data->flags = args->flags; for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) { flip_win = &data->win[i]; @@ -355,6 +414,7 @@ static void tegra_overlay_put_locked(struct overlay_client *client, int idx) flip_args.win[0].buff_id = 0; flip_args.win[1].index = -1; flip_args.win[2].index = -1; + flip_args.flags = 0; tegra_overlay_flip(dev, &flip_args, NULL); if (dev->dc->mode.pclk != 0) |