summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@nokia.com>2010-06-09 15:09:30 +0300
committerTomi Valkeinen <tomi.valkeinen@nokia.com>2010-08-03 15:18:45 +0300
commit8cab90fdb4c71f9a92c09c015aee42ff2149b317 (patch)
tree76d367e62d5bc784f10a74c62da45376f8723580
parent75c7d59daf502a4eb040e181120fb83b4a8c0719 (diff)
downloadlinux-8cab90fdb4c71f9a92c09c015aee42ff2149b317.tar.gz
linux-8cab90fdb4c71f9a92c09c015aee42ff2149b317.tar.bz2
linux-8cab90fdb4c71f9a92c09c015aee42ff2149b317.zip
OMAP: DSS2: Fix update area calculations with multiple scaled overlays
When there are multiple scaled overlays simply checking whether the update area intersects any of them in order is not enough. If eg. VID1 starts out completely outside the update area but VID2 causes the update area to increase in such a way that VID1 now falls partially within the increased update area VID1 should be rechecked and the update area possibly increased even further to fully encompass VID1. So simply keep looping over the overlays until such time that none of the overlays caused the update area to change. Signed-off-by: Ville Syrjälä <ville.syrjala@nokia.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
-rw-r--r--drivers/video/omap2/dss/manager.c141
1 files changed, 78 insertions, 63 deletions
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 7e1ec5af6c70..a1d84ef65904 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -972,6 +972,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
int i;
u16 x, y, w, h;
unsigned long flags;
+ bool area_changed;
x = *xi;
y = *yi;
@@ -992,70 +993,84 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
spin_lock_irqsave(&dss_cache.lock, flags);
- /* We need to show the whole overlay if it is scaled. So look for
- * those, and make the update area larger if found.
- * Also mark the overlay cache dirty */
- for (i = 0; i < num_ovls; ++i) {
- unsigned x1, y1, x2, y2;
- unsigned outw, outh;
-
- oc = &dss_cache.overlay_cache[i];
-
- if (oc->channel != mgr->id)
- continue;
-
- oc->dirty = true;
-
- if (!oc->enabled)
- continue;
-
- if (!dispc_is_overlay_scaled(oc))
- continue;
-
- outw = oc->out_width == 0 ? oc->width : oc->out_width;
- outh = oc->out_height == 0 ? oc->height : oc->out_height;
-
- /* is the overlay outside the update region? */
- if (!rectangle_intersects(x, y, w, h,
- oc->pos_x, oc->pos_y,
- outw, outh))
- continue;
-
- /* if the overlay totally inside the update region? */
- if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
- x, y, w, h))
- continue;
-
- if (x > oc->pos_x)
- x1 = oc->pos_x;
- else
- x1 = x;
-
- if (y > oc->pos_y)
- y1 = oc->pos_y;
- else
- y1 = y;
-
- if ((x + w) < (oc->pos_x + outw))
- x2 = oc->pos_x + outw;
- else
- x2 = x + w;
-
- if ((y + h) < (oc->pos_y + outh))
- y2 = oc->pos_y + outh;
- else
- y2 = y + h;
-
- x = x1;
- y = y1;
- w = x2 - x1;
- h = y2 - y1;
-
- make_even(&x, &w);
-
- DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n",
+ /*
+ * Execute the outer loop until the inner loop has completed
+ * once without increasing the update area. This will ensure that
+ * all scaled overlays end up completely within the update area.
+ */
+ do {
+ area_changed = false;
+
+ /* We need to show the whole overlay if it is scaled. So look
+ * for those, and make the update area larger if found.
+ * Also mark the overlay cache dirty */
+ for (i = 0; i < num_ovls; ++i) {
+ unsigned x1, y1, x2, y2;
+ unsigned outw, outh;
+
+ oc = &dss_cache.overlay_cache[i];
+
+ if (oc->channel != mgr->id)
+ continue;
+
+ oc->dirty = true;
+
+ if (!oc->enabled)
+ continue;
+
+ if (!dispc_is_overlay_scaled(oc))
+ continue;
+
+ outw = oc->out_width == 0 ?
+ oc->width : oc->out_width;
+ outh = oc->out_height == 0 ?
+ oc->height : oc->out_height;
+
+ /* is the overlay outside the update region? */
+ if (!rectangle_intersects(x, y, w, h,
+ oc->pos_x, oc->pos_y,
+ outw, outh))
+ continue;
+
+ /* if the overlay totally inside the update region? */
+ if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
+ x, y, w, h))
+ continue;
+
+ if (x > oc->pos_x)
+ x1 = oc->pos_x;
+ else
+ x1 = x;
+
+ if (y > oc->pos_y)
+ y1 = oc->pos_y;
+ else
+ y1 = y;
+
+ if ((x + w) < (oc->pos_x + outw))
+ x2 = oc->pos_x + outw;
+ else
+ x2 = x + w;
+
+ if ((y + h) < (oc->pos_y + outh))
+ y2 = oc->pos_y + outh;
+ else
+ y2 = y + h;
+
+ x = x1;
+ y = y1;
+ w = x2 - x1;
+ h = y2 - y1;
+
+ make_even(&x, &w);
+
+ DSSDBG("changing upd area due to ovl(%d) "
+ "scaling %d,%d %dx%d\n",
i, x, y, w, h);
- }
+
+ area_changed = true;
+ }
+ } while (area_changed);
mc = &dss_cache.manager_cache[mgr->id];
mc->do_manual_update = true;