summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;