summaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/dss/manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/dss/manager.c')
-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;