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