summaryrefslogtreecommitdiff
path: root/hwc
diff options
context:
space:
mode:
authorLajos Molnar <molnar@ti.com>2011-09-28 23:53:27 -0500
committerErik Gilling <konkers@android.com>2011-10-11 17:53:05 -0700
commit8d546610cba3698c62af537d97e38a7368362f1a (patch)
tree938b6f81feba3acc626fbe6a94bf9a544fcd12ff /hwc
parentffa0d75e7fa7142eb289ccc9c7dc04e4cedb7c46 (diff)
downloadomap4-aah-8d546610cba3698c62af537d97e38a7368362f1a.tar.gz
hwc: allow specifying clone region
Added android property ro.display.clone.region to set the clone region in case we do not want to clone the full framebuffer to HDMI. (E.g. status bar may not need to be cloned.) Change-Id: I35f2207c49b3a56ff61309efebe61b9dee6cfb8c Signed-off-by: Lajos Molnar <molnar@ti.com>
Diffstat (limited to 'hwc')
-rw-r--r--hwc/hwc.c128
1 files changed, 117 insertions, 11 deletions
diff --git a/hwc/hwc.c b/hwc/hwc.c
index 05bdb2d..115ad5a 100644
--- a/hwc/hwc.c
+++ b/hwc/hwc.c
@@ -85,6 +85,7 @@ struct omap4_hwc_ext {
__u32 xres; /* external screen resolution */
__u32 yres;
float m[2][3]; /* external transformation matrix */
+ hwc_rect_t mirror_region; /* region of screen to mirror */
};
typedef struct omap4_hwc_ext omap4_hwc_ext_t;
@@ -424,8 +425,11 @@ static void get_max_dimensions(__u32 orig_xres, __u32 orig_yres,
*adj_yres = (__u32) (y_factor * *adj_yres / x_factor + 0.5);
}
-static void set_ext_matrix(omap4_hwc_ext_t *ext, int orig_w, int orig_h)
+static void set_ext_matrix(omap4_hwc_ext_t *ext, struct hwc_rect region)
{
+ int orig_w = WIDTH(region);
+ int orig_h = HEIGHT(region);
+
/* assume 1:1 lcd pixel ratio */
int source_x = 1;
int source_y = 1;
@@ -434,7 +438,7 @@ static void set_ext_matrix(omap4_hwc_ext_t *ext, int orig_w, int orig_h)
m = (center-from-target-center) * (scale-to-target) * (mirror) * (rotate) * (center-to-original-center) */
memcpy(ext->m, m_unit, sizeof(m_unit));
- m_translate(ext->m, -orig_w >> 1, -orig_h >> 1);
+ m_translate(ext->m, -(orig_w >> 1) - region.left, -(orig_h >> 1) - region.top);
m_rotate(ext->m, ext->current.rotation);
if (ext->current.hflip)
m_scale(ext->m, 1, -1, 1, 1);
@@ -455,7 +459,7 @@ static void set_ext_matrix(omap4_hwc_ext_t *ext, int orig_w, int orig_h)
}
static void
-omap4_hwc_create_ext_matrix(omap4_hwc_ext_t *ext, omap4_hwc_device_t *hwc_dev)
+omap4_hwc_create_ext_matrix(omap4_hwc_ext_t *ext)
{
/* use VGA external resolution as default */
if (!ext->xres ||
@@ -467,16 +471,94 @@ omap4_hwc_create_ext_matrix(omap4_hwc_ext_t *ext, omap4_hwc_device_t *hwc_dev)
/* if docking, we cannot create the matrix ahead of time as it depends on input size */
if (ext->mirror.enabled) {
ext->current = ext->mirror;
- set_ext_matrix(ext, hwc_dev->fb_dev->base.width, hwc_dev->fb_dev->base.height);
+ set_ext_matrix(ext, ext->mirror_region);
}
}
+static int
+crop_to_rect(struct dss2_ovl_cfg *cfg, struct hwc_rect vis_rect)
+{
+ struct {
+ int xy[2];
+ int wh[2];
+ } crop, win;
+ struct {
+ int lt[2];
+ int rb[2];
+ } vis;
+ win.xy[0] = cfg->win.x; win.xy[1] = cfg->win.y;
+ win.wh[0] = cfg->win.w; win.wh[1] = cfg->win.h;
+ crop.xy[0] = cfg->crop.x; crop.xy[1] = cfg->crop.y;
+ crop.wh[0] = cfg->crop.w; crop.wh[1] = cfg->crop.h;
+ vis.lt[0] = vis_rect.left; vis.lt[1] = vis_rect.top;
+ vis.rb[0] = vis_rect.right; vis.rb[1] = vis_rect.bottom;
+
+ int c, swap = cfg->rotation & 1;
+
+ /* align crop window with display coordinates */
+ if (swap)
+ crop.xy[1] -= (crop.wh[1] = -crop.wh[1]);
+ if (cfg->rotation & 2)
+ crop.xy[!swap] -= (crop.wh[!swap] = -crop.wh[!swap]);
+ if ((!cfg->mirror) ^ !(cfg->rotation & 2))
+ crop.xy[swap] -= (crop.wh[swap] = -crop.wh[swap]);
+
+ for (c = 0; c < 2; c++) {
+ /* see if complete buffer is outside the vis or it is
+ fully cropped or scaled to 0 */
+ if (win.wh[c] <= 0 || vis.rb[c] <= vis.lt[c] ||
+ win.xy[c] + win.wh[c] <= vis.lt[c] ||
+ win.xy[c] >= vis.rb[c] ||
+ !crop.wh[c ^ swap])
+ return -ENOENT;
+
+ /* crop left/top */
+ if (win.xy[c] < vis.lt[c]) {
+ /* correction term */
+ int a = (vis.lt[c] - win.xy[c]) * crop.wh[c ^ swap] / win.wh[c];
+ crop.xy[c ^ swap] += a;
+ crop.wh[c ^ swap] -= a;
+ win.wh[c] -= vis.lt[c] - win.xy[c];
+ win.xy[c] = vis.lt[c];
+ }
+ /* crop right/bottom */
+ if (win.xy[c] + win.wh[c] > vis.rb[c]) {
+ crop.wh[c ^ swap] = crop.wh[c ^ swap] * (vis.rb[c] - win.xy[c]) / win.wh[c];
+ win.wh[c] = vis.rb[c] - win.xy[c];
+ }
+
+ if (!crop.wh[c ^ swap] || !win.wh[c])
+ return -ENOENT;
+ }
+
+ /* realign crop window to buffer coordinates */
+ if (cfg->rotation & 2)
+ crop.xy[!swap] -= (crop.wh[!swap] = -crop.wh[!swap]);
+ if ((!cfg->mirror) ^ !(cfg->rotation & 2))
+ crop.xy[swap] -= (crop.wh[swap] = -crop.wh[swap]);
+ if (swap)
+ crop.xy[1] -= (crop.wh[1] = -crop.wh[1]);
+
+ cfg->win.x = win.xy[0]; cfg->win.y = win.xy[1];
+ cfg->win.w = win.wh[0]; cfg->win.h = win.wh[1];
+ cfg->crop.x = crop.xy[0]; cfg->crop.y = crop.xy[1];
+ cfg->crop.w = crop.wh[0]; cfg->crop.h = crop.wh[1];
+
+ return 0;
+}
+
static void
omap4_hwc_adjust_ext_layer(omap4_hwc_ext_t *ext, struct dss2_ovl_info *ovl)
{
struct dss2_ovl_cfg *oc = &ovl->cfg;
float x, y, w, h;
+ /* crop to clone region */
+ if (crop_to_rect(&ovl->cfg, ext->mirror_region)) {
+ ovl->cfg.enabled = 0;
+ return;
+ }
+
/* display position */
x = ext->m[0][0] * oc->win.x + ext->m[0][1] * oc->win.y + ext->m[0][2];
y = ext->m[1][0] * oc->win.x + ext->m[1][1] * oc->win.y + ext->m[1][2];
@@ -985,10 +1067,12 @@ static int omap4_hwc_prepare(struct hwc_composer_device *dev, hwc_layer_list_t*
/* reset mode if we are coming from docking */
if (hwc_dev->ext.last.docking) {
- __u32 xres = (hwc_dev->ext.current.rotation & 1) ? hwc_dev->fb_dev->base.height : hwc_dev->fb_dev->base.width;
- __u32 yres = (hwc_dev->ext.current.rotation & 1) ? hwc_dev->fb_dev->base.width : hwc_dev->fb_dev->base.height;
+ __u32 xres = WIDTH(hwc_dev->ext.mirror_region);
+ __u32 yres = HEIGHT(hwc_dev->ext.mirror_region);
+ if (hwc_dev->ext.current.rotation & 1)
+ swap(xres, yres);
omap4_hwc_set_best_hdmi_mode(hwc_dev, xres, yres, 1, 1);
- set_ext_matrix(&hwc_dev->ext, hwc_dev->fb_dev->base.width, hwc_dev->fb_dev->base.height);
+ set_ext_matrix(&hwc_dev->ext, hwc_dev->ext.mirror_region);
}
}
@@ -1024,7 +1108,12 @@ static int omap4_hwc_prepare(struct hwc_composer_device *dev, hwc_layer_list_t*
}
}
- set_ext_matrix(&hwc_dev->ext, o->cfg.win.w, o->cfg.win.h);
+ struct hwc_rect region = {
+ .left = o->cfg.win.x, .top = o->cfg.win.y,
+ .right = o->cfg.win.x + o->cfg.win.w,
+ .bottom = o->cfg.win.y + o->cfg.win.h
+ };
+ set_ext_matrix(&hwc_dev->ext, region);
}
omap4_hwc_adjust_ext_layer(&hwc_dev->ext, o);
dsscomp->num_ovls++;
@@ -1310,8 +1399,10 @@ static void handle_hotplug(omap4_hwc_device_t *hwc_dev, int state)
/* select best mode for mirroring */
if (ext->mirror.enabled) {
- __u32 xres = (ext->mirror.rotation & 1) ? hwc_dev->fb_dev->base.height : hwc_dev->fb_dev->base.width;
- __u32 yres = (ext->mirror.rotation & 1) ? hwc_dev->fb_dev->base.width : hwc_dev->fb_dev->base.height;
+ __u32 xres = WIDTH(ext->mirror_region);
+ __u32 yres = HEIGHT(ext->mirror_region);
+ if (ext->mirror.rotation & 1)
+ swap(xres, yres);
int res = omap4_hwc_set_best_hdmi_mode(hwc_dev, xres, yres, 1, 1);
if (!res)
ioctl(hwc_dev->hdmi_fb_fd, FBIOBLANK, FB_BLANK_UNBLANK);
@@ -1319,7 +1410,7 @@ static void handle_hotplug(omap4_hwc_device_t *hwc_dev, int state)
ext->mirror.enabled = 0;
}
}
- omap4_hwc_create_ext_matrix(ext, hwc_dev);
+ omap4_hwc_create_ext_matrix(ext);
LOGI("external display changed (state=%d, mirror={%s tform=%ddeg%s}, dock={%s tform=%ddeg%s}, tv=%d", state,
ext->mirror.enabled ? "enabled" : "disabled",
ext->mirror.rotation * 90,
@@ -1472,6 +1563,21 @@ static int omap4_hwc_device_open(const hw_module_t* module, const char* name,
property_get("debug.hwc.nv12_only", value, "0");
hwc_dev->flags_nv12_only = atoi(value);
+ /* get the board specific clone properties */
+ /* 0:0:1280:720 */
+ if (property_get("hwc.hdmi.mirror.region", value, "") <= 0 ||
+ sscanf(value, "%d:%d:%d:%d",
+ &hwc_dev->ext.mirror_region.left, &hwc_dev->ext.mirror_region.top,
+ &hwc_dev->ext.mirror_region.right, &hwc_dev->ext.mirror_region.bottom) != 4 ||
+ hwc_dev->ext.mirror_region.left >= hwc_dev->ext.mirror_region.right ||
+ hwc_dev->ext.mirror_region.top >= hwc_dev->ext.mirror_region.bottom) {
+ struct hwc_rect fb_region = { .right = hwc_dev->fb_dev->base.width, .bottom = hwc_dev->fb_dev->base.height };
+ hwc_dev->ext.mirror_region = fb_region;
+ }
+ LOGI("clone region is set to (%d,%d) to (%d,%d)",
+ hwc_dev->ext.mirror_region.left, hwc_dev->ext.mirror_region.top,
+ hwc_dev->ext.mirror_region.right, hwc_dev->ext.mirror_region.bottom);
+
/* read switch state */
int sw_fd = open("/sys/class/switch/hdmi/state", O_RDONLY);
int hpd = 0;