Merge "hwc: Set GPU Hint from idlefallback state to GPU"
diff --git a/common.mk b/common.mk
index 01cdd3f..774050e 100644
--- a/common.mk
+++ b/common.mk
@@ -28,7 +28,7 @@
endif
ifeq ($(call is-board-platform-in-list, msm8974 msm8226 msm8610 apq8084 \
- mpq8092 msm_bronze msm8916), true)
+ mpq8092 msm_bronze msm8916 msm8994), true)
common_flags += -DVENUS_COLOR_FORMAT
common_flags += -DMDSS_TARGET
endif
diff --git a/libcopybit/Android.mk b/libcopybit/Android.mk
index 2ac7d15..c239c3a 100644
--- a/libcopybit/Android.mk
+++ b/libcopybit/Android.mk
@@ -22,7 +22,7 @@
include $(BUILD_COPY_HEADERS)
LOCAL_MODULE := copybit.$(TARGET_BOARD_PLATFORM)
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
LOCAL_SHARED_LIBRARIES := $(common_libs) libdl libmemalloc
diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp
index 771d483..7e2c500 100644
--- a/libcopybit/copybit_c2d.cpp
+++ b/libcopybit/copybit_c2d.cpp
@@ -257,7 +257,8 @@
static int get_format(int format) {
switch (format) {
case HAL_PIXEL_FORMAT_RGB_565: return C2D_COLOR_FORMAT_565_RGB;
- case HAL_PIXEL_FORMAT_RGB_888: return C2D_COLOR_FORMAT_888_RGB;
+ case HAL_PIXEL_FORMAT_RGB_888: return C2D_COLOR_FORMAT_888_RGB |
+ C2D_FORMAT_SWAP_RB;
case HAL_PIXEL_FORMAT_RGBX_8888: return C2D_COLOR_FORMAT_8888_ARGB |
C2D_FORMAT_SWAP_RB |
C2D_FORMAT_DISABLE_ALPHA;
diff --git a/libexternal/Android.mk b/libexternal/Android.mk
index 3df6984..05e42d4 100644
--- a/libexternal/Android.mk
+++ b/libexternal/Android.mk
@@ -3,7 +3,6 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libexternal
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
LOCAL_SHARED_LIBRARIES := $(common_libs) liboverlay libqdutils
diff --git a/libgralloc/Android.mk b/libgralloc/Android.mk
index 18beaf2..412f1be 100644
--- a/libgralloc/Android.mk
+++ b/libgralloc/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM)
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
LOCAL_SHARED_LIBRARIES := $(common_libs) libmemalloc libqdMetaData
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 6af0eea..7255391 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -181,6 +181,7 @@
} else {
switch (format)
{
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
case HAL_PIXEL_FORMAT_RAW_SENSOR:
aligned_w = ALIGN(width, 32);
@@ -189,7 +190,6 @@
aligned_w = ALIGN(width, 128);
break;
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
- case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YV12:
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_422_SP:
@@ -566,8 +566,7 @@
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: //Same as YCbCr_420_SP_VENUS
- ystride = hnd->width;
- cstride = hnd->width/2;
+ ystride = cstride = hnd->width;
ycbcr->y = (void*)hnd->base;
ycbcr->cb = (void*)(hnd->base + ystride * hnd->height);
ycbcr->cr = (void*)(hnd->base + ystride * hnd->height + 1);
@@ -581,8 +580,7 @@
case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
case HAL_PIXEL_FORMAT_NV21_ZSL:
case HAL_PIXEL_FORMAT_RAW_SENSOR:
- ystride = hnd->width;
- cstride = hnd->width/2;
+ ystride = cstride = hnd->width;
ycbcr->y = (void*)hnd->base;
ycbcr->cr = (void*)(hnd->base + ystride * hnd->height);
ycbcr->cb = (void*)(hnd->base + ystride * hnd->height + 1);
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index 0cba07a..78e875a 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -69,7 +69,8 @@
/* force 1MB alignment selectively for secure buffers, MDP5 onwards */
#ifdef MDSS_TARGET
- if (usage & GRALLOC_USAGE_PROTECTED) {
+ if ((usage & GRALLOC_USAGE_PROTECTED) &&
+ (usage & GRALLOC_USAGE_PRIVATE_MM_HEAP)) {
data.align = ALIGN((int) data.align, SZ_1M);
size = ALIGN(size, data.align);
}
diff --git a/libgralloc/ionalloc.cpp b/libgralloc/ionalloc.cpp
index e6d34f8..2097320 100644
--- a/libgralloc/ionalloc.cpp
+++ b/libgralloc/ionalloc.cpp
@@ -73,11 +73,7 @@
ionAllocData.len = data.size;
ionAllocData.align = data.align;
-#ifdef QCOM_BSP
- ionAllocData.heap_mask = data.flags & ~ION_SECURE;
-#else
ionAllocData.heap_id_mask = data.flags & ~ION_SECURE;
-#endif
ionAllocData.flags = data.uncached ? 0 : ION_FLAG_CACHED;
// ToDo: replace usage of alloc data structure with
// ionallocdata structure.
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index 7dadfe4..ef7778b 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -3,7 +3,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) \
$(TOP)/external/skia/include/core \
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index e5c7ce7..b2466d0 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -214,6 +214,8 @@
}
+ if(ctx->mMDPComp[i])
+ ctx->mMDPComp[i]->reset();
if(ctx->mFBUpdate[i])
ctx->mFBUpdate[i]->reset();
if(ctx->mCopyBit[i])
@@ -223,7 +225,6 @@
}
ctx->mAD->reset();
- MDPComp::reset();
if(ctx->mHWCVirtual)
ctx->mHWCVirtual->destroy(ctx, numDisplays, displays);
}
@@ -424,7 +425,11 @@
ctx->mOverlay->configBegin();
ctx->mOverlay->configDone();
ctx->mRotMgr->clear();
- overlay::Writeback::clear();
+ // If VDS is connected, do not clear WB object as it
+ // will end up detaching IOMMU. This is required
+ // to send black frame to WFD sink on power suspend.
+ // Note: With this change, we keep the WriteBack object
+ // alive on power suspend for AD use case.
}
switch(dpy) {
case HWC_DISPLAY_PRIMARY:
@@ -478,13 +483,6 @@
ret = -1;
}
}
- value = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK;
- if(ioctl(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].fd, FBIOBLANK, value) < 0
- ) {
- ALOGE("%s: Failed to handle blank event(%d) for virtual!!",
- __FUNCTION__, blank );
- return -1;
- }
ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
}
break;
@@ -580,8 +578,14 @@
hwc_layer_1_t *fbLayer = &list->hwLayers[last];
int fd = -1; //FenceFD from the Copybit(valid in async mode)
bool copybitDone = false;
- if(ctx->mCopyBit[dpy])
- copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
+
+ if (ctx->mCopyBit[dpy]) {
+ if (ctx->mMDP.version < qdutils::MDP_V4_0)
+ copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
+ else
+ fd = ctx->mMDPComp[dpy]->drawOverlap(ctx, list);
+ }
+
if(list->numHwLayers > 1)
hwc_sync(ctx, list, dpy, fd);
@@ -601,6 +605,12 @@
hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
}
+ if(isAbcInUse(ctx) == true) {
+ int index = ctx->listStats[dpy].renderBufIndexforABC;
+ hwc_layer_1_t *tempLayer = &list->hwLayers[index];
+ hnd = (private_handle_t *)tempLayer->handle;
+ }
+
if(hnd) {
if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
ALOGE("%s: FBUpdate draw failed", __FUNCTION__);
@@ -825,7 +835,7 @@
dumpsys_log(aBuf, " DisplayPanel=%c\n", ctx->mMDP.panel);
for(int dpy = 0; dpy < HWC_NUM_DISPLAY_TYPES; dpy++) {
if(ctx->mMDPComp[dpy])
- ctx->mMDPComp[dpy]->dump(aBuf);
+ ctx->mMDPComp[dpy]->dump(aBuf, ctx);
}
char ovDump[2048] = {'\0'};
ctx->mOverlay->getDump(ovDump, 2048);
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index f379cf8..f703fa0 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -208,6 +208,46 @@
return -1;
}
+bool CopyBit::prepareOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int overlapIndex) {
+
+ if (ctx->mMDP.version < qdutils::MDP_V4_0) {
+ ALOGE("%s: Invalid request", __FUNCTION__);
+ return false;
+ }
+
+ if (mEngine == NULL || !(validateParams(ctx, list))) {
+ ALOGE("%s: Invalid Params", __FUNCTION__);
+ return false;
+ }
+
+ //Allocate render buffers if they're not allocated
+ hwc_rect_t overlap = list->hwLayers[overlapIndex].displayFrame;
+ int width = overlap.right - overlap.left;
+ int height = overlap.bottom - overlap.top;
+ int alignW, alignH;
+
+ getBufferSizeAndDimensions(width, height, HAL_PIXEL_FORMAT_RGBA_8888,
+ alignW, alignH);
+
+ if ((mAlignedWidth != alignW) || (mAlignedHeight != alignH)) {
+ // Overlap rect has changed, so free render buffers
+ freeRenderBuffers();
+ }
+
+ int ret = allocRenderBuffers(alignW, alignH, HAL_PIXEL_FORMAT_RGBA_8888);
+
+ if (ret < 0) {
+ ALOGE("%s: Render buffer allocation failed", __FUNCTION__);
+ return false;
+ }
+
+ mAlignedWidth = alignW;
+ mAlignedHeight = alignH;
+ mCurRenderBufferIndex = (mCurRenderBufferIndex + 1) % NUM_RENDER_BUFFERS;
+ return true;
+}
+
bool CopyBit::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy) {
@@ -286,8 +326,8 @@
//Allocate render buffers if they're not allocated
if (ctx->mMDP.version != qdutils::MDP_V3_0_4 &&
(useCopybitForYUV || useCopybitForRGB)) {
- int ret = allocRenderBuffers(mAlignedFBWidth,
- mAlignedFBHeight,
+ int ret = allocRenderBuffers(mAlignedWidth,
+ mAlignedHeight,
HAL_PIXEL_FORMAT_RGBA_8888);
if (ret < 0) {
return false;
@@ -340,8 +380,70 @@
return ret;
}
-bool CopyBit::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list,
- int dpy, int32_t *fd) {
+bool CopyBit::drawUsingAppBufferComposition(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list,
+ int dpy, int *copybitFd) {
+ int layerCount = 0;
+ uint32_t last = list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+ private_handle_t *fbhnd = (private_handle_t *)fbLayer->handle;
+
+ if(ctx->enableABC == false)
+ return false;
+
+ if(ctx->listStats[dpy].numAppLayers > MAX_LAYERS_FOR_ABC )
+ return false;
+
+ layerCount = ctx->listStats[dpy].numAppLayers;
+ //bottom most layer should
+ //equal to FB
+ hwc_layer_1_t *tmpLayer = &list->hwLayers[0];
+ private_handle_t *hnd = (private_handle_t *)tmpLayer->handle;
+ if(hnd && fbhnd && (hnd->size == fbhnd->size) &&
+ (hnd->width == fbhnd->width) && (hnd->height == fbhnd->height)){
+ if(tmpLayer->transform ||
+ (!(hnd->format == HAL_PIXEL_FORMAT_RGBA_8888 ||
+ hnd->format == HAL_PIXEL_FORMAT_RGBX_8888)) ||
+ (needsScaling(tmpLayer) == true)) {
+ return false;
+ }else {
+ ctx->listStats[dpy].renderBufIndexforABC = 0;
+ }
+ }
+
+ if(ctx->listStats[dpy].renderBufIndexforABC == 0) {
+ if(layerCount == 1)
+ return true;
+
+ if(layerCount == MAX_LAYERS_FOR_ABC) {
+ // Pass the Acquire Fence FD to driver for base layer
+ int abcRenderBufIdx = ctx->listStats[dpy].renderBufIndexforABC;
+ private_handle_t *renderBuffer =
+ (private_handle_t *)list->hwLayers[abcRenderBufIdx].handle;
+ copybit_device_t *copybit = getCopyBitDevice();
+ if(list->hwLayers[abcRenderBufIdx].acquireFenceFd >=0){
+ copybit->set_sync(copybit,
+ list->hwLayers[abcRenderBufIdx].acquireFenceFd);
+ }
+ for(int i = 1; i < layerCount; i++){
+ int retVal = drawLayerUsingCopybit(ctx,
+ &(list->hwLayers[i]),renderBuffer, 0);
+ if(retVal < 0) {
+ ALOGE("%s : Copybit failed", __FUNCTION__);
+ }
+ }
+ // Get Release Fence FD of copybit for the App layer(s)
+ copybit->flush_get_fence(copybit, copybitFd);
+ close(list->hwLayers[abcRenderBufIdx].acquireFenceFd);
+ list->hwLayers[abcRenderBufIdx].acquireFenceFd = -1;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CopyBit::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy, int32_t *fd) {
// draw layers marked for COPYBIT
int retVal = true;
int copybitLayerCount = 0;
@@ -353,6 +455,10 @@
mFbCache.reset(); // there is no layer marked for copybit
return false ;
}
+
+ if(drawUsingAppBufferComposition(ctx, list, dpy, fd)) {
+ return true;
+ }
//render buffer
if (ctx->mMDP.version == qdutils::MDP_V3_0_4) {
last = (uint32_t)list->numHwLayers - 1;
@@ -436,6 +542,132 @@
return true;
}
+int CopyBit::drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int overlapIndex) {
+ int fd = -1;
+
+ if (ctx->mMDP.version < qdutils::MDP_V4_0) {
+ ALOGE("%s: Invalid request", __FUNCTION__);
+ return fd;
+ }
+
+ private_handle_t *renderBuffer = getCurrentRenderBuffer();
+
+ if (!renderBuffer) {
+ ALOGE("%s: Render buffer layer handle is NULL", __FUNCTION__);
+ return fd;
+ }
+
+ int copybitLayerCount = 0;
+ hwc_rect_t overlap = list->hwLayers[overlapIndex].displayFrame;
+
+ // Draw overlapped content of layers on render buffer
+ for (int i = 0; i <= overlapIndex; i++) {
+
+ int ret = -1;
+ if ((list->hwLayers[i].acquireFenceFd != -1)) {
+ // Wait for acquire fence on the App buffers.
+ ret = sync_wait(list->hwLayers[i].acquireFenceFd, 1000);
+ if (ret < 0) {
+ ALOGE("%s: sync_wait error!! error no = %d err str = %s",
+ __FUNCTION__, errno, strerror(errno));
+ }
+ close(list->hwLayers[i].acquireFenceFd);
+ list->hwLayers[i].acquireFenceFd = -1;
+ }
+
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ int retVal = drawRectUsingCopybit(ctx, layer, renderBuffer, overlap);
+ copybitLayerCount++;
+
+ if(retVal < 0) {
+ ALOGE("%s: drawRectUsingCopybit failed", __FUNCTION__);
+ copybitLayerCount = 0;
+ }
+ }
+
+ if (copybitLayerCount) {
+ copybit_device_t *copybit = getCopyBitDevice();
+ copybit->flush_get_fence(copybit, &fd);
+ }
+
+ ALOGD_IF(DEBUG_COPYBIT, "%s: done!", __FUNCTION__);
+ return fd;
+}
+
+int CopyBit::drawRectUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
+ private_handle_t *renderBuffer, hwc_rect_t rect)
+{
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ if (!ctx) {
+ ALOGE("%s: null context ", __FUNCTION__);
+ return -1;
+ }
+
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if (!hnd) {
+ ALOGE("%s: invalid handle", __FUNCTION__);
+ return -1;
+ }
+
+ private_handle_t *dstHandle = (private_handle_t *)renderBuffer;
+ if (!dstHandle) {
+ ALOGE("%s: RenderBuffer handle is NULL", __FUNCTION__);
+ return -1;
+ }
+
+ // Set the Copybit Source
+ copybit_image_t src;
+ src.handle = (native_handle_t *)layer->handle;
+ src.w = hnd->width;
+ src.h = hnd->height;
+ src.base = (void *)hnd->base;
+ src.format = hnd->format;
+ src.horiz_padding = 0;
+ src.vert_padding = 0;
+
+ hwc_rect_t dispFrame = layer->displayFrame;
+ hwc_rect_t iRect = getIntersection(dispFrame, rect);
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ qhwc::calculate_crop_rects(crop, dispFrame, iRect, layer->transform);
+
+ // Copybit source rect
+ copybit_rect_t srcRect = {crop.left, crop.top, crop.right, crop.bottom};
+
+ // Copybit destination rect
+ copybit_rect_t dstRect = {rect.left, rect.top, rect.right, rect.bottom};
+
+ // Copybit dst
+ copybit_image_t dst;
+ dst.handle = (native_handle_t *)dstHandle;
+ dst.w = ALIGN(dstHandle->width, 32);
+ dst.h = dstHandle->height;
+ dst.base = (void *)dstHandle->base;
+ dst.format = dstHandle->format;
+
+ copybit_device_t *copybit = mEngine;
+
+ // Copybit region
+ hwc_region_t region = layer->visibleRegionScreen;
+ region_iterator copybitRegion(region);
+ int acquireFd = layer->acquireFenceFd;
+
+ copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH, renderBuffer->width);
+ copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT, renderBuffer->height);
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, layer->transform);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, layer->planeAlpha);
+ copybit->set_parameter(copybit, COPYBIT_BLEND_MODE, layer->blending);
+ copybit->set_parameter(copybit, COPYBIT_DITHER,
+ (dst.format == HAL_PIXEL_FORMAT_RGB_565) ? COPYBIT_ENABLE : COPYBIT_DISABLE);
+ copybit->set_sync(copybit, acquireFd);
+ int err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect, ©bitRegion);
+
+ if (err < 0)
+ ALOGE("%s: copybit stretch failed",__FUNCTION__);
+
+ return err;
+}
+
int CopyBit::drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
private_handle_t *renderBuffer, bool isFG)
{
@@ -806,6 +1038,18 @@
mRelFd[mCurRenderBufferIndex] = dup(fd);
}
+void CopyBit::setReleaseFdSync(int fd) {
+ if (mRelFd[mCurRenderBufferIndex] >=0) {
+ int ret = -1;
+ ret = sync_wait(mRelFd[mCurRenderBufferIndex], 1000);
+ if (ret < 0)
+ ALOGE("%s: sync_wait error! errno = %d, err str = %s",
+ __FUNCTION__, errno, strerror(errno));
+ close(mRelFd[mCurRenderBufferIndex]);
+ }
+ mRelFd[mCurRenderBufferIndex] = dup(fd);
+}
+
struct copybit_device_t* CopyBit::getCopyBitDevice() {
return mEngine;
}
@@ -816,8 +1060,8 @@
getBufferSizeAndDimensions(ctx->dpyAttr[dpy].xres,
ctx->dpyAttr[dpy].yres,
HAL_PIXEL_FORMAT_RGBA_8888,
- mAlignedFBWidth,
- mAlignedFBHeight);
+ mAlignedWidth,
+ mAlignedHeight);
hw_module_t const *module;
for (int i = 0; i < NUM_RENDER_BUFFERS; i++) {
diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h
index 14f8cfc..3d3d302 100644
--- a/libhwcomposer/hwc_copybit.h
+++ b/libhwcomposer/hwc_copybit.h
@@ -27,7 +27,7 @@
//twice
#define MAX_SCALE_FACTOR 16
#define MIN_SCALE_FACTOR 0.0625
-
+#define MAX_LAYERS_FOR_ABC 2
namespace qhwc {
class CopyBit {
@@ -49,6 +49,14 @@
void setReleaseFd(int fd);
+ void setReleaseFdSync(int fd);
+
+ bool prepareOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int overlapIndex);
+
+ int drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int overlapIndex);
+
private:
/* cached data */
struct LayerCache {
@@ -73,9 +81,14 @@
// holds the copybit device
struct copybit_device_t *mEngine;
+ bool drawUsingAppBufferComposition(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list,
+ int dpy, int *fd);
// Helper functions for copybit composition
int drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
private_handle_t *renderBuffer, bool isFG);
+ int drawRectUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
+ private_handle_t *renderBuffer, hwc_rect_t rect);
int fillColorUsingCopybit(hwc_layer_1_t *layer,
private_handle_t *renderBuffer);
bool canUseCopybitForYUV (hwc_context_t *ctx);
@@ -111,8 +124,8 @@
//Dynamic composition threshold for deciding copybit usage.
double mDynThreshold;
bool mSwapRectEnable;
- int mAlignedFBWidth;
- int mAlignedFBHeight;
+ int mAlignedWidth;
+ int mAlignedHeight;
int mDirtyLayerIndex;
LayerCache mLayerCache;
FbCache mFbCache;
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index ae29f8f..59f6245 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -275,8 +275,8 @@
__FUNCTION__);
return false;
}
- ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder);
+ ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
return mModeOn;
}
@@ -474,9 +474,18 @@
ovutils::eDest destR = ovutils::OV_INVALID;
- //Request right pipe (2 pipes needed only if dim > 2048)
- if((fbUpdatingRect.right - fbUpdatingRect.left) >
- qdutils::MAX_DISPLAY_DIM) {
+ /* Use 2 pipes IF
+ a) FB's width is > 2048 or
+ b) On primary, driver has indicated with caps to split always. This is
+ based on an empirically derived value of panel height.
+ */
+
+ bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
+ qdutils::MDPVersion::getInstance().isSrcSplitAlways();
+
+ if(((fbUpdatingRect.right - fbUpdatingRect.left) >
+ qdutils::MAX_DISPLAY_DIM) or
+ primarySplitAlways) {
destR = ov.getPipe(pipeSpecs);
if(destR == ovutils::OV_INVALID) {
ALOGE("%s: No pipes available to configure fb for dpy %d's right"
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 06e0b12..cf68a3a 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -26,6 +26,7 @@
#include "hwc_fbupdate.h"
#include "hwc_ad.h"
#include <overlayRotator.h>
+#include "hwc_copybit.h"
using namespace overlay;
using namespace qdutils;
@@ -58,7 +59,7 @@
MDPComp::MDPComp(int dpy):mDpy(dpy){};
-void MDPComp::dump(android::String8& buf)
+void MDPComp::dump(android::String8& buf, hwc_context_t *ctx)
{
if(mCurrentFrame.layerCount > MAX_NUM_APP_LAYERS)
return;
@@ -72,6 +73,21 @@
dumpsys_log(buf,"needsFBRedraw:%3s pipesUsed:%2d MaxPipesPerMixer: %d \n",
(mCurrentFrame.needsRedraw? "YES" : "NO"),
mCurrentFrame.mdpCount, sMaxPipesPerMixer);
+ if(isDisplaySplit(ctx, mDpy)) {
+ dumpsys_log(buf, "Programmed ROI's: Left: [%d, %d, %d, %d] "
+ "Right: [%d, %d, %d, %d] \n",
+ ctx->listStats[mDpy].lRoi.left, ctx->listStats[mDpy].lRoi.top,
+ ctx->listStats[mDpy].lRoi.right,
+ ctx->listStats[mDpy].lRoi.bottom,
+ ctx->listStats[mDpy].rRoi.left,ctx->listStats[mDpy].rRoi.top,
+ ctx->listStats[mDpy].rRoi.right,
+ ctx->listStats[mDpy].rRoi.bottom);
+ } else {
+ dumpsys_log(buf, "Programmed ROI: [%d, %d, %d, %d] \n",
+ ctx->listStats[mDpy].lRoi.left,ctx->listStats[mDpy].lRoi.top,
+ ctx->listStats[mDpy].lRoi.right,
+ ctx->listStats[mDpy].lRoi.bottom);
+ }
dumpsys_log(buf," --------------------------------------------- \n");
dumpsys_log(buf," listIdx | cached? | mdpIndex | comptype | Z \n");
dumpsys_log(buf," --------------------------------------------- \n");
@@ -144,11 +160,20 @@
}
}
- if((property_get("debug.mdpcomp.4k2kSplit", property, "0") > 0) &&
- (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
- (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ if(!qdutils::MDPVersion::getInstance().isSrcSplit() &&
+ property_get("persist.mdpcomp.4k2kSplit", property, "0") > 0 &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX) ||
+ !strncasecmp(property,"true", PROPERTY_VALUE_MAX))) {
sEnable4k2kYUVSplit = true;
}
+
+ if ((property_get("persist.hwc.ptor.enable", property, NULL) > 0) &&
+ ((!strncasecmp(property, "true", PROPERTY_VALUE_MAX )) ||
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX )))) {
+ ctx->mCopyBit[HWC_DISPLAY_PRIMARY] = new CopyBit(ctx,
+ HWC_DISPLAY_PRIMARY);
+ }
+
return true;
}
@@ -159,6 +184,11 @@
ctx->mLayerRotMap[mDpy]->clear();
}
+void MDPComp::reset() {
+ sHandleTimeout = false;
+ mModeOn = false;
+}
+
void MDPComp::timeout_handler(void *udata) {
struct hwc_context_t* ctx = (struct hwc_context_t*)(udata);
@@ -473,11 +503,17 @@
hwc_layer_1_t* layer = &list->hwLayers[index];
if ((mCachedFrame.hnd[index] != layer->handle) ||
isYuvBuffer((private_handle_t *)layer->handle)) {
- hwc_rect_t updatingRect = layer->displayFrame;
+ hwc_rect_t dst = layer->displayFrame;
+ hwc_rect_t updatingRect = dst;
#ifdef QCOM_BSP
if(!needsScaling(layer) && !layer->transform)
- updatingRect = layer->dirtyRect;
+ {
+ hwc_rect_t src = integerizeSourceCrop(layer->sourceCropf);
+ int x_off = dst.left - src.left;
+ int y_off = dst.top - src.top;
+ updatingRect = moveRect(layer->dirtyRect, x_off, y_off);
+ }
#endif
roi = getUnion(roi, updatingRect);
@@ -703,6 +739,8 @@
bool ret = false;
if(fullMDPComp(ctx, list)) {
ret = true;
+ } else if(fullMDPCompWithPTOR(ctx, list)) {
+ ret = true;
} else if(partialMDPComp(ctx, list)) {
ret = true;
}
@@ -752,6 +790,136 @@
return true;
}
+/* Full MDP Composition with Peripheral Tiny Overlap Removal.
+ * MDP bandwidth limitations can be avoided, if the overlap region
+ * covered by the smallest layer at a higher z-order, gets composed
+ * by Copybit on a render buffer, which can be queued to MDP.
+ */
+bool MDPComp::fullMDPCompWithPTOR(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+
+ const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ const int stagesForMDP = min(sMaxPipesPerMixer,
+ ctx->mOverlay->availablePipes(mDpy, Overlay::MIXER_DEFAULT));
+
+ // Hard checks where we cannot use this mode
+ if (mDpy || !ctx->mCopyBit[mDpy] || isDisplaySplit(ctx, mDpy)) {
+ ALOGD_IF(isDebug(), "%s: Feature not supported!", __FUNCTION__);
+ return false;
+ }
+
+ // Frame level checks
+ if ((numAppLayers > stagesForMDP) || isSkipPresent(ctx, mDpy) ||
+ isYuvPresent(ctx, mDpy) || mCurrentFrame.dropCount ||
+ isSecurePresent(ctx, mDpy)) {
+ ALOGD_IF(isDebug(), "%s: Frame not supported!", __FUNCTION__);
+ return false;
+ }
+
+ // Find overlap index
+ int overlapIdx = numAppLayers - 1;
+ uint32_t layerPixelCount, minPixelCount = 0;
+ for (int i = numAppLayers - 1; i >= 0; i--) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ layerPixelCount = (crop.right - crop.left) * (crop.bottom - crop.top);
+ if (!minPixelCount || (layerPixelCount < minPixelCount)) {
+ minPixelCount = layerPixelCount;
+ overlapIdx = i;
+ }
+ }
+
+ // No overlap
+ if (!overlapIdx)
+ return false;
+
+ /* We cannot use this composition mode, if:
+ 1. A below layer needs scaling.
+ 2. Overlap is not peripheral to display.
+ 3. Overlap or a below layer has 90 degree transform.
+ 4. Intersection of Overlap layer with a below layer is not valid.
+ 5. Overlap area > (1/3 * FrameBuffer) area, based on Perf inputs.
+ */
+
+ hwc_rect_t overlap = list->hwLayers[overlapIdx].displayFrame;
+ if (!isPeripheral(overlap, ctx->mViewFrame[mDpy]))
+ return false;
+
+ if ((3 * (overlap.right - overlap.left) * (overlap.bottom - overlap.top)) >
+ ((int)ctx->dpyAttr[mDpy].xres * (int)ctx->dpyAttr[mDpy].yres))
+ return false;
+
+ for (int i = overlapIdx; i >= 0; i--) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ hwc_rect_t dispFrame = layer->displayFrame;
+
+ if (has90Transform(layer))
+ return false;
+
+ if (i < overlapIdx) {
+ if (needsScaling(layer) ||
+ !isValidRect(getIntersection(dispFrame, overlap)))
+ return false;
+ }
+ }
+
+ mOverlapIndex = overlapIdx;
+ if (!ctx->mCopyBit[mDpy]->prepareOverlap(ctx, list, overlapIdx)) {
+ ALOGD_IF(isDebug(), "%s: Overlap prepare failed!",__FUNCTION__);
+ mOverlapIndex = -1;
+ return false;
+ }
+
+ hwc_rect_t sourceCrop[overlapIdx];
+ hwc_rect_t displayFrame[overlapIdx];
+
+ // Remove overlap from crop & displayFrame of below layers
+ for (int i = 0; i < overlapIdx; i++) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ displayFrame[i] = layer->displayFrame;
+ sourceCrop[i] = integerizeSourceCrop(layer->sourceCropf);
+
+ // Update layer attributes
+ hwc_rect_t srcCrop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t destRect = deductRect(layer->displayFrame, overlap);
+ qhwc::calculate_crop_rects(srcCrop, layer->displayFrame, destRect,
+ layer->transform);
+
+ layer->sourceCropf.left = (float)srcCrop.left;
+ layer->sourceCropf.top = (float)srcCrop.top;
+ layer->sourceCropf.right = (float)srcCrop.right;
+ layer->sourceCropf.bottom = (float)srcCrop.bottom;
+ }
+
+ mCurrentFrame.mdpCount = numAppLayers;
+ mCurrentFrame.fbCount = 0;
+ mCurrentFrame.fbZ = -1;
+
+ for (int j = 0; j < numAppLayers; j++)
+ mCurrentFrame.isFBComposed[j] = false;
+
+ bool result = postHeuristicsHandling(ctx, list);
+
+ // Restore layer attributes
+ for (int i = 0; i < overlapIdx; i++) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ layer->displayFrame = displayFrame[i];
+ layer->sourceCropf.left = (float)sourceCrop[i].left;
+ layer->sourceCropf.top = (float)sourceCrop[i].top;
+ layer->sourceCropf.right = (float)sourceCrop[i].right;
+ layer->sourceCropf.bottom = (float)sourceCrop[i].bottom;
+ }
+
+ if (!result) {
+ mOverlapIndex = -1;
+ reset(ctx);
+ }
+
+ ALOGD_IF(isDebug(), "%s: Postheuristics %s!, Overlap index = %d",
+ __FUNCTION__, (result ? "successful" : "failed"), mOverlapIndex);
+ return result;
+}
+
bool MDPComp::partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list)
{
if(!sEnableMixedMode) {
@@ -1379,9 +1547,16 @@
int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
int ret = 0;
- const int numLayers = ctx->listStats[mDpy].numAppLayers;
char property[PROPERTY_VALUE_MAX];
+ if(!ctx || !list) {
+ ALOGE("%s: Invalid context or list",__FUNCTION__);
+ mCachedFrame.reset();
+ return -1;
+ }
+
+ const int numLayers = ctx->listStats[mDpy].numAppLayers;
+
if(property_get("debug.hwc.simulate", property, NULL) > 0) {
int currentFlags = atoi(property);
if(currentFlags != sSimulationFlags) {
@@ -1390,6 +1565,7 @@
sSimulationFlags, sSimulationFlags);
}
}
+ mOverlapIndex = -1;
//Do not cache the information for next draw cycle.
if(numLayers > MAX_NUM_APP_LAYERS or (!numLayers)) {
@@ -1424,7 +1600,8 @@
if(isFrameDoable(ctx)) {
generateROI(ctx, list);
- if(tryFullFrame(ctx, list) || tryVideoOnly(ctx, list)) {
+ mModeOn = tryFullFrame(ctx, list) || tryVideoOnly(ctx, list);
+ if(mModeOn) {
setMDPCompLayerFlags(ctx, list);
} else {
resetROI(ctx, mDpy);
@@ -1443,7 +1620,7 @@
ALOGD("GEOMETRY change: %d",
(list->flags & HWC_GEOMETRY_CHANGED));
android::String8 sDump("");
- dump(sDump);
+ dump(sDump, ctx);
ALOGD("%s",sDump.string());
}
@@ -1484,25 +1661,44 @@
}
return bRet;
}
+
+int MDPComp::drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+ int fd = -1;
+ if (mOverlapIndex != -1) {
+ fd = ctx->mCopyBit[mDpy]->drawOverlap(ctx, list, mOverlapIndex);
+ if (fd < 0) {
+ ALOGD_IF(isDebug(),"%s: failed", __FUNCTION__);
+ mOverlapIndex = -1;
+ }
+ }
+ return fd;
+}
//=============MDPCompNonSplit==================================================
void MDPCompNonSplit::adjustForSourceSplit(hwc_context_t *ctx,
- hwc_display_contents_1_t*) {
- //As we split 4kx2k yuv layer and program to 2 VG pipes
- //(if available) increase mdpcount accordingly
- mCurrentFrame.mdpCount += ctx->listStats[mDpy].yuv4k2kCount;
-
+ hwc_display_contents_1_t* list) {
//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(mCurrentFrame.fbZ >= 0) {
- 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;
+ for (int index = 0, mdpNextZOrder = 0; index < mCurrentFrame.layerCount;
+ index++) {
+ if(!mCurrentFrame.isFBComposed[index]) {
+ if(mdpNextZOrder == mCurrentFrame.fbZ) {
+ mdpNextZOrder++;
+ }
+ mdpNextZOrder++;
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(is4kx2kYuvBuffer(hnd)) {
+ if(mdpNextZOrder <= mCurrentFrame.fbZ)
+ mCurrentFrame.fbZ += 1;
+ mdpNextZOrder++;
+ //As we split 4kx2k yuv layer and program to 2 VG pipes
+ //(if available) increase mdpcount by 1.
+ mCurrentFrame.mdpCount++;
+ }
}
}
}
@@ -1583,18 +1779,8 @@
bool MDPCompNonSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
- if(!isEnabled()) {
- ALOGD_IF(isDebug(),"%s: MDP Comp not configured", __FUNCTION__);
- return true;
- }
-
- if(!ctx || !list) {
- ALOGE("%s: invalid contxt or list",__FUNCTION__);
- return false;
- }
-
- if(ctx->listStats[mDpy].numAppLayers > MAX_NUM_APP_LAYERS) {
- ALOGD_IF(isDebug(),"%s: Exceeding max layer count", __FUNCTION__);
+ if(!isEnabled() or !mModeOn) {
+ ALOGD_IF(isDebug(),"%s: MDP Comp not enabled/configured", __FUNCTION__);
return true;
}
@@ -1674,6 +1860,10 @@
continue;
}
+ if (!mDpy && (i == mOverlapIndex)) {
+ hnd = ctx->mCopyBit[mDpy]->getCurrentRenderBuffer();
+ }
+
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
using pipe: %d", __FUNCTION__, layer,
hnd, dest );
@@ -1707,17 +1897,27 @@
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;
- }
- if(mCurrentFrame.fbZ >= n4k2kYuvIndex){
- mCurrentFrame.fbZ += 1;
+ if(mCurrentFrame.fbZ >= 0) {
+ for (int index = 0, mdpNextZOrder = 0; index < mCurrentFrame.layerCount;
+ index++) {
+ if(!mCurrentFrame.isFBComposed[index]) {
+ if(mdpNextZOrder == mCurrentFrame.fbZ) {
+ mdpNextZOrder++;
+ }
+ mdpNextZOrder++;
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(is4kx2kYuvBuffer(hnd)) {
+ hwc_rect_t dst = layer->displayFrame;
+ if((dst.left > lSplit) || (dst.right < lSplit)) {
+ mCurrentFrame.mdpCount += 1;
+ }
+ if(mdpNextZOrder <= mCurrentFrame.fbZ)
+ mCurrentFrame.fbZ += 1;
+ mdpNextZOrder++;
+ }
+ }
}
}
}
@@ -1834,18 +2034,8 @@
bool MDPCompSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
- if(!isEnabled()) {
- ALOGD_IF(isDebug(),"%s: MDP Comp not configured", __FUNCTION__);
- return true;
- }
-
- if(!ctx || !list) {
- ALOGE("%s: invalid contxt or list",__FUNCTION__);
- return false;
- }
-
- if(ctx->listStats[mDpy].numAppLayers > MAX_NUM_APP_LAYERS) {
- ALOGD_IF(isDebug(),"%s: Exceeding max layer count", __FUNCTION__);
+ if(!isEnabled() or !mModeOn) {
+ ALOGD_IF(isDebug(),"%s: MDP Comp not enabled/configured", __FUNCTION__);
return true;
}
@@ -1919,6 +2109,10 @@
ovutils::eDest indexL = pipe_info.lIndex;
ovutils::eDest indexR = pipe_info.rIndex;
+ if (!mDpy && (i == mOverlapIndex)) {
+ hnd = ctx->mCopyBit[mDpy]->getCurrentRenderBuffer();
+ }
+
int fd = hnd->fd;
int offset = (uint32_t)hnd->offset;
@@ -1990,9 +2184,23 @@
return false;
}
- //If layer's crop width or dest width > 2048, use 2 pipes
- if((dst.right - dst.left) > qdutils::MAX_DISPLAY_DIM or
- (crop.right - crop.left) > qdutils::MAX_DISPLAY_DIM) {
+ /* Use 2 pipes IF
+ a) Layer's crop width is > 2048 or
+ b) Layer's dest width > 2048 or
+ c) On primary, driver has indicated with caps to split always. This is
+ based on an empirically derived value of panel height. Applied only
+ if the layer's width is > mixer's width
+ */
+
+ bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
+ qdutils::MDPVersion::getInstance().isSrcSplitAlways();
+ int lSplit = getLeftSplit(ctx, mDpy);
+ int dstWidth = dst.right - dst.left;
+ int cropWidth = crop.right - crop.left;
+
+ if(dstWidth > qdutils::MAX_DISPLAY_DIM or
+ cropWidth > qdutils::MAX_DISPLAY_DIM or
+ (primarySplitAlways and (cropWidth > lSplit))) {
pipe_info.rIndex = ctx->mOverlay->getPipe(pipeSpecs);
if(pipe_info.rIndex == ovutils::OV_INVALID) {
return false;
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 4d9d232..850e242 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -43,16 +43,19 @@
int prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list);
/* draw */
virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0;
+ //Reset values
+ void reset();
/* dumpsys */
- void dump(android::String8& buf);
+ void dump(android::String8& buf, hwc_context_t *ctx);
bool isGLESOnlyComp() { return (mCurrentFrame.mdpCount == 0); }
+ bool isPTORActive() { return (mOverlapIndex != -1); }
+ int drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t* list);
static MDPComp* getObject(hwc_context_t *ctx, const int& dpy);
/* Handler to invoke frame redraw on Idle Timer expiry */
static void timeout_handler(void *udata);
/* Initialize MDP comp*/
static bool init(hwc_context_t *ctx);
static void resetIdleFallBack() { sIdleFallBack = false; }
- static void reset() { sHandleTimeout = false; };
static bool isIdleFallback() { return sIdleFallBack; }
protected:
@@ -170,6 +173,8 @@
bool tryFullFrame(hwc_context_t *ctx, hwc_display_contents_1_t* list);
/* checks if full MDP comp can be done */
bool fullMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ /* Full MDP Composition with Peripheral Tiny Overlap Removal */
+ bool fullMDPCompWithPTOR(hwc_context_t *ctx,hwc_display_contents_1_t* list);
/* check if we can use layer cache to do at least partial MDP comp */
bool partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
/* Partial MDP comp that uses caching to save power as primary goal */
@@ -244,6 +249,9 @@
struct LayerCache mCachedFrame;
//Enable 4kx2k yuv layer split
static bool sEnable4k2kYUVSplit;
+ /* Overlap layer index */
+ int mOverlapIndex;
+ bool mModeOn; // if prepare happened
bool allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index);
};
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 0bb71f0..77215ca 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -193,6 +193,26 @@
}
}
+
+static status_t setViewFrame(hwc_context_t* ctx, const Parcel* inParcel) {
+ int dpy = inParcel->readInt32();
+ if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
+ Locker::Autolock _sl(ctx->mDrawLock);
+ ctx->mViewFrame[dpy].left = inParcel->readInt32();
+ ctx->mViewFrame[dpy].top = inParcel->readInt32();
+ ctx->mViewFrame[dpy].right = inParcel->readInt32();
+ ctx->mViewFrame[dpy].bottom = inParcel->readInt32();
+ ALOGD_IF(QCLIENT_DEBUG, "%s: mViewFrame[%d] = [%d %d %d %d]",
+ __FUNCTION__, dpy,
+ ctx->mViewFrame[dpy].left, ctx->mViewFrame[dpy].top,
+ ctx->mViewFrame[dpy].right, ctx->mViewFrame[dpy].bottom);
+ return NO_ERROR;
+ } else {
+ ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
+ return BAD_VALUE;
+ }
+}
+
status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
Parcel* outParcel) {
status_t ret = NO_ERROR;
@@ -232,6 +252,9 @@
case IQService::SET_WFD_STATUS:
setWfdStatus(mHwcContext,inParcel->readInt32());
break;
+ case IQService::SET_VIEW_FRAME:
+ setViewFrame(mHwcContext, inParcel);
+ break;
default:
ret = NO_ERROR;
}
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 058606b..671388b 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -83,7 +83,8 @@
(xres < MIN_DISPLAY_XRES || yres < MIN_DISPLAY_YRES));
}
-void changeResolution(hwc_context_t *ctx, int xres_orig, int yres_orig) {
+void changeResolution(hwc_context_t *ctx, int xres_orig, int yres_orig,
+ int width, int height) {
//Store original display resolution.
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_orig;
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_orig;
@@ -99,6 +100,12 @@
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_new;
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_new;
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = true;
+
+ //Caluculate DPI according to changed resolution.
+ float xdpi = ((float)xres_new * 25.4f) / (float)width;
+ float ydpi = ((float)yres_new * 25.4f) / (float)height;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = xdpi;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ydpi;
}
}
}
@@ -168,7 +175,7 @@
(uint32_t)(1000000000l / fps);
//To change resolution of primary display
- changeResolution(ctx, info.xres, info.yres);
+ changeResolution(ctx, info.xres, info.yres, info.width, info.height);
//Unblank primary on first boot
if(ioctl(fb_fd, FBIOBLANK,FB_BLANK_UNBLANK) < 0) {
@@ -274,6 +281,10 @@
ctx->mMDPDownscaleEnabled = true;
}
+ ctx->enableABC = false;
+ property_get("debug.sf.hwc.canUseABC", value, "0");
+ ctx->enableABC = atoi(value) ? true : false;
+
// Initialize gpu perfomance hint related parameters
property_get("sys.hwc.gpu_perf_mode", value, "0");
#ifdef QCOM_BSP
@@ -799,28 +810,6 @@
}
}
-hwc_rect_t calculateDisplayViewFrame(hwc_context_t *ctx, int dpy) {
- int dstWidth = ctx->dpyAttr[dpy].xres;
- int dstHeight = ctx->dpyAttr[dpy].yres;
- int srcWidth = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
- int srcHeight = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
- // default we assume viewframe as a full frame for primary display
- hwc_rect outRect = {0, 0, dstWidth, dstHeight};
- if(dpy) {
- // swap srcWidth and srcHeight, if the device orientation is 90 or 270.
- if(ctx->deviceOrientation & 0x1) {
- swap(srcWidth, srcHeight);
- }
- // Get Aspect Ratio for external
- getAspectRatioPosition(dstWidth, dstHeight, srcWidth,
- srcHeight, outRect);
- }
- ALOGD_IF(HWC_UTILS_DEBUG, "%s: view frame for dpy %d is [%d %d %d %d]",
- __FUNCTION__, dpy, outRect.left, outRect.top,
- outRect.right, outRect.bottom);
- return outRect;
-}
-
void setListStats(hwc_context_t *ctx,
hwc_display_contents_1_t *list, int dpy) {
const int prevYuvCount = ctx->listStats[dpy].yuvCount;
@@ -836,18 +825,13 @@
ctx->listStats[dpy].isDisplayAnimating = false;
ctx->listStats[dpy].secureUI = false;
ctx->listStats[dpy].yuv4k2kCount = 0;
- ctx->mViewFrame[dpy] = (hwc_rect_t){0, 0, 0, 0};
ctx->dpyAttr[dpy].mActionSafePresent = isActionSafePresent(ctx, dpy);
+ ctx->listStats[dpy].renderBufIndexforABC = -1;
resetROI(ctx, dpy);
- // Calculate view frame of ext display from primary resolution
- // and primary device orientation.
- ctx->mViewFrame[dpy] = calculateDisplayViewFrame(ctx, dpy);
-
trimList(ctx, list, dpy);
optimizeLayerRects(list);
-
for (size_t i = 0; i < (size_t)ctx->listStats[dpy].numAppLayers; i++) {
hwc_layer_1_t const* layer = &list->hwLayers[i];
private_handle_t *hnd = (private_handle_t *)layer->handle;
@@ -1323,11 +1307,20 @@
}
for(uint32_t i = 0; i < list->numHwLayers; i++) {
- if(list->hwLayers[i].compositionType == HWC_OVERLAY &&
+ if(((isAbcInUse(ctx)== true ) ||
+ (list->hwLayers[i].compositionType == HWC_OVERLAY)) &&
list->hwLayers[i].acquireFenceFd >= 0) {
if(UNLIKELY(swapzero))
acquireFd[count++] = -1;
- else
+ // if ABC is enabled for more than one layer.
+ // renderBufIndexforABC will work as FB.Hence
+ // set the acquireFD from fd - which is coming from copybit
+ else if(fd >= 0 && (isAbcInUse(ctx) == true)) {
+ if(ctx->listStats[dpy].renderBufIndexforABC ==(int32_t)i)
+ acquireFd[count++] = fd;
+ else
+ continue;
+ } else
acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
}
if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
@@ -1344,6 +1337,11 @@
}
}
+ if ((fd >= 0) && !dpy && ctx->mMDPComp[dpy]->isPTORActive()) {
+ // Acquire c2d fence of Overlap render buffer
+ acquireFd[count++] = fd;
+ }
+
data.acq_fen_fd_cnt = count;
fbFd = ctx->dpyAttr[dpy].fd;
@@ -1379,9 +1377,16 @@
} else if(list->hwLayers[i].releaseFenceFd < 0 ) {
#ifdef QCOM_BSP
//If rotator has not already populated this field
- if(list->hwLayers[i].compositionType == HWC_BLIT) {
- //For Blit, the app layers should be released when the Blit is
- //complete. This fd was passed from copybit->draw
+ // & if it's a not VPU layer
+
+ // if ABC is enabled for more than one layer
+ if(fd >= 0 && (isAbcInUse(ctx) == true) &&
+ ctx->listStats[dpy].renderBufIndexforABC !=(int32_t)i){
+ list->hwLayers[i].releaseFenceFd = dup(fd);
+ } else if((list->hwLayers[i].compositionType == HWC_BLIT)&&
+ (isAbcInUse(ctx) == false)){
+ //For Blit, the app layers should be released when the Blit
+ //is complete. This fd was passed from copybit->draw
list->hwLayers[i].releaseFenceFd = dup(fd);
} else
#endif
@@ -1397,8 +1402,12 @@
fd = -1;
}
- if (ctx->mCopyBit[dpy])
- ctx->mCopyBit[dpy]->setReleaseFd(releaseFd);
+ if (!dpy && ctx->mCopyBit[dpy]) {
+ if (ctx->mMDPComp[dpy]->isPTORActive())
+ ctx->mCopyBit[dpy]->setReleaseFdSync(releaseFd);
+ else
+ ctx->mCopyBit[dpy]->setReleaseFd(releaseFd);
+ }
//Signals when MDP finishes reading rotator buffers.
ctx->mLayerRotMap[dpy]->setReleaseFd(releaseFd);
@@ -1773,14 +1782,17 @@
const int lSplit = getLeftSplit(ctx, dpy);
- if(lDest != OV_INVALID) {
+ // Calculate Left rects
+ if(dst.left < lSplit) {
tmp_cropL = crop;
tmp_dstL = dst;
hwc_rect_t scissor = {0, 0, lSplit, hw_h };
scissor = getIntersection(ctx->mViewFrame[dpy], scissor);
qhwc::calculate_crop_rects(tmp_cropL, tmp_dstL, scissor, 0);
}
- if(rDest != OV_INVALID) {
+
+ // Calculate Right rects
+ if(dst.right > lSplit) {
tmp_cropR = crop;
tmp_dstR = dst;
hwc_rect_t scissor = {lSplit, 0, hw_w, hw_h };
@@ -1793,8 +1805,8 @@
//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) {
+ if((orient & OVERLAY_TRANSFORM_FLIP_H) && (dst.left < lSplit) &&
+ (dst.right > lSplit) && (*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);
@@ -2017,6 +2029,10 @@
ctx->layerProp[dpy] = new LayerProp[numAppLayers];
}
+bool isAbcInUse(hwc_context_t *ctx){
+ return (ctx->enableABC && ctx->listStats[0].renderBufIndexforABC == 0);
+}
+
/* Since we fake non-Hybrid WFD solution as external display, this
* function helps us in determining the priority between external
* (hdmi/non-Hybrid WFD display) and virtual display devices(SSD/
@@ -2043,6 +2059,24 @@
return true;
}
+void dumpBuffer(private_handle_t *ohnd, char *bufferName) {
+ if (ohnd != NULL && ohnd->base) {
+ char dumpFilename[PATH_MAX];
+ bool bResult = false;
+ snprintf(dumpFilename, sizeof(dumpFilename), "/data/%s.%s.%dx%d.raw",
+ bufferName,
+ overlay::utils::getFormatString(utils::getMdpFormat(ohnd->format)),
+ getWidth(ohnd), getHeight(ohnd));
+ FILE* fp = fopen(dumpFilename, "w+");
+ if (NULL != fp) {
+ bResult = (bool) fwrite((void*)ohnd->base, ohnd->size, 1, fp);
+ fclose(fp);
+ }
+ ALOGD("Buffer[%s] Dump to %s: %s",
+ bufferName, dumpFilename, bResult ? "Success" : "Fail");
+ }
+}
+
bool isGLESComp(hwc_context_t *ctx,
hwc_display_contents_1_t* list) {
int numAppLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
@@ -2122,6 +2156,20 @@
#endif
}
+bool isPeripheral(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
+ // To be peripheral, 3 boundaries should match.
+ uint8_t eqBounds = 0;
+ if (rect1.left == rect2.left)
+ eqBounds++;
+ if (rect1.top == rect2.top)
+ eqBounds++;
+ if (rect1.right == rect2.right)
+ eqBounds++;
+ if (rect1.bottom == rect2.bottom)
+ eqBounds++;
+ return (eqBounds == 3);
+}
+
void BwcPM::setBwc(const hwc_rect_t& crop,
const hwc_rect_t& dst, const int& transform,
ovutils::eMdpFlags& mdpFlags) {
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index bf4fd44..06f7f9f 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -127,6 +127,8 @@
bool isSecurePresent;
hwc_rect_t lRoi; //left ROI
hwc_rect_t rRoi; //right ROI. Unused in single DSI panels.
+ //App Buffer Composition index
+ int renderBufIndexforABC;
};
struct LayerProp {
@@ -222,11 +224,6 @@
// -----------------------------------------------------------------------------
// Utility functions - implemented in hwc_utils.cpp
void dumpLayer(hwc_layer_1_t const* l);
-
-// Calculate viewframe for external/primary display from primary resolution and
-// primary device orientation
-hwc_rect_t calculateDisplayViewFrame(hwc_context_t *ctx, int dpy);
-
void setListStats(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy);
void initContext(hwc_context_t *ctx);
@@ -251,9 +248,11 @@
int getBlending(int blending);
bool isGLESOnlyComp(hwc_context_t *ctx, const int& dpy);
void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers);
+bool isAbcInUse(hwc_context_t *ctx);
bool canUseMDPforVirtualDisplay(hwc_context_t* ctx,
const hwc_display_contents_1_t *list);
+void dumpBuffer(private_handle_t *ohnd, char *bufferName);
//Helper function to dump logs
void dumpsys_log(android::String8& buf, const char* fmt, ...);
@@ -373,6 +372,9 @@
// due to idle fallback or MDP composition.
void setGPUHint(hwc_context_t* ctx, hwc_display_contents_1_t* list);
+// Returns true if rect1 is peripheral to rect2, false otherwise.
+bool isPeripheral(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
+
// Inline utility functions
static inline bool isSkipLayer(const hwc_layer_1_t* l) {
return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER)));
@@ -562,6 +564,8 @@
// persist.hwc.enable_vds
bool mVDSEnabled;
struct gpu_hint_info mGPUHintInfo;
+ //App Buffer Composition
+ bool enableABC;
};
namespace qhwc {
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
index 97b19ea..01c0873 100644
--- a/libhwcomposer/hwc_virtual.cpp
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -29,6 +29,7 @@
#include "hwc_dump_layers.h"
#include "hwc_copybit.h"
#include "hwc_virtual.h"
+#include "sync/sync.h"
#define HWCVIRTUAL_LOG 0
@@ -48,6 +49,16 @@
}
}
+HWCVirtualVDS::HWCVirtualVDS() {
+ char value[PROPERTY_VALUE_MAX];
+ mVDSDumpEnabled = false;
+ if((property_get("debug.hwc.enable_vds_dump", value, NULL) > 0)) {
+ if(atoi(value) != 0) {
+ mVDSDumpEnabled = true;
+ }
+ }
+}
+
void HWCVirtualVDS::init(hwc_context_t *ctx) {
const int dpy = HWC_DISPLAY_VIRTUAL;
ctx->mFBUpdate[dpy] =
@@ -137,6 +148,7 @@
* Mark all application layers as OVERLAY so that
* GPU will not compose.
*/
+ Writeback::getInstance(); //Ensure that WB is active during pause
for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
hwc_layer_1_t *layer = &list->hwLayers[i];
layer->compositionType = HWC_OVERLAY;
@@ -177,6 +189,10 @@
int fd = -1; //FenceFD from the Copybit
hwc_sync(ctx, list, dpy, fd);
+ // Dump the layers for virtual
+ if(ctx->mHwcDebug[dpy])
+ ctx->mHwcDebug[dpy]->dumpLayers(list);
+
if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
ALOGE("%s: MDPComp draw failed", __FUNCTION__);
ret = -1;
@@ -200,6 +216,19 @@
ret = -1;
}
+ if(mVDSDumpEnabled) {
+ char bufferName[128];
+ // Dumping frame buffer
+ sync_wait(fbLayer->acquireFenceFd, 1000);
+ snprintf(bufferName, sizeof(bufferName), "vds.fb");
+ dumpBuffer((private_handle_t *)fbLayer->handle, bufferName);
+ // Dumping WB output for non-secure session
+ if(!isSecureBuffer(ohnd)) {
+ sync_wait(list->retireFenceFd, 1000);
+ snprintf(bufferName, sizeof(bufferName), "vds.wb");
+ dumpBuffer(ohnd, bufferName);
+ }
+ }
} else if(list->outbufAcquireFenceFd >= 0) {
//If we dont handle the frame, set retireFenceFd to outbufFenceFd,
//which will make sure, the framework waits on it and closes it.
@@ -224,6 +253,17 @@
}
usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
* 2 / 1000);
+ // At this point all the pipes used by External have been
+ // marked as UNSET.
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ // Perform commit to unstage the pipes.
+ if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail! for %d dpy",
+ __FUNCTION__, dpy);
+ }
+ ctx->proc->invalidate(ctx->proc);
+ }
return;
}
diff --git a/libhwcomposer/hwc_virtual.h b/libhwcomposer/hwc_virtual.h
index 87004c3..26d89c9 100644
--- a/libhwcomposer/hwc_virtual.h
+++ b/libhwcomposer/hwc_virtual.h
@@ -46,7 +46,7 @@
class HWCVirtualVDS : public HWCVirtualBase {
public:
- explicit HWCVirtualVDS(){};
+ explicit HWCVirtualVDS();
virtual ~HWCVirtualVDS(){};
// Chooses composition type and configures pipe for each layer in virtual
// display list
@@ -64,6 +64,12 @@
hwc_display_contents_1_t** displays);
virtual void pause(hwc_context_t* ctx, int dpy);
virtual void resume(hwc_context_t* ctx, int dpy);
+private:
+ // If WFD is enabled through VDS solution
+ // we can dump the frame buffer and WB
+ // output buffer by setting the property
+ // debug.hwc.enable_vds_dump
+ bool mVDSDumpEnabled;
};
class HWCVirtualV4L2 : public HWCVirtualBase {
diff --git a/liblight/Android.mk b/liblight/Android.mk
index 40115d5..977fc55 100644
--- a/liblight/Android.mk
+++ b/liblight/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := lights.c
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdlights\"
LOCAL_MODULE := lights.$(TARGET_BOARD_PLATFORM)
diff --git a/libmemtrack/Android.mk b/libmemtrack/Android.mk
index 306eb07..2fda0b7 100644
--- a/libmemtrack/Android.mk
+++ b/libmemtrack/Android.mk
@@ -18,7 +18,7 @@
# hw/<POWERS_HARDWARE_MODULE_ID>.<ro.hardware>.so
include $(CLEAR_VARS)
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_C_INCLUDES += hardware/libhardware/include
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := memtrack_msm.c kgsl.c
diff --git a/liboverlay/Android.mk b/liboverlay/Android.mk
index 277b44c..aa1ea24 100644
--- a/liboverlay/Android.mk
+++ b/liboverlay/Android.mk
@@ -3,7 +3,6 @@
include $(CLEAR_VARS)
LOCAL_MODULE := liboverlay
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
LOCAL_SHARED_LIBRARIES := $(common_libs) libqdutils libmemalloc \
diff --git a/liboverlay/overlayRotator.cpp b/liboverlay/overlayRotator.cpp
index 0e5b0ec..0671b62 100644
--- a/liboverlay/overlayRotator.cpp
+++ b/liboverlay/overlayRotator.cpp
@@ -145,7 +145,7 @@
//Return a rot object, creating one if necessary
overlay::Rotator *rot = NULL;
if(mUseCount >= MAX_ROT_SESS) {
- ALOGE("%s, MAX rotator sessions reached", __func__);
+ ALOGW("%s, MAX rotator sessions reached, request rejected", __func__);
} else {
if(mRot[mUseCount] == NULL)
mRot[mUseCount] = overlay::Rotator::getRotator();
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index 53c54e6..f7b44bd 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -210,9 +210,7 @@
// Holder of rotator objects. Manages lifetimes
class RotMgr {
public:
- //Maximum sessions based on VG pipes, since rotator is used only for videos.
- //Even though we can have 4 mixer stages, that much may be unnecessary.
- enum { MAX_ROT_SESS = 3 };
+ enum { MAX_ROT_SESS = 4 };
~RotMgr();
void configBegin();
diff --git a/libqdutils/Android.mk b/libqdutils/Android.mk
index 2907ccf..212c8d8 100644
--- a/libqdutils/Android.mk
+++ b/libqdutils/Android.mk
@@ -21,7 +21,6 @@
LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
LOCAL_COPY_HEADERS := qdMetaData.h
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_SHARED_LIBRARIES := liblog libcutils
LOCAL_C_INCLUDES := $(common_includes)
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
diff --git a/libqdutils/display_config.cpp b/libqdutils/display_config.cpp
index 60f1f68..7ff106f 100644
--- a/libqdutils/display_config.cpp
+++ b/libqdutils/display_config.cpp
@@ -113,4 +113,25 @@
return err;
}
+int setViewFrame(int dpy, int l, int t, int r, int b) {
+ status_t err = (status_t) FAILED_TRANSACTION;
+ sp<IQService> binder = getBinder();
+ Parcel inParcel, outParcel;
+ inParcel.writeInt32(dpy);
+ inParcel.writeInt32(l);
+ inParcel.writeInt32(t);
+ inParcel.writeInt32(r);
+ inParcel.writeInt32(b);
+
+ if(binder != NULL) {
+ err = binder->dispatch(IQService::SET_VIEW_FRAME,
+ &inParcel, &outParcel);
+ }
+ if(err)
+ ALOGE("%s: Failed to set view frame for dpy %d err=%d",
+ __FUNCTION__, dpy, err);
+
+ return err;
+}
+
}; //namespace
diff --git a/libqdutils/display_config.h b/libqdutils/display_config.h
index 29edbef..a69265b 100644
--- a/libqdutils/display_config.h
+++ b/libqdutils/display_config.h
@@ -73,4 +73,7 @@
// get the active visible region for the display
// Returns 0 on success, negative values on errors
int getDisplayVisibleRegion(int dpy, hwc_rect_t &rect);
+
+// set the view frame information in hwc context from surfaceflinger
+int setViewFrame(int dpy, int l, int t, int r, int b);
}; //namespace
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 96ed4d2..bc63ddf 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -88,6 +88,7 @@
mLowBw = 0;
mHighBw = 0;
mSourceSplit = false;
+ mSourceSplitAlways = false;
mRGBHasNoScalar = false;
updatePanelInfo();
@@ -306,6 +307,30 @@
free(line);
fclose(sysfsFd);
}
+
+ if(mSourceSplit) {
+ memset(sysfsPath, 0, sizeof(sysfsPath));
+ snprintf(sysfsPath , sizeof(sysfsPath),
+ "/sys/class/graphics/fb0/msm_fb_src_split_info");
+
+ sysfsFd = fopen(sysfsPath, "rb");
+ if (sysfsFd == NULL) {
+ ALOGE("%s: Opening file %s failed with error %s", __FUNCTION__,
+ sysfsPath, strerror(errno));
+ return false;
+ } else {
+ line = (char *) malloc(len);
+ if((read = getline(&line, &len, sysfsFd)) != -1) {
+ if(!strncmp(line, "src_split_always",
+ strlen("src_split_always"))) {
+ mSourceSplitAlways = true;
+ }
+ }
+ free(line);
+ fclose(sysfsFd);
+ }
+ }
+
ALOGD_IF(DEBUG, "%s: mMDPVersion: %d mMdpRev: %x mRGBPipes:%d,"
"mVGPipes:%d", __FUNCTION__, mMDPVersion, mMdpRev,
mRGBPipes, mVGPipes);
@@ -371,6 +396,10 @@
return mSourceSplit;
}
+bool MDPVersion::isSrcSplitAlways() const {
+ return mSourceSplitAlways;
+}
+
bool MDPVersion::isRGBScalarSupported() const {
return (!mRGBHasNoScalar);
}
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index e862d2d..8bb9c39 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -140,6 +140,7 @@
unsigned long getLowBw() { return mLowBw; }
unsigned long getHighBw() { return mHighBw; }
bool isSrcSplit() const;
+ bool isSrcSplitAlways() const;
bool isRGBScalarSupported() const;
bool is8x26();
bool is8x74v2();
@@ -170,6 +171,8 @@
unsigned long mLowBw; //kbps
unsigned long mHighBw; //kbps
bool mSourceSplit;
+ //Additional property on top of source split
+ bool mSourceSplitAlways;
bool mRGBHasNoScalar;
};
}; //namespace qdutils
diff --git a/libqservice/Android.mk b/libqservice/Android.mk
index 0c6123b..78b1d77 100644
--- a/libqservice/Android.mk
+++ b/libqservice/Android.mk
@@ -3,7 +3,6 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libqservice
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
LOCAL_SHARED_LIBRARIES := $(common_libs) libbinder
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 02f7341..5c9acf7 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -51,6 +51,7 @@
GET_DISPLAY_VISIBLE_REGION, // Get the visibleRegion for dpy
PAUSE_WFD, // Pause/Resume WFD
SET_WFD_STATUS, // Set if wfd connection is on/off
+ SET_VIEW_FRAME, // Set view frame of display
COMMAND_LIST_END = 400,
};
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index e4af422..12dd995 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -28,6 +28,8 @@
*/
#include <QService.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
#define QSERVICE_DEBUG 0
@@ -55,6 +57,10 @@
status_t QService::dispatch(uint32_t command, const Parcel* inParcel,
Parcel* outParcel) {
status_t err = (status_t) FAILED_TRANSACTION;
+ IPCThreadState* ipc = IPCThreadState::self();
+ //Rewind parcel in case we're calling from the same process
+ if (ipc->getCallingPid() == getpid())
+ inParcel->setDataPosition(0);
if (mClient.get()) {
ALOGD_IF(QSERVICE_DEBUG, "Dispatching command: %d", command);
err = mClient->notifyCallback(command, inParcel, outParcel);
diff --git a/libvirtual/Android.mk b/libvirtual/Android.mk
index beeef25..a41ef33 100644
--- a/libvirtual/Android.mk
+++ b/libvirtual/Android.mk
@@ -3,7 +3,6 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libvirtual
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
LOCAL_SHARED_LIBRARIES := $(common_libs) liboverlay libqdutils