From 1b51063e0db44d90cc8da021a7ee05ce24975d71 Mon Sep 17 00:00:00 2001 From: Kinjal Bhavsar Date: Thu, 10 Feb 2011 20:05:58 -0800 Subject: [PATCH] liboverlay: Add TV detection and monoscopic display for S3D Add the state machine for overlay configuration. When connected, check whether the TV on HDMI is 3D capable or not using the EDID info. Show L channel on primary panel; and R channel on 2D TV if non 3DTV is connected via HDMI, else switch TV to 3D mode. Change-Id: I3109f8b0b81a8f5ad542db038262fd668e225e96 --- libgralloc-qsd8k/gralloc_priv.h | 16 +- liboverlay/overlay.cpp | 884 +++++++++++++++++++------------- liboverlay/overlayLib.cpp | 313 ++++++----- liboverlay/overlayLib.h | 51 +- 4 files changed, 770 insertions(+), 494 deletions(-) diff --git a/libgralloc-qsd8k/gralloc_priv.h b/libgralloc-qsd8k/gralloc_priv.h index 39b488e..228b6be 100755 --- a/libgralloc-qsd8k/gralloc_priv.h +++ b/libgralloc-qsd8k/gralloc_priv.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -154,15 +154,15 @@ enum { /* possible formats for 3D content*/ enum { - HAL_NO_3D = 0x00, - HAL_3D_IN_SIDE_BY_SIDE_HALF_L_R = 0x10000, + HAL_NO_3D = 0x0000, + HAL_3D_IN_SIDE_BY_SIDE_L_R = 0x10000, HAL_3D_IN_TOP_BOTTOM = 0x20000, HAL_3D_IN_INTERLEAVE = 0x40000, - HAL_3D_IN_SIDE_BY_SIDE_FULL = 0x80000, - HAL_3D_IN_SIDE_BY_SIDE_HALF_R_L = 0xC0000, - HAL_3D_OUT_SIDE_BY_SIDE = 0x1000, - HAL_3D_OUT_TOP_BOTTOM = 0x2000, - HAL_3D_OUT_INTERLEAVE = 0x4000, + HAL_3D_IN_SIDE_BY_SIDE_R_L = 0x80000, + HAL_3D_OUT_SIDE_BY_SIDE = 0x1000, + HAL_3D_OUT_TOP_BOTTOM = 0x2000, + HAL_3D_OUT_INTERLEAVE = 0x4000, + HAL_3D_OUT_MONOSCOPIC = 0x8000 }; enum { diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp index aa2b524..db8468b 100644 --- a/liboverlay/overlay.cpp +++ b/liboverlay/overlay.cpp @@ -39,21 +39,20 @@ struct overlay_control_context_t { struct overlay_control_device_t device; void *sharedMemBase; unsigned int format3D; //input and output 3D format, zero means no 3D -}; - -struct ov_crop_rect_t { - int x; - int y; - int w; - int h; + unsigned int state; + unsigned int orientation; + overlay_rect posPanel; }; struct overlay_data_context_t { struct overlay_data_device_t device; OverlayDataChannel* pobjDataChannel[2]; - int setCrop; unsigned int format3D; - struct ov_crop_rect_t cropRect; + unsigned int state; + bool setCrop; + overlay_rect cropRect; + int srcFD; //store the FD as it will needed for fb1 + int size; //size of the overlay created void *sharedMemBase; }; @@ -65,7 +64,7 @@ static struct hw_module_methods_t overlay_module_methods = { }; struct private_overlay_module_t { - overlay_module_t base; + overlay_module_t base; Mutex *pobjMutex; }; @@ -104,7 +103,6 @@ static int handle_get_rotId(const overlay_handle_t overlay, int index = 0) { return static_cast(overlay)->rotid[index]; } - static int handle_get_size(const overlay_handle_t overlay) { return static_cast(overlay)->size; } @@ -159,13 +157,10 @@ public: int getRotSessionId(int index = 0) { return mHandle.rotid[index]; } int getSharedMemoryFD() {return mHandle.sharedMemoryFd;} - bool startControlChannel(int fbnum, bool norot = false, - unsigned int format3D = 0, int zorder = 0) { - int index = 0; - if (format3D) + bool startControlChannel(int fbnum, bool norot = false, int zorder = 0) { + int index = fbnum; + if (mHandle.format3D) index = zorder; - else - index = fbnum; if (!mHandle.pobjControlChannel[index]) mHandle.pobjControlChannel[index] = new OverlayControlChannel(); else { @@ -174,7 +169,7 @@ public: } bool ret = mHandle.pobjControlChannel[index]->startControlChannel( mHandle.w, mHandle.h, mHandle.format, fbnum, norot, false, - format3D, zorder, true); + mHandle.format3D, zorder, true); if (ret) { if (!(mHandle.pobjControlChannel[index]-> getOvSessionID(mHandle.ovid[index]) && @@ -223,6 +218,16 @@ public: return ret; } + bool getPositionS3D(overlay_rect *rect, int channel) { + if (!mHandle.pobjControlChannel[channel]) { + LOGE("%s:Failed got channel %d", __func__, channel); + return false; + } + + return mHandle.pobjControlChannel[channel]->getPositionS3D( + channel, mHandle.format3D, rect); + } + bool getPosition(int *x, int *y, uint32_t *w, uint32_t *h, int channel) { if (!mHandle.pobjControlChannel[channel]) return false; @@ -241,12 +246,7 @@ public: close(mHandle.sharedMemoryFd); closeControlChannel(0); closeControlChannel(1); - FILE *fp = NULL; - fp = fopen(FORMAT_3D_FILE, "wb"); - if(fp) { - fprintf(fp, "0"); //Sending hdmi info packet(2D) - fclose(fp); - } + send3DInfoPacket (0); } int getFBWidth(int channel) { @@ -260,6 +260,10 @@ public: return false; return mHandle.pobjControlChannel[channel]->getFBHeight(); } + + inline void setFormat3D(unsigned int format3D) { + mHandle.format3D = format3D; + } }; // **************************************************************************** @@ -297,6 +301,19 @@ public: return result; } + static void error_cleanup_control(overlay_control_context_t *ctx, overlay_object *overlay, int fd, int index) { + LOGE("Failed to start control channel %d", index); + for (int i = 0; i < index; i++) + overlay->closeControlChannel(i); + if(ctx && (ctx->sharedMemBase != MAP_FAILED)) { + munmap(ctx->sharedMemBase, sizeof(overlay_shared_data)); + ctx->sharedMemBase = MAP_FAILED; + } + if(fd > 0) + close(fd); + delete overlay; + } + static overlay_t* overlay_createOverlay(struct overlay_control_device_t *dev, uint32_t w, uint32_t h, int32_t format) { overlay_object *overlay = NULL; @@ -307,10 +324,9 @@ public: // Open shared memory to store shared data int size = sizeof(overlay_shared_data); - void *base; + void *base; int fd = ashmem_create_region(SHARED_MEMORY_REGION_NAME, size); - if(fd < 0) { LOGE("%s: create shared memory failed", __func__); return NULL; @@ -347,26 +363,30 @@ public: } if(!fOut3D) { switch (fIn3D) { - case HAL_3D_IN_SIDE_BY_SIDE_HALF_L_R: - case HAL_3D_IN_SIDE_BY_SIDE_HALF_R_L: - case HAL_3D_IN_SIDE_BY_SIDE_FULL: + case HAL_3D_IN_SIDE_BY_SIDE_L_R: + case HAL_3D_IN_SIDE_BY_SIDE_R_L: // For all side by side formats, set the output // format as Side-by-Side i.e 0x1 - format3D |= HAL_3D_IN_SIDE_BY_SIDE_HALF_L_R >> SHIFT_3D; + format3D |= HAL_3D_IN_SIDE_BY_SIDE_L_R >> SHIFT_3D; break; default: format3D |= fIn3D >> SHIFT_3D; //Set the output format break; } } - + unsigned int curState = overlay::getOverlayConfig(format3D); + if (curState == OV_3D_VIDEO_2D_PANEL || curState == OV_3D_VIDEO_2D_TV) { + LOGI("3D content on 2D display: set the output format as monoscopic"); + format3D = FORMAT_3D_INPUT(format3D) | HAL_3D_OUT_MONOSCOPIC_MASK; + } + LOGD("createOverlay: creating overlay with format3D: 0x%x, curState: %d", format3D, curState); ctx->sharedMemBase = base; ctx->format3D = format3D; + ctx->state = curState; memset(ctx->sharedMemBase, 0, size); /* number of buffer is not being used as overlay buffers are coming from client */ overlay = new overlay_object(w, h, format, fd, format3D); - if (overlay == NULL) { LOGE("%s: can't create overlay object!", __FUNCTION__); if(ctx && (ctx->sharedMemBase != MAP_FAILED)) { @@ -377,81 +397,49 @@ public: close(fd); return NULL; } - - if (format3D) { - bool res1, res2; - if (format3D & HAL_3D_IN_SIDE_BY_SIDE_HALF_R_L) { - // For R-L formats, set the Zorder of the second channel as 0 - res1 = overlay->startControlChannel(1, false, format3D, 1); - res2 = overlay->startControlChannel(1, false, format3D, 0); - } else { - res1 = overlay->startControlChannel(1, false, format3D, 0); - res2 = overlay->startControlChannel(1, false, format3D, 1); - } - if (!res1 || !res2) { - LOGE("Failed to start control channel for VG pipe 0 or 1"); - overlay->closeControlChannel(0); - overlay->closeControlChannel(1); - if(ctx && (ctx->sharedMemBase != MAP_FAILED)) { - munmap(ctx->sharedMemBase, size); - ctx->sharedMemBase = MAP_FAILED; - } - if(fd > 0) - close(fd); - - delete overlay; + bool noRot; +#ifdef USE_MSM_ROTATOR + noRot = false; +#else + noRot = true; +#endif + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + if (!overlay->startControlChannel(FRAMEBUFFER_0, noRot)) { + error_cleanup_control(ctx, overlay, fd, FRAMEBUFFER_0); return NULL; } - return overlay; - } -#ifdef USE_MSM_ROTATOR - if (!overlay->startControlChannel(0)) { -#else - if (!overlay->startControlChannel(0, true)) { -#endif - LOGE("Failed to start control channel for framebuffer 0"); - overlay->closeControlChannel(0); - if(ctx && (ctx->sharedMemBase != MAP_FAILED)) { - munmap(ctx->sharedMemBase, size); - ctx->sharedMemBase = MAP_FAILED; + break; + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + if (!overlay->startControlChannel(FRAMEBUFFER_0, noRot, VG0_PIPE)) { + error_cleanup_control(ctx, overlay, fd, VG0_PIPE); + return NULL; } - if(fd > 0) - close(fd); - - delete overlay; - return NULL; - } - - char value[PROPERTY_VALUE_MAX]; - property_get("hw.hdmiON", value, "0"); - if (!atoi(value)) { - return overlay; - } - - if (!overlay->startControlChannel(1, true)) { - LOGE("Failed to start control channel for framebuffer 1"); - overlay->closeControlChannel(1); - if(ctx && (ctx->sharedMemBase != MAP_FAILED)) { - munmap(ctx->sharedMemBase, size); - ctx->sharedMemBase = MAP_FAILED; + if (!overlay->startControlChannel(FRAMEBUFFER_1, true, VG1_PIPE)) { + error_cleanup_control(ctx, overlay, fd, VG1_PIPE); + return NULL; } - if(fd > 0) - close(fd); - - delete overlay; - return NULL; - } - else { - overlay_rect rect; - if(overlay->getAspectRatioPosition(&rect, 1)) { - if (!overlay->setPosition(rect.x, rect.y, rect.width, rect.height, 1)) { - LOGE("Failed to upscale for framebuffer 1"); + break; + case OV_3D_VIDEO_3D_TV: + for (int i=0; istartControlChannel(FRAMEBUFFER_1, true, i)) { + error_cleanup_control(ctx, overlay, fd, i); + return NULL; } } + break; + default: + break; + } + overlay_shared_data* data = static_cast(ctx->sharedMemBase); + data->state = ctx->state; + for (int i=0; iovid[i] = overlay->getHwOvId(i); + data->rotid[i] = overlay->getRotSessionId(i); } - return overlay; - } static void overlay_destroyOverlay(struct overlay_control_device_t *dev, @@ -480,37 +468,47 @@ public: dev->common.module); Mutex::Autolock objLock(m->pobjMutex); bool ret; - if(ctx->format3D){ - int wHDMI = obj->getFBWidth(1); - int hHDMI = obj->getFBHeight(1); - if(ctx->format3D & HAL_3D_OUT_SIDE_BY_SIDE_HALF_MASK) { - ret = obj->setPosition(0, 0, wHDMI/2, hHDMI, 0); - if (!ret) - return -1; - ret = obj->setPosition(wHDMI/2, 0, wHDMI/2, hHDMI, 1); - if (!ret) - return -1; - } - else if (ctx->format3D & HAL_3D_OUT_TOP_BOTTOM_MASK) { - ret = obj->setPosition(0, 0, wHDMI, hHDMI/2, 0); - if (!ret) - return -1; - ret = obj->setPosition(0, hHDMI/2, wHDMI, hHDMI/2, 1); - if (!ret) - return -1; - } - else if (ctx->format3D & HAL_3D_OUT_INTERLEAVE_MASK) { - //TBD - } else if (ctx->format3D & HAL_3D_OUT_SIDE_BY_SIDE_FULL_MASK) { - //TBD - } else { - LOGE("%s: Unsupported 3D output format!!!", __func__); - } - } - else { - ret = obj->setPosition(x, y, w, h, 0); - if (!ret) + overlay_rect rect; + // saving the position for the disconnection event + ctx->posPanel.x = x; + ctx->posPanel.y = y; + ctx->posPanel.w = w; + ctx->posPanel.h = h; + + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + if(!obj->setPosition(x, y, w, h, VG0_PIPE)) { + LOGE("%s:Failed for channel 0", __func__); return -1; + } + break; + case OV_2D_VIDEO_ON_TV: + if(!obj->setPosition(x, y, w, h, VG0_PIPE)) { + LOGE("%s:Failed for channel 0", __func__); + return -1; + } + obj->getAspectRatioPosition(&rect, VG1_PIPE); + if(!obj->setPosition(rect.x, rect.y, rect.w, rect.h, VG1_PIPE)) { + LOGE("%s:Failed for channel 1", __func__); + return -1; + } + break; + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + for (int i = 0; i < NUM_CHANNELS; i++) { + if (!obj->getPositionS3D(&rect, i)) + ret = obj->setPosition(x, y, w, h, i); + else + ret = obj->setPosition(rect.x, rect.y, rect.w, rect.h, i); + if (!ret) { + LOGE("%s:Failed for channel %d", __func__, i); + return -1; + } + } + break; + default: + break; } return 0; } @@ -530,7 +528,7 @@ public: data.readyToQueue = 1; memcpy(ctx->sharedMemBase, (void*)&data, sizeof(overlay_shared_data)); } -return 0; + return 0; } static int overlay_getPosition(struct overlay_control_device_t *dev, @@ -542,12 +540,91 @@ return 0; dev->common.module); Mutex::Autolock objLock(m->pobjMutex); overlay_object * obj = static_cast(overlay); - bool ret = obj->getPosition(x, y, w, h, 0); - if (!ret) - return -1; - return 0; + return obj->getPosition(x, y, w, h, 0) ? 0 : -1; } - +#if 0 + static bool overlay_configPipes(overlay_control_context_t *ctx, + overlay_object *obj, int enable, + unsigned int curState) { + bool noRot = true; + overlay_rect rect; +#ifdef USE_MSM_ROTATOR + noRot = false; +#else + noRot = true; +#endif + if(enable) { + if( (ctx->state == OV_2D_VIDEO_ON_PANEL) || + (ctx->state == OV_3D_VIDEO_2D_PANEL && curState == OV_3D_VIDEO_2D_TV) ) { + LOGI("2D TV connected, Open a new control channel for TV."); + //Start a new channel for mirroring on HDMI + if (!obj->startControlChannel(FRAMEBUFFER_1, true, VG1_PIPE)) { + obj->closeControlChannel(FRAMEBUFFER_1); + return false; + } + if (ctx->format3D) + obj->getPositionS3D(&rect, FRAMEBUFFER_1); + else + obj->getAspectRatioPosition(&rect, FRAMEBUFFER_1); + if(!obj->setPosition(rect.x, rect.y, rect.w, rect.h, FRAMEBUFFER_1)) { + LOGE("%s:Failed to set position for framebuffer 1", __func__); + return false; + } + } else if( (ctx->state == OV_3D_VIDEO_2D_PANEL && curState == OV_3D_VIDEO_3D_TV) ) { + LOGI("3D TV connected, close old ctl channel and open two ctl channels for 3DTV."); + //close the channel 0 as it is configured for panel + obj->closeControlChannel(FRAMEBUFFER_0); + //update the output from monoscopic to stereoscopic + ctx->format3D = FORMAT_3D_INPUT(ctx->format3D) | ctx->format3D >> SHIFT_3D; + obj->setFormat3D(ctx->format3D); + LOGI("Control: new S3D format : 0x%x", ctx->format3D); + //now open both the channels + for (int i = 0; i < NUM_CHANNELS; i++) { + if (!obj->startControlChannel(FRAMEBUFFER_1, true, i)) { + LOGE("%s:Failed to open control channel for pipe %d", __func__, i); + return false; + } + obj->getPositionS3D(&rect, i); + if(!obj->setPosition(rect.x, rect.y, rect.w, rect.h, i)) { + LOGE("%s: failed for channel %d", __func__, i); + return false; + } + } + } + } else { + if ( (ctx->state == OV_2D_VIDEO_ON_TV) || + (ctx->state == OV_3D_VIDEO_2D_TV && curState == OV_3D_VIDEO_2D_PANEL) ) { + LOGI("2D TV disconnected, close the control channel."); + obj->closeControlChannel(VG1_PIPE); + } else if (ctx->state == OV_3D_VIDEO_3D_TV && curState == OV_3D_VIDEO_2D_PANEL) { + LOGI("3D TV disconnected, close the control channels & open one for panel."); + // Close both the pipes' control channel + obj->closeControlChannel(VG0_PIPE); + obj->closeControlChannel(VG1_PIPE); + //update the format3D as monoscopic + ctx->format3D = FORMAT_3D_INPUT(ctx->format3D) | HAL_3D_OUT_MONOSCOPIC_MASK; + obj->setFormat3D(ctx->format3D); + LOGI("Control: New format3D: 0x%x", ctx->format3D); + //now open the channel 0 + if (!obj->startControlChannel(FRAMEBUFFER_0, noRot)) { + LOGE("%s:Failed to open control channel for pipe 0", __func__); + return false; + } + if(!obj->setPosition(ctx->posPanel.x, ctx->posPanel.y, ctx->posPanel.w, ctx->posPanel.h, FRAMEBUFFER_0)) { + LOGE("%s:Failed to set position for framebuffer 0", __func__); + return false; + } + if (!obj->setParameter(OVERLAY_TRANSFORM, ctx->orientation, VG0_PIPE)) { + LOGE("%s: Failed to set orienatation for channel 0", __func__); + return -1; + } + } + } + //update the context's state + ctx->state = curState; + return true; + } +#endif static int overlay_setParameter(struct overlay_control_device_t *dev, overlay_t* overlay, int param, int value) { @@ -555,28 +632,60 @@ return 0; overlay_object *obj = static_cast(overlay); private_overlay_module_t* m = reinterpret_cast( dev->common.module); - Mutex::Autolock objLock(m->pobjMutex); if (obj && (obj->getSharedMemoryFD() > 0) && (ctx->sharedMemBase != MAP_FAILED)) { - overlay_shared_data data; - data.readyToQueue = 0; - memcpy(ctx->sharedMemBase, (void*)&data, sizeof(data)); + overlay_shared_data* data = static_cast(ctx->sharedMemBase); + data->readyToQueue = 0; +#if 0 + /* SF will inform Overlay HAL the HDMI cable connection. + This avoids polling on the system property hw.hdmiON */ + if(param == OVERLAY_HDMI_ENABLE) { + unsigned int curState = getOverlayConfig(ctx->format3D); + if(ctx->state != curState) { + LOGI("Overlay Configured for : %d Current state: %d", ctx->state, curState); + if(!overlay_configPipes(ctx, obj, value, curState)) { + LOGE("In overlay_setParameter: reconfiguring of Overlay failed !!"); + return -1; + } + else { + data->state = ctx->state; + for (int i=0; iovid[i] = obj->getHwOvId(i); + data->rotid[i] = obj->getRotSessionId(i); + } + } + } + } +#endif } - bool ret; - if (ctx->format3D) { - ret = obj->setParameter(param, value, 0); - if (!ret) - return -1; - ret = obj->setParameter(param, value, 1); - if (!ret) - return -1; - } - else { - ret = obj->setParameter(param, value, 0); - if (!ret) - return -1; +// if(param != OVERLAY_HDMI_ENABLE) + { + //Save the panel orientation + if (param == OVERLAY_TRANSFORM) + ctx->orientation = value; + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + if(!obj->setParameter(param, value, VG0_PIPE)) { + LOGE("%s: Failed for channel 0", __func__); + return -1; + } + break; + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + for (int i=0; isetParameter(param, value, i)) { + LOGE("%s: Failed for channel %d", __func__, i); + return -1; + } + } + break; + default: + break; + } } return 0; } @@ -597,6 +706,15 @@ return 0; // Data module // **************************************************************************** + static void error_cleanup_data(struct overlay_data_context_t* ctx, int index) + { + LOGE("Couldn't start data channel %d", index); + for (int i = 0; ipobjDataChannel[i]; + ctx->pobjDataChannel[i] = NULL; + } + } + int overlay_initialize(struct overlay_data_device_t *dev, overlay_handle_t handle) { @@ -617,11 +735,20 @@ return 0; int size = handle_get_size(handle); int sharedFd = handle_get_shared_fd(handle); unsigned int format3D = handle_get_format3D(handle); - FILE *fp = NULL; private_overlay_module_t* m = reinterpret_cast( dev->common.module); Mutex::Autolock objLock(m->pobjMutex); - + bool noRot = true; +#ifdef USE_MSM_ROTATOR + noRot = false; +#else + noRot = true; +#endif + //default: set crop info to src size. + ctx->cropRect.x = 0; + ctx->cropRect.y = 0; + //ctx->cropRect.w = handle_get_width(handle); + //ctx->cropRect.h = handle_get_height(handle); ctx->sharedMemBase = MAP_FAILED; ctx->format3D = format3D; @@ -637,64 +764,67 @@ return 0; LOGE("Received invalid shared memory fd"); return -1; } - - if (ctx->format3D) { - bool res1, res2; - ctx->pobjDataChannel[0] = new OverlayDataChannel(); - ctx->pobjDataChannel[1] = new OverlayDataChannel(); - res1 = - ctx->pobjDataChannel[0]->startDataChannel(ovid, rotid, size, 1); - ovid = handle_get_ovId(handle, 1); - rotid = handle_get_rotId(handle, 1); - res2 = - ctx->pobjDataChannel[1]->startDataChannel(ovid, rotid, size, 1); - if (!res1 || !res2) { - LOGE("Couldnt start data channel for VG pipe 0 or 1"); - delete ctx->pobjDataChannel[0]; - ctx->pobjDataChannel[0] = 0; - delete ctx->pobjDataChannel[1]; - ctx->pobjDataChannel[1] = 0; + overlay_shared_data* data = static_cast + (ctx->sharedMemBase); + if (data == NULL){ + LOGE("%s:Shared data is NULL!!", __func__); + return -1; + } + ctx->state = data->state; + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + ctx->pobjDataChannel[VG0_PIPE] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[VG0_PIPE]->startDataChannel(ovid, rotid, size, FRAMEBUFFER_0, noRot)) { + error_cleanup_data(ctx, VG0_PIPE); return -1; } - //Sending hdmi info packet(3D output format) - fp = fopen(FORMAT_3D_FILE, "wb"); - if (fp) { - fprintf(fp, "%d", format3D & OUTPUT_MASK_3D); - fclose(fp); - fp = NULL; + //setting the crop value + if(!ctx->pobjDataChannel[VG0_PIPE]->setCrop( + ctx->cropRect.x,ctx->cropRect.y, + ctx->cropRect.w,ctx->cropRect.h)) { + LOGE("%s:failed to crop pipe 0", __func__); } - return 0; - } - ctx->pobjDataChannel[0] = new OverlayDataChannel(); - if (!ctx->pobjDataChannel[0]->startDataChannel(ovid, rotid, - size, 0)) { - LOGE("Couldnt start data channel for framebuffer 0"); - delete ctx->pobjDataChannel[0]; - ctx->pobjDataChannel[0] = 0; - return -1; - } - - char value[PROPERTY_VALUE_MAX]; - property_get("hw.hdmiON", value, "0"); - if (!atoi(value)) { - ctx->pobjDataChannel[1] = 0; - return 0; - } - - ovid = handle_get_ovId(handle, 1); - rotid = handle_get_rotId(handle, 1); - ctx->pobjDataChannel[1] = new OverlayDataChannel(); - if (!ctx->pobjDataChannel[1]->startDataChannel(ovid, rotid, - size, 1, true)) { - LOGE("Couldnt start data channel for framebuffer 1"); - delete ctx->pobjDataChannel[1]; - ctx->pobjDataChannel[1] = 0; - } - fp = fopen(FORMAT_3D_FILE, "wb"); - if (fp) { - fprintf(fp, "0"); //Sending hdmi info packet(2D) - fclose(fp); - fp = NULL; + break; + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + for (int i = 0; i < NUM_CHANNELS; i++) { + ovid = handle_get_ovId(handle, i); + rotid = handle_get_rotId(handle, i); + ctx->pobjDataChannel[i] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[i]->startDataChannel(ovid, rotid, size, i, true)) { + error_cleanup_data(ctx, i); + return -1; + } + //setting the crop value + if(!ctx->pobjDataChannel[i]->setCrop( + ctx->cropRect.x,ctx->cropRect.y, + ctx->cropRect.w,ctx->cropRect.h)) { + LOGE("%s:failed to crop pipe %d", __func__, i); + } + } + break; + case OV_3D_VIDEO_3D_TV: + overlay_rect rect; + for (int i = 0; i < NUM_CHANNELS; i++) { + ovid = handle_get_ovId(handle, i); + rotid = handle_get_rotId(handle, i); + ctx->pobjDataChannel[i] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[i]->startDataChannel(ovid, rotid, size, FRAMEBUFFER_1, true)) { + error_cleanup_data(ctx, i); + return -1; + } + ctx->pobjDataChannel[i]->getCropS3D(&ctx->cropRect, i, ctx->format3D, &rect); + if (!ctx->pobjDataChannel[i]->setCrop(rect.x, rect.y, rect.w, rect.h)) { + LOGE("%s: Failed to crop channel %d", __func__, i); + //return -1; + } + } + if(!send3DInfoPacket(ctx->format3D & OUTPUT_MASK_3D)) + LOGI("%s:Error setting the 3D mode for TV", __func__); + break; + default: + break; } return 0; } @@ -706,7 +836,7 @@ return 0; * representing this buffer. */ - /* no interal overlay buffer to dequeue */ + /* no internal overlay buffer to dequeue */ LOGE("%s: no buffer to dequeue ...\n", __FUNCTION__); return 0; @@ -720,7 +850,12 @@ return 0; private_overlay_module_t* m = reinterpret_cast( dev->common.module); Mutex::Autolock objLock(m->pobjMutex); - + bool noRot = true; +#ifdef USE_MSM_ROTATOR + noRot = false; +#else + noRot = true; +#endif // Check if readyToQueue is enabled. overlay_shared_data data; if(ctx->sharedMemBase != MAP_FAILED) @@ -732,60 +867,150 @@ return 0; LOGE("Overlay is not ready to queue buffers"); return -1; } - - bool result; - if (ctx->format3D) { - if ( (ctx->format3D & HAL_3D_OUT_SIDE_BY_SIDE_HALF_MASK) || - (ctx->format3D & HAL_3D_OUT_TOP_BOTTOM_MASK) ) { - result = (ctx->pobjDataChannel[0] && - ctx->pobjDataChannel[0]-> - queueBuffer((uint32_t) buffer)); - if (!result) - LOGE("Queuebuffer failed for VG pipe 0"); - result = (ctx->pobjDataChannel[1] && - ctx->pobjDataChannel[1]-> - queueBuffer((uint32_t) buffer)); - if (!result) - LOGE("Queuebuffer failed for VG pipe 1"); +#if 0 + if(data->state != ctx->state) { + LOGI("Data: State has changed from %d to %d", ctx->state, data->state); + if( (ctx->state == OV_2D_VIDEO_ON_PANEL) || + (ctx->state == OV_3D_VIDEO_2D_PANEL && data->state == OV_3D_VIDEO_2D_TV) ) { + LOGI("2D TV connected, Open a new data channel for TV."); + //Start a new channel for mirroring on HDMI + ctx->pobjDataChannel[VG1_PIPE] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[VG1_PIPE]->startDataChannel( + data->ovid[VG1_PIPE], data->rotid[VG1_PIPE], ctx->size, + FRAMEBUFFER_1, true)) { + delete ctx->pobjDataChannel[VG1_PIPE]; + ctx->pobjDataChannel[VG1_PIPE] = NULL; + return -1; + } + //setting the crop value + if(ctx->format3D) { + overlay_rect rect; + ctx->pobjDataChannel[VG1_PIPE]->getCropS3D(&ctx->cropRect, VG1_PIPE, ctx->format3D, &rect); + if (!ctx->pobjDataChannel[VG1_PIPE]->setCrop(rect.x, rect.y, rect.w, rect.h)) { + LOGE("%s: Failed to crop pipe 1", __func__); + } + } else { + if(!ctx->pobjDataChannel[VG1_PIPE]->setCrop( + ctx->cropRect.x,ctx->cropRect.y, + ctx->cropRect.w,ctx->cropRect.h)) { + LOGE("%s:failed to crop pipe 1", __func__); + } + } + //setting the srcFD + if (!ctx->pobjDataChannel[VG1_PIPE]->setFd(ctx->srcFD)) { + LOGE("%s: Failed to set fd for pipe 1", __func__); + return -1; + } + } else if( (ctx->state == OV_3D_VIDEO_2D_PANEL && data->state == OV_3D_VIDEO_3D_TV) ) { + LOGI("3D TV connected, close data channel and open both data channels for 3DTV."); + //close the channel 0 as it is configured for panel + ctx->pobjDataChannel[VG0_PIPE]->closeDataChannel(); + delete ctx->pobjDataChannel[VG0_PIPE]; + ctx->pobjDataChannel[VG0_PIPE] = NULL; + //update the output from monoscopic to stereoscopic + ctx->format3D = FORMAT_3D_INPUT(ctx->format3D) | ctx->format3D >> SHIFT_3D; + LOGI("Data: New S3D format : 0x%x", ctx->format3D); + //now open both the channels + overlay_rect rect; + for (int i = 0; i < NUM_CHANNELS; i++) { + ctx->pobjDataChannel[i] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[i]->startDataChannel( + data->ovid[i], data->rotid[i], ctx->size, + FRAMEBUFFER_1, true)) { + error_cleanup_data(ctx, i); + return -1; + } + ctx->pobjDataChannel[i]->getCropS3D(&ctx->cropRect, i, ctx->format3D, &rect); + if (!ctx->pobjDataChannel[i]->setCrop(rect.x, rect.y, rect.w, rect.h)) { + LOGE("%s: Failed to crop pipe %d", __func__, i); + return -1; + } + if (!ctx->pobjDataChannel[i]->setFd(ctx->srcFD)) { + LOGE("%s: Failed to set fd for pipe %d", __func__, i); + return -1; + } + } + send3DInfoPacket(ctx->format3D & OUTPUT_MASK_3D); + } else if( (ctx->state == OV_2D_VIDEO_ON_TV) || + (ctx->state == OV_3D_VIDEO_2D_TV && data->state == OV_3D_VIDEO_2D_PANEL) ) { + LOGI("2D TV disconnected, close the data channel for TV."); + ctx->pobjDataChannel[VG1_PIPE]->closeDataChannel(); + delete ctx->pobjDataChannel[VG1_PIPE]; + ctx->pobjDataChannel[VG1_PIPE] = NULL; + } else if (ctx->state == OV_3D_VIDEO_3D_TV && data->state == OV_3D_VIDEO_2D_PANEL) { + LOGI("3D TV disconnected, close the data channels for 3DTV and open one for panel."); + // Close both the pipes' data channel + for (int i = 0; i < NUM_CHANNELS; i++) { + ctx->pobjDataChannel[i]->closeDataChannel(); + delete ctx->pobjDataChannel[i]; + ctx->pobjDataChannel[i] = NULL; + } + send3DInfoPacket(0); + //update the format3D as monoscopic + ctx->format3D = FORMAT_3D_INPUT(ctx->format3D) | HAL_3D_OUT_MONOSCOPIC_MASK; + //now open the channel 0 + ctx->pobjDataChannel[VG0_PIPE] = new OverlayDataChannel(); + if (!ctx->pobjDataChannel[VG0_PIPE]->startDataChannel( + data->ovid[VG0_PIPE], data->rotid[VG0_PIPE], ctx->size, + FRAMEBUFFER_0, noRot)) { + error_cleanup_data(ctx, VG0_PIPE); + return -1; + } + overlay_rect rect; + ctx->pobjDataChannel[VG0_PIPE]->getCropS3D(&ctx->cropRect, VG0_PIPE, ctx->format3D, &rect); + //setting the crop value + if(!ctx->pobjDataChannel[VG0_PIPE]->setCrop( rect.x, rect.y,rect.w, rect.h)) { + LOGE("%s:failed to crop pipe 0", __func__); + } + //setting the srcFD + if (!ctx->pobjDataChannel[VG0_PIPE]->setFd(ctx->srcFD)) { + LOGE("%s: Failed set fd for pipe 0", __func__); + return -1; + } } - else if (ctx->format3D & HAL_3D_OUT_INTERLEAVE_MASK) { - //TBD - } else if (ctx->format3D & HAL_3D_OUT_SIDE_BY_SIDE_FULL_MASK) { - //TBD - } else { - LOGE("%s:Unknown 3D Format...", __func__); - } - return 0; + //update the context's state + ctx->state = data->state; } - if(ctx->setCrop) { - bool result = (ctx->pobjDataChannel[0] && - ctx->pobjDataChannel[0]-> - setCrop(ctx->cropRect.x,ctx->cropRect.y,ctx->cropRect.w,ctx->cropRect.h)); - ctx->setCrop = 0; - if (!result) { - LOGE("set crop failed for framebuffer 0"); +#endif + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + if (ctx->setCrop) { + if(!ctx->pobjDataChannel[VG0_PIPE]->setCrop(ctx->cropRect.x, ctx->cropRect.y, ctx->cropRect.w, ctx->cropRect.h)) { + LOGE("%s: failed for pipe 0", __func__); + } + ctx->setCrop = false; + } + if(!ctx->pobjDataChannel[VG0_PIPE]->queueBuffer((uint32_t) buffer)) { + LOGE("%s: failed for VG pipe 0", __func__); return -1; } - } - - result = (ctx->pobjDataChannel[0] && - ctx->pobjDataChannel[0]-> - queueBuffer((uint32_t) buffer)); - if (!result) - LOGE("Queuebuffer failed for framebuffer 0"); - else { - char value[PROPERTY_VALUE_MAX]; - property_get("hw.hdmiON", value, "0"); - if (!atoi(value)) { - return 0; - } - result = (ctx->pobjDataChannel[1] && - ctx->pobjDataChannel[1]-> - queueBuffer((uint32_t) buffer)); - if (!result) { - LOGE("QueueBuffer failed for framebuffer 1"); - return -1; - } + break; + case OV_3D_VIDEO_2D_PANEL: + if (ctx->setCrop) { + overlay_rect rect; + ctx->pobjDataChannel[VG0_PIPE]->getCropS3D(&ctx->cropRect, VG0_PIPE, ctx->format3D, &rect); + if(!ctx->pobjDataChannel[VG0_PIPE]->setCrop(rect.x, rect.y, rect.w, rect.h)) { + LOGE("%s: failed for pipe 0", __func__); + } + ctx->setCrop = false; + } + if(!ctx->pobjDataChannel[VG0_PIPE]->queueBuffer((uint32_t) buffer)) { + LOGE("%s: failed for VG pipe 0", __func__); + return -1; + } + break; + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + for (int i=0; ipobjDataChannel[i]->queueBuffer((uint32_t) buffer)) { + LOGE("%s: failed for VG pipe %d", __func__, i); + return -1; + } + } + break; + default: + break; } return -1; @@ -797,41 +1022,28 @@ return 0; dev->common.module); struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev; Mutex::Autolock objLock(m->pobjMutex); - bool ret; - if (ctx->format3D) { - ret = (ctx->pobjDataChannel[0] && - ctx->pobjDataChannel[0]->setFd(fd)); - if (!ret) { - LOGE("set fd failed for VG pipe 0"); + ctx->srcFD = fd; + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + if(!ctx->pobjDataChannel[VG0_PIPE]->setFd(fd)) { + LOGE("%s: failed for VG pipe 0", __func__); return -1; } - ret = (ctx->pobjDataChannel[1] && - ctx->pobjDataChannel[1]->setFd(fd)); - if (!ret) { - LOGE("set fd failed for VG pipe 1"); - return -1; + break; + case OV_2D_VIDEO_ON_TV: + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + for (int i=0; ipobjDataChannel[i]->setFd(fd)) { + LOGE("%s: failed for pipe %d", __func__, i); + return -1; + } } - return 0; + break; + default: + break; } - ret = (ctx->pobjDataChannel[0] && - ctx->pobjDataChannel[0]->setFd(fd)); - if (!ret) { - LOGE("set fd failed for framebuffer 0"); - return -1; - } - - char value[PROPERTY_VALUE_MAX]; - property_get("hw.hdmiON", value, "0"); - if (!atoi(value)) { - return 0; - } - - ret = (ctx->pobjDataChannel[1] && - ctx->pobjDataChannel[1]->setFd(fd)); - if (!ret) { - LOGE("set fd failed for framebuffer 1"); - } - return 0; } @@ -842,68 +1054,36 @@ return 0; dev->common.module); struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev; Mutex::Autolock objLock(m->pobjMutex); - bool ret = false; - // for the 3D usecase extract L and R channels from a frame - if(ctx->format3D) { - if ((ctx->format3D & HAL_3D_IN_SIDE_BY_SIDE_HALF_L_R) || - (ctx->format3D & HAL_3D_IN_SIDE_BY_SIDE_HALF_R_L)) { - ret = (ctx->pobjDataChannel[0] && - ctx->pobjDataChannel[0]-> - setCrop(0, 0, w/2, h)); - if (!ret) { - LOGE("set crop failed for VG pipe 0"); - return -1; - } - ret = (ctx->pobjDataChannel[1] && - ctx->pobjDataChannel[1]-> - setCrop(w/2, 0, w/2, h)); - if (!ret) { - LOGE("set crop failed for VG pipe 1"); - return -1; - } - } - else if (ctx->format3D & HAL_3D_IN_TOP_BOTTOM) { - ret = (ctx->pobjDataChannel[0] && - ctx->pobjDataChannel[0]-> - setCrop(0, 0, w, h/2)); - if (!ret) { - LOGE("set crop failed for VG pipe 0"); - return -1; - } - ret = (ctx->pobjDataChannel[1] && - ctx->pobjDataChannel[1]-> - setCrop(0, h/2, w, h/2)); - if (!ret) { - LOGE("set crop failed for VG pipe 1"); - return -1; - } - } - else if (ctx->format3D & HAL_3D_IN_INTERLEAVE) { - //TBD - } else if (ctx->format3D & HAL_3D_IN_SIDE_BY_SIDE_FULL) { - //TBD - } - return 0; - } - //For primary set Crop - ctx->setCrop = 1; + overlay_rect rect; ctx->cropRect.x = x; ctx->cropRect.y = y; ctx->cropRect.w = w; ctx->cropRect.h = h; - - char value[PROPERTY_VALUE_MAX]; - property_get("hw.hdmiON", value, "0"); - if (!atoi(value)) { - return 0; - } - - ret = (ctx->pobjDataChannel[1] && - ctx->pobjDataChannel[1]-> - setCrop(x, y, w, h)); - if (!ret) { - LOGE("set crop failed for framebuffer 1"); - return -1; + switch (ctx->state) { + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + ctx->setCrop = true; + break; + case OV_2D_VIDEO_ON_TV: + for (int i=0; ipobjDataChannel[i]->setCrop(x, y, w, h)) { + LOGE("%s: failed for pipe %d", __func__, i); + return -1; + } + } + break; + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + for (int i=0; ipobjDataChannel[i]->getCropS3D(&ctx->cropRect, i, ctx->format3D, &rect); + if(!ctx->pobjDataChannel[i]->setCrop(rect.x, rect.y, rect.w, rect.h)) { + LOGE("%s: failed for pipe %d", __func__, i); + return -1; + } + } + break; + default: + break; } return 0; } @@ -917,7 +1097,7 @@ return 0; int overlay_getBufferCount(struct overlay_data_device_t *dev) { - return( 0 ); + return 0; } @@ -1010,7 +1190,7 @@ return 0; dev->device.common.close = overlay_data_close; dev->device.initialize = overlay_initialize; - dev->device.setCrop = overlay_setCrop; + dev->device.setCrop = overlay_setCrop; dev->device.dequeueBuffer = overlay_dequeueBuffer; dev->device.queueBuffer = overlay_queueBuffer; dev->device.setFd = overlay_setFd; diff --git a/liboverlay/overlayLib.cpp b/liboverlay/overlayLib.cpp index 33dd458..ba35210 100644 --- a/liboverlay/overlayLib.cpp +++ b/liboverlay/overlayLib.cpp @@ -139,6 +139,60 @@ static void reportError(const char* message) { using namespace overlay; +bool overlay::isHDMIConnected () { + char value[PROPERTY_VALUE_MAX]; + property_get("hw.hdmiON", value, "0"); + int isHDMI = atoi(value); + return isHDMI ? true : false; +} + +bool overlay::is3DTV() { + char is3DTV = '0'; + FILE *fp = fopen(EDID_3D_INFO_FILE, "r"); + if (fp) { + fread(&is3DTV, 1, 1, fp); + fclose(fp); + } + LOGI("3DTV EDID flag: %d", is3DTV); + return (is3DTV == '0') ? false : true; +} + +bool overlay::send3DInfoPacket (unsigned int format3D) { + FILE *fp = fopen(FORMAT_3D_FILE, "wb"); + if (fp) { + fprintf(fp, "%d", format3D); + fclose(fp); + fp = NULL; + return true; + } + LOGE("%s:no sysfs entry for setting 3d mode!", __func__); + return false; +} + +unsigned int overlay::getOverlayConfig (unsigned int format3D) { + bool isTV3D = false, isHDMI = false; + unsigned int curState = 0; + isHDMI = overlay::isHDMIConnected(); + if (isHDMI) { + LOGD("%s: HDMI connected... checking the TV type", __func__); + isTV3D = overlay::is3DTV(); + if (format3D) { + if (isTV3D) + curState = OV_3D_VIDEO_3D_TV; + else + curState = OV_3D_VIDEO_2D_TV; + } else + curState = OV_2D_VIDEO_ON_TV; + } else { + LOGD("%s: HDMI not connected...", __func__); + if(format3D) + curState = OV_3D_VIDEO_2D_PANEL; + else + curState = OV_2D_VIDEO_ON_PANEL; + } + return curState; +} + Overlay::Overlay() : mChannelUP(false), mHDMIConnected(false), mCloseChannel(false), mS3DFormat(0) { } @@ -160,7 +214,6 @@ bool Overlay::startChannel(int w, int h, int format, int fbnum, unsigned int format3D, int channel, bool ignoreFB, int num_buffers) { int zorder = 0; - if (format3D) zorder = channel; mChannelUP = objOvCtrlChannel[channel].startControlChannel(w, h, format, fbnum, @@ -180,7 +233,7 @@ bool Overlay::startChannelHDMI(int w, int h, int format, bool norot) { ret = startChannel(w, h, format, FRAMEBUFFER_1, true, 0, 0, VG1_PIPE); overlay_rect rect; if(ret && objOvCtrlChannel[VG1_PIPE].getAspectRatioPosition(w, h, format, &rect)) { - if(!setChannelPosition(rect.x, rect.y, rect.width, rect.height, VG1_PIPE)) { + if(!setChannelPosition(rect.x, rect.y, rect.w, rect.h, VG1_PIPE)) { LOGE("Failed to upscale for framebuffer 1"); return false; } @@ -189,29 +242,20 @@ bool Overlay::startChannelHDMI(int w, int h, int format, bool norot) { return ret; } -bool Overlay::startChannelS3D(int w, int h, int format, bool norot, int s3DFormat) { - - if (!mHDMIConnected) { - // S3D without HDMI is not supported yet - return true; - } +bool Overlay::startChannelS3D(int w, int h, int format, bool norot) { + bool ret = false; // Start both the channels for the S3D content - bool ret = startChannel(w, h, format, FRAMEBUFFER_1, norot, 0, mS3DFormat, VG0_PIPE); + if (mS3DFormat & HAL_3D_OUT_MONOSCOPIC_MASK) + ret = startChannel(w, h, format, FRAMEBUFFER_0, norot, 0, mS3DFormat, VG0_PIPE); + else + ret = startChannel(w, h, format, FRAMEBUFFER_1, norot, 0, mS3DFormat, VG0_PIPE); if (ret) { ret = startChannel(w, h, format, FRAMEBUFFER_1, norot, 0, mS3DFormat, VG1_PIPE); } - if (ret) { - FILE *fp = fopen(FORMAT_3D_FILE, "wb"); - if (fp) { - fprintf(fp, "%d", mS3DFormat & OUTPUT_MASK_3D); - fclose(fp); - fp = NULL; - } - } - if (!ret) { closeChannel(); - } + } else if (!(mS3DFormat & HAL_3D_OUT_MONOSCOPIC_MASK)) + ret = overlay::send3DInfoPacket(mS3DFormat & OUTPUT_MASK_3D); return ret; } @@ -221,12 +265,7 @@ bool Overlay::closeChannel() { return true; if(mS3DFormat) { - FILE *fp = fopen(FORMAT_3D_FILE, "wb"); - if (fp) { - fprintf(fp, "0"); - fclose(fp); - fp = NULL; - } + overlay::send3DInfoPacket(0); } for (int i = 0; i < NUM_CHANNELS; i++) { objOvCtrlChannel[i].closeControlChannel(); @@ -260,12 +299,16 @@ bool Overlay::setChannelPosition(int x, int y, uint32_t w, uint32_t h, int chann bool Overlay::setPositionS3D(int x, int y, uint32_t w, uint32_t h) { bool ret = false; - for (int i = 0; i < NUM_CHANNELS; i++) { overlay_rect rect; ret = objOvCtrlChannel[i].getPositionS3D(i, mS3DFormat, &rect); - if (ret) { - setChannelPosition(rect.x, rect.y, rect.width, rect.height, i); + if (!ret) + ret = setChannelPosition(x, y, w, h, i); + else + ret = setChannelPosition(rect.x, rect.y, rect.w, rect.h, i); + if (!ret) { + LOGE("%s: failed for channel %d", __func__, i); + return ret; } } return ret; @@ -322,7 +365,15 @@ bool Overlay::setSource(uint32_t w, uint32_t h, int format, int orientation, if (!fOut3D) { format3D |= fIn3D >> SHIFT_3D; //Set the output format } - + if (format3D) { + bool isTV3D = false; + if (hdmiConnected) + isTV3D = overlay::is3DTV(); + if (!isTV3D) { + LOGD("Set the output format as monoscopic"); + format3D = FORMAT_3D_INPUT(format3D) | HAL_3D_OUT_MONOSCOPIC_MASK; + } + } int stateChanged = 0; int hw_format = get_mdp_format(colorFormat); int s3dChanged =0, hdmiChanged = 0; @@ -340,9 +391,9 @@ bool Overlay::setSource(uint32_t w, uint32_t h, int format, int orientation, mS3DFormat = format3D; if (mHDMIConnected) { - if (format3D) { + if (mS3DFormat) { // Start both the VG pipes - return startChannelS3D(w, h, colorFormat, !orientation, format3D); + return startChannelS3D(w, h, colorFormat, !orientation); } else { return startChannelHDMI(w, h, colorFormat, !orientation); } @@ -359,22 +410,31 @@ bool Overlay::setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) { if (!mChannelUP) return false; bool ret; + overlay_rect rect, inRect; + inRect.x = x; inRect.y = y; inRect.w = w; inRect.h = h; if (mHDMIConnected) { if (mS3DFormat) { - overlay_rect rect; - overlay_rect inRect; - inRect.x = x; inRect.y = y; inRect.width = w; inRect.height = h; - // Set the crop for both VG pipes for (int i = 0; i < NUM_CHANNELS; i++) { objOvDataChannel[i].getCropS3D(&inRect, i, mS3DFormat, &rect); - ret = setChannelCrop(rect.x, rect.y, rect.width, rect.height, i); + ret = setChannelCrop(rect.x, rect.y, rect.w, rect.h, i); + if (!ret) { + LOGE("%s: Failure for channel %d", __func__, i); + return ret; + } } return ret; } else { - setChannelCrop(x, y, w, h, VG1_PIPE); + ret = setChannelCrop(x, y, w, h, VG1_PIPE); + if (!ret) { + LOGE("%s: Failure for channel 1", __func__); + return ret; + } } + } else if (mS3DFormat & HAL_3D_OUT_MONOSCOPIC_MASK) { + objOvDataChannel[VG0_PIPE].getCropS3D(&inRect, VG0_PIPE, mS3DFormat, &rect); + return setChannelCrop(rect.x, rect.y, rect.w, rect.h, VG0_PIPE); } return setChannelCrop(x, y, w, h, VG0_PIPE); } @@ -423,15 +483,8 @@ bool Overlay::queueBuffer(buffer_handle_t buffer) { bool ret = true; if (mHDMIConnected) { - if (mS3DFormat) { - // Queue the buffer on VG1 pipe - if ((mS3DFormat & HAL_3D_OUT_SIDE_BY_SIDE_HALF_MASK) || - (mS3DFormat & HAL_3D_OUT_TOP_BOTTOM_MASK)) { - ret = queueBuffer(fd, offset, VG1_PIPE); - } - } else { - ret = queueBuffer(fd, offset, VG1_PIPE); - } + // Queue the buffer on VG1 pipe + ret = queueBuffer(fd, offset, VG1_PIPE); } if (ret && setFd(fd)) { return queueBuffer(offset); @@ -467,8 +520,8 @@ OverlayControlChannel::~OverlayControlChannel() { bool OverlayControlChannel::getAspectRatioPosition(int w, int h, int format, overlay_rect *rect) { int width = w, height = h, x, y; - int fbWidthHDMI = getFBWidth(); - int fbHeightHDMI = getFBHeight(); + int fbWidth = getFBWidth(); + int fbHeight = getFBHeight(); // width and height for YUV TILE format int tempWidth = w, tempHeight = h; /* Calculate the width and height if it is YUV TILE format*/ @@ -476,17 +529,17 @@ bool OverlayControlChannel::getAspectRatioPosition(int w, int h, int format, ove tempWidth = w - ( (((w-1)/64 +1)*64) - w); tempHeight = h - ((((h-1)/32 +1)*32) - h); } - if (width * fbHeightHDMI > fbWidthHDMI * height) { - height = fbWidthHDMI * height / width; + if (width * fbHeight > fbWidth * height) { + height = fbWidth * height / width; EVEN_OUT(height); - width = fbWidthHDMI; - } else if (width * fbHeightHDMI < fbWidthHDMI * height) { - width = fbHeightHDMI * width / height; + width = fbWidth; + } else if (width * fbHeight < fbWidth * height) { + width = fbHeight * width / height; EVEN_OUT(width); - height = fbHeightHDMI; + height = fbHeight; } else { - width = fbWidthHDMI; - height = fbHeightHDMI; + width = fbWidth; + height = fbHeight; } /* Scaling of upto a max of 8 times supported */ if(width >(tempWidth * HW_OVERLAY_MAGNIFICATION_LIMIT)){ @@ -495,54 +548,66 @@ bool OverlayControlChannel::getAspectRatioPosition(int w, int h, int format, ove if(height >(tempHeight*HW_OVERLAY_MAGNIFICATION_LIMIT)) { height = HW_OVERLAY_MAGNIFICATION_LIMIT * tempHeight; } - if (width > fbWidthHDMI) width = fbWidthHDMI; - if (height > fbHeightHDMI) height = fbHeightHDMI; - x = (fbWidthHDMI - width) / 2; - y = (fbHeightHDMI - height) / 2; + if (width > fbWidth) width = fbWidth; + if (height > fbHeight) height = fbHeight; + x = (fbWidth - width) / 2; + y = (fbHeight - height) / 2; rect->x = x; rect->y = y; - rect->width = width; - rect->height = height; + rect->w = width; + rect->h = height; return true; } bool OverlayControlChannel::getPositionS3D(int channel, int format, overlay_rect *rect) { - int wHDMI = getFBWidth(); - int hHDMI = getFBHeight(); - - if (format & HAL_3D_OUT_SIDE_BY_SIDE_HALF_MASK) { + int wDisp = getFBWidth(); + int hDisp = getFBHeight(); + switch (format & OUTPUT_MASK_3D) { + case HAL_3D_OUT_SIDE_BY_SIDE_MASK: if (channel == VG0_PIPE) { rect->x = 0; rect->y = 0; - rect->width = wHDMI/2; - rect->height = hHDMI; + rect->w = wDisp/2; + rect->h = hDisp; } else { - rect->x = wHDMI/2; + rect->x = wDisp/2; rect->y = 0; - rect->width = wHDMI/2; - rect->height = hHDMI; + rect->w = wDisp/2; + rect->h = hDisp; } - } else if (format & HAL_3D_OUT_TOP_BOTTOM_MASK) { + break; + case HAL_3D_OUT_TOP_BOTTOM_MASK: if (channel == VG0_PIPE) { rect->x = 0; rect->y = 0; - rect->width = wHDMI; - rect->height = hHDMI/2; + rect->w = wDisp; + rect->h = hDisp/2; } else { rect->x = 0; - rect->y = hHDMI/2; - rect->width = wHDMI; - rect->height = hHDMI/2; + rect->y = hDisp/2; + rect->w = wDisp; + rect->h = hDisp/2; } - } else if (format & HAL_3D_OUT_INTERLEAVE_MASK) { - //TBD - } else if (format & HAL_3D_OUT_SIDE_BY_SIDE_FULL_MASK) { - //TBD - } else { - reportError("Unsupported 3D output format"); + break; + case HAL_3D_OUT_MONOSCOPIC_MASK: + if (channel == VG1_PIPE) { + rect->x = 0; + rect->y = 0; + rect->w = wDisp; + rect->h = hDisp; + } + else + return false; + break; + case HAL_3D_OUT_INTERLEAVE_MASK: + break; + default: + reportError("Unsupported 3D output format"); + break; } return true; } + bool OverlayControlChannel::openDevices(int fbnum) { if (fbnum < 0) return false; @@ -675,11 +740,11 @@ bool OverlayControlChannel::startOVRotatorSessions(int w, int h, if(mUIChannel) mRotInfo.enable = 1; mRotInfo.session_id = 0; - int result = ioctl(mRotFD, MSM_ROTATOR_IOCTL_START, &mRotInfo); - if (result) { + int result = ioctl(mRotFD, MSM_ROTATOR_IOCTL_START, &mRotInfo); + if (result) { reportError("Rotator session failed"); - ret = false; - } + ret = false; + } } if (!mNoRot && isRGBType(format) && mOrientation && mOVInfo.is_fg) { @@ -807,12 +872,12 @@ bool OverlayControlChannel::startControlChannel(int w, int h, } hw_format = get_mdp_format(colorFormat); if (hw_format < 0) { - reportError("Unsupported format"); + reportError("Unsupported format"); return false; } mFormat3D = format3D; - if (!mFormat3D) { + if ( !mFormat3D || (mFormat3D && HAL_3D_OUT_MONOSCOPIC_MASK) ) { // Set the share bit for sharing the VG pipe flags |= MDP_OV_PIPE_SHARE; } @@ -920,7 +985,7 @@ bool OverlayControlChannel::setPosition(int x, int y, uint32_t w, uint32_t h) { if (ioctl(mFD, MSMFB_OVERLAY_SET, &ov)) { reportError("setPosition, Overlay SET failed"); - return false; + return false; } mOVInfo = ov; @@ -958,7 +1023,7 @@ bool OverlayControlChannel::setParameter(int param, int value, bool fetch) { case OVERLAY_TRANSFORM: { int val = mOVInfo.user_data[0]; - if (value && mNoRot) + if (mNoRot) return true; int rot = value; @@ -1152,7 +1217,7 @@ bool OverlayDataChannel::startDataChannel( memset(&mRotData, 0, sizeof(mRotData)); if (objOvCtrlChannel.getOvSessionID(ovid) && objOvCtrlChannel.getRotSessionID(rotid) && - objOvCtrlChannel.getSize(size)) { + objOvCtrlChannel.getSize(size)) { return startDataChannel(ovid, rotid, size, fbnum, norot, uichannel, num_buffers); } @@ -1277,7 +1342,7 @@ bool OverlayDataChannel::setFd(int fd) { bool OverlayDataChannel::queueBuffer(uint32_t offset) { if ((!isChannelUP()) || mOvData.data.memory_id < 0) { reportError("QueueBuffer failed, either channel is not set or no file descriptor to read from"); - return false; + return false; } msmfb_overlay_data *odPtr; @@ -1296,7 +1361,7 @@ bool OverlayDataChannel::queueBuffer(uint32_t offset) { if (!result) { mOvDataRot.data.offset = (uint32_t) mRotData.dst.offset; - odPtr = &mOvDataRot; + odPtr = &mOvDataRot; } else if (max_num_buffers == mNumBuffers) { reportError("Rotator failed.."); @@ -1306,7 +1371,7 @@ bool OverlayDataChannel::queueBuffer(uint32_t offset) { if (ioctl(mFD, MSMFB_OVERLAY_PLAY, odPtr)) { reportError("overlay play failed."); - return false; + return false; } return true; @@ -1314,51 +1379,67 @@ bool OverlayDataChannel::queueBuffer(uint32_t offset) { bool OverlayDataChannel::getCropS3D(overlay_rect *inRect, int channel, int format, overlay_rect *rect) { - - bool ret; - // for the 3D usecase extract L and R channels from a frame - if ( (format & HAL_3D_IN_SIDE_BY_SIDE_HALF_L_R) || - (format & HAL_3D_IN_SIDE_BY_SIDE_HALF_R_L) ) { + // for the 3D usecase extract channels from a frame + switch (format & INPUT_MASK_3D) { + case HAL_3D_IN_SIDE_BY_SIDE_L_R: if(channel == 0) { rect->x = 0; rect->y = 0; - rect->width = inRect->width/2; - rect->height = inRect->height; + rect->w = inRect->w/2; + rect->h = inRect->h; } else { - rect->x = inRect->width/2; + rect->x = inRect->w/2; rect->y = 0; - rect->width = inRect->width/2; - rect->height = inRect->height; + rect->w = inRect->w/2; + rect->h = inRect->h; } - } else if (format & HAL_3D_IN_TOP_BOTTOM) { + break; + case HAL_3D_IN_SIDE_BY_SIDE_R_L: + if(channel == 1) { + rect->x = 0; + rect->y = 0; + rect->w = inRect->w/2; + rect->h = inRect->h; + } else { + rect->x = inRect->w/2; + rect->y = 0; + rect->w = inRect->w/2; + rect->h = inRect->h; + } + break; + case HAL_3D_IN_TOP_BOTTOM: if(channel == 0) { rect->x = 0; rect->y = 0; - rect->width = inRect->width; - rect->height = inRect->height/2; + rect->w = inRect->w; + rect->h = inRect->h/2; } else { rect->x = 0; - rect->y = inRect->height/2; - rect->width = inRect->width; - rect->height = inRect->height/2; + rect->y = inRect->h/2; + rect->w = inRect->w; + rect->h = inRect->h/2; } - } else if (format & HAL_3D_IN_INTERLEAVE) { - //TBD + break; + case HAL_3D_IN_INTERLEAVE: + break; + default: + reportError("Unsupported 3D format..."); + break; } return true; } bool OverlayDataChannel::setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) { if (!isChannelUP()) { - reportError("Channel not set"); - return false; + reportError("Channel not set"); + return false; } mdp_overlay ov; ov.id = mOvData.id; if (ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) { reportError("setCrop, overlay GET failed"); - return false; + return false; } if ((ov.user_data[0] == MDP_ROT_90) || diff --git a/liboverlay/overlayLib.h b/liboverlay/overlayLib.h index 55af19f..c7ac671 100644 --- a/liboverlay/overlayLib.h +++ b/liboverlay/overlayLib.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -69,29 +69,41 @@ enum { #define COLOR_FORMAT(x) (x & 0xFFF) // in the final 3D format, the MSB 2Bytes are the input format and the // LSB 2bytes are the output format. Shift the output byte 12 bits. -#define FORMAT_3D_OUTPUT(x) ((x & 0xF000) >> 12) -#define FORMAT_3D_INPUT(x) (x & 0xF0000) -#define INPUT_MASK_3D 0xFFFF0000 -#define OUTPUT_MASK_3D 0x0000FFFF -#define SHIFT_3D 16 +#define SHIFT_OUTPUT_3D 12 +#define FORMAT_3D_OUTPUT(x) ((x & 0xF000) >> SHIFT_OUTPUT_3D) +#define FORMAT_3D_INPUT(x) (x & 0xF0000) +#define INPUT_MASK_3D 0xFFFF0000 +#define OUTPUT_MASK_3D 0x0000FFFF +#define SHIFT_3D 16 // The output format is the 2MSB bytes. Shift the format by 12 to reflect this -#define HAL_3D_OUT_SIDE_BY_SIDE_HALF_MASK ((HAL_3D_IN_SIDE_BY_SIDE_HALF_L_R|HAL_3D_IN_SIDE_BY_SIDE_HALF_R_L) >> SHIFT_3D) -#define HAL_3D_OUT_SIDE_BY_SIDE_FULL_MASK (HAL_3D_IN_SIDE_BY_SIDE_FULL >> SHIFT_3D) -#define HAL_3D_OUT_TOP_BOTTOM_MASK (HAL_3D_OUT_TOP_BOTTOM >> 12) -#define HAL_3D_OUT_INTERLEAVE_MASK (HAL_3D_OUT_INTERLEAVE >> 12) +#define HAL_3D_OUT_SIDE_BY_SIDE_MASK (HAL_3D_OUT_SIDE_BY_SIDE >> SHIFT_OUTPUT_3D) +#define HAL_3D_OUT_TOP_BOTTOM_MASK (HAL_3D_OUT_TOP_BOTTOM >> SHIFT_OUTPUT_3D) +#define HAL_3D_OUT_INTERLEAVE_MASK (HAL_3D_OUT_INTERLEAVE >> SHIFT_OUTPUT_3D) +#define HAL_3D_OUT_MONOSCOPIC_MASK (HAL_3D_OUT_MONOSCOPIC >> SHIFT_OUTPUT_3D) + #define FORMAT_3D_FILE "/sys/class/graphics/fb1/format_3d" +#define EDID_3D_INFO_FILE "/sys/class/graphics/fb1/3d_present" /* -------------------------- end 3D defines ----------------------------------------*/ namespace overlay { -const int max_num_buffers = 3; -struct overlay_rect { - int x; - int y; - int width; - int height; +enum { + OV_2D_VIDEO_ON_PANEL = 0, + OV_2D_VIDEO_ON_TV, + OV_3D_VIDEO_2D_PANEL, + OV_3D_VIDEO_2D_TV, + OV_3D_VIDEO_3D_PANEL, + OV_3D_VIDEO_3D_TV }; +bool isHDMIConnected(); +bool is3DTV(); +bool send3DInfoPacket(unsigned int format3D); +unsigned int getOverlayConfig (unsigned int format3D); + +const int max_num_buffers = 3; +typedef struct mdp_rect overlay_rect; + class OverlayControlChannel { bool mNoRot; @@ -184,8 +196,8 @@ class Overlay { bool mChannelUP; bool mHDMIConnected; - int mS3DFormat; bool mCloseChannel; + unsigned int mS3DFormat; OverlayControlChannel objOvCtrlChannel[2]; OverlayDataChannel objOvDataChannel[2]; @@ -221,7 +233,7 @@ public: private: bool startChannelHDMI(int w, int h, int format, bool norot); - bool startChannelS3D(int w, int h, int format, bool norot, int s3DFormat); + bool startChannelS3D(int w, int h, int format, bool norot); bool setPositionS3D(int x, int y, uint32_t w, uint32_t h); bool setParameterS3D(int param, int value); bool setChannelPosition(int x, int y, uint32_t w, uint32_t h, int channel = 0); @@ -232,6 +244,9 @@ private: struct overlay_shared_data { int readyToQueue; + unsigned int state; + int rotid[2]; + int ovid[2]; }; }; #endif