summaryrefslogtreecommitdiffstats
path: root/hwc
diff options
context:
space:
mode:
authorJagadeesh Pakaravoor <j-pakaravoor@ti.com>2011-12-05 14:20:15 -0600
committerDaniel Levin <dendy@ti.com>2012-11-28 21:16:24 +0200
commitaa98f0999fe81764228c139ece3aa890c5a23cf5 (patch)
treeb2b7f9d491f9028fa3ce069275e1bb07ba13f19a /hwc
parent3e744b70d9fa563ce73bd7604a2afd4cd1824e30 (diff)
downloadhardware_ti_omap4-aa98f0999fe81764228c139ece3aa890c5a23cf5.zip
hardware_ti_omap4-aa98f0999fe81764228c139ece3aa890c5a23cf5.tar.gz
hardware_ti_omap4-aa98f0999fe81764228c139ece3aa890c5a23cf5.tar.bz2
hwc: add S3D support
Add support to handle s3d layer if an external S3D TV is plugged in. For now if there's no s3d external tv, the s3d layer is skipped (to be handled by SF). Consolidated the ics branch S3D patches into a feature commit for JB. ff833da Fix flickering during S3D layer transitions 8e54c33 Fix typo in index when cloning s3d layer to ext TV. 37c16f2 [HWC] Add S3D support to hwcomposer hal 4f714c3 PATCH[3/3] OMAP_ENHANCEMENT_S3D cleanup. This patch depends on http://review.omapzoom.org/#/c/24872 Change-Id: I10d743ab3eb4f204512faccabc084aa26b1dd458 Signed-off-by: Jagadeesh Pakaravoor <j-pakaravoor@ti.com> Signed-off-by: Tony Lofthouse <a0741364@ti.com> Signed-off-by: Muralidhar Dixit <murali.dixit@ti.com>
Diffstat (limited to 'hwc')
-rw-r--r--hwc/Android.mk5
-rw-r--r--hwc/hwc.c262
2 files changed, 264 insertions, 3 deletions
diff --git a/hwc/Android.mk b/hwc/Android.mk
index 489d739..60b421d 100644
--- a/hwc/Android.mk
+++ b/hwc/Android.mk
@@ -16,6 +16,11 @@ LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := hwcomposer.omap4
LOCAL_CFLAGS := -DLOG_TAG=\"ti_hwc\"
LOCAL_C_INCLUDES += external/libpng external/zlib
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/../edid/inc
+LOCAL_SHARED_LIBRARIES += libedid
+
# LOG_NDEBUG=0 means verbose logging enabled
# LOCAL_CFLAGS += -DLOG_NDEBUG=0
include $(BUILD_SHARED_LIBRARY)
diff --git a/hwc/hwc.c b/hwc/hwc.c
index e5d1a04..1ef6afe 100644
--- a/hwc/hwc.c
+++ b/hwc/hwc.c
@@ -25,6 +25,7 @@
#include <linux/omapfb.h>
#include <sys/mman.h>
#include <sys/resource.h>
+#include <stdbool.h>
#include <cutils/properties.h>
#include <cutils/log.h>
@@ -37,6 +38,9 @@
#include <utils/Timers.h>
#include <system/graphics.h>
+#include <ui/S3DFormat.h>
+#include <edid_parser.h>
+
#include <linux/bltsville.h>
#define MAX_HWC_LAYERS 32
@@ -100,6 +104,11 @@ struct omap4_hwc_ext {
__u32 yres;
float m[2][3]; /* external transformation matrix */
hwc_rect_t mirror_region; /* region of screen to mirror */
+
+ bool s3d_enabled;
+ bool s3d_capable;
+ enum S3DLayoutType s3d_type;
+ enum S3DLayoutOrder s3d_order;
};
typedef struct omap4_hwc_ext omap4_hwc_ext_t;
@@ -193,6 +202,9 @@ struct omap4_hwc_device {
int last_ext_ovls; /* # of overlays on external/internal display for last composition */
int last_int_ovls;
+ enum S3DLayoutType s3d_input_type;
+ enum S3DLayoutOrder s3d_input_order;
+
enum bltmode blt_mode;
enum bltpolicy blt_policy;
@@ -403,6 +415,17 @@ static int omap4_hwc_is_valid_format(int format)
}
}
+static __u32 get_s3d_layout_type(hwc_layer_t *layer)
+{
+ return (layer->flags & S3DLayoutTypeMask) >> S3DLayoutTypeShift;
+}
+
+static __u32 get_s3d_layout_order(hwc_layer_t *layer)
+{
+ return (layer->flags & S3DLayoutOrderMask) >> S3DLayoutOrderShift;
+}
+
+
static int scaled(hwc_layer_t *layer)
{
int w = WIDTH(layer->sourceCrop);
@@ -411,7 +434,9 @@ static int scaled(hwc_layer_t *layer)
if (layer->transform & HWC_TRANSFORM_ROT_90)
swap(w, h);
- return WIDTH(layer->displayFrame) != w || HEIGHT(layer->displayFrame) != h;
+ /* An S3D layer also needs scaling due to subsampling */
+ return WIDTH(layer->displayFrame) != w || HEIGHT(layer->displayFrame) != h
+ || get_s3d_layout_type(layer) != eMono;
}
static int is_protected(hwc_layer_t *layer)
@@ -1073,10 +1098,28 @@ static void gather_layer_statistics(omap4_hwc_device_t *hwc_dev, struct counts *
for (i = 0; list && i < list->numHwLayers; i++) {
hwc_layer_t *layer = &list->hwLayers[i];
IMG_native_handle_t *handle = (IMG_native_handle_t *)layer->handle;
+ __u32 s3d_layout_type = get_s3d_layout_type(layer);
layer->compositionType = HWC_FRAMEBUFFER;
if (omap4_hwc_is_valid_layer(hwc_dev, layer, handle)) {
+
+ if (s3d_layout_type != eMono) {
+ /* For now we can only handle 1 S3D layer, skip any additional ones */
+ if (num->s3d > 0 || !hwc_dev->ext.dock.enabled || !hwc_dev->ext.s3d_capable) {
+ layer->flags |= HWC_SKIP_LAYER;
+ continue;
+ } else if (num->s3d == 0) {
+ /* For now, S3D layer is made a dockable layer to trigger docking logic. */
+ if (!dockable(layer)) {
+ num->dockable++;
+ }
+ num->s3d++;
+ hwc_dev->s3d_input_type = s3d_layout_type;
+ hwc_dev->s3d_input_order = get_s3d_layout_order(layer);
+ }
+ }
+
num->possible_overlay_layers++;
/* NV12 layers can only be rendered on scaling overlays */
@@ -1118,6 +1161,11 @@ static void decide_supported_cloning(omap4_hwc_device_t *hwc_dev, struct counts
/* reserve just a video pipeline for HDMI if docking */
hwc_dev->ext_ovls = (num->dockable || ext->force_dock) ? 1 : 0;
+
+ if (num->s3d && (hwc_dev->ext.s3d_type != hwc_dev->s3d_input_type)) {
+ /* S3D layers are dockable, and they need two overlays */
+ hwc_dev->ext_ovls += 1;
+ }
num->max_hw_overlays -= max(hwc_dev->ext_ovls, hwc_dev->last_ext_ovls);
/* use mirroring transform if we are auto-switching to docking mode while mirroring*/
@@ -1293,6 +1341,152 @@ static int clone_external_layer(omap4_hwc_device_t *hwc_dev, int ix) {
return clone_layer(hwc_dev, ix);
}
+
+const char hdmiS3DTypePath[] = "/sys/devices/platform/omapdss/display1/s3d_type";
+const char hdmiS3DEnablePath[] = "/sys/devices/platform/omapdss/display1/s3d_enable";
+
+static void
+omap4_hwc_s3d_hdmi_enable(omap4_hwc_device_t *hwc_dev, bool enable)
+{
+ size_t bytesWritten;
+ char data;
+ int fd;
+
+ if (hwc_dev->ext.s3d_enabled == enable) {
+ return;
+ }
+
+ if (enable) {
+ char type[2];
+
+ switch(hwc_dev->ext.s3d_type) {
+ case eSideBySide:
+ snprintf(type, sizeof(type), "%d", HDMI_SIDE_BY_SIDE_HALF);
+ break;
+ case eTopBottom:
+ snprintf(type, sizeof(type), "%d", HDMI_TOPBOTTOM);
+ break;
+ default:
+ return;
+ }
+
+ fd = open(hdmiS3DTypePath, O_WRONLY);
+ if (fd < 0) {
+ ALOGE("Failed to open sysfs %s", hdmiS3DTypePath);
+ return;
+ }
+ bytesWritten = write(fd, type, sizeof(type));
+ close(fd);
+
+ if (bytesWritten != sizeof(type)) {
+ ALOGE("Failed to write (%s) to sysfs %s", type, hdmiS3DTypePath);
+ return;
+ }
+ }
+ data = enable ? '1' : '0';
+
+ fd = open(hdmiS3DEnablePath, O_WRONLY);
+ if (fd < 0) {
+ ALOGE("Failed to open sysfs %s", hdmiS3DEnablePath);
+ return;
+ }
+ bytesWritten = write(fd, &data, 1);
+ close(fd);
+
+ if (bytesWritten != 1) {
+ ALOGE("Failed to write(%d) to sysfs %s", enable, hdmiS3DEnablePath);
+ return;
+ }
+
+ hwc_dev->ext.s3d_enabled = enable;
+}
+
+static void
+omap4_hwc_adjust_ext_s3d_layer(omap4_hwc_device_t *hwc_dev,
+ struct dss2_ovl_info *ovl,
+ bool leftView)
+{
+ struct dss2_ovl_cfg *oc = &ovl->cfg;
+ float x, y, w, h;
+
+ switch (hwc_dev->s3d_input_type) {
+ case eSideBySide:
+ oc->crop.w = oc->crop.w/2;
+ if ((leftView && hwc_dev->s3d_input_order == eRightViewFirst) ||
+ (!leftView && hwc_dev->s3d_input_order == eLeftViewFirst)) {
+ oc->crop.x = oc->crop.x + oc->crop.w;
+ }
+ break;
+ case eTopBottom:
+ oc->crop.h = oc->crop.h/2;
+ if ((leftView && hwc_dev->s3d_input_order == eRightViewFirst) ||
+ (!leftView && hwc_dev->s3d_input_order == eLeftViewFirst)) {
+ oc->crop.y = oc->crop.y + oc->crop.h;
+ }
+ break;
+ default:
+ /* Should never fall here! */
+ ALOGE("Unsupported S3D layer type!");
+ break;
+ }
+
+ switch (hwc_dev->ext.s3d_type) {
+ case eSideBySide:
+ oc->win.w = oc->win.w/2;
+ if ((leftView && hwc_dev->ext.s3d_order == eRightViewFirst) ||
+ (!leftView && hwc_dev->ext.s3d_order == eLeftViewFirst)) {
+ oc->win.x = oc->win.x/2 + hwc_dev->ext.xres/2;
+ } else {
+ oc->win.x = oc->win.x/2;
+ }
+ break;
+ case eTopBottom:
+ oc->win.h = oc->win.h/2;
+ if ((leftView && hwc_dev->ext.s3d_order == eRightViewFirst) ||
+ (!leftView && hwc_dev->ext.s3d_order == eLeftViewFirst)) {
+ oc->win.y = oc->win.y/2 + hwc_dev->ext.yres/2;
+ } else {
+ oc->win.y = oc->win.y/2;
+ }
+ break;
+ default:
+ /* Currently unhandled!!! */
+ ALOGE("Unsupported S3D display type!");
+ break;
+ }
+}
+
+static int
+clone_s3d_external_layer(omap4_hwc_device_t *hwc_dev, int ix_s3d)
+{
+ struct dsscomp_setup_dispc_data *dsscomp = &hwc_dev->comp_data.dsscomp_data;
+ int r;
+
+ /* S3D layers are forced into docking layers. If the display layout and
+ * the layer layout don't match, we have to use 2 overlay pipelines */
+ r = clone_external_layer(hwc_dev, ix_s3d);
+ if (r) {
+ ALOGE("Failed to clone s3d layer (%d)", r);
+ return r;
+ }
+
+ r = clone_layer(hwc_dev, ix_s3d);
+ if (r) {
+ ALOGE("Failed to clone s3d layer (%d)", r);
+ return r;
+ }
+
+ if (dsscomp->num_ovls < 2) {
+ ALOGE("Number of overlays is inconsistent (%d)", dsscomp->num_ovls);
+ return -EINVAL;
+ }
+
+ omap4_hwc_adjust_ext_s3d_layer(hwc_dev, &dsscomp->ovls[dsscomp->num_ovls - 1], true);
+ omap4_hwc_adjust_ext_s3d_layer(hwc_dev, &dsscomp->ovls[dsscomp->num_ovls - 2], false);
+
+ return 0;
+}
+
static int setup_mirroring(omap4_hwc_device_t *hwc_dev)
{
omap4_hwc_ext_t *ext = &hwc_dev->ext;
@@ -1508,6 +1702,7 @@ static int omap4_hwc_prepare(struct hwc_composer_device *dev, hwc_layer_list_t*
int fb_z = -1;
int scaled_gfx = 0;
int ix_docking = -1;
+ int ix_s3d = -1;
int blit_all = 0;
blit_reset(hwc_dev, list ? list->flags : 0);
@@ -1593,6 +1788,10 @@ static int omap4_hwc_prepare(struct hwc_composer_device *dev, hwc_layer_list_t*
display_area(&dsscomp->ovls[dsscomp->num_ovls]) > display_area(&dsscomp->ovls[ix_docking])))
ix_docking = dsscomp->num_ovls;
+ /* remember the ix for s3d layer */
+ if (get_s3d_layout_type(layer) != eMono) {
+ ix_s3d = dsscomp->num_ovls;
+ }
dsscomp->num_ovls++;
z++;
} else if (hwc_dev->use_sgx) {
@@ -1652,8 +1851,27 @@ static int omap4_hwc_prepare(struct hwc_composer_device *dev, hwc_layer_list_t*
hwc_dev->post2_layers = dsscomp->num_ovls;
omap4_hwc_ext_t *ext = &hwc_dev->ext;
- if (ext->current.enabled && hwc_dev->ext_ovls) {
- if (ext->current.docking && ix_docking >= 0) {
+ if (ext->current.enabled && ((!num.protected && hwc_dev->ext_ovls) ||
+ (hwc_dev->ext_ovls_wanted && hwc_dev->ext_ovls >= hwc_dev->ext_ovls_wanted))) {
+ if (ext->current.docking && ix_s3d >= 0) {
+ if (clone_s3d_external_layer(hwc_dev, ix_s3d) == 0) {
+ dsscomp->ovls[dsscomp->num_ovls - 2].cfg.zorder = z++;
+ dsscomp->ovls[dsscomp->num_ovls - 1].cfg.zorder = z++;
+ /* For now, show only the left view of an S3D layer
+ * in the local display while we have hdmi attached */
+ switch (hwc_dev->s3d_input_type) {
+ case eSideBySide:
+ dsscomp->ovls[ix_s3d].cfg.crop.w = dsscomp->ovls[ix_s3d].cfg.crop.w/2;
+ break;
+ case eTopBottom:
+ dsscomp->ovls[ix_s3d].cfg.crop.h = dsscomp->ovls[ix_s3d].cfg.crop.h/2;
+ break;
+ default:
+ ALOGE("Unsupported S3D input type");
+ break;
+ }
+ }
+ } else if (ext->current.docking && ix_docking >= 0) {
if (clone_external_layer(hwc_dev, ix_docking) == 0)
dsscomp->ovls[dsscomp->num_ovls - 1].cfg.zorder = z++;
} else if (ext->current.docking && ix_docking < 0 && ext->force_dock) {
@@ -1690,6 +1908,9 @@ static int omap4_hwc_prepare(struct hwc_composer_device *dev, hwc_layer_list_t*
omap4_hwc_adjust_primary_display_layer(hwc_dev, &dsscomp->ovls[i]);
}
+
+ omap4_hwc_s3d_hdmi_enable(hwc_dev, ix_s3d >= 0);
+
ext->last = ext->current;
if (z != dsscomp->num_ovls || dsscomp->num_ovls > MAX_HW_OVERLAYS)
@@ -2086,6 +2307,38 @@ static void set_primary_display_transform_matrix(omap4_hwc_device_t *hwc_dev)
}
+
+static void handle_s3d_hotplug(omap4_hwc_ext_t *ext, int state)
+{
+ struct edid_t *edid = NULL;
+ if (state) {
+ int fd = open("/sys/devices/platform/omapdss/display1/edid", O_RDONLY);
+ if (!fd)
+ return;
+ uint8_t edid_data[EDID_SIZE];
+ size_t bytes_read = read(fd, edid_data, EDID_SIZE);
+ close(fd);
+ if (bytes_read < EDID_SIZE)
+ return;
+ if (edid_parser_init(&edid, edid_data))
+ return;
+ }
+
+ ext->s3d_enabled = false;
+ ext->s3d_capable = false;
+ ext->s3d_type = eMono;
+ ext->s3d_order = eLeftViewFirst;
+
+ if (edid) {
+ ext->s3d_capable = edid_s3d_capable(edid);
+ /* For now assume Side-by-Side half support applies to all modes */
+ ext->s3d_type = eSideBySide;
+ ext->s3d_order = eLeftViewFirst;
+ edid_parser_deinit(edid);
+ }
+}
+
+
static void handle_hotplug(omap4_hwc_device_t *hwc_dev)
{
omap4_hwc_ext_t *ext = &hwc_dev->ext;
@@ -2115,6 +2368,9 @@ static void handle_hotplug(omap4_hwc_device_t *hwc_dev)
}
pthread_mutex_lock(&hwc_dev->lock);
+
+ handle_s3d_hotplug(ext, state);
+
ext->dock.enabled = ext->mirror.enabled = 0;
if (state) {
/* check whether we can clone and/or dock */