summaryrefslogtreecommitdiff
path: root/hwc
diff options
context:
space:
mode:
authorLajos Molnar <molnar@ti.com>2011-09-14 18:24:18 -0500
committerErik Gilling <konkers@android.com>2011-09-21 14:07:46 -0700
commitbd43f27d21c976df59645759598e530ba1a8e01e (patch)
tree23858367cbfd8bfeef41494f0cc46d66ba122160 /hwc
parent834b8ba01376239a2f286a3766c14bdeeb166498 (diff)
downloadomap4-aah-bd43f27d21c976df59645759598e530ba1a8e01e.tar.gz
hwc: set hdmi resolution in docking mode based on layer dimensions
This allows e.g. playing 1080p video in 1080p mode. Change-Id: Ie0063baeb5d09325ab36a10b73050d9eb3fbbbe0
Diffstat (limited to 'hwc')
-rw-r--r--hwc/hwc.c232
1 files changed, 130 insertions, 102 deletions
diff --git a/hwc/hwc.c b/hwc/hwc.c
index c326a57..526cb69 100644
--- a/hwc/hwc.c
+++ b/hwc/hwc.c
@@ -84,6 +84,8 @@ struct omap4_hwc_device {
__u16 ext_height;
__u32 ext_xres;
__u32 ext_yres;
+ __u32 last_xres_used;
+ __u32 last_yres_used;
float m[2][3];
IMG_framebuffer_device_public_t *fb_dev;
struct dsscomp_setup_dispc_data dsscomp_data;
@@ -569,6 +571,103 @@ static int omap4_hwc_is_valid_layer(omap4_hwc_device_t *hwc_dev,
return omap4_hwc_can_scale_layer(hwc_dev, layer, handle);
}
+static int omap4_hwc_set_best_hdmi_mode(omap4_hwc_device_t *hwc_dev, __u32 xres, __u32 yres)
+{
+ struct _qdis {
+ struct dsscomp_display_info dis;
+ struct dsscomp_videomode modedb[16];
+ } d = { .dis = { .ix = 1 } };
+
+ d.dis.modedb_len = sizeof(d.modedb) / sizeof(*d.modedb);
+ int ret = ioctl(hwc_dev->dsscomp_fd, DSSCOMP_QUERY_DISPLAY, &d);
+ if (ret)
+ return ret;
+
+ __u32 i, best = ~0, best_score = 0;
+ hwc_dev->ext_width = d.dis.width_in_mm;
+ hwc_dev->ext_height = d.dis.height_in_mm;
+ hwc_dev->ext_xres = d.dis.timings.x_res;
+ hwc_dev->ext_yres = d.dis.timings.y_res;
+ __u32 ext_fb_xres, ext_fb_yres;
+ for (i = 0; i < d.dis.modedb_len; i++) {
+ __u32 score = 0;
+ __u32 area = xres * yres;
+ __u32 mode_area = d.modedb[i].xres * d.modedb[i].yres;
+ __u32 ext_width = d.dis.width_in_mm;
+ __u32 ext_height = d.dis.height_in_mm;
+
+ if (d.modedb[i].flag & FB_FLAG_RATIO_4_3) {
+ ext_width = 4;
+ ext_height = 3;
+ } else if (d.modedb[i].flag & FB_FLAG_RATIO_16_9) {
+ ext_width = 16;
+ ext_height = 9;
+ }
+
+ get_max_dimensions(xres, yres, 1, 1, d.modedb[i].xres, d.modedb[i].yres,
+ ext_width, ext_height, &ext_fb_xres, &ext_fb_yres);
+
+ if (!omap4_hwc_can_scale(xres, yres, ext_fb_xres, ext_fb_yres,
+ hwc_dev->ext & EXT_TRANSFORM, &d.dis, &limits))
+ continue;
+
+ /* prefer CEA modes */
+ if (d.modedb[i].flag & (FB_FLAG_RATIO_4_3 | FB_FLAG_RATIO_16_9))
+ score |= (1 << 30);
+
+ /* prefer to upscale (1% tolerance) */
+ if (ext_fb_xres >= xres * 99 / 100 && ext_fb_yres >= yres * 99 / 100)
+ score |= (1 << 29);
+
+ /* pick smallest leftover area */
+ score |= (1 << 24) * ((16 * ext_fb_xres * ext_fb_yres + (mode_area >> 1)) / mode_area);
+
+ /* pick closest screen size */
+ if (ext_fb_xres * ext_fb_yres > area)
+ score |= (1 << 19) * (16 * area / ext_fb_xres / ext_fb_yres);
+ else
+ score |= (1 << 19) * (16 * ext_fb_xres * ext_fb_yres / area);
+
+ /* pick highest frame rate */
+ score |= (1 << 11) * d.modedb[i].refresh;
+
+ LOGD("#%d: %dx%d %dHz", i, d.modedb[i].xres, d.modedb[i].yres, d.modedb[i].refresh);
+ if (debug)
+ LOGD(" score=%u adj.res=%dx%d", score, ext_fb_xres, ext_fb_yres);
+ if (best_score < score) {
+ hwc_dev->ext_width = ext_width;
+ hwc_dev->ext_height = ext_height;
+ hwc_dev->ext_xres = d.modedb[i].xres;
+ hwc_dev->ext_yres = d.modedb[i].yres;
+ best = i;
+ best_score = score;
+ }
+ }
+ if (~best) {
+ struct dsscomp_setup_display_data sdis = { .ix = 1, };
+ sdis.mode = d.dis.modedb[best];
+ LOGD("picking #%d", best);
+ ioctl(hwc_dev->dsscomp_fd, DSSCOMP_SETUP_DISPLAY, &sdis);
+ } else {
+ __u32 ext_width = d.dis.width_in_mm;
+ __u32 ext_height = d.dis.height_in_mm;
+ __u32 ext_fb_xres, ext_fb_yres;
+
+ get_max_dimensions(xres, yres, 1, 1, d.dis.timings.x_res, d.dis.timings.y_res,
+ ext_width, ext_height, &ext_fb_xres, &ext_fb_yres);
+ if (!omap4_hwc_can_scale(xres, yres, ext_fb_xres, ext_fb_yres,
+ hwc_dev->ext & EXT_TRANSFORM, &d.dis, &limits)) {
+ LOGE("DSS scaler cannot support HDMI cloning");
+ return -1;
+ }
+ }
+ hwc_dev->last_xres_used = xres;
+ hwc_dev->last_yres_used = yres;
+ if (d.dis.channel == OMAP_DSS_CHANNEL_DIGIT)
+ hwc_dev->ext |= EXT_TV;
+ return 0;
+}
+
struct counts {
unsigned int possible_overlay_layers;
unsigned int composited_layers;
@@ -843,8 +942,12 @@ static int omap4_hwc_prepare(struct hwc_composer_device *dev, hwc_layer_list_t*
ix_front = dsscomp->num_ovls - 1;
/* reset mode if we are coming from docking */
- if (hwc_dev->ext != hwc_dev->ext_last)
+ if (hwc_dev->ext != hwc_dev->ext_last) {
+ __u32 xres = (hwc_dev->ext & 1) ? hwc_dev->fb_dev->base.height : hwc_dev->fb_dev->base.width;
+ __u32 yres = (hwc_dev->ext & 1) ? hwc_dev->fb_dev->base.width : hwc_dev->fb_dev->base.height;
+ omap4_hwc_set_best_hdmi_mode(hwc_dev, xres, yres);
set_ext_matrix(hwc_dev, hwc_dev->fb_dev->base.width, hwc_dev->fb_dev->base.height);
+ }
}
for (ix = ix_back; hwc_dev->ext && ix >= 0 && ix <= ix_front; ix++) {
@@ -858,6 +961,17 @@ static int omap4_hwc_prepare(struct hwc_composer_device *dev, hwc_layer_list_t*
o->ba = ix;
if (hwc_dev->ext & EXT_DOCK) {
+ /* adjust hdmi mode based on resolution */
+ if (o->cfg.crop.w != hwc_dev->last_xres_used ||
+ o->cfg.crop.h != hwc_dev->last_yres_used) {
+ LOGD("set up HDMI for %d*%d\n", o->cfg.crop.w, o->cfg.crop.h);
+ if (omap4_hwc_set_best_hdmi_mode(hwc_dev, o->cfg.crop.w, o->cfg.crop.h)) {
+ o->cfg.enabled = 0;
+ hwc_dev->ext = 0;
+ continue;
+ }
+ }
+
/* full screen video */
o->cfg.win.x = 0;
o->cfg.win.y = 0;
@@ -1093,108 +1207,22 @@ static void handle_hotplug(omap4_hwc_device_t *hwc_dev, int state)
pthread_mutex_lock(&hwc_dev->lock);
hwc_dev->ext = 0;
if (state) {
- struct _qdis {
- struct dsscomp_display_info dis;
- struct dsscomp_videomode modedb[16];
- } d = { .dis = { .ix = 1 } };
- d.dis.modedb_len = sizeof(d.modedb) / sizeof(*d.modedb);
- int ret = ioctl(hwc_dev->dsscomp_fd, DSSCOMP_QUERY_DISPLAY, &d);
- if (!ret) {
- __u32 i, best = ~0, best_score = 0;
- hwc_dev->ext = EXT_ON | 3;
- hwc_dev->ext_width = d.dis.width_in_mm;
- hwc_dev->ext_height = d.dis.height_in_mm;
- hwc_dev->ext_xres = d.dis.timings.x_res;
- hwc_dev->ext_yres = d.dis.timings.y_res;
- for (i = 0; i < d.dis.modedb_len; i++) {
- __u32 score = 0;
- __u32 fb_xres = (hwc_dev->ext & 1) ? hwc_dev->fb_dev->base.height : hwc_dev->fb_dev->base.width;
- __u32 fb_yres = (hwc_dev->ext & 1) ? hwc_dev->fb_dev->base.width : hwc_dev->fb_dev->base.height;
- __u32 fb_area = fb_xres * fb_yres;
- __u32 mode_area = d.modedb[i].xres * d.modedb[i].yres;
- __u32 ext_width = d.dis.width_in_mm;
- __u32 ext_height = d.dis.height_in_mm;
- __u32 ext_fb_xres, ext_fb_yres;
-
- if (d.modedb[i].flag & FB_FLAG_RATIO_4_3) {
- ext_width = 4;
- ext_height = 3;
- } else if (d.modedb[i].flag & FB_FLAG_RATIO_16_9) {
- ext_width = 16;
- ext_height = 9;
- }
-
- get_max_dimensions(fb_xres, fb_yres, 1, 1, d.modedb[i].xres, d.modedb[i].yres,
- ext_width, ext_height, &ext_fb_xres, &ext_fb_yres);
-
- if (!omap4_hwc_can_scale(fb_xres, fb_yres, ext_fb_xres, ext_fb_yres,
- hwc_dev->ext & EXT_TRANSFORM, &d.dis, &limits))
- continue;
-
- /* prefer CEA modes */
- if (d.modedb[i].flag & (FB_FLAG_RATIO_4_3 | FB_FLAG_RATIO_16_9))
- score |= (1 << 30);
-
- /* prefer to upscale (1% tolerance) */
- if (ext_fb_xres >= fb_xres * 99 / 100 && ext_fb_yres >= fb_yres * 99 / 100)
- score |= (1 << 29);
-
- /* pick smallest leftover area */
- score |= (1 << 24) * ((16 * ext_fb_xres * ext_fb_yres + (mode_area >> 1)) / mode_area);
-
- /* pick closest screen size */
- if (ext_fb_xres * ext_fb_yres > fb_area)
- score |= (1 << 19) * (16 * fb_area / ext_fb_xres / ext_fb_yres);
- else
- score |= (1 << 19) * (16 * ext_fb_xres * ext_fb_yres / fb_area);
-
- /* pick highest frame rate */
- score |= (1 << 11) * d.modedb[i].refresh;
-
- LOGD("#%d: %dx%d %dHz", i, d.modedb[i].xres, d.modedb[i].yres, d.modedb[i].refresh);
- if (debug)
- LOGD(" score=%u adj.res=%dx%d", score, ext_fb_xres, ext_fb_yres);
- if (best_score < score) {
- hwc_dev->ext_width = ext_width;
- hwc_dev->ext_height = ext_height;
- hwc_dev->ext_xres = d.modedb[i].xres;
- hwc_dev->ext_yres = d.modedb[i].yres;
- best = i;
- best_score = score;
- }
- }
- if (~best) {
- struct dsscomp_setup_display_data sdis = { .ix = 1, };
- sdis.mode = d.dis.modedb[best];
- LOGD("picking #%d", best);
- ioctl(hwc_dev->dsscomp_fd, DSSCOMP_SETUP_DISPLAY, &sdis);
- } else {
- __u32 fb_xres = (hwc_dev->ext & 1) ? hwc_dev->fb_dev->base.height : hwc_dev->fb_dev->base.width;
- __u32 fb_yres = (hwc_dev->ext & 1) ? hwc_dev->fb_dev->base.width : hwc_dev->fb_dev->base.height;
- __u32 ext_width = d.dis.width_in_mm;
- __u32 ext_height = d.dis.height_in_mm;
- __u32 ext_fb_xres, ext_fb_yres;
-
- get_max_dimensions(fb_xres, fb_yres, 1, 1, d.dis.timings.x_res, d.dis.timings.y_res,
- ext_width, ext_height, &ext_fb_xres, &ext_fb_yres);
- if (!omap4_hwc_can_scale(fb_xres, fb_yres, ext_fb_xres, ext_fb_yres,
- hwc_dev->ext & EXT_TRANSFORM, &d.dis, &limits)) {
- LOGE("DSS scaler cannot support HDMI cloning");
- hwc_dev->ext = 0;
- }
- }
-
- if (hwc_dev->ext) {
- if (d.dis.channel == OMAP_DSS_CHANNEL_DIGIT)
- hwc_dev->ext |= EXT_TV;
- ioctl(hwc_dev->hdmi_fb_fd, FBIOBLANK, FB_BLANK_UNBLANK);
- }
+ hwc_dev->ext = EXT_ON | 3;
+ __u32 xres = (hwc_dev->ext & 1) ? hwc_dev->fb_dev->base.height : hwc_dev->fb_dev->base.width;
+ __u32 yres = (hwc_dev->ext & 1) ? hwc_dev->fb_dev->base.width : hwc_dev->fb_dev->base.height;
+ int res = omap4_hwc_set_best_hdmi_mode(hwc_dev, xres, yres);
+ if (!res) {
+ ioctl(hwc_dev->hdmi_fb_fd, FBIOBLANK, FB_BLANK_UNBLANK);
+
+ /* FIXME set up hwc_dev->ext based on mirroring needs */
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.hwc.ext", value, "0");
+ hwc_dev->ext |= atoi(value) & EXT_DOCK;
+ if (hwc_dev->ext & EXT_DOCK)
+ hwc_dev->ext &= ~EXT_TRANSFORM;
+ } else {
+ hwc_dev->ext = 0;
}
-
- /* FIXME set up hwc_dev->ext based on mirroring needs */
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.hwc.ext", value, "0");
- hwc_dev->ext |= atoi(value) & EXT_DOCK;
}
omap4_hwc_create_ext_matrix(hwc_dev);
LOGI("external display changed (state=%d, on=%d, dock=%d, tv=%d, trform=%ddeg%s)", state,