summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorFrancis Hart <fhart@nvidia.com>2011-03-23 12:30:15 +0200
committerVarun Colbert <vcolbert@nvidia.com>2011-04-15 18:34:31 -0700
commit063b3c474383cb38a515e4460196bd8ed3946306 (patch)
treed48663027048d7886153e6207fb8b436a8181b86 /drivers
parentf9dce2202b259c240cf5867654b5340ff8e0c3ab (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.c66
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)