display: Support for S3D video
1. Add support to set HDMI to 3D mode
2. Add binder API to force 3D mode
3. Switch to 3D mode based on metadata
4. Configure pipes appropriately
5. Only side-by-side and top-bottom formats are currently supported
Change-Id: Iae579ecfa45aae088ff543d4143e5025e8c682fa
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 8660740..ef83008 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -25,6 +25,7 @@
#include <overlayRotator.h>
#include "hwc_fbupdate.h"
#include "mdp_version.h"
+#include <video/msm_hdmi_modes.h>
using namespace qdutils;
using namespace overlay;
@@ -499,10 +500,25 @@
hwc_rect_t dstL = displayFrame;
hwc_rect_t dstR = displayFrame;
+ if(ctx->dpyAttr[mDpy].s3dMode == HDMI_S3D_SIDE_BY_SIDE) {
+ dstL.left = displayFrame.left/2;
+ dstL.right = displayFrame.right/2;
+
+ dstR.left = mAlignedFBWidth/2 + displayFrame.left/2;
+ dstR.right = mAlignedFBWidth/2 + displayFrame.right/2;
+ } else if(ctx->dpyAttr[mDpy].s3dMode == HDMI_S3D_TOP_AND_BOTTOM) {
+ dstL.top = displayFrame.top/2;
+ dstL.bottom = displayFrame.bottom/2;
+
+ dstR.top = mAlignedFBHeight/2 + displayFrame.top/2;
+ dstR.bottom = mAlignedFBHeight/2 + displayFrame.bottom/2;
+ }
+
//Request left pipe (or 1 by default)
Overlay::PipeSpecs pipeSpecs;
pipeSpecs.formatClass = Overlay::FORMAT_RGB;
- pipeSpecs.needsScaling = qhwc::needsScaling(layer);
+ pipeSpecs.needsScaling = (qhwc::needsScaling(layer) ||
+ needs3DComposition(ctx,mDpy));
pipeSpecs.dpy = mDpy;
pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
pipeSpecs.fb = true;
@@ -519,6 +535,7 @@
a) FB's width is > Mixer width or
b) On primary, driver has indicated with caps to split always. This is
based on an empirically derived value of panel height.
+ c) The composition is 3D
*/
const bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
@@ -533,7 +550,8 @@
if((cropWidth > qdutils::MDPVersion::getInstance().getMaxPipeWidth()) or
(primarySplitAlways and
- (cropWidth > lSplit or layerClock > mixerClock))) {
+ (cropWidth > lSplit or layerClock > mixerClock)) or
+ needs3DComposition(ctx, mDpy)) {
destR = ov.getPipe(pipeSpecs);
if(destR == ovutils::OV_INVALID) {
ALOGE("%s: No pipes available to configure fb for dpy %d's right"
@@ -546,10 +564,12 @@
}
//Split crop equally when using 2 pipes
- cropL.right = (sourceCrop.right + sourceCrop.left) / 2;
- cropR.left = cropL.right;
- dstL.right = (displayFrame.right + displayFrame.left) / 2;
- dstR.left = dstL.right;
+ if(!needs3DComposition(ctx, mDpy)) {
+ cropL.right = (sourceCrop.right + sourceCrop.left) / 2;
+ cropR.left = cropL.right;
+ dstL.right = (displayFrame.right + displayFrame.left) / 2;
+ dstR.left = dstL.right;
+ }
}
mDestLeft = destL;
@@ -563,6 +583,12 @@
}
}
+ // XXX: Figure out why we need this with source split
+ // Currently, the driver silently fails to configure the right pipe
+ // if we don't increment the zorder
+ if (needs3DComposition(ctx, mDpy))
+ parg.zorder = eZorder(parg.zorder + 1);
+
//configure right pipe
if(destR != OV_INVALID) {
if(configMdp(ctx->mOverlay, parg, orient,
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index caa1344..3d3812c 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -806,6 +806,10 @@
return false;
}
+ // No MDP composition for 3D
+ if(needs3DComposition(ctx, mDpy))
+ return false;
+
// check for action safe flag and MDP scaling mode which requires scaling.
if(ctx->dpyAttr[mDpy].mActionSafePresent
|| ctx->dpyAttr[mDpy].mMDPScalingMode) {
@@ -1340,7 +1344,7 @@
if(mCurrentFrame.fbCount)
mCurrentFrame.fbZ = mCurrentFrame.mdpCount;
- if(sEnableYUVsplit){
+ if(sEnableYUVsplit || needs3DComposition(ctx, mDpy)){
adjustForSourceSplit(ctx, list);
}
@@ -1370,6 +1374,10 @@
return false;
}
+ // No MDP composition for 3D
+ if(needs3DComposition(ctx,mDpy))
+ return false;
+
const bool secureOnly = true;
return mdpOnlyLayersComp(ctx, list, not secureOnly) or
mdpOnlyLayersComp(ctx, list, secureOnly);
@@ -1831,6 +1839,9 @@
}
continue;
}
+ if(needs3DComposition(ctx,mDpy) && get3DFormat(hnd) != HAL_NO_3D) {
+ mdpNextZOrder++;
+ }
if(configure(ctx, layer, mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
layer %d",__FUNCTION__, index);
@@ -2083,7 +2094,7 @@
return ret;
}
-bool MDPComp::allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index) {
+bool MDPComp::allocSplitVGPipes(hwc_context_t *ctx, int index) {
bool bRet = true;
int mdpIndex = mCurrentFrame.layerToMDP[index];
@@ -2186,7 +2197,7 @@
hwc_layer_1_t* layer = &list->hwLayers[index];
private_handle_t *hnd = (private_handle_t *)layer->handle;
if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
- if(allocSplitVGPipesfor4k2k(ctx, index)){
+ if(allocSplitVGPipes(ctx, index)){
continue;
}
}
@@ -2363,7 +2374,9 @@
mdpNextZOrder++;
hwc_layer_1_t* layer = &list->hwLayers[index];
private_handle_t *hnd = (private_handle_t *)layer->handle;
- if(isYUVSplitNeeded(hnd)) {
+ if(isYUVSplitNeeded(hnd) ||
+ (needs3DComposition(ctx,mDpy) &&
+ get3DFormat(hnd) != HAL_NO_3D)) {
hwc_rect_t dst = layer->displayFrame;
if((dst.left > lSplit) || (dst.right < lSplit)) {
mCurrentFrame.mdpCount += 1;
@@ -2426,11 +2439,16 @@
const int lSplit = getLeftSplit(ctx, mDpy);
if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
if((dst.left > lSplit)||(dst.right < lSplit)){
- if(allocSplitVGPipesfor4k2k(ctx, index)){
+ if(allocSplitVGPipes(ctx, index)){
continue;
}
}
}
+ //XXX: Check for forced 2D composition
+ if(needs3DComposition(ctx, mDpy) && get3DFormat(hnd) != HAL_NO_3D)
+ if(allocSplitVGPipes(ctx,index))
+ continue;
+
int mdpIndex = mCurrentFrame.layerToMDP[index];
PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
info.pipeInfo = new MdpPipeInfoSplit;
@@ -2493,7 +2511,9 @@
}
// Set the Handle timeout to true for MDP or MIXED composition.
- if(sIdleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
+ if(sIdleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount &&
+ !(needs3DComposition(ctx, HWC_DISPLAY_PRIMARY) ||
+ needs3DComposition(ctx, HWC_DISPLAY_EXTERNAL))) {
sHandleTimeout = true;
}
@@ -2518,7 +2538,8 @@
int mdpIndex = mCurrentFrame.layerToMDP[i];
- if(isYUVSplitNeeded(hnd) && sEnableYUVsplit)
+ if((isYUVSplitNeeded(hnd) && sEnableYUVsplit) ||
+ (needs3DComposition(ctx, mDpy) && get3DFormat(hnd) != HAL_NO_3D))
{
MdpYUVPipeInfo& pipe_info =
*(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
@@ -2826,6 +2847,7 @@
int rotFlags = ROT_FLAGS_NONE;
uint32_t format = ovutils::getMdpFormat(hnd->format, hnd->flags);
Whf whf(getWidth(hnd), getHeight(hnd), format, hnd->size);
+ eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d"
"dest_pipeR: %d",__FUNCTION__, layer, z, lDest, rDest);
@@ -2841,6 +2863,12 @@
trimAgainstROI(ctx, crop, dst);
}
+ if(needs3DComposition(ctx, mDpy) &&
+ get3DFormat(hnd) != HAL_NO_3D){
+ return configure3DVideo(ctx, layer, mDpy, mdpFlags, z, lDest,
+ rDest, &PipeLayerPair.rot);
+ }
+
// Handle R/B swap
if (layer->flags & HWC_FORMAT_RB_SWAP) {
if (hnd->format == HAL_PIXEL_FORMAT_RGBA_8888)
@@ -2857,7 +2885,6 @@
calcExtDisplayPosition(ctx, hnd, mDpy, crop, dst, transform, orient);
int downscale = getRotDownscale(ctx, layer);
- eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
setMdpFlags(ctx, layer, mdpFlags, downscale, transform);
if(lDest != OV_INVALID && rDest != OV_INVALID) {
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 7c46c1a..a83f51f 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -270,7 +270,7 @@
//Enable 4kx2k yuv layer split
static bool sEnableYUVsplit;
bool mModeOn; // if prepare happened
- bool allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index);
+ bool allocSplitVGPipes(hwc_context_t *ctx, int index);
//Enable Partial Update for MDP3 targets
static bool enablePartialUpdateForMDP3;
static void *sLibPerfHint;
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 09013c6..487ec77 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -35,6 +35,8 @@
#include <hwc_virtual.h>
#include <overlay.h>
#include <display_config.h>
+#include <hdmi.h>
+#include <video/msm_hdmi_modes.h>
#define QCLIENT_DEBUG 0
@@ -338,6 +340,21 @@
}
}
+static void setS3DMode(hwc_context_t* ctx, int mode) {
+ if (ctx->mHDMIDisplay) {
+ if(ctx->mHDMIDisplay->isS3DModeSupported(mode)) {
+ ALOGD("%s: Force S3D mode to %d", __FUNCTION__, mode);
+ Locker::Autolock _sl(ctx->mDrawLock);
+ ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].s3dModeForced = true;
+ setup3DMode(ctx, HWC_DISPLAY_EXTERNAL, mode);
+ } else {
+ ALOGD("%s: mode %d is not supported", __FUNCTION__, mode);
+ }
+ } else {
+ ALOGE("%s: No HDMI Display detected", __FUNCTION__);
+ }
+}
+
status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
Parcel* outParcel) {
status_t ret = NO_ERROR;
@@ -398,6 +415,9 @@
case IQService::TOGGLE_SCREEN_UPDATE:
toggleScreenUpdate(mHwcContext, inParcel->readInt32());
break;
+ case IQService::SET_S3D_MODE:
+ setS3DMode(mHwcContext, inParcel->readInt32());
+ break;
default:
ret = NO_ERROR;
}
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 9ea8246..05ab503 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -45,6 +45,7 @@
#include "qd_utils.h"
#include <sys/sysinfo.h>
#include <dlfcn.h>
+#include <video/msm_hdmi_modes.h>
using namespace qClient;
using namespace qService;
@@ -351,8 +352,14 @@
ctx->dpyAttr[i].mActionSafePresent = false;
ctx->dpyAttr[i].mAsWidthRatio = 0;
ctx->dpyAttr[i].mAsHeightRatio = 0;
+ ctx->dpyAttr[i].s3dMode = HDMI_S3D_NONE;
+ ctx->dpyAttr[i].s3dModeForced = false;
}
+ //Make sure that the 3D mode is unset at bootup
+ //This makes sure that the state is accurate on framework reboots
+ ctx->mHDMIDisplay->configure3D(HDMI_S3D_NONE);
+
for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
ctx->mPrevHwLayerCount[i] = 0;
}
@@ -1008,6 +1015,8 @@
ctx->listStats[dpy].refreshRateRequest = ctx->dpyAttr[dpy].refreshRate;
uint32_t refreshRate = 0;
qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
+ int s3dFormat = HAL_NO_3D;
+ int s3dLayerCount = 0;
ctx->listStats[dpy].mAIVVideoMode = false;
resetROI(ctx, dpy);
@@ -1063,6 +1072,14 @@
ctx->listStats[dpy].yuv4k2kIndices[yuv4k2kCount] = (int)i;
yuv4k2kCount++;
}
+
+ // Gets set if one YUV layer is 3D
+ if (displaySupports3D(ctx,dpy)) {
+ s3dFormat = get3DFormat(hnd);
+ if(s3dFormat != HAL_NO_3D)
+ s3dLayerCount++;
+ }
+
}
if(layer->blending == HWC_BLENDING_PREMULT)
ctx->listStats[dpy].preMultipliedAlpha = true;
@@ -1089,6 +1106,17 @@
}
#endif
}
+
+ //Set the TV's 3D mode based on format if it was not forced
+ //Only one 3D YUV layer is supported on external
+ //If there is more than one 3D YUV layer, the switch to 3D cannot occur.
+ if( !ctx->dpyAttr[dpy].s3dModeForced && (s3dLayerCount <= 1)) {
+ //XXX: Rapidly going in and out of 3D mode in some cases such
+ // as rotation might cause flickers. The OEMs are recommended to disable
+ // rotation on HDMI globally or in the app that plays 3D video
+ setup3DMode(ctx, dpy, convertS3DFormatToMode(s3dFormat));
+ }
+
if(ctx->listStats[dpy].yuvCount > 0) {
if (property_get("hw.cabl.yuv", property, NULL) > 0) {
if (atoi(property) != 1) {
@@ -2197,6 +2225,113 @@
return 0;
}
+int configure3DVideo(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
+ const eDest& lDest, const eDest& rDest,
+ Rotator **rot) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(!hnd) {
+ ALOGE("%s: layer handle is NULL", __FUNCTION__);
+ return -1;
+ }
+ //Both pipes are configured to the same mixer
+ eZorder lz = z;
+ eZorder rz = (eZorder)(z + 1);
+
+ MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t dst = layer->displayFrame;
+ int transform = layer->transform;
+ eTransform orient = static_cast<eTransform>(transform);
+ int rotFlags = ROT_FLAGS_NONE;
+ uint32_t format = ovutils::getMdpFormat(hnd->format, hnd->flags);
+ Whf whf(getWidth(hnd), getHeight(hnd), format, (uint32_t)hnd->size);
+
+ int downscale = getRotDownscale(ctx, layer);
+ setMdpFlags(ctx, layer, mdpFlagsL, downscale, transform);
+
+ //XXX: Check if rotation is supported and valid for 3D
+ if((has90Transform(layer) or downscale) and isRotationDoable(ctx, hnd)) {
+ (*rot) = ctx->mRotMgr->getNext();
+ if((*rot) == NULL) return -1;
+ ctx->mLayerRotMap[dpy]->add(layer, *rot);
+ //Configure rotator for pre-rotation
+ if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
+ ALOGE("%s: configRotator failed!", __FUNCTION__);
+ return -1;
+ }
+ updateSource(orient, whf, crop, *rot);
+ rotFlags |= ROT_PREROTATED;
+ }
+
+ eMdpFlags mdpFlagsR = mdpFlagsL;
+
+ hwc_rect_t cropL = crop, dstL = dst;
+ hwc_rect_t cropR = crop, dstR = dst;
+ int hw_w = ctx->dpyAttr[dpy].xres;
+ int hw_h = ctx->dpyAttr[dpy].yres;
+
+ if(get3DFormat(hnd) == HAL_3D_SIDE_BY_SIDE_L_R ||
+ get3DFormat(hnd) == HAL_3D_SIDE_BY_SIDE_R_L) {
+ // Calculate Left rects
+ // XXX: This assumes crop.right/2 is the center point of the video
+ cropL.right = crop.right/2;
+ dstL.left = dst.left/2;
+ dstL.right = dst.right/2;
+
+ // Calculate Right rects
+ cropR.left = crop.right/2;
+ dstR.left = hw_w/2 + dst.left/2;
+ dstR.right = hw_w/2 + dst.right/2;
+ } else if(get3DFormat(hnd) == HAL_3D_TOP_BOTTOM) {
+ // Calculate Left rects
+ cropL.bottom = crop.bottom/2;
+ dstL.top = dst.top/2;
+ dstL.bottom = dst.bottom/2;
+
+ // Calculate Right rects
+ cropR.top = crop.bottom/2;
+ dstR.top = hw_h/2 + dst.top/2;
+ dstR.bottom = hw_h/2 + dst.bottom/2;
+ } else {
+ ALOGE("%s: Unsupported 3D mode ", __FUNCTION__);
+ return -1;
+ }
+
+ //For the mdp, since either we are pre-rotating or MDP does flips
+ orient = OVERLAY_TRANSFORM_0;
+ transform = 0;
+
+ //configure left pipe
+ if(lDest != OV_INVALID) {
+ PipeArgs pargL(mdpFlagsL, whf, lz,
+ static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+
+ if(configMdp(ctx->mOverlay, pargL, orient,
+ cropL, dstL, metadata, lDest) < 0) {
+ ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
+ return -1;
+ }
+ }
+
+ //configure right pipe
+ if(rDest != OV_INVALID) {
+ PipeArgs pargR(mdpFlagsR, whf, rz,
+ static_cast<eRotFlags>(rotFlags),
+ layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+ if(configMdp(ctx->mOverlay, pargR, orient,
+ cropR, dstR, metadata, rDest) < 0) {
+ ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
const eDest& lDest, const eDest& rDest,
@@ -2810,4 +2945,41 @@
ctx->dpyAttr[dpy].isActive = false;
}
+int convertS3DFormatToMode(int s3DFormat) {
+ int ret;
+ switch(s3DFormat) {
+ case HAL_3D_SIDE_BY_SIDE_L_R:
+ case HAL_3D_SIDE_BY_SIDE_R_L:
+ ret = HDMI_S3D_SIDE_BY_SIDE;
+ break;
+ case HAL_3D_TOP_BOTTOM:
+ ret = HDMI_S3D_TOP_AND_BOTTOM;
+ break;
+ default:
+ ret = HDMI_S3D_NONE;
+ }
+ return ret;
+}
+
+bool needs3DComposition(hwc_context_t* ctx, int dpy) {
+ return (displaySupports3D(ctx, dpy) && ctx->dpyAttr[dpy].connected &&
+ ctx->dpyAttr[dpy].s3dMode != HDMI_S3D_NONE);
+}
+
+void setup3DMode(hwc_context_t *ctx, int dpy, int s3dMode) {
+ if (ctx->dpyAttr[dpy].s3dMode != s3dMode) {
+ ALOGD("%s: setup 3D mode: %d", __FUNCTION__, s3dMode);
+ if(ctx->mHDMIDisplay->configure3D(s3dMode)) {
+ ctx->dpyAttr[dpy].s3dMode = s3dMode;
+ }
+ }
+}
+
+bool displaySupports3D(hwc_context_t* ctx, int dpy) {
+ return ((dpy == HWC_DISPLAY_EXTERNAL) ||
+ ((dpy == HWC_DISPLAY_PRIMARY) &&
+ ctx->mHDMIDisplay->isHDMIPrimaryDisplay()));
+}
+
+
};//namespace qhwc
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 4f1b5e6..52b22b1 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -117,6 +117,18 @@
uint32_t xres_new;
uint32_t yres_new;
+ // This is the 3D mode to which the TV is set
+ // The mode may be set via the appearance of a layer with 3D format
+ // or by forcing the mode via binder.
+ // If the mode is set via binder, the s3dModeForced flag is set, so that the
+ // mode is not changed back when the 3D video layer drops out.
+ // If the forced mode is different from the one in 3D video, the results
+ // are unpredictable. The assumption is made here that the caller forcing
+ // the mode via binder knows the right formats to use.
+ // The s3dModeForced flag is also used to force 2D if the s3dMode is
+ // HDMI_S3D_NONE
+ int s3dMode;
+ bool s3dModeForced;
};
struct ListStats {
@@ -411,6 +423,15 @@
const ovutils::eDest& lDest,
const ovutils::eDest& rDest, overlay::Rotator **rot);
+//Check if the current round needs 3D composition
+bool needs3DComposition(hwc_context_t* ctx, int dpy);
+
+//Routine to configure 3D video
+int configure3DVideo(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
+ ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+ const ovutils::eDest& lDest,
+ const ovutils::eDest& rDest, overlay::Rotator **rot);
+
//Routine to split and configure high resolution YUV layer (> 2048 width)
int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
const int& dpy,
@@ -444,6 +465,16 @@
// Checks if boot animation has completed and applies default mode
void processBootAnimCompleted(hwc_context_t *ctx);
+//The gralloc API and driver have different formats
+//The format needs to be converted before passing to libhdmi
+int convertS3DFormatToMode(int s3DFormat);
+
+//Configure resources for 3D mode
+void setup3DMode(hwc_context_t* ctx, int dpy, int s3dMode);
+
+//Checks if this display supports 3D
+bool displaySupports3D(hwc_context_t* ctx, int dpy);
+
// Inline utility functions
static inline bool isSkipLayer(const hwc_layer_1_t* l) {
return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER)));
@@ -489,6 +520,14 @@
return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY));
}
+static inline uint32_t get3DFormat(const private_handle_t* hnd) {
+ MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
+ if(isYuvBuffer(hnd) && metadata && metadata->operation & S3D_FORMAT) {
+ return metadata->s3dFormat;
+ }
+ return HAL_NO_3D;
+}
+
static inline int getWidth(const private_handle_t* hnd) {
MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
@@ -644,7 +683,7 @@
bool mBWCEnabled;
// Provides a way for OEM's to disable setting dynfps via metadata.
bool mUseMetaDataRefreshRate;
- // Stores the hpd enabled status- avoids re-enabling HDP on suspend resume.
+ // Stores the hpd enabled status- avoids re-enabling HDP on suspend resume.
bool mHPDEnabled;
//Used to notify that boot has completed
bool mBootAnimCompleted;