Merge "hwcomposer : Fixing copybit render buffer fence closing."
diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp
index 5d8da05..9558f69 100644
--- a/libcopybit/copybit.cpp
+++ b/libcopybit/copybit.cpp
@@ -637,6 +637,7 @@
return -EINVAL;
}
+ int status = 0;
struct blitReq* list = &ctx->list;
mdp_blit_req* req = &list->req[list->count++];
set_infos(ctx, req, MDP_SOLID_FILL);
@@ -654,7 +655,11 @@
req->const_color.b = (uint32_t)((color >> 16) & 0xff);
req->const_color.alpha = (uint32_t)((color >> 24) & 0xff);
- int status = msm_copybit(ctx, list);
+ if (list->count == sizeof(list->req)/sizeof(list->req[0])) {
+ status = msm_copybit(ctx, list);
+ list->sync.acq_fen_fd_cnt = 0;
+ list->count = 0;
+ }
return status;
}
@@ -714,6 +719,10 @@
ctx->mAlpha = MDP_ALPHA_NOP;
ctx->mFlags = 0;
ctx->sync.flags = 0;
+ ctx->relFence = -1;
+ for (int i=0; i < MDP_MAX_FENCE_FD; i++) {
+ ctx->acqFence[i] = -1;
+ }
ctx->sync.acq_fen_fd = ctx->acqFence;
ctx->sync.rel_fen_fd = &ctx->relFence;
ctx->list.count = 0;
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 045edd8..d905e0d 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -42,6 +42,9 @@
#define MAX_SYSFS_FILE_PATH 255
#define UNKNOWN_STRING "unknown"
#define SPD_NAME_LENGTH 16
+/* Max. resolution assignable to when downscale */
+#define SUPPORTED_DOWNSCALE_EXT_AREA (1920*1080)
+
int ExternalDisplay::configure() {
if(!openFrameBuffer()) {
@@ -590,7 +593,7 @@
// downscale mode
// Restrict this upto 1080p resolution max
if(((priW * priH) > (width * height)) &&
- (priW <= qdutils::MAX_DISPLAY_DIM )) {
+ ((priW * priH) <= SUPPORTED_DOWNSCALE_EXT_AREA)) {
mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priW;
mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priH;
// HDMI is always in landscape, so always assign the higher
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index d86be3e..a805486 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -138,15 +138,6 @@
ctx->layerProp[dpy] = new LayerProp[numAppLayers];
}
-static void handleGeomChange(hwc_context_t *ctx, int dpy,
- hwc_display_contents_1_t *list) {
- /* No point to calling overlay_set on MDP3 */
- if(list->flags & HWC_GEOMETRY_CHANGED &&
- ctx->mMDP.version >= qdutils::MDP_V4_0) {
- ctx->mOverlay->forceSet(dpy);
- }
-}
-
static int hwc_prepare_primary(hwc_composer_device_1 *dev,
hwc_display_contents_1_t *list) {
ATRACE_CALL();
@@ -155,22 +146,17 @@
if (LIKELY(list && list->numHwLayers > 1) &&
ctx->dpyAttr[dpy].isActive) {
reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
- handleGeomChange(ctx, dpy, list);
- uint32_t last = list->numHwLayers - 1;
- hwc_layer_1_t *fbLayer = &list->hwLayers[last];
- if(fbLayer->handle) {
- setListStats(ctx, list, dpy);
+ setListStats(ctx, list, dpy);
#ifdef VPU_TARGET
- ctx->mVPUClient->prepare(ctx, list);
+ ctx->mVPUClient->prepare(ctx, list);
#endif
- if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
- const int fbZ = 0;
- ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
- }
- if (ctx->mMDP.version < qdutils::MDP_V4_0) {
- if(ctx->mCopyBit[dpy])
- ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
- }
+ if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+ const int fbZ = 0;
+ ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
+ }
+ if (ctx->mMDP.version < qdutils::MDP_V4_0) {
+ if(ctx->mCopyBit[dpy])
+ ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
}
}
return 0;
@@ -186,25 +172,20 @@
ctx->dpyAttr[dpy].isActive &&
ctx->dpyAttr[dpy].connected) {
reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
- handleGeomChange(ctx, dpy, list);
- uint32_t last = list->numHwLayers - 1;
- hwc_layer_1_t *fbLayer = &list->hwLayers[last];
if(!ctx->dpyAttr[dpy].isPause) {
- if(fbLayer->handle) {
- ctx->dpyAttr[dpy].isConfiguring = false;
- setListStats(ctx, list, dpy);
- if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
- const int fbZ = 0;
- ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
- }
+ ctx->dpyAttr[dpy].isConfiguring = false;
+ setListStats(ctx, list, dpy);
+ if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+ const int fbZ = 0;
+ ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
+ }
- if(ctx->listStats[dpy].isDisplayAnimating) {
- // Mark all app layers as HWC_OVERLAY for external during
- // animation, so that SF doesnt draw it on FB
- for(int i = 0 ;i < ctx->listStats[dpy].numAppLayers; i++) {
- hwc_layer_1_t *layer = &list->hwLayers[i];
- layer->compositionType = HWC_OVERLAY;
- }
+ if(ctx->listStats[dpy].isDisplayAnimating) {
+ // Mark all app layers as HWC_OVERLAY for external during
+ // animation, so that SF doesnt draw it on FB
+ for(int i = 0 ;i < ctx->listStats[dpy].numAppLayers; i++) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ layer->compositionType = HWC_OVERLAY;
}
}
} else {
@@ -229,25 +210,20 @@
ctx->dpyAttr[dpy].isActive &&
ctx->dpyAttr[dpy].connected) {
reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
- handleGeomChange(ctx, dpy, list);
- uint32_t last = list->numHwLayers - 1;
- hwc_layer_1_t *fbLayer = &list->hwLayers[last];
if(!ctx->dpyAttr[dpy].isPause) {
- if(fbLayer->handle) {
- ctx->dpyAttr[dpy].isConfiguring = false;
- setListStats(ctx, list, dpy);
- if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
- const int fbZ = 0;
- ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
- }
+ ctx->dpyAttr[dpy].isConfiguring = false;
+ setListStats(ctx, list, dpy);
+ if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+ const int fbZ = 0;
+ ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
+ }
- if(ctx->listStats[dpy].isDisplayAnimating) {
- // Mark all app layers as HWC_OVERLAY for virtual during
- // animation, so that SF doesnt draw it on FB
- for(int i = 0 ;i < ctx->listStats[dpy].numAppLayers; i++) {
- hwc_layer_1_t *layer = &list->hwLayers[i];
- layer->compositionType = HWC_OVERLAY;
- }
+ if(ctx->listStats[dpy].isDisplayAnimating) {
+ // Mark all app layers as HWC_OVERLAY for virtual during
+ // animation, so that SF doesnt draw it on FB
+ for(int i = 0 ;i < ctx->listStats[dpy].numAppLayers; i++) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ layer->compositionType = HWC_OVERLAY;
}
}
} else {
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 8a6761f..ba8b9d2 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -164,25 +164,45 @@
LayerProp *layerProp = ctx->layerProp[dpy];
size_t fbLayerIndex = ctx->listStats[dpy].fbLayerIndex;
hwc_layer_1_t *fbLayer = &list->hwLayers[fbLayerIndex];
- private_handle_t *fbHnd = (private_handle_t *)fbLayer->handle;
-
// Following are MDP3 limitations for which we
// need to fallback to GPU composition:
// 1. Plane alpha is not supported by MDP3.
+ // 2. Scaling is within range
if (qdutils::MDPVersion::getInstance().getMDPVersion() < 400) {
for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
+ int dst_h, dst_w, src_h, src_w;
+ float dx, dy;
hwc_layer_1_t *layer = (hwc_layer_1_t *) &list->hwLayers[i];
if (layer->planeAlpha != 0xFF)
return true;
+ hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+
+ if (layer->transform & HAL_TRANSFORM_ROT_90) {
+ src_h = sourceCrop.right - sourceCrop.left;
+ src_w = sourceCrop.bottom - sourceCrop.top;
+ } else {
+ src_h = sourceCrop.bottom - sourceCrop.top;
+ src_w = sourceCrop.right - sourceCrop.left;
+ }
+ dst_h = layer->displayFrame.bottom - layer->displayFrame.top;
+ dst_w = layer->displayFrame.right - layer->displayFrame.left;
+
+ dx = (float)dst_w/src_w;
+ dy = (float)dst_h/src_h;
+ if (dx > MAX_SCALE_FACTOR || dx < MIN_SCALE_FACTOR)
+ return false;
+
+ if (dy > MAX_SCALE_FACTOR || dy < MIN_SCALE_FACTOR)
+ return false;
}
}
//Allocate render buffers if they're not allocated
if (useCopybitForYUV || useCopybitForRGB) {
- int ret = allocRenderBuffers(fbHnd->width,
- fbHnd->height,
- fbHnd->format);
+ int ret = allocRenderBuffers(mAlignedFBWidth,
+ mAlignedFBHeight,
+ HAL_PIXEL_FORMAT_RGBA_8888);
if (ret < 0) {
return false;
} else {
@@ -598,6 +618,7 @@
copybit->set_parameter(copybit, COPYBIT_DITHER,
(dst.format == HAL_PIXEL_FORMAT_RGB_565) ?
COPYBIT_ENABLE : COPYBIT_DISABLE);
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
copybit->set_parameter(copybit, COPYBIT_BLEND_MODE, layer->blending);
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, layer->planeAlpha);
copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER,COPYBIT_ENABLE);
@@ -675,8 +696,15 @@
return mEngine;
}
-CopyBit::CopyBit():mIsModeOn(false), mCopyBitDraw(false),
- mCurRenderBufferIndex(0){
+CopyBit::CopyBit(hwc_context_t *ctx, const int& dpy) : mIsModeOn(false),
+ mCopyBitDraw(false), mCurRenderBufferIndex(0) {
+
+ getBufferSizeAndDimensions(ctx->dpyAttr[dpy].xres,
+ ctx->dpyAttr[dpy].yres,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ mAlignedFBWidth,
+ mAlignedFBHeight);
+
hw_module_t const *module;
for (int i = 0; i < NUM_RENDER_BUFFERS; i++) {
mRenderBuffer[i] = NULL;
diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h
index 8278ff3..4d8123c 100644
--- a/libhwcomposer/hwc_copybit.h
+++ b/libhwcomposer/hwc_copybit.h
@@ -22,12 +22,17 @@
#include "hwc_utils.h"
#define NUM_RENDER_BUFFERS 3
+//These scaling factors are specific for MDP3. Normally scaling factor
+//is only 4, but copybit will create temp buffer to let it run through
+//twice
+#define MAX_SCALE_FACTOR 16
+#define MIN_SCALE_FACTOR 0.0625
namespace qhwc {
class CopyBit {
public:
- CopyBit();
+ CopyBit(hwc_context_t *ctx, const int& dpy);
~CopyBit();
// API to get copybit engine(non static)
struct copybit_device_t *getCopyBitDevice();
@@ -84,6 +89,8 @@
//Dynamic composition threshold for deciding copybit usage.
double mDynThreshold;
+ int mAlignedFBWidth;
+ int mAlignedFBHeight;
};
}; //namespace qhwc
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index ce18695..bb9adbf 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -39,20 +39,29 @@
IFBUpdate* IFBUpdate::getObject(hwc_context_t *ctx, const int& dpy) {
if(isDisplaySplit(ctx, dpy)) {
- return new FBUpdateSplit(dpy);
+ return new FBUpdateSplit(ctx, dpy);
}
- return new FBUpdateNonSplit(dpy);
+ return new FBUpdateNonSplit(ctx, dpy);
}
-inline void IFBUpdate::reset() {
+IFBUpdate::IFBUpdate(hwc_context_t *ctx, const int& dpy) : mDpy(dpy) {
+ getBufferSizeAndDimensions(ctx->dpyAttr[dpy].xres,
+ ctx->dpyAttr[dpy].yres,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ mAlignedFBWidth,
+ mAlignedFBHeight);
+}
+
+void IFBUpdate::reset() {
mModeOn = false;
mRot = NULL;
}
//================= Low res====================================
-FBUpdateNonSplit::FBUpdateNonSplit(const int& dpy): IFBUpdate(dpy) {}
+FBUpdateNonSplit::FBUpdateNonSplit(hwc_context_t *ctx, const int& dpy):
+ IFBUpdate(ctx, dpy) {}
-inline void FBUpdateNonSplit::reset() {
+void FBUpdateNonSplit::reset() {
IFBUpdate::reset();
mDest = ovutils::OV_INVALID;
}
@@ -107,9 +116,10 @@
layer->compositionType = HWC_OVERLAY;
}
overlay::Overlay& ov = *(ctx->mOverlay);
- private_handle_t *hnd = (private_handle_t *)layer->handle;
- ovutils::Whf info(getWidth(hnd), getHeight(hnd),
- ovutils::getMdpFormat(hnd->format), hnd->size);
+
+ ovutils::Whf info(mAlignedFBWidth,
+ mAlignedFBHeight,
+ ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888));
//Request a pipe
ovutils::eMdpPipeType type = ovutils::OV_MDP_PIPE_ANY;
@@ -160,7 +170,7 @@
displayFrame = sourceCrop;
}
}
- calcExtDisplayPosition(ctx, hnd, mDpy, sourceCrop, displayFrame,
+ calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
transform, orient);
setMdpFlags(layer, mdpFlags, 0, transform);
// For External use rotator if there is a rotation value set
@@ -168,6 +178,8 @@
sourceCrop, mdpFlags, rotFlags);
if(!ret) {
ALOGE("%s: preRotate for external Failed!", __FUNCTION__);
+ ctx->mOverlay->clear(mDpy);
+ ctx->mLayerRotMap[mDpy]->clear();
return false;
}
//For the mdp, since either we are pre-rotating or MDP does flips
@@ -182,6 +194,7 @@
if(configMdp(ctx->mOverlay, parg, orient, sourceCrop, displayFrame,
NULL, mDest) < 0) {
ALOGE("%s: configMdp failed for dpy %d", __FUNCTION__, mDpy);
+ ctx->mLayerRotMap[mDpy]->clear();
ret = false;
}
}
@@ -212,9 +225,10 @@
}
//================= High res====================================
-FBUpdateSplit::FBUpdateSplit(const int& dpy): IFBUpdate(dpy) {}
+FBUpdateSplit::FBUpdateSplit(hwc_context_t *ctx, const int& dpy):
+ IFBUpdate(ctx, dpy) {}
-inline void FBUpdateSplit::reset() {
+void FBUpdateSplit::reset() {
IFBUpdate::reset();
mDestLeft = ovutils::OV_INVALID;
mDestRight = ovutils::OV_INVALID;
@@ -246,9 +260,10 @@
layer->compositionType = HWC_OVERLAY;
}
overlay::Overlay& ov = *(ctx->mOverlay);
- private_handle_t *hnd = (private_handle_t *)layer->handle;
- ovutils::Whf info(getWidth(hnd), getHeight(hnd),
- ovutils::getMdpFormat(hnd->format), hnd->size);
+
+ ovutils::Whf info(mAlignedFBWidth,
+ mAlignedFBHeight,
+ ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888));
//Request left pipe
ovutils::eDest destL = ov.nextPipe(ovutils::OV_MDP_PIPE_ANY, mDpy,
@@ -353,6 +368,9 @@
ALOGE("%s: commit fails for right", __FUNCTION__);
ret = false;
}
+ if(ret == false) {
+ ctx->mLayerRotMap[mDpy]->clear();
+ }
}
return ret;
}
diff --git a/libhwcomposer/hwc_fbupdate.h b/libhwcomposer/hwc_fbupdate.h
index ce6af63..355e429 100644
--- a/libhwcomposer/hwc_fbupdate.h
+++ b/libhwcomposer/hwc_fbupdate.h
@@ -35,7 +35,7 @@
//Framebuffer update Interface
class IFBUpdate {
public:
- explicit IFBUpdate(const int& dpy) : mDpy(dpy) {}
+ explicit IFBUpdate(hwc_context_t *ctx, const int& dpy);
virtual ~IFBUpdate() {};
// Sets up members and prepares overlay if conditions are met
virtual bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
@@ -51,12 +51,14 @@
const int mDpy; // display to update
bool mModeOn; // if prepare happened
overlay::Rotator *mRot;
+ int mAlignedFBWidth;
+ int mAlignedFBHeight;
};
//Non-Split panel handler.
class FBUpdateNonSplit : public IFBUpdate {
public:
- explicit FBUpdateNonSplit(const int& dpy);
+ explicit FBUpdateNonSplit(hwc_context_t *ctx, const int& dpy);
virtual ~FBUpdateNonSplit() {};
bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
int fbZorder);
@@ -77,7 +79,7 @@
//Split panel handler.
class FBUpdateSplit : public IFBUpdate {
public:
- explicit FBUpdateSplit(const int& dpy);
+ explicit FBUpdateSplit(hwc_context_t *ctx, const int& dpy);
virtual ~FBUpdateSplit() {};
bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
int fbZorder);
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index bdc2dbd..48d9575 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -43,8 +43,9 @@
bool MDPComp::sEnableMixedMode = true;
bool MDPComp::sEnablePartialFrameUpdate = false;
int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
-float MDPComp::sMaxBw = 2.3f;
-uint32_t MDPComp::sCompBytesClaimed = 0;
+double MDPComp::sMaxBw = 0.0;
+double MDPComp::sBwClaimed = 0.0;
+bool MDPComp::sEnable4k2kYUVSplit = false;
MDPComp* MDPComp::getObject(hwc_context_t *ctx, const int& dpy) {
if(isDisplaySplit(ctx, dpy)) {
@@ -128,13 +129,6 @@
sMaxPipesPerMixer = min(val, MAX_PIPES_PER_MIXER);
}
- if(property_get("debug.mdpcomp.bw", property, "0") > 0) {
- float val = atof(property);
- if(val > 0.0f) {
- sMaxBw = val;
- }
- }
-
if(ctx->mMDP.panel != MIPI_CMD_PANEL) {
// Idle invalidation is not necessary on command mode panels
long idle_timeout = DEFAULT_IDLE_TIME;
@@ -154,6 +148,12 @@
idleInvalidator->init(timeout_handler, ctx, idle_timeout);
}
}
+
+ if((property_get("debug.mdpcomp.4k2kSplit", property, "0") > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ sEnable4k2kYUVSplit = true;
+ }
return true;
}
@@ -293,6 +293,10 @@
private_handle_t *hnd = (private_handle_t *)layer->handle;
if(!hnd) {
+ if (layer->flags & HWC_COLOR_FILL) {
+ // Color layer
+ return true;
+ }
ALOGE("%s: layer handle is NULL", __FUNCTION__);
return false;
}
@@ -322,23 +326,25 @@
if((crop_w < 5)||(crop_h < 5))
return false;
- const uint32_t downscale =
+ if((w_dscale > 1.0f) || (h_dscale > 1.0f)) {
+ const uint32_t downscale =
qdutils::MDPVersion::getInstance().getMaxMDPDownscale();
- if(ctx->mMDP.version >= qdutils::MDSS_V5) {
- /* Workaround for downscales larger than 4x.
- * Will be removed once decimator block is enabled for MDSS
- */
- if(!qdutils::MDPVersion::getInstance().supportsDecimation()) {
- if(crop_w > MAX_DISPLAY_DIM || w_dscale > downscale ||
- h_dscale > downscale)
- return false;
- } else {
- if(w_dscale > 64 || h_dscale > 64)
+ if(ctx->mMDP.version >= qdutils::MDSS_V5) {
+ /* Workaround for downscales larger than 4x.
+ * Will be removed once decimator block is enabled for MDSS
+ */
+ if(!qdutils::MDPVersion::getInstance().supportsDecimation()) {
+ if(crop_w > MAX_DISPLAY_DIM || w_dscale > downscale ||
+ h_dscale > downscale)
+ return false;
+ } else {
+ if(w_dscale > 64 || h_dscale > 64)
+ return false;
+ }
+ } else { //A-family
+ if(w_dscale > downscale || h_dscale > downscale)
return false;
}
- } else { //A-family
- if(w_dscale > downscale || h_dscale > downscale)
- return false;
}
return true;
@@ -580,6 +586,15 @@
ALOGD_IF(isDebug(), "%s: Unsupported layer in list",__FUNCTION__);
return false;
}
+
+ //For 8x26, if there is only one layer which needs scale for secondary
+ //while no scale for primary display, DMA pipe is occupied by primary.
+ //If need to fall back to GLES composition, virtual display lacks DMA
+ //pipe and error is reported.
+ if(qdutils::MDPVersion::getInstance().is8x26() &&
+ mDpy >= HWC_DISPLAY_EXTERNAL &&
+ qhwc::needsScaling(ctx, layer, mDpy))
+ return false;
}
mCurrentFrame.fbCount = 0;
mCurrentFrame.fbZ = -1;
@@ -588,6 +603,10 @@
mCurrentFrame.mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount -
mCurrentFrame.dropCount;
+ if(sEnable4k2kYUVSplit){
+ modifymdpCountfor4k2k(ctx, list);
+ }
+
if(!resourceCheck(ctx, list)) {
ALOGD_IF(isDebug(), "%s: resource check failed", __FUNCTION__);
return false;
@@ -605,7 +624,8 @@
bool ret = false;
if(isLoadBasedCompDoable(ctx, list)) {
- ret = loadBasedComp(ctx, list);
+ ret = loadBasedCompPreferGPU(ctx, list) ||
+ loadBasedCompPreferMDP(ctx, list);
}
if(!ret) {
@@ -642,6 +662,10 @@
int mdpCount = mCurrentFrame.mdpCount;
+ if(sEnable4k2kYUVSplit){
+ modifymdpCountfor4k2k(ctx, list);
+ }
+
//Will benefit cases where a video has non-updating background.
if((mDpy > HWC_DISPLAY_PRIMARY) and
(mdpCount > MAX_SEC_LAYERS)) {
@@ -657,14 +681,16 @@
return true;
}
-bool MDPComp::loadBasedComp(hwc_context_t *ctx,
+bool MDPComp::loadBasedCompPreferGPU(hwc_context_t *ctx,
hwc_display_contents_1_t* list) {
int numAppLayers = ctx->listStats[mDpy].numAppLayers;
mCurrentFrame.reset(numAppLayers);
- //TODO BatchSize could be optimized further based on available pipes, split
- //displays etc.
- const int batchSize = numAppLayers - (sMaxPipesPerMixer - 1);
+ int stagesForMDP = min(sMaxPipesPerMixer, ctx->mOverlay->availablePipes(
+ mDpy, Overlay::MIXER_DEFAULT));
+ //If MDP has X possible stages, it can take X layers.
+ const int batchSize = numAppLayers - (stagesForMDP - 1); //1 for FB
+
if(batchSize <= 0) {
ALOGD_IF(isDebug(), "%s: Not attempting", __FUNCTION__);
return false;
@@ -710,6 +736,10 @@
mCurrentFrame.fbCount = batchSize;
mCurrentFrame.mdpCount = mCurrentFrame.layerCount - batchSize;
+ if(sEnable4k2kYUVSplit){
+ modifymdpCountfor4k2k(ctx, list);
+ }
+
if(!resourceCheck(ctx, list)) {
ALOGD_IF(isDebug(), "%s: resource check failed", __FUNCTION__);
return false;
@@ -720,6 +750,63 @@
return true;
}
+bool MDPComp::loadBasedCompPreferMDP(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ //TODO get the ib from sysfs node.
+ //Full screen is from ib perspective, not actual full screen
+ const int bpp = 4;
+ double panelRefRate =
+ 1000000000.0 / ctx->dpyAttr[mDpy].vsync_period;
+
+ double bwLeft = sMaxBw - sBwClaimed;
+
+ const int fullScreenLayers = bwLeft * 1000000000 / (ctx->dpyAttr[mDpy].xres
+ * ctx->dpyAttr[mDpy].yres * bpp * panelRefRate);
+
+ const int fbBatchSize = numAppLayers - (fullScreenLayers - 1);
+ //If batch size is not at least 2, we aren't really preferring MDP, since
+ //only 1 layer going to GPU could actually translate into an entire FB
+ //needed to be fetched by MDP, thus needing more b/w rather than less.
+ if(fbBatchSize < 2 || fbBatchSize > numAppLayers) {
+ ALOGD_IF(isDebug(), "%s: Not attempting", __FUNCTION__);
+ return false;
+ }
+
+ //Top-most layers constitute FB batch
+ const int fbBatchStart = numAppLayers - fbBatchSize;
+
+ //Bottom-most layers constitute MDP batch
+ for(int i = 0; i < fbBatchStart; i++) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ if(not isSupportedForMDPComp(ctx, layer)) {
+ ALOGD_IF(isDebug(), "%s: MDP unsupported layer found at %d",
+ __FUNCTION__, i);
+ return false;
+ }
+ mCurrentFrame.isFBComposed[i] = false;
+ }
+
+ mCurrentFrame.fbZ = fbBatchStart;
+ mCurrentFrame.fbCount = fbBatchSize;
+ mCurrentFrame.mdpCount = mCurrentFrame.layerCount - fbBatchSize;
+
+ if(sEnable4k2kYUVSplit){
+ modifymdpCountfor4k2k(ctx, list);
+ }
+
+ if(!resourceCheck(ctx, list)) {
+ ALOGD_IF(isDebug(), "%s: resource check failed", __FUNCTION__);
+ return false;
+ }
+
+ ALOGD_IF(isDebug(), "%s: FB Z %d, num app layers %d, MDP Batch Size %d",
+ __FUNCTION__, mCurrentFrame.fbZ, numAppLayers,
+ numAppLayers - fbBatchSize);
+
+ return true;
+}
+
bool MDPComp::isLoadBasedCompDoable(hwc_context_t *ctx,
hwc_display_contents_1_t* list) {
if(mDpy or isSecurePresent(ctx, mDpy) or
@@ -736,7 +823,6 @@
mCurrentFrame.reset(numAppLayers);
updateYUV(ctx, list, secureOnly);
int mdpCount = mCurrentFrame.mdpCount;
- int fbNeeded = (mCurrentFrame.fbCount != 0);
if(!isYuvPresent(ctx, mDpy)) {
return false;
@@ -1037,41 +1123,28 @@
MdpPipeInfo* cur_pipe = mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
cur_pipe->zOrder = mdpNextZOrder++;
-
- if(configure(ctx, layer, mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
- ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
- layer %d",__FUNCTION__, index);
- return false;
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
+ if(configure4k2kYuv(ctx, layer,
+ mCurrentFrame.mdpToLayer[mdpIndex])
+ != 0 ){
+ ALOGD_IF(isDebug(), "%s: Failed to configure split pipes \
+ for layer %d",__FUNCTION__, index);
+ return false;
+ }
+ else{
+ mdpNextZOrder++;
+ }
+ continue;
}
- }
- }
-
- return true;
-}
-
-bool MDPComp::programYUV(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
- if(!allocLayerPipes(ctx, list)) {
- ALOGD_IF(isDebug(), "%s: Unable to allocate MDP pipes", __FUNCTION__);
- return false;
- }
- //If we are in this block, it means we have yuv + rgb layers both
- int mdpIdx = 0;
- for (int index = 0; index < mCurrentFrame.layerCount; index++) {
- if(!mCurrentFrame.isFBComposed[index]) {
- hwc_layer_1_t* layer = &list->hwLayers[index];
- int mdpIndex = mCurrentFrame.layerToMDP[index];
- MdpPipeInfo* cur_pipe =
- mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
- cur_pipe->zOrder = mdpIdx++;
-
- if(configure(ctx, layer,
- mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
+ if(configure(ctx, layer, mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
layer %d",__FUNCTION__, index);
return false;
}
}
}
+
return true;
}
@@ -1087,7 +1160,7 @@
return false;
}
- uint32_t size = calcMDPBytesRead(ctx, list);
+ double size = calcMDPBytesRead(ctx, list);
if(!bandwidthCheck(ctx, size)) {
ALOGD_IF(isDebug(), "%s: Exceeds bandwidth",__FUNCTION__);
return false;
@@ -1096,12 +1169,15 @@
return true;
}
-uint32_t MDPComp::calcMDPBytesRead(hwc_context_t *ctx,
+double MDPComp::calcMDPBytesRead(hwc_context_t *ctx,
hwc_display_contents_1_t* list) {
- uint32_t size = 0;
+ double size = 0;
+ const double GIG = 1000000000.0;
- if(!qdutils::MDPVersion::getInstance().is8x74v2())
- return 0;
+ //Skip for targets where no device tree value for bw is supplied
+ if(sMaxBw <= 0.0) {
+ return 0.0;
+ }
for (uint32_t i = 0; i < list->numHwLayers - 1; i++) {
if(!mCurrentFrame.isFBComposed[i]) {
@@ -1111,33 +1187,37 @@
hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
hwc_rect_t dst = layer->displayFrame;
float bpp = ((float)hnd->size) / (hnd->width * hnd->height);
- size += bpp * (crop.right - crop.left) *
- (crop.bottom - crop.top) *
- ctx->dpyAttr[mDpy].yres / (dst.bottom - dst.top);
+ size += (bpp * (crop.right - crop.left) *
+ (crop.bottom - crop.top) *
+ ctx->dpyAttr[mDpy].yres / (dst.bottom - dst.top)) /
+ GIG;
}
}
}
if(mCurrentFrame.fbCount) {
hwc_layer_1_t* layer = &list->hwLayers[list->numHwLayers - 1];
- private_handle_t *hnd = (private_handle_t *)layer->handle;
- if (hnd)
- size += hnd->size;
+ int tempw, temph;
+ size += (getBufferSizeAndDimensions(
+ layer->displayFrame.right - layer->displayFrame.left,
+ layer->displayFrame.bottom - layer->displayFrame.top,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ tempw, temph)) / GIG;
}
return size;
}
-bool MDPComp::bandwidthCheck(hwc_context_t *ctx, const uint32_t& size) {
- //Will be added for other targets if we run into bandwidth issues and when
- //we have profiling data to set an upper limit.
- if(qdutils::MDPVersion::getInstance().is8x74v2()) {
- const uint32_t ONE_GIG = 1024 * 1024 * 1024;
- double panelRefRate =
- 1000000000.0 / ctx->dpyAttr[mDpy].vsync_period;
- if((size + sCompBytesClaimed) > ((sMaxBw / panelRefRate) * ONE_GIG)) {
- return false;
- }
+bool MDPComp::bandwidthCheck(hwc_context_t *ctx, const double& size) {
+ //Skip for targets where no device tree value for bw is supplied
+ if(sMaxBw <= 0.0) {
+ return true;
+ }
+
+ double panelRefRate =
+ 1000000000.0 / ctx->dpyAttr[mDpy].vsync_period;
+ if((size * panelRefRate) > (sMaxBw - sBwClaimed)) {
+ return false;
}
return true;
}
@@ -1145,6 +1225,7 @@
int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
int ret = 0;
const int numLayers = ctx->listStats[mDpy].numAppLayers;
+ MDPVersion& mdpVersion = qdutils::MDPVersion::getInstance();
//reset old data
mCurrentFrame.reset(numLayers);
@@ -1172,11 +1253,31 @@
generateROI(ctx, list);
+ //Convert from kbps to gbps
+ sMaxBw = mdpVersion.getHighBw() / 1000000.0;
+ if (ctx->mExtDisplay->isConnected() || ctx->mMDP.panel != MIPI_CMD_PANEL) {
+ sMaxBw = mdpVersion.getLowBw() / 1000000.0;
+ }
+
//Check whether layers marked for MDP Composition is actually doable.
if(isFullFrameDoable(ctx, list)) {
mCurrentFrame.map();
//Configure framebuffer first if applicable
if(mCurrentFrame.fbZ >= 0) {
+ //If 4k2k Yuv layer split is possible, and if
+ //fbz is above 4k2k layer, increment fb zorder by 1
+ //as we split 4k2k layer and increment zorder for right half
+ //of the layer
+ if(sEnable4k2kYUVSplit){
+ int n4k2kYuvCount = ctx->listStats[mDpy].yuv4k2kCount;
+ for(int index = 0; index < n4k2kYuvCount; index++){
+ int n4k2kYuvIndex =
+ ctx->listStats[mDpy].yuv4k2kIndices[index];
+ if(mCurrentFrame.fbZ > n4k2kYuvIndex){
+ mCurrentFrame.fbZ += 1;
+ }
+ }
+ }
if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list,
mCurrentFrame.fbZ)) {
ALOGE("%s configure framebuffer failed", __func__);
@@ -1207,6 +1308,11 @@
//Try to compose atleast YUV layers through MDP comp and let
//all the RGB layers compose in FB
//Destination over
+
+ if(sEnable4k2kYUVSplit){
+ modifymdpCountfor4k2k(ctx, list);
+ }
+
mCurrentFrame.fbZ = -1;
if(mCurrentFrame.fbCount)
mCurrentFrame.fbZ = mCurrentFrame.mdpCount;
@@ -1223,7 +1329,7 @@
goto exit;
}
}
- if(!programYUV(ctx, list)) {
+ if(!programMDP(ctx, list)) {
reset(numLayers, list);
ctx->mOverlay->clear(mDpy);
ret = -1;
@@ -1250,12 +1356,51 @@
}
exit:
- sCompBytesClaimed += calcMDPBytesRead(ctx, list);
+ double panelRefRate =
+ 1000000000.0 / ctx->dpyAttr[mDpy].vsync_period;
+ sBwClaimed += calcMDPBytesRead(ctx, list) * panelRefRate;
return ret;
}
+bool MDPComp::allocSplitVGPipesfor4k2k(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list, int index) {
+
+ bool bRet = true;
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ int mdpIndex = mCurrentFrame.layerToMDP[index];
+ PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
+ info.pipeInfo = new MdpYUVPipeInfo;
+ info.rot = NULL;
+ MdpYUVPipeInfo& pipe_info = *(MdpYUVPipeInfo*)info.pipeInfo;
+ ePipeType type = MDPCOMP_OV_VG;
+
+ pipe_info.lIndex = ovutils::OV_INVALID;
+ pipe_info.rIndex = ovutils::OV_INVALID;
+
+ pipe_info.lIndex = getMdpPipe(ctx, type, Overlay::MIXER_DEFAULT);
+ if(pipe_info.lIndex == ovutils::OV_INVALID){
+ bRet = false;
+ ALOGD_IF(isDebug(),"%s: allocating first VG pipe failed",
+ __FUNCTION__);
+ }
+ pipe_info.rIndex = getMdpPipe(ctx, type, Overlay::MIXER_DEFAULT);
+ if(pipe_info.rIndex == ovutils::OV_INVALID){
+ bRet = false;
+ ALOGD_IF(isDebug(),"%s: allocating second VG pipe failed",
+ __FUNCTION__);
+ }
+ return bRet;
+}
//=============MDPCompNonSplit===================================================
+void MDPCompNonSplit::modifymdpCountfor4k2k(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list){
+ //As we split 4kx2k yuv layer and program to 2 VG pipes
+ //(if available) increase mdpcount accordingly
+ mCurrentFrame.mdpCount += ctx->listStats[mDpy].yuv4k2kCount;
+}
+
/*
* Configures pipe(s) for MDP composition
*/
@@ -1307,7 +1452,10 @@
hwc_layer_1_t* layer = &list->hwLayers[i];
hwc_rect_t dst = layer->displayFrame;
private_handle_t *hnd = (private_handle_t *)layer->handle;
- if(isYuvBuffer(hnd)) {
+ if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
+ pipesNeeded = pipesNeeded + 2;
+ }
+ else if(isYuvBuffer(hnd)) {
pipesNeeded++;
}
}
@@ -1332,6 +1480,12 @@
hwc_layer_1_t* layer = &list->hwLayers[index];
private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
+ if(allocSplitVGPipesfor4k2k(ctx, list, index)){
+ continue;
+ }
+ }
+
int mdpIndex = mCurrentFrame.layerToMDP[index];
PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
info.pipeInfo = new MdpPipeInfoNonSplit;
@@ -1357,6 +1511,20 @@
return true;
}
+int MDPCompNonSplit::configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair) {
+ MdpYUVPipeInfo& mdp_info =
+ *(static_cast<MdpYUVPipeInfo*>(PipeLayerPair.pipeInfo));
+ eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
+ eIsFg isFg = IS_FG_OFF;
+ eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
+ eDest lDest = mdp_info.lIndex;
+ eDest rDest = mdp_info.rIndex;
+
+ return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, isFg,
+ lDest, rDest, &PipeLayerPair.rot);
+}
+
bool MDPCompNonSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
if(!isEnabled()) {
@@ -1389,42 +1557,86 @@
hwc_layer_1_t *layer = &list->hwLayers[i];
private_handle_t *hnd = (private_handle_t *)layer->handle;
if(!hnd) {
- ALOGE("%s handle null", __FUNCTION__);
- return false;
+ if (!(layer->flags & HWC_COLOR_FILL)) {
+ ALOGE("%s handle null", __FUNCTION__);
+ return false;
+ }
+ // No PLAY for Color layer
+ layerProp[i].mFlags &= ~HWC_MDPCOMP;
+ continue;
}
int mdpIndex = mCurrentFrame.layerToMDP[i];
- MdpPipeInfoNonSplit& pipe_info =
+ if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit)
+ {
+ MdpYUVPipeInfo& pipe_info =
+ *(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+ Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
+ ovutils::eDest indexL = pipe_info.lIndex;
+ ovutils::eDest indexR = pipe_info.rIndex;
+ int fd = hnd->fd;
+ uint32_t offset = hnd->offset;
+ if(rot) {
+ rot->queueBuffer(fd, offset);
+ fd = rot->getDstMemId();
+ offset = rot->getDstOffset();
+ }
+ if(indexL != ovutils::OV_INVALID) {
+ ovutils::eDest destL = (ovutils::eDest)indexL;
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer, hnd, indexL );
+ if (!ov.queueBuffer(fd, offset, destL)) {
+ ALOGE("%s: queueBuffer failed for display:%d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+ }
+
+ if(indexR != ovutils::OV_INVALID) {
+ ovutils::eDest destR = (ovutils::eDest)indexR;
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer, hnd, indexR );
+ if (!ov.queueBuffer(fd, offset, destR)) {
+ ALOGE("%s: queueBuffer failed for display:%d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+ }
+ }
+ else{
+ MdpPipeInfoNonSplit& pipe_info =
*(MdpPipeInfoNonSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
- ovutils::eDest dest = pipe_info.index;
- if(dest == ovutils::OV_INVALID) {
- ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, dest);
- return false;
- }
-
- if(!(layerProp[i].mFlags & HWC_MDPCOMP)) {
- continue;
- }
-
- ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
- using pipe: %d", __FUNCTION__, layer,
- hnd, dest );
-
- int fd = hnd->fd;
- uint32_t offset = hnd->offset;
-
- Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
- if(rot) {
- if(!rot->queueBuffer(fd, offset))
+ ovutils::eDest dest = pipe_info.index;
+ if(dest == ovutils::OV_INVALID) {
+ ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, dest);
return false;
- fd = rot->getDstMemId();
- offset = rot->getDstOffset();
- }
+ }
- if (!ov.queueBuffer(fd, offset, dest)) {
- ALOGE("%s: queueBuffer failed for display:%d ", __FUNCTION__, mDpy);
- return false;
+ if(!(layerProp[i].mFlags & HWC_MDPCOMP)) {
+ continue;
+ }
+
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer,
+ hnd, dest );
+
+ int fd = hnd->fd;
+ uint32_t offset = hnd->offset;
+
+ Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
+ if(rot) {
+ if(!rot->queueBuffer(fd, offset))
+ return false;
+ fd = rot->getDstMemId();
+ offset = rot->getDstOffset();
+ }
+
+ if (!ov.queueBuffer(fd, offset, dest)) {
+ ALOGE("%s: queueBuffer failed for display:%d ",
+ __FUNCTION__, mDpy);
+ return false;
+ }
}
layerProp[i].mFlags &= ~HWC_MDPCOMP;
@@ -1434,6 +1646,23 @@
//=============MDPCompSplit===================================================
+void MDPCompSplit::modifymdpCountfor4k2k(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list){
+ //if 4kx2k yuv layer is totally present in either in left half
+ //or right half then try splitting the yuv layer to avoid decimation
+ int n4k2kYuvCount = ctx->listStats[mDpy].yuv4k2kCount;
+ const int lSplit = getLeftSplit(ctx, mDpy);
+ for(int index = 0; index < n4k2kYuvCount; index++){
+ int n4k2kYuvIndex = ctx->listStats[mDpy].yuv4k2kIndices[index];
+ hwc_layer_1_t* layer = &list->hwLayers[n4k2kYuvIndex];
+ hwc_rect_t dst = layer->displayFrame;
+
+ if((dst.left > lSplit)||(dst.right < lSplit)){
+ mCurrentFrame.mdpCount += 1;
+ }
+ }
+}
+
int MDPCompSplit::pipesNeeded(hwc_context_t *ctx,
hwc_display_contents_1_t* list,
int mixer) {
@@ -1506,6 +1735,12 @@
hwc_layer_1_t* layer = &list->hwLayers[i];
hwc_rect_t dst = layer->displayFrame;
private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
+ if((dst.left > lSplit)||(dst.right < lSplit)){
+ pipesNeeded = pipesNeeded + 2;
+ continue;
+ }
+ }
if(isYuvBuffer(hnd)) {
if(dst.left < lSplit) {
pipesNeeded++;
@@ -1561,6 +1796,15 @@
hwc_layer_1_t* layer = &list->hwLayers[index];
private_handle_t *hnd = (private_handle_t *)layer->handle;
+ hwc_rect_t dst = layer->displayFrame;
+ const int lSplit = getLeftSplit(ctx, mDpy);
+ if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit){
+ if((dst.left > lSplit)||(dst.right < lSplit)){
+ if(allocSplitVGPipesfor4k2k(ctx, list, index)){
+ continue;
+ }
+ }
+ }
int mdpIndex = mCurrentFrame.layerToMDP[index];
PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
info.pipeInfo = new MdpPipeInfoSplit;
@@ -1585,6 +1829,27 @@
return true;
}
+int MDPCompSplit::configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair) {
+ const int lSplit = getLeftSplit(ctx, mDpy);
+ hwc_rect_t dst = layer->displayFrame;
+ if((dst.left > lSplit)||(dst.right < lSplit)){
+ MdpYUVPipeInfo& mdp_info =
+ *(static_cast<MdpYUVPipeInfo*>(PipeLayerPair.pipeInfo));
+ eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
+ eIsFg isFg = IS_FG_OFF;
+ eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
+ eDest lDest = mdp_info.lIndex;
+ eDest rDest = mdp_info.rIndex;
+
+ return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, isFg,
+ lDest, rDest, &PipeLayerPair.rot);
+ }
+ else{
+ return configure(ctx, layer, PipeLayerPair);
+ }
+}
+
/*
* Configures pipe(s) for MDP composition
*/
@@ -1647,48 +1912,88 @@
int mdpIndex = mCurrentFrame.layerToMDP[i];
- MdpPipeInfoSplit& pipe_info =
- *(MdpPipeInfoSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
- Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
+ if(is4kx2kYuvBuffer(hnd) && sEnable4k2kYUVSplit)
+ {
+ MdpYUVPipeInfo& pipe_info =
+ *(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+ Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
+ ovutils::eDest indexL = pipe_info.lIndex;
+ ovutils::eDest indexR = pipe_info.rIndex;
+ int fd = hnd->fd;
+ uint32_t offset = hnd->offset;
+ if(rot) {
+ rot->queueBuffer(fd, offset);
+ fd = rot->getDstMemId();
+ offset = rot->getDstOffset();
+ }
+ if(indexL != ovutils::OV_INVALID) {
+ ovutils::eDest destL = (ovutils::eDest)indexL;
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer, hnd, indexL );
+ if (!ov.queueBuffer(fd, offset, destL)) {
+ ALOGE("%s: queueBuffer failed for display:%d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+ }
- ovutils::eDest indexL = pipe_info.lIndex;
- ovutils::eDest indexR = pipe_info.rIndex;
-
- int fd = hnd->fd;
- int offset = hnd->offset;
-
- if(ctx->mAD->isModeOn()) {
- if(ctx->mAD->draw(ctx, fd, offset)) {
- fd = ctx->mAD->getDstFd(ctx);
- offset = ctx->mAD->getDstOffset(ctx);
+ if(indexR != ovutils::OV_INVALID) {
+ ovutils::eDest destR = (ovutils::eDest)indexR;
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer, hnd, indexR );
+ if (!ov.queueBuffer(fd, offset, destR)) {
+ ALOGE("%s: queueBuffer failed for display:%d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
}
}
+ else{
+ MdpPipeInfoSplit& pipe_info =
+ *(MdpPipeInfoSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+ Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
- if(rot) {
- rot->queueBuffer(fd, offset);
- fd = rot->getDstMemId();
- offset = rot->getDstOffset();
- }
+ ovutils::eDest indexL = pipe_info.lIndex;
+ ovutils::eDest indexR = pipe_info.rIndex;
- //************* play left mixer **********
- if(indexL != ovutils::OV_INVALID) {
- ovutils::eDest destL = (ovutils::eDest)indexL;
- ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
- using pipe: %d", __FUNCTION__, layer, hnd, indexL );
- if (!ov.queueBuffer(fd, offset, destL)) {
- ALOGE("%s: queueBuffer failed for left mixer", __FUNCTION__);
- return false;
+ int fd = hnd->fd;
+ int offset = hnd->offset;
+
+ if(ctx->mAD->isModeOn()) {
+ if(ctx->mAD->draw(ctx, fd, offset)) {
+ fd = ctx->mAD->getDstFd(ctx);
+ offset = ctx->mAD->getDstOffset(ctx);
+ }
}
- }
- //************* play right mixer **********
- if(indexR != ovutils::OV_INVALID) {
- ovutils::eDest destR = (ovutils::eDest)indexR;
- ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
- using pipe: %d", __FUNCTION__, layer, hnd, indexR );
- if (!ov.queueBuffer(fd, offset, destR)) {
- ALOGE("%s: queueBuffer failed for right mixer", __FUNCTION__);
- return false;
+ if(rot) {
+ rot->queueBuffer(fd, offset);
+ fd = rot->getDstMemId();
+ offset = rot->getDstOffset();
+ }
+
+ //************* play left mixer **********
+ if(indexL != ovutils::OV_INVALID) {
+ ovutils::eDest destL = (ovutils::eDest)indexL;
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer, hnd, indexL );
+ if (!ov.queueBuffer(fd, offset, destL)) {
+ ALOGE("%s: queueBuffer failed for left mixer",
+ __FUNCTION__);
+ return false;
+ }
+ }
+
+ //************* play right mixer **********
+ if(indexR != ovutils::OV_INVALID) {
+ ovutils::eDest destR = (ovutils::eDest)indexR;
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer, hnd, indexR );
+ if (!ov.queueBuffer(fd, offset, destR)) {
+ ALOGE("%s: queueBuffer failed for right mixer",
+ __FUNCTION__);
+ return false;
+ }
}
}
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 7063d32..986b0e6 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -52,7 +52,7 @@
/* Initialize MDP comp*/
static bool init(hwc_context_t *ctx);
static void resetIdleFallBack() { sIdleFallBack = false; }
- static void reset() { sCompBytesClaimed = 0; };
+ static void reset() { sBwClaimed = 0.0; };
protected:
enum { MAX_SEC_LAYERS = 1 }; //TODO add property support
@@ -70,6 +70,12 @@
virtual ~MdpPipeInfo(){};
};
+ struct MdpYUVPipeInfo : public MdpPipeInfo{
+ ovutils::eDest lIndex;
+ ovutils::eDest rIndex;
+ virtual ~MdpYUVPipeInfo(){};
+ };
+
/* per layer data */
struct PipeLayerPair {
MdpPipeInfo *pipeInfo;
@@ -133,7 +139,12 @@
/* Checks for pipes needed versus pipes available */
virtual bool arePipesAvailable(hwc_context_t *ctx,
hwc_display_contents_1_t* list) = 0;
-
+ /* increments mdpCount if 4k2k yuv layer split is enabled*/
+ virtual void modifymdpCountfor4k2k(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) = 0;
+ /* configures 4kx2k yuv layer*/
+ virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair) = 0;
/* set/reset flags for MDPComp */
void setMDPCompLayerFlags(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
@@ -147,8 +158,16 @@
bool partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
/* Partial MDP comp that uses caching to save power as primary goal */
bool cacheBasedComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
- /* Partial MDP comp that uses number of pixels to optimize perf goal */
- bool loadBasedComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ /* Partial MDP comp that prefers GPU perf-wise. Since the GPU's
+ * perf is proportional to the pixels it processes, we use the number of
+ * pixels as a heuristic */
+ bool loadBasedCompPreferGPU(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+ /* Partial MDP comp that prefers MDP perf-wise. Since the MDP's perf is
+ * proportional to the bandwidth, overlaps it sees, we use that as a
+ * heuristic */
+ bool loadBasedCompPreferMDP(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
/* Checks if its worth doing load based partial comp */
bool isLoadBasedCompDoable(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
@@ -157,11 +176,11 @@
bool secureOnly);
/* checks for conditions where YUV layers cannot be bypassed */
bool isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer);
- /* calcs bytes read by MDP for a given frame */
- uint32_t calcMDPBytesRead(hwc_context_t *ctx,
+ /* calcs bytes read by MDP in gigs for a given frame */
+ double calcMDPBytesRead(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
/* checks if the required bandwidth exceeds a certain max */
- bool bandwidthCheck(hwc_context_t *ctx, const uint32_t& size);
+ bool bandwidthCheck(hwc_context_t *ctx, const double& size);
/* generates ROI based on the modified area of the frame */
void generateROI(hwc_context_t *ctx, hwc_display_contents_1_t* list);
bool validateAndApplyROI(hwc_context_t *ctx, hwc_display_contents_1_t* list,
@@ -190,7 +209,6 @@
void updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list,
bool secureOnly);
bool programMDP(hwc_context_t *ctx, hwc_display_contents_1_t* list);
- bool programYUV(hwc_context_t *ctx, hwc_display_contents_1_t* list);
void reset(const int& numAppLayers, hwc_display_contents_1_t* list);
bool isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer);
bool resourceCheck(hwc_context_t *ctx, hwc_display_contents_1_t *list);
@@ -204,13 +222,17 @@
static bool sIdleFallBack;
static int sMaxPipesPerMixer;
//Max bandwidth. Value is in GBPS. For ex: 2.3 means 2.3GBPS
- static float sMaxBw;
- //Tracks composition bytes claimed. Represented as the total w*h*bpp
- //going to MDP mixers
- static uint32_t sCompBytesClaimed;
+ static double sMaxBw;
+ //Tracks composition bandwidth claimed. Represented as the total
+ //w*h*bpp*fps (gigabytes-per-second) going to MDP mixers.
+ static double sBwClaimed;
static IdleInvalidator *idleInvalidator;
struct FrameInfo mCurrentFrame;
struct LayerCache mCachedFrame;
+ //Enable 4kx2k yuv layer split
+ static bool sEnable4k2kYUVSplit;
+ bool allocSplitVGPipesfor4k2k(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list, int index);
};
class MDPCompNonSplit : public MDPComp {
@@ -240,6 +262,14 @@
/* Checks for video pipes needed versus pipes available */
virtual bool areVGPipesAvailable(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
+
+ /* increments mdpCount if 4k2k yuv layer split is enabled*/
+ virtual void modifymdpCountfor4k2k(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+
+ /* configures 4kx2k yuv layer to 2 VG pipes*/
+ virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair);
};
class MDPCompSplit : public MDPComp {
@@ -273,6 +303,14 @@
virtual bool areVGPipesAvailable(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
+ /* increments mdpCount if 4k2k yuv layer split is enabled*/
+ virtual void modifymdpCountfor4k2k(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+
+ /* configures 4kx2k yuv layer*/
+ virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair);
+
int pipesNeeded(hwc_context_t *ctx, hwc_display_contents_1_t* list,
int mixer);
};
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index a17565b..3b98788 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -51,57 +51,28 @@
ALOGD_IF(QCLIENT_DEBUG,"QClient Destructor invoked");
}
-status_t QClient::notifyCallback(uint32_t msg, uint32_t value) {
-
- if (msg > IQService::VPU_COMMAND_LIST_START &&
- msg < IQService::VPU_COMMAND_LIST_END) {
- return vpuCommand(msg, value);
- }
-
- switch(msg) {
- case IQService::SECURING:
- securing(value);
- break;
- case IQService::UNSECURING:
- unsecuring(value);
- break;
- case IQService::SCREEN_REFRESH:
- return screenRefresh();
- break;
- case IQService::EXTERNAL_ORIENTATION:
- setExtOrientation(value);
- break;
- case IQService::BUFFER_MIRRORMODE:
- setBufferMirrorMode(value);
- break;
- default:
- return NO_ERROR;
- }
- return NO_ERROR;
-}
-
-void QClient::securing(uint32_t startEnd) {
- Locker::Autolock _sl(mHwcContext->mDrawLock);
+static void securing(hwc_context_t *ctx, uint32_t startEnd) {
+ Locker::Autolock _sl(ctx->mDrawLock);
//The only way to make this class in this process subscribe to media
//player's death.
IMediaDeathNotifier::getMediaPlayerService();
- mHwcContext->mSecuring = startEnd;
+ ctx->mSecuring = startEnd;
//We're done securing
if(startEnd == IQService::END)
- mHwcContext->mSecureMode = true;
- if(mHwcContext->proc)
- mHwcContext->proc->invalidate(mHwcContext->proc);
+ ctx->mSecureMode = true;
+ if(ctx->proc)
+ ctx->proc->invalidate(ctx->proc);
}
-void QClient::unsecuring(uint32_t startEnd) {
- Locker::Autolock _sl(mHwcContext->mDrawLock);
- mHwcContext->mSecuring = startEnd;
+static void unsecuring(hwc_context_t *ctx, uint32_t startEnd) {
+ Locker::Autolock _sl(ctx->mDrawLock);
+ ctx->mSecuring = startEnd;
//We're done unsecuring
if(startEnd == IQService::END)
- mHwcContext->mSecureMode = false;
- if(mHwcContext->proc)
- mHwcContext->proc->invalidate(mHwcContext->proc);
+ ctx->mSecureMode = false;
+ if(ctx->proc)
+ ctx->proc->invalidate(ctx->proc);
}
void QClient::MPDeathNotifier::died() {
@@ -113,33 +84,68 @@
mHwcContext->proc->invalidate(mHwcContext->proc);
}
-android::status_t QClient::screenRefresh() {
+static android::status_t screenRefresh(hwc_context_t *ctx) {
status_t result = NO_INIT;
#ifdef QCOM_BSP
- if(mHwcContext->proc) {
- mHwcContext->proc->invalidate(mHwcContext->proc);
+ if(ctx->proc) {
+ ctx->proc->invalidate(ctx->proc);
result = NO_ERROR;
}
#endif
return result;
}
-android::status_t QClient::vpuCommand(uint32_t command, uint32_t setting) {
+static android::status_t vpuCommand(hwc_context_t *ctx,
+ uint32_t command,
+ const Parcel* inParcel,
+ Parcel* outParcel) {
status_t result = NO_INIT;
#ifdef QCOM_BSP
#ifdef VPU_TARGET
- result = mHwcContext->mVPUClient->processCommand(command, setting);
+ result = ctx->mVPUClient->processCommand(command, inParcel, outParcel);
#endif
#endif
return result;
}
-void QClient::setExtOrientation(uint32_t orientation) {
- mHwcContext->mExtOrientation = orientation;
+static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) {
+ ctx->mExtOrientation = orientation;
}
-void QClient::setBufferMirrorMode(uint32_t enable) {
- mHwcContext->mBufferMirrorMode = enable;
+static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) {
+ ctx->mBufferMirrorMode = enable;
}
+status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
+ Parcel* outParcel) {
+
+ if (command > IQService::VPU_COMMAND_LIST_START &&
+ command < IQService::VPU_COMMAND_LIST_END) {
+ return vpuCommand(mHwcContext, command, inParcel, outParcel);
+ }
+
+ switch(command) {
+ case IQService::SECURING:
+ securing(mHwcContext, inParcel->readInt32());
+ break;
+ case IQService::UNSECURING:
+ unsecuring(mHwcContext, inParcel->readInt32());
+ break;
+ case IQService::SCREEN_REFRESH:
+ return screenRefresh(mHwcContext);
+ break;
+ case IQService::EXTERNAL_ORIENTATION:
+ setExtOrientation(mHwcContext, inParcel->readInt32());
+ break;
+ case IQService::BUFFER_MIRRORMODE:
+ setBufferMirrorMode(mHwcContext, inParcel->readInt32());
+ break;
+ default:
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+}
+
+
+
}
diff --git a/libhwcomposer/hwc_qclient.h b/libhwcomposer/hwc_qclient.h
index fa1d6b0..d955377 100644
--- a/libhwcomposer/hwc_qclient.h
+++ b/libhwcomposer/hwc_qclient.h
@@ -39,6 +39,7 @@
struct hwc_context_t;
+class Params;
namespace qClient {
// ----------------------------------------------------------------------------
@@ -46,7 +47,9 @@
public:
QClient(hwc_context_t *ctx);
virtual ~QClient();
- virtual android::status_t notifyCallback(uint32_t msg, uint32_t value);
+ virtual android::status_t notifyCallback(uint32_t command,
+ const android::Parcel* inParcel,
+ android::Parcel* outParcel);
private:
//Notifies of Media Player death
@@ -57,13 +60,6 @@
hwc_context_t *mHwcContext;
};
- void securing(uint32_t startEnd);
- void unsecuring(uint32_t startEnd);
- android::status_t screenRefresh();
- void setExtOrientation(uint32_t orientation);
- void setBufferMirrorMode(uint32_t enable);
- android::status_t vpuCommand(uint32_t command, uint32_t setting);
-
hwc_context_t *mHwcContext;
const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier;
};
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 5cb87f8..10afc92 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -55,7 +55,7 @@
if (compositionType & (qdutils::COMPOSITION_TYPE_DYN |
qdutils::COMPOSITION_TYPE_MDP |
qdutils::COMPOSITION_TYPE_C2D)) {
- ctx->mCopyBit[dpy] = new CopyBit();
+ ctx->mCopyBit[dpy] = new CopyBit(ctx, dpy);
}
}
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index f32ad34..6f2cb9c 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -150,7 +150,8 @@
if (compositionType & (qdutils::COMPOSITION_TYPE_DYN |
qdutils::COMPOSITION_TYPE_MDP |
qdutils::COMPOSITION_TYPE_C2D)) {
- ctx->mCopyBit[HWC_DISPLAY_PRIMARY] = new CopyBit();
+ ctx->mCopyBit[HWC_DISPLAY_PRIMARY] = new CopyBit(ctx,
+ HWC_DISPLAY_PRIMARY);
}
ctx->mExtDisplay = new ExternalDisplay(ctx);
@@ -743,6 +744,7 @@
ctx->listStats[dpy].roi = ovutils::Dim(0, 0,
(int)ctx->dpyAttr[dpy].xres, (int)ctx->dpyAttr[dpy].yres);
ctx->listStats[dpy].secureUI = false;
+ ctx->listStats[dpy].yuv4k2kCount = 0;
trimList(ctx, list, dpy);
optimizeLayerRects(ctx, list, dpy);
@@ -765,6 +767,7 @@
//reset yuv indices
ctx->listStats[dpy].yuvIndices[i] = -1;
+ ctx->listStats[dpy].yuv4k2kIndices[i] = -1;
if (isSecureBuffer(hnd)) {
ctx->listStats[dpy].isSecurePresent = true;
@@ -779,6 +782,12 @@
ctx->listStats[dpy].yuvIndices[yuvCount] = i;
yuvCount++;
+ if(UNLIKELY(is4kx2kYuvBuffer(hnd))){
+ int& yuv4k2kCount = ctx->listStats[dpy].yuv4k2kCount;
+ ctx->listStats[dpy].yuv4k2kIndices[yuv4k2kCount] = i;
+ yuv4k2kCount++;
+ }
+
if((layer->transform & HWC_TRANSFORM_ROT_90) &&
canUseRotator(ctx, dpy)) {
if( (dpy == HWC_DISPLAY_PRIMARY) &&
@@ -1253,7 +1262,7 @@
ovutils::eMdpFlags &mdpFlags,
int rotDownscale, int transform) {
private_handle_t *hnd = (private_handle_t *)layer->handle;
- MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+ MetaData_t *metadata = hnd ? (MetaData_t *)hnd->base_metadata : NULL;
if(layer->blending == HWC_BLENDING_PREMULT) {
ovutils::setMdpFlags(mdpFlags,
@@ -1366,6 +1375,42 @@
return 0;
}
+int configColorLayer(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ const int& dpy, eMdpFlags& mdpFlags, eZorder& z,
+ eIsFg& isFg, const eDest& dest) {
+
+ hwc_rect_t dst = layer->displayFrame;
+ trimLayer(ctx, dpy, 0, dst, dst);
+
+ int w = ctx->dpyAttr[dpy].xres;
+ int h = ctx->dpyAttr[dpy].yres;
+ int dst_w = dst.right - dst.left;
+ int dst_h = dst.bottom - dst.top;
+ uint32_t color = layer->transform;
+ Whf whf(w, h, getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888), 0);
+
+ if (layer->blending == HWC_BLENDING_PREMULT)
+ ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_BLEND_FG_PREMULT);
+
+ PipeArgs parg(mdpFlags, whf, z, isFg, static_cast<eRotFlags>(0),
+ layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+
+ // Configure MDP pipe for Color layer
+ Dim pos(dst.left, dst.top, dst_w, dst_h);
+ ctx->mOverlay->setSource(parg, dest);
+ ctx->mOverlay->setColor(color, dest);
+ ctx->mOverlay->setTransform(0, dest);
+ ctx->mOverlay->setCrop(pos, dest);
+ ctx->mOverlay->setPosition(pos, dest);
+
+ if (!ctx->mOverlay->commit(dest)) {
+ ALOGE("%s: Configure color layer failed!", __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
void updateSource(eTransform& orient, Whf& whf,
hwc_rect_t& crop) {
Dim srcCrop(crop.left, crop.top,
@@ -1396,7 +1441,12 @@
eIsFg& isFg, const eDest& dest, Rotator **rot) {
private_handle_t *hnd = (private_handle_t *)layer->handle;
+
if(!hnd) {
+ if (layer->flags & HWC_COLOR_FILL) {
+ // Configure Color layer
+ return configColorLayer(ctx, layer, dpy, mdpFlags, z, isFg, dest);
+ }
ALOGE("%s: layer handle is NULL", __FUNCTION__);
return -1;
}
@@ -1468,6 +1518,7 @@
if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) {
ALOGE("%s: configRotator failed!", __FUNCTION__);
ctx->mOverlay->clear(dpy);
+ ctx->mLayerRotMap[dpy]->clear();
return -1;
}
ctx->mLayerRotMap[dpy]->add(layer, *rot);
@@ -1485,6 +1536,7 @@
if(configMdp(ctx->mOverlay, parg, orient, crop, dst, metadata, dest) < 0) {
ALOGE("%s: commit failed for low res panel", __FUNCTION__);
+ ctx->mLayerRotMap[dpy]->clear();
return -1;
}
return 0;
@@ -1594,6 +1646,7 @@
if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
ALOGE("%s: configRotator failed!", __FUNCTION__);
ctx->mOverlay->clear(dpy);
+ ctx->mLayerRotMap[dpy]->clear();
return -1;
}
ctx->mLayerRotMap[dpy]->add(layer, *rot);
@@ -1659,6 +1712,7 @@
if(configMdp(ctx->mOverlay, pargL, orient,
tmp_cropL, tmp_dstL, metadata, lDest) < 0) {
ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
+ ctx->mLayerRotMap[dpy]->clear();
return -1;
}
}
@@ -1674,6 +1728,130 @@
if(configMdp(ctx->mOverlay, pargR, orient,
tmp_cropR, tmp_dstR, metadata, rDest) < 0) {
ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
+ ctx->mLayerRotMap[dpy]->clear();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
+ eIsFg& isFg, 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;
+ }
+
+ MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+
+ int hw_w = ctx->dpyAttr[dpy].xres;
+ int hw_h = ctx->dpyAttr[dpy].yres;
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);;
+ hwc_rect_t dst = layer->displayFrame;
+ int transform = layer->transform;
+ eTransform orient = static_cast<eTransform>(transform);
+ const int downscale = 0;
+ int rotFlags = ROT_FLAGS_NONE;
+ //Splitting only YUV layer on primary panel needs different zorders
+ //for both layers as both the layers are configured to single mixer
+ eZorder lz = z;
+ eZorder rz = (eZorder)(z + 1);
+
+ Whf whf(getWidth(hnd), getHeight(hnd),
+ getMdpFormat(hnd->format), hnd->size);
+
+ setMdpFlags(layer, mdpFlagsL, 0, transform);
+ trimLayer(ctx, dpy, transform, crop, dst);
+
+ if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
+ (*rot) = ctx->mRotMgr->getNext();
+ if((*rot) == NULL) return -1;
+ if(!dpy)
+ BwcPM::setBwc(ctx, crop, dst, transform, mdpFlagsL);
+ //Configure rotator for pre-rotation
+ if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
+ ALOGE("%s: configRotator failed!", __FUNCTION__);
+ ctx->mOverlay->clear(dpy);
+ return -1;
+ }
+ ctx->mLayerRotMap[dpy]->add(layer, *rot);
+ whf.format = (*rot)->getDstFormat();
+ updateSource(orient, whf, crop);
+ rotFlags |= ROT_PREROTATED;
+ }
+
+ eMdpFlags mdpFlagsR = mdpFlagsL;
+ int lSplit = dst.left + (dst.right - dst.left)/2;
+
+ hwc_rect_t tmp_cropL = {0}, tmp_dstL = {0};
+ hwc_rect_t tmp_cropR = {0}, tmp_dstR = {0};
+
+ if(lDest != OV_INVALID) {
+ tmp_cropL = crop;
+ tmp_dstL = dst;
+ hwc_rect_t scissor = {dst.left, dst.top, lSplit, dst.bottom };
+ qhwc::calculate_crop_rects(tmp_cropL, tmp_dstL, scissor, 0);
+ }
+ if(rDest != OV_INVALID) {
+ tmp_cropR = crop;
+ tmp_dstR = dst;
+ hwc_rect_t scissor = {lSplit, dst.top, dst.right, dst.bottom };
+ qhwc::calculate_crop_rects(tmp_cropR, tmp_dstR, scissor, 0);
+ }
+
+ sanitizeSourceCrop(tmp_cropL, tmp_cropR, hnd);
+
+ //When buffer is H-flipped, contents of mixer config also needs to swapped
+ //Not needed if the layer is confined to one half of the screen.
+ //If rotator has been used then it has also done the flips, so ignore them.
+ if((orient & OVERLAY_TRANSFORM_FLIP_H) && lDest != OV_INVALID
+ && rDest != OV_INVALID && (*rot) == NULL) {
+ hwc_rect_t new_cropR;
+ new_cropR.left = tmp_cropL.left;
+ new_cropR.right = new_cropR.left + (tmp_cropR.right - tmp_cropR.left);
+
+ hwc_rect_t new_cropL;
+ new_cropL.left = new_cropR.right;
+ new_cropL.right = tmp_cropR.right;
+
+ tmp_cropL.left = new_cropL.left;
+ tmp_cropL.right = new_cropL.right;
+
+ tmp_cropR.left = new_cropR.left;
+ tmp_cropR.right = new_cropR.right;
+
+ }
+
+ //For the mdp, since either we are pre-rotating or MDP does flips
+ orient = OVERLAY_TRANSFORM_0;
+ transform = 0;
+
+ //configure left half
+ if(lDest != OV_INVALID) {
+ PipeArgs pargL(mdpFlagsL, whf, lz, isFg,
+ static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+
+ if(configMdp(ctx->mOverlay, pargL, orient,
+ tmp_cropL, tmp_dstL, metadata, lDest) < 0) {
+ ALOGE("%s: commit failed for left half config", __FUNCTION__);
+ return -1;
+ }
+ }
+
+ //configure right half
+ if(rDest != OV_INVALID) {
+ PipeArgs pargR(mdpFlagsR, whf, rz, isFg,
+ static_cast<eRotFlags>(rotFlags),
+ layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+ if(configMdp(ctx->mOverlay, pargR, orient,
+ tmp_cropR, tmp_dstR, metadata, rDest) < 0) {
+ ALOGE("%s: commit failed for right half config", __FUNCTION__);
return -1;
}
}
@@ -1685,9 +1863,9 @@
if(qdutils::MDPVersion::getInstance().is8x26() &&
ctx->mVirtualDisplay->isConnected() &&
!ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause) {
- // Allow if YUV needs rotation and DMA is configured to BLOCK mode for
- // primary. For portrait videos usecase on WFD, Driver supports
- // multiplexing of DMA pipe in LINE and BLOCK mode.
+ /* 8x26 mdss driver supports multiplexing of DMA pipe
+ * in LINE and BLOCK modes for writeback panels.
+ */
if(dpy == HWC_DISPLAY_PRIMARY)
return false;
}
@@ -1775,6 +1953,21 @@
mCount = 0;
}
+void LayerRotMap::clear() {
+ for (uint32_t i = 0; i < mCount; i++) {
+ //mCount represents rotator objects for just this display.
+ //We could have popped mCount topmost objects from mRotMgr, but if each
+ //round has the same failure, typical of stability runs, it would lead
+ //to unnecessary memory allocation, deallocation each time. So we let
+ //the rotator objects be around, but just knock off the fences they
+ //hold. Ultimately the rotator objects will be GCed when not required.
+ //Also resetting fences is required if at least one rotation round has
+ //succeeded before. It'll be a NOP otherwise.
+ mRot[i]->resetReleaseFd();
+ }
+ reset();
+}
+
void LayerRotMap::setReleaseFd(const int& fence) {
for(uint32_t i = 0; i < mCount; i++) {
mRot[i]->setReleaseFd(dup(fence));
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 66a02d6..2503e43 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -99,6 +99,8 @@
int extOnlyLayerIndex;
bool needsAlphaScale;
bool preMultipliedAlpha;
+ int yuv4k2kIndices[MAX_NUM_APP_LAYERS];
+ int yuv4k2kCount;
// Notifies hwcomposer about the start and end of animation
// This will be set to true during animation, otherwise false.
bool isDisplayAnimating;
@@ -140,7 +142,11 @@
LayerRotMap() { reset(); }
enum { MAX_SESS = 3 };
void add(hwc_layer_1_t* layer, overlay::Rotator *rot);
+ //Resets the mapping of layer to rotator
void reset();
+ //Clears mappings and existing rotator fences
+ //Intended to be used during errors
+ void clear();
uint32_t getCount() const;
hwc_layer_1_t* getLayer(uint32_t index) const;
overlay::Rotator* getRot(uint32_t index) const;
@@ -268,6 +274,10 @@
const hwc_rect_t& pos, const MetaData_t *metadata,
const ovutils::eDest& dest);
+int configColorLayer(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
+ ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+ ovutils::eIsFg& isFg, const ovutils::eDest& dest);
+
void updateSource(ovutils::eTransform& orient, ovutils::Whf& whf,
hwc_rect_t& crop);
@@ -283,6 +293,13 @@
ovutils::eIsFg& isFg, 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,
+ ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+ ovutils::eIsFg& isFg, const ovutils::eDest& lDest,
+ const ovutils::eDest& rDest, overlay::Rotator **rot);
+
//On certain targets DMA pipes are used for rotation and they won't be available
//for line operations. On a per-target basis we can restrict certain use cases
//from using rotator, since we know before-hand that such scenarios can lead to
@@ -305,6 +322,12 @@
return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO));
}
+// Returns true if the buffer is yuv
+static inline bool is4kx2kYuvBuffer(const private_handle_t* hnd) {
+ return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) &&
+ (hnd->width > 2048));
+}
+
// Returns true if the buffer is secure
static inline bool isSecureBuffer(const private_handle_t* hnd) {
return (hnd && (private_handle_t::PRIV_FLAGS_SECURE_BUFFER & hnd->flags));
@@ -459,7 +482,8 @@
}
static inline bool has90Transform(hwc_layer_1_t *layer) {
- return (layer->transform & HWC_TRANSFORM_ROT_90);
+ return ((layer->transform & HWC_TRANSFORM_ROT_90) &&
+ !(layer->flags & HWC_COLOR_FILL));
}
inline bool isSecurePresent(hwc_context_t *ctx, int dpy) {
diff --git a/libhwcomposer/hwc_vpuclient.cpp b/libhwcomposer/hwc_vpuclient.cpp
index bdfeae5..23c6841 100644
--- a/libhwcomposer/hwc_vpuclient.cpp
+++ b/libhwcomposer/hwc_vpuclient.cpp
@@ -31,9 +31,11 @@
#include "hwc_vpuclient.h"
#include "hwc_utils.h"
#include <vpu/vpu.h>
+#include <binder/Parcel.h>
using namespace vpu;
+using namespace android;
namespace qhwc {
VPUClient::VPUClient()
@@ -78,11 +80,14 @@
return err;
}
-int VPUClient::processCommand(uint32_t command, uint32_t setting)
+int VPUClient::processCommand(uint32_t command,
+ const Parcel* inParcel, Parcel* outParcel)
{
if(!mVPU)
return 0;
- return mVPU->processCommand(command, setting);
+ //XXX: Enable when VPU enables it
+ //return mVPU->processCommand(command, inParcel, outParcel);
+ return 0;
}
}; // namespace qhwc
diff --git a/libhwcomposer/hwc_vpuclient.h b/libhwcomposer/hwc_vpuclient.h
index 8cc7137..9985517 100644
--- a/libhwcomposer/hwc_vpuclient.h
+++ b/libhwcomposer/hwc_vpuclient.h
@@ -39,6 +39,9 @@
namespace vpu {
class VPU;
};
+namespace android {
+class Parcel;
+};
namespace qhwc {
@@ -52,7 +55,8 @@
int draw(hwc_context_t *ctx, hwc_display_contents_1_t* list);
- int processCommand(uint32_t command, uint32_t setting);
+ int processCommand(uint32_t command,
+ const android::Parcel* inParcel, android::Parcel* outParcel);
private:
vpu::VPU *mVPU;
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index 9222af5..ad23e84 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -52,6 +52,7 @@
mDumpStr[0] = '\0';
initScalar();
+ setDMAMultiplexingSupported();
}
Overlay::~Overlay() {
@@ -67,7 +68,6 @@
PipeBook::resetUse(i);
PipeBook::resetAllocation(i);
}
- sForceSetBitmap = 0;
mDumpStr[0] = '\0';
#ifdef USES_QSEED_SCALAR
@@ -80,7 +80,8 @@
void Overlay::configDone() {
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
- if(PipeBook::isNotUsed(i)) {
+ if((PipeBook::isNotUsed(i) && !sessionInProgress((eDest)i)) ||
+ isSessionEnded((eDest)i)) {
//Forces UNSET on pipes, flushes rotator memory and session, closes
//fds
if(mPipeBook[i].valid()) {
@@ -106,6 +107,27 @@
#endif
}
+int Overlay::getPipeId(utils::eDest dest) {
+ return mPipeBook[(int)dest].mPipe->getPipeId();
+}
+
+eDest Overlay::getDest(int pipeid) {
+ eDest dest = OV_INVALID;
+ // finding the dest corresponding to the given pipe
+ for(int i=0; i < PipeBook::NUM_PIPES; ++i) {
+ if(mPipeBook[i].valid() && mPipeBook[i].mPipe->getPipeId() == pipeid) {
+ return (eDest)i;
+ }
+ }
+ return dest;
+}
+
+eDest Overlay::reservePipe(int pipeid) {
+ eDest dest = getDest(pipeid);
+ PipeBook::setAllocation((int)dest);
+ return dest;
+}
+
eDest Overlay::nextPipe(eMdpPipeType type, int dpy, int mixer) {
eDest dest = OV_INVALID;
@@ -117,8 +139,10 @@
(mPipeBook[i].mMixer == MIXER_UNUSED || //Free or same mixer
mPipeBook[i].mMixer == mixer) &&
PipeBook::isNotAllocated(i) && //Free pipe
- !(sDMAMode == DMA_BLOCK_MODE && //DMA pipe in Line mode
- PipeBook::getPipeType((eDest)i) == OV_MDP_PIPE_DMA)) {
+ ( (sDMAMultiplexingSupported && dpy) ||
+ !(sDMAMode == DMA_BLOCK_MODE && //DMA pipe in Line mode
+ PipeBook::getPipeType((eDest)i) == OV_MDP_PIPE_DMA)) ){
+ //DMA-Multiplexing is only supported for WB on 8x26
dest = (eDest)i;
PipeBook::setAllocation(i);
break;
@@ -131,6 +155,7 @@
mPipeBook[index].mMixer = mixer;
if(not mPipeBook[index].valid()) {
mPipeBook[index].mPipe = new GenericPipe(dpy);
+ mPipeBook[index].mSession = PipeBook::NONE;
char str[32];
snprintf(str, 32, "Set=%s dpy=%d mix=%d; ",
PipeBook::getDestStr(dest), dpy, mixer);
@@ -146,6 +171,13 @@
return dest;
}
+void Overlay::endAllSessions() {
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ if(mPipeBook[i].valid() && mPipeBook[i].mSession==PipeBook::START)
+ mPipeBook[i].mSession = PipeBook::END;
+ }
+}
+
bool Overlay::isPipeTypeAttached(eMdpPipeType type) {
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if(type == PipeBook::getPipeType((eDest)i) &&
@@ -164,19 +196,14 @@
if(mPipeBook[index].mPipe->commit()) {
ret = true;
PipeBook::setUse((int)dest);
- if(sForceSetBitmap & (1 << mPipeBook[index].mDisplay)) {
- mPipeBook[index].mPipe->forceSet();
- }
} else {
int dpy = mPipeBook[index].mDisplay;
- for(int i = 0; i < PipeBook::NUM_PIPES; i++)
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if (mPipeBook[i].mDisplay == dpy) {
PipeBook::resetAllocation(i);
PipeBook::resetUse(i);
- if(mPipeBook[i].valid()) {
- mPipeBook[i].mPipe->forceSet();
- }
}
+ }
}
return ret;
}
@@ -200,6 +227,13 @@
mPipeBook[index].mPipe->setCrop(d);
}
+void Overlay::setColor(const uint32_t color,
+ utils::eDest dest) {
+ int index = (int)dest;
+ validate(index);
+ mPipeBook[index].mPipe->setColor(color);
+}
+
void Overlay::setPosition(const utils::Dim& d,
utils::eDest dest) {
int index = (int)dest;
@@ -397,9 +431,6 @@
// Mark as available for this round
PipeBook::resetUse(i);
PipeBook::resetAllocation(i);
- if(mPipeBook[i].valid()) {
- mPipeBook[i].mPipe->forceSet();
- }
}
}
}
@@ -453,12 +484,13 @@
}
mDisplay = DPY_UNUSED;
mMixer = MIXER_UNUSED;
+ mSession = NONE;
}
Overlay* Overlay::sInstance = 0;
int Overlay::sDpyFbMap[DPY_MAX] = {0, -1, -1};
int Overlay::sDMAMode = DMA_LINE_MODE;
-int Overlay::sForceSetBitmap = 0;
+bool Overlay::sDMAMultiplexingSupported = false;
int Overlay::PipeBook::NUM_PIPES = 0;
int Overlay::PipeBook::sPipeUsageBitmap = 0;
int Overlay::PipeBook::sLastUsageBitmap = 0;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index 854fa30..fe855c1 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -31,6 +31,7 @@
#define OVERLAY_H
#include "overlayUtils.h"
+#include "mdp_version.h"
#include "utils/threads.h"
struct MetaData_t;
@@ -76,15 +77,33 @@
* asisgned to a mixer within a display it cannot be reused for another
* mixer without being UNSET once*/
utils::eDest nextPipe(utils::eMdpPipeType, int dpy, int mixer);
+ /* Returns the eDest corresponding to an already allocated pipeid.
+ * Useful for the reservation case, when libvpu reserves the pipe at its
+ * end, and expect the overlay to allocate a given pipe for a layer.
+ */
+ utils::eDest reservePipe(int pipeid);
+ /* getting dest for the given pipeid */
+ utils::eDest getDest(int pipeid);
+ /* getting overlay.pipeid for the given dest */
+ int getPipeId(utils::eDest dest);
void setSource(const utils::PipeArgs args, utils::eDest dest);
void setCrop(const utils::Dim& d, utils::eDest dest);
+ void setColor(const uint32_t color, utils::eDest dest);
void setTransform(const int orientation, utils::eDest dest);
void setPosition(const utils::Dim& dim, utils::eDest dest);
void setVisualParams(const MetaData_t& data, utils::eDest dest);
bool commit(utils::eDest dest);
bool queueBuffer(int fd, uint32_t offset, utils::eDest dest);
+ /* pipe reservation session is running */
+ bool sessionInProgress(utils::eDest dest);
+ /* pipe reservation session has ended*/
+ bool isSessionEnded(utils::eDest dest);
+ /* start session for the pipe reservation */
+ void startSession(utils::eDest dest);
+ /* end all started sesisons */
+ void endAllSessions();
/* Returns available ("unallocated") pipes for a display's mixer */
int availablePipes(int dpy, int mixer);
/* Returns available ("unallocated") pipes for a display */
@@ -101,8 +120,6 @@
void getDump(char *buf, size_t len);
/* Reset usage and allocation bits on all pipes for given display */
void clear(int dpy);
- /* Marks the display, whose pipes need to be forcibaly configured */
- void forceSet(const int& dpy);
/* Closes open pipes, called during startup */
static int initOverlay();
@@ -122,6 +139,7 @@
explicit Overlay();
/*Validate index range, abort if invalid */
void validate(int index);
+ static void setDMAMultiplexingSupported();
void dump() const;
/* Creates a scalar object using libscale.so */
static void initScalar();
@@ -160,7 +178,13 @@
static int NUM_PIPES;
static utils::eMdpPipeType pipeTypeLUT[utils::OV_MAX];
-
+ /* Session for reserved pipes */
+ enum Session {
+ NONE,
+ START,
+ END
+ };
+ Session mSession;
private:
//usage tracks if a successful commit happened. So a pipe could be
@@ -185,7 +209,7 @@
static Overlay *sInstance;
static int sDpyFbMap[DPY_MAX];
static int sDMAMode;
- static int sForceSetBitmap;
+ static bool sDMAMultiplexingSupported;
static void *sLibScaleHandle;
static scale::Scale *sScale;
};
@@ -247,6 +271,12 @@
sDMAMode = mode;
}
+inline void Overlay::setDMAMultiplexingSupported() {
+ sDMAMultiplexingSupported = false;
+ if(qdutils::MDPVersion::getInstance().is8x26())
+ sDMAMultiplexingSupported = true;
+}
+
inline int Overlay::getDMAMode() {
return sDMAMode;
}
@@ -256,10 +286,6 @@
return sDpyFbMap[dpy];
}
-inline void Overlay::forceSet(const int& dpy) {
- sForceSetBitmap |= (1 << dpy);
-}
-
inline scale::Scale *Overlay::getScalar() {
return sScale;
}
@@ -312,6 +338,18 @@
return pipeTypeLUT[(int)dest];
}
+inline void Overlay::startSession(utils::eDest dest) {
+ mPipeBook[(int)dest].mSession = PipeBook::START;
+}
+
+inline bool Overlay::sessionInProgress(utils::eDest dest) {
+ return (mPipeBook[(int)dest].mSession == PipeBook::START);
+}
+
+inline bool Overlay::isSessionEnded(utils::eDest dest) {
+ return (mPipeBook[(int)dest].mSession == PipeBook::END);
+}
+
inline const char* Overlay::PipeBook::getDestStr(utils::eDest dest) {
switch(getPipeType(dest)) {
case utils::OV_MDP_PIPE_RGB: return "RGB";
diff --git a/liboverlay/overlayCtrlData.h b/liboverlay/overlayCtrlData.h
index 6746792..1b26b66 100644
--- a/liboverlay/overlayCtrlData.h
+++ b/liboverlay/overlayCtrlData.h
@@ -61,6 +61,8 @@
void setSource(const utils::PipeArgs& args);
/* set crop info and pass it down to mdp */
void setCrop(const utils::Dim& d);
+ /* set color for mdp pipe */
+ void setColor(const uint32_t color);
/* set orientation */
void setTransform(const utils::eTransform& p);
/* set mdp position using dim */
@@ -85,7 +87,6 @@
void dump() const;
/* Return the dump in the specified buffer */
void getDump(char *buf, size_t len);
- void forceSet();
private:
// mdp ctrl struct(info e.g.)
@@ -174,6 +175,11 @@
mMdp.setCrop(d);
}
+inline void Ctrl::setColor(const uint32_t color)
+{
+ mMdp.setColor(color);
+}
+
inline bool Ctrl::setVisualParams(const MetaData_t &metadata)
{
if (!mMdp.setVisualParams(metadata)) {
@@ -225,10 +231,6 @@
mMdp.getDump(buf, len);
}
-inline void Ctrl::forceSet() {
- mMdp.forceSet();
-}
-
inline Data::Data() {
mMdp.reset();
}
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index b4058bd..006e05d 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -69,7 +69,6 @@
mLkgo.id = MSMFB_NEW_REQUEST;
mOrientation = utils::OVERLAY_TRANSFORM_0;
mDownscale = 0;
- mForceSet = false;
mDpy = 0;
#ifdef USES_POST_PROCESSING
mPPChanged = false;
@@ -122,6 +121,10 @@
setSrcRectDim(d);
}
+void MdpCtrl::setColor(const uint32_t color) {
+ mOVInfo.bg_color = color;
+}
+
void MdpCtrl::setPosition(const overlay::utils::Dim& d) {
setDstRectDim(d);
}
@@ -207,8 +210,7 @@
doDownscale();
- if(this->ovChanged() || mForceSet) {
- mForceSet = false;
+ if(this->ovChanged()) {
if(!mdp_wrapper::setOverlay(mFd.getFD(), mOVInfo)) {
ALOGE("MdpCtrl failed to setOverlay, restoring last known "
"good ov info");
diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h
index fe4ad69..3cb6a41 100644
--- a/liboverlay/overlayMdp.h
+++ b/liboverlay/overlayMdp.h
@@ -57,6 +57,8 @@
* Dim - ROI dimensions.
*/
void setCrop(const utils::Dim& d);
+ /* set color for mdp pipe */
+ void setColor(const uint32_t color);
void setTransform(const utils::eTransform& orient);
/* given a dim and w/h, set overlay dim */
void setPosition(const utils::Dim& dim);
@@ -81,7 +83,6 @@
utils::Dim getSrcRectDim() const;
/* setVisualParam */
bool setVisualParams(const MetaData_t& data);
- void forceSet();
private:
/* Perform transformation calculations */
@@ -131,7 +132,6 @@
/* FD for the mdp fbnum */
OvFD mFd;
int mDownscale;
- bool mForceSet;
int mDpy;
#ifdef USES_POST_PROCESSING
@@ -346,10 +346,6 @@
mOVInfo.flags |= MDP_SOURCE_ROTATED_90;
}
-inline void MdpCtrl::forceSet() {
- mForceSet = true;
-}
-
/////// MdpCtrl3D //////
inline MdpCtrl3D::MdpCtrl3D() { reset(); }
diff --git a/liboverlay/overlayRotator.cpp b/liboverlay/overlayRotator.cpp
index 7b3dda1..4b6a8bc 100644
--- a/liboverlay/overlayRotator.cpp
+++ b/liboverlay/overlayRotator.cpp
@@ -107,6 +107,12 @@
mRelFence[mCurrOffset] = fence;
}
+void RotMem::Mem::resetReleaseFd() {
+ //Will wait for previous offline rotation to finish, close fence fd
+ //and reset
+ setReleaseFd(-1);
+}
+
//============RotMgr=========================
RotMgr::RotMgr() {
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index 7c1095f..6bb94a6 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -56,6 +56,7 @@
bool close() { return m.close(); }
uint32_t size() const { return m.bufSz(); }
void setReleaseFd(const int& fence);
+ void resetReleaseFd();
// Max rotator buffers
enum { ROT_NUM_BUFS = 2 };
// rotator data info dst offset
@@ -72,6 +73,7 @@
Mem& prev() { return m[(_curr+1) % MAX_ROT_MEM]; }
RotMem& operator++() { ++_curr; return *this; }
void setReleaseFd(const int& fence) { curr().setReleaseFd(fence); }
+ void resetReleaseFd() { curr().resetReleaseFd(); }
bool close();
uint32_t _curr;
Mem m[MAX_ROT_MEM];
@@ -96,6 +98,7 @@
virtual void dump() const = 0;
virtual void getDump(char *buf, size_t len) const = 0;
void setReleaseFd(const int& fence) { mMem.setReleaseFd(fence); }
+ void resetReleaseFd() { mMem.resetReleaseFd(); }
static Rotator *getRotator();
protected:
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index 06e8257..e0b580b 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -84,6 +84,10 @@
mCtrlData.ctrl.setCrop(d);
}
+void GenericPipe::setColor(const uint32_t color) {
+ mCtrlData.ctrl.setColor(color);
+}
+
void GenericPipe::setTransform(const utils::eTransform& orient) {
mCtrlData.ctrl.setTransform(orient);
}
@@ -163,8 +167,8 @@
return true;
}
-void GenericPipe::forceSet() {
- mCtrlData.ctrl.forceSet();
+int GenericPipe::getPipeId() {
+ return mCtrlData.ctrl.getPipeId();
}
} //namespace overlay
diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h
index 2472f4e..ecdd001 100644
--- a/liboverlay/pipes/overlayGenPipe.h
+++ b/liboverlay/pipes/overlayGenPipe.h
@@ -48,6 +48,8 @@
void setSource(const utils::PipeArgs& args);
/* set crop a.k.a the region of interest */
void setCrop(const utils::Dim& d);
+ /* set color for mdp pipe */
+ void setColor(const uint32_t color);
/* set orientation*/
void setTransform(const utils::eTransform& param);
/* set mdp posision using dim */
@@ -73,10 +75,7 @@
void dump() const;
/* Return the dump in the specified buffer */
void getDump(char *buf, size_t len);
- /* Marks the pipe for forcible setting of params
- * even if they haven't changed
- */
- void forceSet();
+ int getPipeId();
private:
/* set Closed pipe */
diff --git a/libqdutils/cb_utils.cpp b/libqdutils/cb_utils.cpp
index bc7e5b1..d8eec2a 100644
--- a/libqdutils/cb_utils.cpp
+++ b/libqdutils/cb_utils.cpp
@@ -49,6 +49,10 @@
Region wormholeRegion(fbFrameRect);
for (uint32_t i = 0 ; i < last; i++) {
+ //TODO Work on using hwc clear instead of gpu for HWC_BLIT
+ //If layer is marked for HWC_BLIT clear is done by GPU
+ if(list->hwLayers[i].compositionType == HWC_BLIT)
+ return 0;
// need to take care only in per pixel blending.
// Restrict calculation only for copybit layers.
if((list->hwLayers[i].blending != HWC_BLENDING_NONE) ||
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 1850801..b219cd5 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -27,9 +27,6 @@
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cutils/log.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/fb.h>
#include <linux/msm_mdp.h>
#include "mdp_version.h"
@@ -42,81 +39,35 @@
MDPVersion::MDPVersion()
{
- int fb_fd = open("/dev/graphics/fb0", O_RDWR);
- char panel_type = 0;
- struct fb_fix_screeninfo fb_finfo;
-
- mMDPVersion = MDP_V_UNKNOWN;
+ mMDPVersion = MDSS_V5;
mMdpRev = 0;
mRGBPipes = 0;
mVGPipes = 0;
mDMAPipes = 0;
mFeatures = 0;
mMDPUpscale = 0;
- //TODO get this from driver, default for A-fam to 8
- mMDPDownscale = 8;
- mFd = fb_fd;
+ mMDPDownscale = 0;
+ mPanelType = NO_PANEL;
+ mLowBw = 0;
+ mHighBw = 0;
- if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_finfo) < 0) {
- ALOGE("FBIOGET_FSCREENINFO failed");
- } else {
- if(!strncmp(fb_finfo.id, "msmfb", 5)) {
- char str_ver[4] = { 0 };
- memcpy(str_ver, &fb_finfo.id[5], 3);
- str_ver[3] = '\0';
- mMDPVersion = atoi(str_ver);
- //Normalize MDP version to ease comparison.
- //This is needed only because
- //MDP 3.0.3 reports value as 303 which
- //is more than all the others
- if (mMDPVersion < 100)
- mMDPVersion *= 10;
-
- mRGBPipes = mVGPipes = 2;
-
- } else if (!strncmp(fb_finfo.id, "mdssfb", 6)) {
- mMDPVersion = MDSS_V5;
- if(!updateSysFsInfo()) {
- ALOGE("Unable to read updateSysFsInfo");
- }
- if (mMdpRev == MDP_V3_0_4){
- mMDPVersion = MDP_V3_0_4;
- }
- }
-
- /* Assumes panel type is 2nd element in '_' delimited id string */
- char * ptype = strstr(fb_finfo.id, "_");
- if (!ptype || (*(++ptype) == '\0')) {
- ALOGE("Invalid framebuffer info string: %s", fb_finfo.id);
- ptype = fb_finfo.id;
- }
- panel_type = *ptype;
+ if(!updatePanelInfo()) {
+ ALOGE("Unable to read Primary Panel Information");
}
- mPanelType = panel_type;
+ if(!updateSysFsInfo()) {
+ ALOGE("Unable to read display sysfs node");
+ }
+ if (mMdpRev == MDP_V3_0_4){
+ mMDPVersion = MDP_V3_0_4;
+ }
+
mHasOverlay = false;
if((mMDPVersion >= MDP_V4_0) ||
(mMDPVersion == MDP_V_UNKNOWN) ||
(mMDPVersion == MDP_V3_0_4))
mHasOverlay = true;
- if(mMDPVersion >= MDSS_V5) {
- char split[64] = {0};
- FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r");
- if(fp){
- //Format "left right" space as delimiter
- if(fread(split, sizeof(char), 64, fp)) {
- mSplit.mLeft = atoi(split);
- ALOGI_IF(mSplit.mLeft, "Left Split=%d", mSplit.mLeft);
- char *rght = strpbrk(split, " ");
- if(rght)
- mSplit.mRight = atoi(rght + 1);
- ALOGI_IF(rght, "Right Split=%d", mSplit.mRight);
- }
- } else {
- ALOGE("Failed to open mdss_fb_split node");
- }
-
- if(fp)
- fclose(fp);
+ if(!updateSplitInfo()) {
+ ALOGE("Unable to read display split node");
}
}
@@ -140,7 +91,39 @@
*idx = index;
return 0;
}
+// This function reads the sysfs node to read the primary panel type
+// and updates information accordingly
+bool MDPVersion::updatePanelInfo() {
+ FILE *displayDeviceFP = NULL;
+ const int MAX_FRAME_BUFFER_NAME_SIZE = 128;
+ char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
+ const char *strCmdPanel = "mipi dsi cmd panel";
+ const char *strVideoPanel = "mipi dsi video panel";
+ const char *strLVDSPanel = "lvds panel";
+ const char *strEDPPanel = "edp panel";
+ displayDeviceFP = fopen("/sys/class/graphics/fb0/msm_fb_type", "r");
+ if(displayDeviceFP){
+ fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
+ displayDeviceFP);
+ if(strncmp(fbType, strCmdPanel, strlen(strCmdPanel)) == 0) {
+ mPanelType = MIPI_CMD_PANEL;
+ }
+ else if(strncmp(fbType, strVideoPanel, strlen(strVideoPanel)) == 0) {
+ mPanelType = MIPI_VIDEO_PANEL;
+ }
+ else if(strncmp(fbType, strLVDSPanel, strlen(strLVDSPanel)) == 0) {
+ mPanelType = LVDS_PANEL;
+ }
+ else if(strncmp(fbType, strEDPPanel, strlen(strEDPPanel)) == 0) {
+ mPanelType = EDP_PANEL;
+ }
+ fclose(displayDeviceFP);
+ return true;
+ }else {
+ return false;
+ }
+}
// This function reads the sysfs node to read MDP capabilities
// and parses and updates information accordingly.
@@ -187,8 +170,13 @@
else if(!strncmp(tokens[0], "max_upscale_ratio",
strlen("max_upscale_ratio"))) {
mMDPUpscale = atoi(tokens[1]);
- }
- else if(!strncmp(tokens[0], "features", strlen("features"))) {
+ } else if(!strncmp(tokens[0], "max_bandwidth_low",
+ strlen("max_bandwidth_low"))) {
+ mLowBw = atol(tokens[1]);
+ } else if(!strncmp(tokens[0], "max_bandwidth_high",
+ strlen("max_bandwidth_high"))) {
+ mHighBw = atol(tokens[1]);
+ } else if(!strncmp(tokens[0], "features", strlen("features"))) {
for(int i=1; i<index;i++) {
if(!strncmp(tokens[i], "bwc", strlen("bwc"))) {
mFeatures |= MDP_BWC_EN;
@@ -210,9 +198,39 @@
mRGBPipes, mVGPipes);
ALOGD_IF(DEBUG, "%s:mDMAPipes:%d \t mMDPDownscale:%d, mFeatures:%d",
__FUNCTION__, mDMAPipes, mMDPDownscale, mFeatures);
+ ALOGD_IF(DEBUG, "%s:mLowBw: %lu mHighBw: %lu", __FUNCTION__, mLowBw,
+ mHighBw);
+
return true;
}
+// This function reads the sysfs node to read MDP capabilities
+// and parses and updates information accordingly.
+bool MDPVersion::updateSplitInfo() {
+ if(mMDPVersion >= MDSS_V5) {
+ char split[64] = {0};
+ FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r");
+ if(fp){
+ //Format "left right" space as delimiter
+ if(fread(split, sizeof(char), 64, fp)) {
+ mSplit.mLeft = atoi(split);
+ ALOGI_IF(mSplit.mLeft, "Left Split=%d", mSplit.mLeft);
+ char *rght = strpbrk(split, " ");
+ if(rght)
+ mSplit.mRight = atoi(rght + 1);
+ ALOGI_IF(mSplit.mRight, "Right Split=%d", mSplit.mRight);
+ }
+ } else {
+ ALOGE("Failed to open mdss_fb_split node");
+ return false;
+ }
+ if(fp)
+ fclose(fp);
+ }
+ return true;
+}
+
+
bool MDPVersion::supportsDecimation() {
return mFeatures & MDP_DECIMATION_EN;
}
@@ -226,32 +244,5 @@
return (mFeatures & MDP_BWC_EN);
}
-bool MDPVersion::is8x26() {
- // check for 8x26 variants
- // chip variants have same major number and minor numbers usually vary
- // for e.g., MDSS_MDP_HW_REV_101 is 0x10010000
- // 1001 - major number
- // 0000 - minor number
- // 8x26 v1 minor number is 0000
- // v2 minor number is 0001 etc..
- if( mMdpRev >= MDSS_MDP_HW_REV_101 && mMdpRev < MDSS_MDP_HW_REV_102) {
- return true;
- }
- return false;
-}
-
-bool MDPVersion::is8x74v2() {
- if( mMdpRev >= MDSS_MDP_HW_REV_102 && mMdpRev < MDSS_MDP_HW_REV_200) {
- return true;
- }
- return false;
-}
-
-bool MDPVersion::is8x92() {
- if( mMdpRev >= MDSS_MDP_HW_REV_200 && mMdpRev < MDSS_MDP_HW_REV_206) {
- return true;
- }
- return false;
-}
}; //namespace qdutils
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index b995582..60a2985 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -38,6 +38,10 @@
*/
using namespace android;
namespace qdutils {
+// These panel definitions are available at mdss_mdp.h which is internal header
+// file and is not available at <linux/mdss_mdp.h>.
+// ToDo: once it is available at linux/mdss_mdp.h, these below definitions can
+// be removed.
enum mdp_version {
MDP_V_UNKNOWN = 0,
MDP_V2_2 = 220,
@@ -53,10 +57,20 @@
MDSS_V5 = 500,
};
+// chip variants have same major number and minor numbers usually vary
+// for e.g., MDSS_MDP_HW_REV_101 is 0x10010000
+// 1001 - major number
+// 0000 - minor number
+// 8x26 v1 minor number is 0000
+// v2 minor number is 0001 etc..
enum mdp_rev {
MDSS_MDP_HW_REV_100 = 0x10000000, //8974 v1
MDSS_MDP_HW_REV_101 = 0x10010000, //8x26
MDSS_MDP_HW_REV_102 = 0x10020000, //8974 v2
+ MDSS_MDP_HW_REV_103 = 0x10030000, //8084
+ MDSS_MDP_HW_REV_104 = 0x10040000, //Next version
+ MDSS_MDP_HW_REV_105 = 0x10050000, //Next version
+ MDSS_MDP_HW_REV_107 = 0x10070000, //Next version
MDSS_MDP_HW_REV_200 = 0x20000000, //8092
MDSS_MDP_HW_REV_206 = 0x20060000, //Future
};
@@ -65,6 +79,7 @@
MAX_DISPLAY_DIM = 2048,
};
+#define NO_PANEL '0'
#define MDDI_PANEL '1'
#define EBI2_PANEL '2'
#define LCDC_PANEL '3'
@@ -75,6 +90,7 @@
#define MIPI_CMD_PANEL '9'
#define WRITEBACK_PANEL 'a'
#define LVDS_PANEL 'b'
+#define EDP_PANEL 'c'
class MDPVersion;
@@ -102,13 +118,32 @@
bool supportsDecimation();
uint32_t getMaxMDPDownscale();
bool supportsBWC();
- bool is8x26();
- bool is8x74v2();
- bool is8x92();
int getLeftSplit() { return mSplit.left(); }
int getRightSplit() { return mSplit.right(); }
+ unsigned long getLowBw() { return mLowBw; }
+ unsigned long getHighBw() { return mHighBw; }
+
+ bool is8x26() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_101 and
+ mMdpRev < MDSS_MDP_HW_REV_102);
+ }
+ bool is8x74v2() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_102 and
+ mMdpRev < MDSS_MDP_HW_REV_103);
+ }
+ bool is8084() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_103 and
+ mMdpRev < MDSS_MDP_HW_REV_104);
+ }
+ bool is8092() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_200 and
+ mMdpRev < MDSS_MDP_HW_REV_206);
+ }
+
private:
bool updateSysFsInfo();
+ bool updatePanelInfo();
+ bool updateSplitInfo();
int tokenizeParams(char *inputParams, const char *delim,
char* tokenStr[], int *idx);
int mFd;
@@ -123,6 +158,8 @@
uint32_t mMDPDownscale;
uint32_t mMDPUpscale;
Split mSplit;
+ unsigned long mLowBw; //kbps
+ unsigned long mHighBw; //kbps
};
}; //namespace qdutils
#endif //INCLUDE_LIBQCOMUTILS_MDPVER
diff --git a/libqdutils/qdMetaData.cpp b/libqdutils/qdMetaData.cpp
index 89ca92e..f39eef9 100644
--- a/libqdutils/qdMetaData.cpp
+++ b/libqdutils/qdMetaData.cpp
@@ -81,6 +81,26 @@
case UPDATE_BUFFER_GEOMETRY:
memcpy((void *)&data->bufferDim, param, sizeof(BufferDim_t));
break;
+ case PP_PARAM_VFM_DATA:
+ {
+ int32_t indx = 0;
+ VfmData_t* pVfmData = reinterpret_cast <VfmData_t *>(param);
+ int32_t dataType = pVfmData->dataType;
+
+ if(dataType > 0){
+ indx = getVfmDataIdx(dataType);
+ if(indx < MAX_VFM_DATA_COUNT){
+ data->vfmDataBitMap |= dataType;
+ memcpy((void *)&data->vfmData[indx], param,
+ sizeof(VfmData_t));
+ }else{
+ ALOGE("unknown dataType %d", dataType);
+ }
+ }else{
+ ALOGE("invalid dataType in PP_PARAM_VFM_DATA %d", dataType);
+ }
+ }
+ break;
default:
ALOGE("Unknown paramType %d", paramType);
break;
diff --git a/libqdutils/qdMetaData.h b/libqdutils/qdMetaData.h
index d5354a4..4b6e678 100644
--- a/libqdutils/qdMetaData.h
+++ b/libqdutils/qdMetaData.h
@@ -31,6 +31,19 @@
#define _QDMETADATA_H
#define MAX_IGC_LUT_ENTRIES 256
+#define MAX_VFM_DATA_SIZE 64 //bytes per data buffer
+#define MAX_VFM_DATA_COUNT 16 //number of data buffers
+
+/* This macro finds the index corresponding to a type */
+/* This is equivalent to indx = LOG_2(type) */
+inline int32_t getVfmDataIdx(int32_t type){
+ int32_t indx = 0, x = type;
+ while( x >> 1) {
+ x = (x >> 1);
+ indx++;
+ }
+ return indx;
+}
struct HSICData_t {
int32_t hue;
@@ -57,6 +70,11 @@
int32_t sliceHeight;
};
+struct VfmData_t {
+ int32_t dataType;
+ char data[MAX_VFM_DATA_SIZE];
+};
+
struct MetaData_t {
int32_t operation;
int32_t interlaced;
@@ -67,6 +85,8 @@
IGCData_t igcData;
Sharp2Data_t Sharp2Data;
int64_t timestamp;
+ int32_t vfmDataBitMap;
+ VfmData_t vfmData[MAX_VFM_DATA_COUNT];
};
typedef enum {
@@ -78,6 +98,7 @@
PP_PARAM_SHARP2 = 0x0020,
PP_PARAM_TIMESTAMP = 0x0040,
UPDATE_BUFFER_GEOMETRY = 0x0080,
+ PP_PARAM_VFM_DATA = 0x0100,
} DispParamType;
int setMetaData(private_handle_t *handle, DispParamType paramType, void *param);
diff --git a/libqservice/IQClient.cpp b/libqservice/IQClient.cpp
index 30fbb64..a6251c8 100644
--- a/libqservice/IQClient.cpp
+++ b/libqservice/IQClient.cpp
@@ -28,6 +28,9 @@
using namespace android;
// ---------------------------------------------------------------------------
+// XXX: Since qservice currently runs as part of hwc instead of a standalone
+// process, the implementation below is overridden and the notifyCallback in
+// hwc_qclient is directly called.
namespace qClient {
@@ -41,13 +44,17 @@
BpQClient(const sp<IBinder>& impl)
: BpInterface<IQClient>(impl) {}
- virtual status_t notifyCallback(uint32_t msg, uint32_t value) {
- Parcel data, reply;
+ virtual status_t notifyCallback(uint32_t command,
+ const Parcel* inParcel,
+ Parcel* outParcel) {
+ Parcel data;
+ Parcel *reply = outParcel;
data.writeInterfaceToken(IQClient::getInterfaceDescriptor());
- data.writeInt32(msg);
- data.writeInt32(value);
- remote()->transact(NOTIFY_CALLBACK, data, &reply);
- status_t result = reply.readInt32();
+ data.writeInt32(command);
+ if (inParcel->dataAvail())
+ data.appendFrom(inParcel, inParcel->dataPosition(),
+ inParcel->dataAvail());
+ status_t result = remote()->transact(NOTIFY_CALLBACK, data, reply);
return result;
}
};
@@ -55,21 +62,21 @@
IMPLEMENT_META_INTERFACE(QClient, "android.display.IQClient");
// ----------------------------------------------------------------------
-
+//Stub implementation - nothing needed here
status_t BnQClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case NOTIFY_CALLBACK: {
CHECK_INTERFACE(IQClient, data, reply);
- uint32_t msg = data.readInt32();
- uint32_t value = data.readInt32();
- notifyCallback(msg, value);
+ uint32_t command = data.readInt32();
+ notifyCallback(command, &data, reply);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
+
}
}; // namespace qClient
diff --git a/libqservice/IQClient.h b/libqservice/IQClient.h
index a28f826..7d816d2 100644
--- a/libqservice/IQClient.h
+++ b/libqservice/IQClient.h
@@ -33,7 +33,9 @@
{
public:
DECLARE_META_INTERFACE(QClient);
- virtual android::status_t notifyCallback(uint32_t msg, uint32_t value) = 0;
+ virtual android::status_t notifyCallback(uint32_t command,
+ const android::Parcel* inParcel,
+ android::Parcel* outParcel) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index 33f79c6..d2180bb 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -27,9 +27,10 @@
#include <binder/IPCThreadState.h>
#include <utils/Errors.h>
#include <private/android_filesystem_config.h>
-
#include <IQService.h>
+#define QSERVICE_DEBUG 0
+
using namespace android;
using namespace qClient;
@@ -43,56 +44,25 @@
BpQService(const sp<IBinder>& impl)
: BpInterface<IQService>(impl) {}
- virtual void securing(uint32_t startEnd) {
- Parcel data, reply;
- data.writeInterfaceToken(IQService::getInterfaceDescriptor());
- data.writeInt32(startEnd);
- remote()->transact(SECURING, data, &reply);
- }
-
- virtual void unsecuring(uint32_t startEnd) {
- Parcel data, reply;
- data.writeInterfaceToken(IQService::getInterfaceDescriptor());
- data.writeInt32(startEnd);
- remote()->transact(UNSECURING, data, &reply);
- }
-
virtual void connect(const sp<IQClient>& client) {
+ ALOGD_IF(QSERVICE_DEBUG, "%s: connect client", __FUNCTION__);
Parcel data, reply;
data.writeInterfaceToken(IQService::getInterfaceDescriptor());
data.writeStrongBinder(client->asBinder());
remote()->transact(CONNECT, data, &reply);
}
- virtual status_t screenRefresh() {
- Parcel data, reply;
+ virtual android::status_t dispatch(uint32_t command, const Parcel* inParcel,
+ Parcel* outParcel) {
+ ALOGD_IF(QSERVICE_DEBUG, "%s: dispatch in:%p", __FUNCTION__, inParcel);
+ status_t err = android::FAILED_TRANSACTION;
+ Parcel data;
+ Parcel *reply = outParcel;
data.writeInterfaceToken(IQService::getInterfaceDescriptor());
- remote()->transact(SCREEN_REFRESH, data, &reply);
- 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);
- }
-
- virtual void setBufferMirrorMode(uint32_t enable) {
- Parcel data, reply;
- data.writeInterfaceToken(IQService::getInterfaceDescriptor());
- data.writeInt32(enable);
- remote()->transact(BUFFER_MIRRORMODE, data, &reply);
- }
-
- virtual status_t vpuCommand(uint32_t command, uint32_t setting) {
- Parcel data, reply;
- data.writeInterfaceToken(IQService::getInterfaceDescriptor());
- data.writeInt32(setting);
- remote()->transact(command, data, &reply);
- status_t result = reply.readInt32();
- return result;
+ if (inParcel && inParcel->dataSize() > 0)
+ data.appendFrom(inParcel, 0, inParcel->dataSize());
+ err = remote()->transact(command, data, reply);
+ return err;
}
};
@@ -105,7 +75,8 @@
status_t BnQService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
- // IPC should be from mediaserver only
+ ALOGD_IF(QSERVICE_DEBUG, "%s: code: %d", __FUNCTION__, code);
+ // IPC should be from certain processes only
IPCThreadState* ipc = IPCThreadState::self();
const int callerPid = ipc->getCallingPid();
const int callerUid = ipc->getCallingUid();
@@ -114,94 +85,35 @@
getProcName(callerPid, callingProcName, MAX_BUF_SIZE);
- const bool permission = (callerUid == AID_MEDIA);
+ const bool permission = (callerUid == AID_MEDIA ||
+ callerUid == AID_GRAPHICS ||
+ callerUid == AID_ROOT ||
+ callerUid == AID_SYSTEM);
- if (code > VPU_COMMAND_LIST_START && code < VPU_COMMAND_LIST_END) {
- if(callerUid != AID_SYSTEM && callerUid != AID_ROOT) {
- ALOGE("display.qservice VPU command access denied: \
- pid=%d uid=%d process=%s",callerPid,
+ if (code == CONNECT) {
+ CHECK_INTERFACE(IQService, data, reply);
+ if(callerUid != AID_GRAPHICS) {
+ ALOGE("display.qservice CONNECT access denied: \
+ pid=%d uid=%d process=%s",
+ callerPid, callerUid, callingProcName);
+ return PERMISSION_DENIED;
+ }
+ sp<IQClient> client =
+ interface_cast<IQClient>(data.readStrongBinder());
+ connect(client);
+ return NO_ERROR;
+ } else if (code > COMMAND_LIST_START && code < COMMAND_LIST_END) {
+ if(!permission) {
+ ALOGE("display.qservice access denied: command=%d\
+ pid=%d uid=%d process=%s", code, callerPid,
callerUid, callingProcName);
return PERMISSION_DENIED;
}
CHECK_INTERFACE(IQService, data, reply);
- int32_t setting = data.readInt32();
- return vpuCommand(code, setting);
- }
-
- switch(code) {
- case SECURING: {
- if(!permission) {
- ALOGE("display.qservice SECURING access denied: \
- pid=%d uid=%d process=%s",
- callerPid, callerUid, callingProcName);
- return PERMISSION_DENIED;
- }
- CHECK_INTERFACE(IQService, data, reply);
- uint32_t startEnd = data.readInt32();
- securing(startEnd);
- return NO_ERROR;
- } break;
- case UNSECURING: {
- if(!permission) {
- ALOGE("display.qservice UNSECURING access denied: \
- pid=%d uid=%d process=%s",
- callerPid, callerUid, callingProcName);
- return PERMISSION_DENIED;
- }
- CHECK_INTERFACE(IQService, data, reply);
- uint32_t startEnd = data.readInt32();
- unsecuring(startEnd);
- return NO_ERROR;
- } break;
- case CONNECT: {
- CHECK_INTERFACE(IQService, data, reply);
- if(callerUid != AID_GRAPHICS) {
- ALOGE("display.qservice CONNECT access denied: \
- pid=%d uid=%d process=%s",
- callerPid, callerUid, callingProcName);
- return PERMISSION_DENIED;
- }
- sp<IQClient> client =
- interface_cast<IQClient>(data.readStrongBinder());
- connect(client);
- return NO_ERROR;
- } break;
- case SCREEN_REFRESH: {
- CHECK_INTERFACE(IQService, data, reply);
- if(callerUid != AID_SYSTEM) {
- ALOGE("display.qservice SCREEN_REFRESH access denied: \
- pid=%d uid=%d process=%s",callerPid,
- callerUid, callingProcName);
- return PERMISSION_DENIED;
- }
- return screenRefresh();
- } break;
- case EXTERNAL_ORIENTATION: {
- CHECK_INTERFACE(IQService, data, reply);
- if(callerUid != AID_SYSTEM) {
- ALOGE("display.qservice EXTERNAL_ORIENTATION access denied: \
- pid=%d uid=%d process=%s",callerPid,
- callerUid, callingProcName);
- return PERMISSION_DENIED;
- }
- uint32_t orientation = data.readInt32();
- setExtOrientation(orientation);
- return NO_ERROR;
- } break;
- case BUFFER_MIRRORMODE: {
- CHECK_INTERFACE(IQService, data, reply);
- if(callerUid != AID_SYSTEM) {
- ALOGE("display.qservice BUFFER_MIRRORMODE access denied: \
- pid=%d uid=%d process=%s",callerPid,
- callerUid, callingProcName);
- return PERMISSION_DENIED;
- }
- uint32_t enable = data.readInt32();
- setBufferMirrorMode(enable);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
+ dispatch(code, &data, reply);
+ return NO_ERROR;
+ } else {
+ return BBinder::onTransact(code, data, reply, flags);
}
}
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 9cd122e..7ad443d 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -29,35 +29,39 @@
#include <binder/IBinder.h>
#include <IQClient.h>
+
namespace qService {
// ----------------------------------------------------------------------------
+
class IQService : public android::IInterface
{
public:
DECLARE_META_INTERFACE(QService);
enum {
- // Hardware securing start/end notification
- SECURING = android::IBinder::FIRST_CALL_TRANSACTION,
- UNSECURING, // Hardware unsecuring start/end notification
- CONNECT,
- SCREEN_REFRESH,
- EXTERNAL_ORIENTATION,
- BUFFER_MIRRORMODE,
- //VPU command codes - list is defined in vpu.h
- VPU_COMMAND_LIST_START = 100,
- VPU_COMMAND_LIST_END = 200,
+ COMMAND_LIST_START = android::IBinder::FIRST_CALL_TRANSACTION,
+ SECURING, // Hardware securing start/end notification
+ UNSECURING, // Hardware unsecuring start/end notification
+ CONNECT, // Connect to qservice
+ SCREEN_REFRESH, // Refresh screen through SF invalidate
+ EXTERNAL_ORIENTATION, // Set external orientation
+ BUFFER_MIRRORMODE, // Buffer mirrormode
+ VPU_COMMAND_LIST_START = 100, //Reserved block for VPU commands
+ VPU_COMMAND_LIST_END = 200,
+ COMMAND_LIST_END = 400,
};
+
enum {
END = 0,
START,
};
- virtual void securing(uint32_t startEnd) = 0;
- virtual void unsecuring(uint32_t startEnd) = 0;
+
+ // Register a client that can be notified
virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
- virtual android::status_t screenRefresh() = 0;
- virtual void setExtOrientation(uint32_t orientation) = 0;
- virtual void setBufferMirrorMode(uint32_t enable) = 0;
- virtual android::status_t vpuCommand(uint32_t command, uint32_t setting) = 0;
+ // Generic function to dispatch binder commands
+ // The type of command decides how the data is parceled
+ virtual android::status_t dispatch(uint32_t command,
+ const android::Parcel* inParcel,
+ android::Parcel* outParcel) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index 327888c..aac5788 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -47,49 +47,19 @@
ALOGD_IF(QSERVICE_DEBUG,"QService Destructor invoked");
}
-void QService::securing(uint32_t startEnd) {
- if(mClient.get()) {
- mClient->notifyCallback(SECURING, startEnd);
- }
-}
-
-void QService::unsecuring(uint32_t startEnd) {
- if(mClient.get()) {
- mClient->notifyCallback(UNSECURING, startEnd);
- }
-}
-
void QService::connect(const sp<qClient::IQClient>& client) {
+ ALOGD_IF(QSERVICE_DEBUG,"client connected");
mClient = client;
}
-android::status_t QService::screenRefresh() {
- status_t result = NO_ERROR;
- if(mClient.get()) {
- result = mClient->notifyCallback(SCREEN_REFRESH, 0);
+status_t QService::dispatch(uint32_t command, const Parcel* inParcel,
+ Parcel* outParcel) {
+ status_t err = FAILED_TRANSACTION;
+ if (mClient.get()) {
+ ALOGD_IF(QSERVICE_DEBUG, "Dispatching command: %d", command);
+ err = mClient->notifyCallback(command, inParcel, outParcel);
}
- return result;
-}
-
-android::status_t QService::vpuCommand(uint32_t command, uint32_t setting ) {
- status_t result = NO_ERROR;
- if(mClient.get()) {
- result = mClient->notifyCallback(command, setting);
- }
- return result;
-}
-
-
-void QService::setExtOrientation(uint32_t orientation) {
- if(mClient.get()) {
- mClient->notifyCallback(EXTERNAL_ORIENTATION, orientation);
- }
-}
-
-void QService::setBufferMirrorMode(uint32_t enable) {
- if(mClient.get()) {
- mClient->notifyCallback(BUFFER_MIRRORMODE, enable);
- }
+ return err;
}
void QService::init()
diff --git a/libqservice/QService.h b/libqservice/QService.h
index de18b59..a8e4cdb 100644
--- a/libqservice/QService.h
+++ b/libqservice/QService.h
@@ -45,13 +45,10 @@
class QService : public BnQService {
public:
virtual ~QService();
- virtual void securing(uint32_t startEnd);
- 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);
- virtual void setBufferMirrorMode(uint32_t enable);
- virtual android::status_t vpuCommand(uint32_t command, uint32_t setting);
+ virtual android::status_t dispatch(uint32_t command,
+ const android::Parcel* data,
+ android::Parcel* reply);
static void init();
private:
QService();
diff --git a/libqservice/QServiceUtils.h b/libqservice/QServiceUtils.h
new file mode 100644
index 0000000..3d1adc0
--- /dev/null
+++ b/libqservice/QServiceUtils.h
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2013 The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation. nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef QSERVICEUTILS_H
+#define QSERVICEUTILS_H
+#include <binder/Parcel.h>
+#include <binder/IServiceManager.h>
+#include <utils/RefBase.h>
+#include <IQService.h>
+
+// ----------------------------------------------------------------------------
+// Helpers
+// ----------------------------------------------------------------------------
+inline android::sp<qService::IQService> getBinder() {
+ android::sp<android::IServiceManager> sm = android::defaultServiceManager();
+ android::sp<qService::IQService> binder =
+ android::interface_cast<qService::IQService>
+ (sm->getService(android::String16("display.qservice")));
+ if (binder == NULL) {
+ ALOGE("%s: invalid binder object", __FUNCTION__);
+ }
+ return binder;
+}
+
+inline android::status_t sendSingleParam(uint32_t command, uint32_t value) {
+ android::status_t err = android::FAILED_TRANSACTION;
+ android::sp<qService::IQService> binder = getBinder();
+ android::Parcel inParcel, outParcel;
+ inParcel.writeInt32(value);
+ if(binder != NULL) {
+ err = binder->dispatch(command, &inParcel , &outParcel);
+ }
+ return err;
+}
+
+// ----------------------------------------------------------------------------
+// Convenience wrappers that clients can call
+// ----------------------------------------------------------------------------
+inline android::status_t securing(uint32_t startEnd) {
+ return sendSingleParam(qService::IQService::SECURING, startEnd);
+}
+
+inline android::status_t unsecuring(uint32_t startEnd) {
+ return sendSingleParam(qService::IQService::UNSECURING, startEnd);
+}
+
+inline android::status_t screenRefresh() {
+ return sendSingleParam(qService::IQService::SCREEN_REFRESH, 1);
+}
+
+inline android::status_t setExtOrientation(uint32_t orientation) {
+ return sendSingleParam(qService::IQService::EXTERNAL_ORIENTATION,
+ orientation);
+}
+
+inline android::status_t setBufferMirrorMode(uint32_t enable) {
+ return sendSingleParam(qService::IQService::BUFFER_MIRRORMODE, enable);
+}
+
+#endif /* end of include guard: QSERVICEUTILS_H */