From: Greg Hackmann <ghackmann@google.com>
Date: Fri, 13 Jul 2012 20:23:11 +0000 (-0700)
Subject: hwc: enable overlay support for all hardware windows
X-Git-Tag: cm-10.1-M1~324
X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=31991d5b23d9099b66a73fea7fc5cc9b05ff26a6;p=GitHub%2FLineageOS%2Fandroid_hardware_samsung_slsi_exynos5.git

hwc: enable overlay support for all hardware windows

Change-Id: Ic154afc5e955275468f228a6a0a0f4cf02b99034
Signed-off-by: Greg Hackmann <ghackmann@google.com>
---

diff --git a/libhwc/hwc.cpp b/libhwc/hwc.cpp
index c61e421..1d24cdb 100644
--- a/libhwc/hwc.cpp
+++ b/libhwc/hwc.cpp
@@ -52,8 +52,9 @@ struct hwc_callback_entry
 };
 typedef android::Vector<struct hwc_callback_entry> hwc_callback_queue_t;
 
-const size_t NUM_HW_WINDOWS = 2;
+const size_t NUM_HW_WINDOWS = 5;
 const size_t NO_FB_NEEDED = NUM_HW_WINDOWS + 1;
+const size_t MAX_PIXELS = 2560 * 1600 * 2;
 
 struct exynos5_hwc_composer_device_1_t;
 
@@ -123,6 +124,13 @@ static void dump_config(s3c_fb_win_config &c)
 
 inline int WIDTH(const hwc_rect &rect) { return rect.right - rect.left; }
 inline int HEIGHT(const hwc_rect &rect) { return rect.bottom - rect.top; }
