display: Add support orientation control on ext display
- The required orientation on External can be set using the
properyt sys.ext_orientation.
- Values can be HAL_TRANSFORM_ROT_90, HAL_TRANSFORM_ROT_270
- According to the value set, the FB_TARGET for External will
be rotated and positioned as per aspect ratio on Ext
- For YUV(video layer) it just calculates the position, as the
rotation should be the source orientation
- This feature is supported only for low resolution panel.
Change-Id: I3d532ee0cb8dca3c37869537b55cd8044fd9047e
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 439432e..b9be4d4 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -19,12 +19,17 @@
*/
#define DEBUG_FBUPDATE 0
+#include <cutils/properties.h>
#include <gralloc_priv.h>
+#include <overlayRotator.h>
#include "hwc_fbupdate.h"
#include "mdp_version.h"
+#include "external.h"
using namespace qdutils;
+using overlay::Rotator;
+
namespace qhwc {
namespace ovutils = overlay::utils;
@@ -38,6 +43,7 @@
inline void IFBUpdate::reset() {
mModeOn = false;
+ mRot = NULL;
}
//================= Low res====================================
@@ -87,46 +93,71 @@
mDest = dest;
ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
-
+ ovutils::eIsFg isFg = ovutils::IS_FG_OFF;
ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
- ovutils::PipeArgs parg(mdpFlags,
- info,
- zOrder,
- ovutils::IS_FG_OFF,
- ovutils::ROT_FLAGS_NONE);
- ov.setSource(parg, dest);
-
hwc_rect_t sourceCrop = layer->sourceCrop;
hwc_rect_t displayFrame = layer->displayFrame;
- if(extOnlyLayerIndex == -1) {
+ int transform = layer->transform;
+ int fbWidth = ctx->dpyAttr[mDpy].xres;
+ int fbHeight = ctx->dpyAttr[mDpy].yres;
+ int rotFlags = ovutils::ROT_FLAGS_NONE;
+
+ ovutils::eTransform orient =
+ static_cast<ovutils::eTransform>(transform);
+ if(mDpy && ctx->mExtOrientation) {
+ // If there is a external orientation set, use that
+ transform = ctx->mExtOrientation;
+ orient = static_cast<ovutils::eTransform >(ctx->mExtOrientation);
+ }
+
+ // Dont do wormhole calculation when extorientation is set on External
+ if((!mDpy || (mDpy && !ctx->mExtOrientation))
+ && extOnlyLayerIndex == -1) {
getNonWormholeRegion(list, sourceCrop);
displayFrame = sourceCrop;
}
-
- // x,y,w,h
- ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
- sourceCrop.right - sourceCrop.left,
- sourceCrop.bottom - sourceCrop.top);
- ov.setCrop(dcrop, dest);
-
- int transform = layer->transform;
- ovutils::eTransform orient =
- static_cast<ovutils::eTransform>(transform);
- ov.setTransform(orient, dest);
-
ovutils::Dim dpos(displayFrame.left,
displayFrame.top,
displayFrame.right - displayFrame.left,
displayFrame.bottom - displayFrame.top);
// Calculate the actionsafe dimensions for External(dpy = 1 or 2)
- if(mDpy)
+ if(mDpy && !ctx->mExtOrientation)
getActionSafePosition(ctx, mDpy, dpos.x, dpos.y, dpos.w, dpos.h);
- ov.setPosition(dpos, dest);
+ if(mDpy) {
+ getAspectRatioPosition(ctx, mDpy, ctx->mExtOrientation, dpos.x,
+ dpos.y, dpos.w, dpos.h);
+ // Convert dim to hwc_rect_t
+ displayFrame.left = dpos.x;
+ displayFrame.top = dpos.y;
+ displayFrame.right = dpos.w + displayFrame.left;
+ displayFrame.bottom = dpos.h + displayFrame.top;
+ }
+ setMdpFlags(layer, mdpFlags, 0);
+ // For External use rotator if there is a rotation value set
+ if(mDpy && (ctx->mExtOrientation & HWC_TRANSFORM_ROT_90)) {
+ mRot = ctx->mRotMgr->getNext();
+ if(mRot == NULL) return -1;
+ //Configure rotator for pre-rotation
+ if(configRotator(mRot, info, sourceCrop, mdpFlags, orient, 0) < 0) {
+ ALOGE("%s: configRotator Failed!", __FUNCTION__);
+ mRot = NULL;
+ return -1;
+ }
+ info.format = (mRot)->getDstFormat();
+ updateSource(orient, info, sourceCrop);
+ rotFlags |= ovutils::ROT_PREROTATED;
+ }
+ //For the mdp, since either we are pre-rotating or MDP does flips
+ orient = ovutils::OVERLAY_TRANSFORM_0;
+ transform = 0;
+ ovutils::PipeArgs parg(mdpFlags, info, zOrder, isFg,
+ static_cast<ovutils::eRotFlags>(rotFlags));
ret = true;
- if (!ov.commit(dest)) {
- ALOGE("%s: commit fails", __FUNCTION__);
+ if(configMdp(ctx->mOverlay, parg, orient, sourceCrop, displayFrame,
+ NULL, mDest) < 0) {
+ ALOGE("%s: ConfigMdp failed for low res", __FUNCTION__);
ret = false;
}
}
@@ -141,7 +172,15 @@
bool ret = true;
overlay::Overlay& ov = *(ctx->mOverlay);
ovutils::eDest dest = mDest;
- if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) {
+ int fd = hnd->fd;
+ uint32_t offset = hnd->offset;
+ if(mRot) {
+ if(!mRot->queueBuffer(fd, offset))
+ return false;
+ fd = mRot->getDstMemId();
+ offset = mRot->getDstOffset();
+ }
+ if (!ov.queueBuffer(fd, offset, dest)) {
ALOGE("%s: queueBuffer failed for FBUpdate", __FUNCTION__);
ret = false;
}
@@ -155,6 +194,7 @@
IFBUpdate::reset();
mDestLeft = ovutils::OV_INVALID;
mDestRight = ovutils::OV_INVALID;
+ mRot = NULL;
}
bool FBUpdateHighRes::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
diff --git a/libhwcomposer/hwc_fbupdate.h b/libhwcomposer/hwc_fbupdate.h
index 4291a50..5cf75f7 100644
--- a/libhwcomposer/hwc_fbupdate.h
+++ b/libhwcomposer/hwc_fbupdate.h
@@ -25,6 +25,10 @@
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+namespace overlay {
+ class Rotator;
+}
+
namespace qhwc {
namespace ovutils = overlay::utils;
@@ -46,6 +50,7 @@
protected:
const int mDpy; // display to update
bool mModeOn; // if prepare happened
+ overlay::Rotator *mRot;
};
//Low resolution (<= 2048) panel handler.
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index edf579f..65667bd 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -107,4 +107,9 @@
#endif
return result;
}
+
+void QClient::setExtOrientation(uint32_t orientation) {
+ mHwcContext->mExtOrientation = orientation;
+}
+
}
diff --git a/libhwcomposer/hwc_qclient.h b/libhwcomposer/hwc_qclient.h
index 9cb2680..4cbabef 100644
--- a/libhwcomposer/hwc_qclient.h
+++ b/libhwcomposer/hwc_qclient.h
@@ -60,6 +60,7 @@
void securing(uint32_t startEnd);
void unsecuring(uint32_t startEnd);
android::status_t screenRefresh();
+ void setExtOrientation(uint32_t orientation);
hwc_context_t *mHwcContext;
const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier;
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index fdaa1cb..5a00578 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -156,6 +156,7 @@
ctx->vstate.enable = false;
ctx->vstate.fakevsync = false;
ctx->mExtDispConfiguring = false;
+ ctx->mExtOrientation = 0;
//Right now hwc starts the service but anybody could do it, or it could be
//independent process as well.
@@ -276,6 +277,31 @@
return;
}
+/* Calculates the aspect ratio for external based on the primary */
+void getAspectRatioPosition(hwc_context_t *ctx, int dpy, int orientation,
+ uint32_t& x, uint32_t& y, uint32_t& w, uint32_t& h) {
+ int fbWidth = ctx->dpyAttr[dpy].xres;
+ int fbHeight = ctx->dpyAttr[dpy].yres;
+
+ switch(orientation) {
+ case HAL_TRANSFORM_ROT_90:
+ case HAL_TRANSFORM_ROT_270:
+ x = (fbWidth - (ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres
+ * fbHeight/ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres))/2;
+ y = 0;
+ w = (ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres *
+ fbHeight/ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres);
+ h = fbHeight;
+ break;
+ default:
+ //Do nothing
+ break;
+ }
+ ALOGD_IF(HWC_UTILS_DEBUG, "%s: Position: x = %d, y = %d w = %d h = %d",
+ __FUNCTION__, x, y, w ,h);
+}
+
+
bool needsScaling(hwc_layer_1_t const* layer) {
int dst_w, dst_h, src_w, src_h;
@@ -375,6 +401,24 @@
}
}
}
+ if(dpy) {
+ //uncomment the below code for testing purpose.
+ /* char value[PROPERTY_VALUE_MAX];
+ property_get("sys.ext_orientation", value, "0");
+ // Assuming the orientation value is in terms of HAL_TRANSFORM,
+ // This needs mapping to HAL, if its in different convention
+ ctx->mExtOrientation = atoi(value); */
+ // Assuming the orientation value is in terms of HAL_TRANSFORM,
+ // This needs mapping to HAL, if its in different convention
+ if(ctx->mExtOrientation) {
+ ALOGD_IF(HWC_UTILS_DEBUG, "%s: ext orientation = %d",
+ __FUNCTION__, ctx->mExtOrientation);
+ if(ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
+ ctx->isPaddingRound = true;
+ }
+ Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
+ }
+ }
}
@@ -679,7 +723,7 @@
}
}
-static inline int configRotator(Rotator *rot, const Whf& whf,
+inline int configRotator(Rotator *rot, const Whf& whf,
const hwc_rect_t& crop, const eMdpFlags& mdpFlags,
const eTransform& orient, const int& downscale) {
Dim rotCrop(crop.left, crop.top, (crop.right - crop.left),
@@ -693,7 +737,7 @@
return 0;
}
-static inline int configMdp(Overlay *ov, const PipeArgs& parg,
+inline int configMdp(Overlay *ov, const PipeArgs& parg,
const eTransform& orient, const hwc_rect_t& crop,
const hwc_rect_t& pos, const MetaData_t *metadata,
const eDest& dest) {
@@ -719,7 +763,7 @@
return 0;
}
-static inline void updateSource(eTransform& orient, Whf& whf,
+inline void updateSource(eTransform& orient, Whf& whf,
hwc_rect_t& crop) {
Dim srcCrop(crop.left, crop.top,
crop.right - crop.left,
@@ -765,6 +809,21 @@
Whf whf(hnd->width, hnd->height,
getMdpFormat(hnd->format), hnd->size);
+ uint32_t x = dst.left, y = dst.right;
+ uint32_t w = dst.right - dst.left;
+ uint32_t h = dst.bottom - dst.top;
+
+ if(dpy && ctx->mExtOrientation) {
+ // Just need to set the position to portrait as the transformation
+ // will already be set to required orientation on TV
+ getAspectRatioPosition(ctx, dpy, ctx->mExtOrientation, x, y, w, h);
+ // Convert position to hwc_rect_t
+ dst.left = x;
+ dst.top = y;
+ dst.right = w + dst.left;
+ dst.bottom = h + dst.top;
+ }
+
if(isYuvBuffer(hnd) && ctx->mMDP.version >= qdutils::MDP_V4_2 &&
ctx->mMDP.version < qdutils::MDSS_V5) {
downscale = getDownscaleFactor(
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 0e603ce..ab645bc 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -133,6 +133,10 @@
void getActionSafePosition(hwc_context_t *ctx, int dpy, uint32_t& x,
uint32_t& y, uint32_t& w, uint32_t& h);
+
+void getAspectRatioPosition(hwc_context_t *ctx, int dpy, int orientation,
+ uint32_t& x, uint32_t& y, uint32_t& w, uint32_t& h);
+
//Close acquireFenceFds of all layers of incoming list
void closeAcquireFds(hwc_display_contents_1_t* list);
@@ -149,6 +153,20 @@
ovutils::eMdpFlags &mdpFlags,
int rotDownscale = 0);
+int configRotator(overlay::Rotator *rot, const ovutils::Whf& whf,
+ const hwc_rect_t& crop, const ovutils::eMdpFlags& mdpFlags,
+ const ovutils::eTransform& orient, const int& downscale);
+
+int configMdp(overlay::Overlay *ov, const ovutils::PipeArgs& parg,
+ const ovutils::eTransform& orient, const hwc_rect_t& crop,
+ const hwc_rect_t& pos, const MetaData_t *metadata,
+ const ovutils::eDest& dest);
+
+void updateSource(ovutils::eTransform& orient, ovutils::Whf& whf,
+ hwc_rect_t& crop);
+
+
+
//Routine to configure low resolution panels (<= 2048 width)
int configureLowRes(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
ovutils::eMdpFlags& mdpFlags, const ovutils::eZorder& z,
@@ -276,6 +294,8 @@
struct vsync_state vstate;
//Drawing round when we use GPU
bool isPaddingRound;
+ // External Orientation
+ int mExtOrientation;
};
namespace qhwc {
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index 53b05e3..af11f88 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -71,6 +71,13 @@
status_t result = reply.readInt32();
return result;
}
+
+ virtual void setExtOrientation(uint32_t orientation) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IQService::getInterfaceDescriptor());
+ data.writeInt32(orientation);
+ remote()->transact(EXTERNAL_ORIENTATION, data, &reply);
+ }
};
IMPLEMENT_META_INTERFACE(QService, "android.display.IQService");
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 79e831d..ff034be 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -41,6 +41,7 @@
UNSECURING, // Hardware unsecuring start/end notification
CONNECT,
SCREEN_REFRESH,
+ EXTERNAL_ORIENTATION,
};
enum {
END = 0,
@@ -50,6 +51,7 @@
virtual void unsecuring(uint32_t startEnd) = 0;
virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
virtual android::status_t screenRefresh() = 0;
+ virtual void setExtOrientation(uint32_t orientation) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index 54e285c..f780a75 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -71,6 +71,12 @@
return result;
}
+void QService::setExtOrientation(uint32_t orientation) {
+ if(mClient.get()) {
+ mClient->notifyCallback(EXTERNAL_ORIENTATION, orientation);
+ }
+}
+
void QService::init()
{
if(!sQService) {
diff --git a/libqservice/QService.h b/libqservice/QService.h
index 268bf81..8eefa21 100644
--- a/libqservice/QService.h
+++ b/libqservice/QService.h
@@ -49,6 +49,7 @@
virtual void unsecuring(uint32_t startEnd);
virtual void connect(const android::sp<qClient::IQClient>& client);
virtual android::status_t screenRefresh();
+ virtual void setExtOrientation(uint32_t orientation);
static void init();
private:
QService();