hwc/overlay: Video on 4k2k external, 4k2k rotation.
-Add support for Video via overlay on 4k2k external panel.
-Add support for rotating videos on 4k2k panels. We use
pre-rotation in hwc to rotate a video into a single buffer,
irrespective of panel size. Then this buffer is fed to MDP.
Rotator objects are managed by the new RotMgr.
-Cleaup mdpcomp and overlay.
Change-Id: Ifb08534747e8e18b6c58dd8a3e1a9947409100f1
diff --git a/libhwcomposer/hwc_video.cpp b/libhwcomposer/hwc_video.cpp
index edd0ba8..2166a5b 100644
--- a/libhwcomposer/hwc_video.cpp
+++ b/libhwcomposer/hwc_video.cpp
@@ -24,26 +24,36 @@
#include "hwc_utils.h"
#include "qdMetaData.h"
#include "mdp_version.h"
+#include <overlayRotator.h>
+
+using overlay::Rotator;
namespace qhwc {
namespace ovutils = overlay::utils;
-//Static Members
-bool VideoOverlay::sIsModeOn[] = {false};
-ovutils::eDest VideoOverlay::sDest[] = {ovutils::OV_INVALID};
+//===========IVideoOverlay=========================
+IVideoOverlay* IVideoOverlay::getObject(const int& width, const int& dpy) {
+ if(width > MAX_DISPLAY_DIM) {
+ return new VideoOverlayHighRes(dpy);
+ }
+ return new VideoOverlayLowRes(dpy);
+}
+
+//===========VideoOverlayLowRes=========================
+
+VideoOverlayLowRes::VideoOverlayLowRes(const int& dpy): IVideoOverlay(dpy) {}
//Cache stats, figure out the state, config overlay
-bool VideoOverlay::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
- int dpy) {
+bool VideoOverlayLowRes::prepare(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list) {
- if(ctx->listStats[dpy].yuvCount > 1)
+ if(ctx->listStats[mDpy].yuvCount > 1)
return false;
- int yuvIndex = ctx->listStats[dpy].yuvIndices[0];
- sIsModeOn[dpy] = false;
-
- int hw_w = ctx->dpyAttr[dpy].xres;
+ int yuvIndex = ctx->listStats[mDpy].yuvIndices[0];
+ int hw_w = ctx->dpyAttr[mDpy].xres;
+ mModeOn = false;
if(hw_w > MAX_DISPLAY_DIM) {
ALOGD_IF(VIDEO_DEBUG,"%s, \
@@ -61,7 +71,7 @@
return false;
}
- if(yuvIndex == -1 || ctx->listStats[dpy].yuvCount != 1) {
+ if(yuvIndex == -1 || ctx->listStats[mDpy].yuvCount != 1) {
return false;
}
@@ -83,126 +93,55 @@
}
}
}
- if(configure(ctx, dpy, layer)) {
+
+ if(configure(ctx, layer)) {
markFlags(layer);
- sIsModeOn[dpy] = true;
+ mModeOn = true;
}
- return sIsModeOn[dpy];
+ return mModeOn;
}
-void VideoOverlay::markFlags(hwc_layer_1_t *layer) {
+void VideoOverlayLowRes::markFlags(hwc_layer_1_t *layer) {
if(layer) {
layer->compositionType = HWC_OVERLAY;
layer->hints |= HWC_HINT_CLEAR_FB;
}
}
-bool VideoOverlay::configure(hwc_context_t *ctx, int dpy,
+bool VideoOverlayLowRes::configure(hwc_context_t *ctx,
hwc_layer_1_t *layer) {
+
overlay::Overlay& ov = *(ctx->mOverlay);
private_handle_t *hnd = (private_handle_t *)layer->handle;
- ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
+ ovutils::Whf info(hnd->width, hnd->height,
+ ovutils::getMdpFormat(hnd->format), hnd->size);
//Request a VG pipe
- ovutils::eDest dest = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, dpy);
+ ovutils::eDest dest = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, mDpy);
if(dest == ovutils::OV_INVALID) { //None available
return false;
}
- sDest[dpy] = dest;
-
+ mDest = dest;
ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
- if (isSecureBuffer(hnd)) {
- ovutils::setMdpFlags(mdpFlags,
- ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
+ ovutils::eZorder zOrder = ovutils::ZORDER_1;
+ ovutils::eIsFg isFg = ovutils::IS_FG_OFF;
+ if (ctx->listStats[mDpy].numAppLayers == 1) {
+ isFg = ovutils::IS_FG_SET;
}
- if(layer->blending == HWC_BLENDING_PREMULT) {
- ovutils::setMdpFlags(mdpFlags,
- ovutils::OV_MDP_BLEND_FG_PREMULT);
- }
-
- MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
- if (metadata && (metadata->operation & PP_PARAM_INTERLACED) &&
- metadata->interlaced) {
- ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_DEINTERLACE);
- }
-
- ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF;
- if (ctx->listStats[dpy].numAppLayers == 1) {
- isFgFlag = ovutils::IS_FG_SET;
- }
-
- ovutils::eRotFlags rotFlags = ovutils::ROT_FLAGS_NONE;
- if(ctx->mMDP.version >= qdutils::MDP_V4_2 &&
- ctx->mMDP.version < qdutils::MDSS_V5) {
- rotFlags = ovutils::ROT_DOWNSCALE_ENABLED;
- }
-
- ovutils::PipeArgs parg(mdpFlags,
- info,
- ovutils::ZORDER_1,
- isFgFlag,
- rotFlags);
-
- ov.setSource(parg, dest);
-
- int transform = layer->transform;
- ovutils::eTransform orient =
- static_cast<ovutils::eTransform>(transform);
-
- hwc_rect_t sourceCrop = layer->sourceCrop;
- hwc_rect_t displayFrame = layer->displayFrame;
-
- //Calculate the rect for primary based on whether the supplied position
- //is within or outside bounds.
- const int fbWidth = ctx->dpyAttr[dpy].xres;
- const int fbHeight = ctx->dpyAttr[dpy].yres;
-
- if( displayFrame.left < 0 ||
- displayFrame.top < 0 ||
- displayFrame.right > fbWidth ||
- displayFrame.bottom > fbHeight) {
- hwc_rect_t scissor = {0, 0, fbWidth, fbHeight};
- calculate_crop_rects(sourceCrop, displayFrame, scissor, transform);
- }
-
- // source crop x,y,w,h
- ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
- sourceCrop.right - sourceCrop.left,
- sourceCrop.bottom - sourceCrop.top);
- //Only for Primary
- ov.setCrop(dcrop, dest);
-
- ov.setTransform(orient, dest);
-
- // position x,y,w,h
- 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(dpy)
- getActionSafePosition(ctx, dpy, dpos.x, dpos.y, dpos.w, dpos.h);
-
- ov.setPosition(dpos, dest);
-
- if (!ov.commit(dest)) {
- ALOGE("%s: commit fails", __FUNCTION__);
- return false;
- }
- return true;
+ return (configureLowRes(ctx, layer, mDpy, mdpFlags, zOrder, isFg, dest,
+ &mRot) == 0 );
}
-bool VideoOverlay::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list,
- int dpy)
-{
- if(!sIsModeOn[dpy]) {
+bool VideoOverlayLowRes::draw(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list) {
+ if(!mModeOn) {
return true;
}
- int yuvIndex = ctx->listStats[dpy].yuvIndices[0];
+ int yuvIndex = ctx->listStats[mDpy].yuvIndices[0];
if(yuvIndex == -1) {
return true;
}
@@ -210,16 +149,148 @@
private_handle_t *hnd = (private_handle_t *)
list->hwLayers[yuvIndex].handle;
- bool ret = true;
overlay::Overlay& ov = *(ctx->mOverlay);
+ int fd = hnd->fd;
+ uint32_t offset = hnd->offset;
+ Rotator *rot = mRot;
- if (!ov.queueBuffer(hnd->fd, hnd->offset,
- sDest[dpy])) {
- ALOGE("%s: queueBuffer failed for dpy=%d", __FUNCTION__, dpy);
- ret = false;
+ if(rot) {
+ if(!rot->queueBuffer(fd, offset))
+ return false;
+ fd = rot->getDstMemId();
+ offset = rot->getDstOffset();
}
- return ret;
+ if (!ov.queueBuffer(fd, offset, mDest)) {
+ ALOGE("%s: queueBuffer failed for dpy=%d", __FUNCTION__, mDpy);
+ return false;
+ }
+
+ return true;
}
+//===========VideoOverlayHighRes=========================
+
+VideoOverlayHighRes::VideoOverlayHighRes(const int& dpy): IVideoOverlay(dpy) {}
+
+//Cache stats, figure out the state, config overlay
+bool VideoOverlayHighRes::prepare(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list) {
+
+ int yuvIndex = ctx->listStats[mDpy].yuvIndices[0];
+ int hw_w = ctx->dpyAttr[mDpy].xres;
+ mModeOn = false;
+
+ if(!ctx->mMDP.hasOverlay) {
+ ALOGD_IF(VIDEO_DEBUG,"%s, this hw doesnt support overlay", __FUNCTION__);
+ return false;
+ }
+
+ if(yuvIndex == -1 || ctx->listStats[mDpy].yuvCount != 1) {
+ return false;
+ }
+
+ //index guaranteed to be not -1 at this point
+ hwc_layer_1_t *layer = &list->hwLayers[yuvIndex];
+ if(configure(ctx, layer)) {
+ markFlags(layer);
+ mModeOn = true;
+ }
+
+ return mModeOn;
+}
+
+void VideoOverlayHighRes::markFlags(hwc_layer_1_t *layer) {
+ if(layer) {
+ layer->compositionType = HWC_OVERLAY;
+ layer->hints |= HWC_HINT_CLEAR_FB;
+ }
+}
+
+bool VideoOverlayHighRes::configure(hwc_context_t *ctx,
+ hwc_layer_1_t *layer) {
+
+ int hw_w = ctx->dpyAttr[mDpy].xres;
+ overlay::Overlay& ov = *(ctx->mOverlay);
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ ovutils::Whf info(hnd->width, hnd->height,
+ ovutils::getMdpFormat(hnd->format), hnd->size);
+
+ //Request a VG pipe
+ mDestL = ovutils::OV_INVALID;
+ mDestR = ovutils::OV_INVALID;
+ hwc_rect_t dst = layer->displayFrame;
+ if(dst.left > hw_w/2) {
+ mDestR = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, mDpy);
+ if(mDestR == ovutils::OV_INVALID)
+ return false;
+ } else if (dst.right <= hw_w/2) {
+ mDestL = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, mDpy);
+ if(mDestL == ovutils::OV_INVALID)
+ return false;
+ } else {
+ mDestL = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, mDpy);
+ mDestR = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, mDpy);
+ if(mDestL == ovutils::OV_INVALID ||
+ mDestR == ovutils::OV_INVALID)
+ return false;
+ }
+
+ ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
+ ovutils::eZorder zOrder = ovutils::ZORDER_1;
+ ovutils::eIsFg isFg = ovutils::IS_FG_OFF;
+ if (ctx->listStats[mDpy].numAppLayers == 1) {
+ isFg = ovutils::IS_FG_SET;
+ }
+
+ return (configureHighRes(ctx, layer, mDpy, mdpFlags, zOrder, isFg, mDestL,
+ mDestR, &mRot) == 0 );
+}
+
+bool VideoOverlayHighRes::draw(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list) {
+ if(!mModeOn) {
+ return true;
+ }
+
+ int yuvIndex = ctx->listStats[mDpy].yuvIndices[0];
+ if(yuvIndex == -1) {
+ return true;
+ }
+
+ private_handle_t *hnd = (private_handle_t *)
+ list->hwLayers[yuvIndex].handle;
+
+ overlay::Overlay& ov = *(ctx->mOverlay);
+ int fd = hnd->fd;
+ uint32_t offset = hnd->offset;
+ Rotator *rot = mRot;
+
+ if(rot) {
+ if(!rot->queueBuffer(fd, offset))
+ return false;
+ fd = rot->getDstMemId();
+ offset = rot->getDstOffset();
+ }
+
+ if(mDestL != ovutils::OV_INVALID) {
+ if (!ov.queueBuffer(fd, offset, mDestL)) {
+ ALOGE("%s: queueBuffer failed for dpy=%d's left mixer",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+ }
+
+ if(mDestR != ovutils::OV_INVALID) {
+ if (!ov.queueBuffer(fd, offset, mDestR)) {
+ ALOGE("%s: queueBuffer failed for dpy=%d's right mixer"
+ , __FUNCTION__, mDpy);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
}; //namespace qhwc