+template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; }
+template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; }
+
+static bool is_transformed(const hwc_layer_1_t &layer)
+{
+	return layer.transform != 0;
+}
 
 static bool is_scaled(const hwc_layer_1_t &layer)
 {
@@ -271,10 +279,11 @@ bool exynos5_supports_overlay(hwc_layer_1_t &layer, size_t i) {
 		return false;
 	}
 	if (is_scaled(layer)) {
-		// TODO: this can be made into an overlay if a gscaler
-		// unit is available.  Also some size and pixel format
-		// limitations (see 46-3 of datasheet)
-		ALOGV("\tlayer %u: scaling and transforming not supported", i);
+		ALOGV("\tlayer %u: scaling not supported", i);
+		return false;
+	}
+	if (is_transformed(layer)) {
+		ALOGV("\tlayer %u: transformations not supported", i);
 		return false;
 	}
 	if (layer.blending != HWC_BLENDING_NONE) {
@@ -286,6 +295,24 @@ bool exynos5_supports_overlay(hwc_layer_1_t &layer, size_t i) {
 	return true;
 }
 
+inline bool intersect(const hwc_rect &r1, const hwc_rect &r2)
+{
+	return !(r1.left > r2.right ||
+		r1.right < r2.left ||
+		r1.top > r2.bottom ||
+		r1.bottom < r2.top);
+}
+
+inline hwc_rect intersection(const hwc_rect &r1, const hwc_rect &r2)
+{
+	hwc_rect i;
+	i.top = max(r1.top, r2.top);
+	i.bottom = min(r1.bottom, r2.bottom);
+	i.left = max(r1.left, r2.left);
+	i.right = min(r1.right, r2.right);
+	return i;
+}
+
 static int exynos5_prepare(hwc_composer_device_1_t *dev, hwc_layer_list_1_t* list)
 {
 	if (!list)
@@ -309,7 +336,7 @@ static int exynos5_prepare(hwc_composer_device_1_t *dev, hwc_layer_list_1_t* lis
         pdev->bufs.overlay_map[i] = -1;
 
 	bool fb_needed = false;
-	size_t first_fb = 0, last_fb;
+	size_t first_fb = 0, last_fb = 0;
 
 	// find unsupported overlays
 	for (size_t i = 0; i < list->numHwLayers; i++) {
@@ -339,28 +366,96 @@ static int exynos5_prepare(hwc_composer_device_1_t *dev, hwc_layer_list_1_t* lis
 		for (size_t i = first_fb; i < last_fb; i++)
 			list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
 
-	// if we need a framebuffer but can't fit it in, reserve the last
-	// window as a framebuffer
-	if ((fb_needed && first_fb >= NUM_HW_WINDOWS) ||
-			(!fb_needed && list->numHwLayers > NUM_HW_WINDOWS)) {
-		fb_needed = true;
-		first_fb = NUM_HW_WINDOWS - 1;
-		for (size_t i = first_fb; i < list->numHwLayers; i++)
-			list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
-	}
+	// Incrementally try to add our supported layers to hardware windows.
+	// If adding a layer would violate a hardware constraint, force it
+	// into the framebuffer and try again.  (Revisiting the entire list is
+	// necessary because adding a layer to the framebuffer can cause other
+	// windows to retroactively violate constraints.)
+	bool changed;
+	do {
+		android::Vector<hwc_rect> rects;
+		android::Vector<hwc_rect> overlaps;
+		size_t pixels_left, windows_left;
+
+		if (fb_needed) {
+			hwc_rect_t fb_rect;
+			fb_rect.top = fb_rect.left = 0;
+			fb_rect.right = pdev->gralloc_module->xres - 1;
+			fb_rect.bottom = pdev->gralloc_module->yres - 1;
+			pixels_left = MAX_PIXELS - pdev->gralloc_module->xres *
+					pdev->gralloc_module->yres;
+			windows_left = NUM_HW_WINDOWS - 1;
+			rects.push_back(fb_rect);
+		}
+		else {
+			pixels_left = MAX_PIXELS;
+			windows_left = NUM_HW_WINDOWS;
+		}
+		changed = false;
+
+		for (size_t i = 0; i < list->numHwLayers; i++) {
+			hwc_layer_1_t &layer = list->hwLayers[i];
+
+			// we've already accounted for the framebuffer above
+			if (layer.compositionType == HWC_FRAMEBUFFER)
+				continue;
+
+			// only layer 0 can be HWC_BACKGROUND, so we can
+			// unconditionally allow it without extra checks
+			if (layer.compositionType == HWC_BACKGROUND) {
+				windows_left--;
+				continue;
+			}
+
+			size_t pixels_needed = WIDTH(layer.displayFrame) *
+					HEIGHT(layer.displayFrame);
+			bool can_compose = windows_left && pixels_needed <= pixels_left;
+
+			// hwc_rect_t right and bottom values are normally exclusive;
+			// the intersection logic is simpler if we make them inclusive
+			hwc_rect_t visible_rect = layer.displayFrame;
+			visible_rect.right--; visible_rect.bottom--;
+
+			// no more than 2 layers can overlap on a given pixel
+			for (size_t j = 0; can_compose && j < overlaps.size(); j++) {
+				if (intersect(visible_rect, overlaps.itemAt(j)))
+					can_compose = false;
+			}
+
+			if (!can_compose) {
+				layer.compositionType = HWC_FRAMEBUFFER;
+				if (!fb_needed) {
+					first_fb = last_fb = i;
+					fb_needed = true;
+				}
+				else {
+					first_fb = min(i, first_fb);
+					last_fb = max(i, last_fb);
+				}
+				changed = true;
+				break;
+			}
+
+			for (size_t j = 0; j < rects.size(); j++) {
+				const hwc_rect_t &other_rect = rects.itemAt(j);
+				if (intersect(visible_rect, other_rect))
+					overlaps.push_back(intersection(visible_rect, other_rect));
+			}
+			rects.push_back(visible_rect);
+			pixels_left -= pixels_needed;
+			windows_left--;
+		}
+
+		if (changed)
+			for (size_t i = first_fb; i < last_fb; i++)
+				list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
+	} while(changed);
 
 	unsigned int nextWindow = 0;
 
-	// assign as many overlays as possible to windows
 	for (size_t i = 0; i < list->numHwLayers; i++) {
 		hwc_layer_1_t &layer = list->hwLayers[i];
 
-		if (nextWindow == NUM_HW_WINDOWS) {
-			ALOGV("not enough windows to assign layer %u", i);
-			layer.compositionType = HWC_FRAMEBUFFER;
-			continue;
-		}
-
 		if (fb_needed && i == first_fb) {
 			ALOGV("assigning framebuffer to window %u\n",
 					nextWindow);