Merge "hwc: Handle validateAndSet failures in AD prepare call"
diff --git a/libcopybit/Android.mk b/libcopybit/Android.mk
index b3d4249..2ac7d15 100644
--- a/libcopybit/Android.mk
+++ b/libcopybit/Android.mk
@@ -17,7 +17,7 @@
include $(CLEAR_VARS)
LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
-LOCAL_COPY_HEADERS := copybit.h copybit_priv.h
+LOCAL_COPY_HEADERS := copybit.h copybit_priv.h c2d2.h
#Copy the headers regardless of whether copybit is built
include $(BUILD_COPY_HEADERS)
diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp
index 852b8c0..da0396f 100644
--- a/libcopybit/copybit_c2d.cpp
+++ b/libcopybit/copybit_c2d.cpp
@@ -35,8 +35,6 @@
#include <EGL/eglplatform.h>
#include <cutils/native_handle.h>
-#include <cutils/ashmem.h>
-#include <linux/ashmem.h>
#include <gralloc_priv.h>
#include <copybit.h>
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index b08c0c1..98a22cd 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -34,7 +34,6 @@
#include "external.h"
#include "overlayUtils.h"
#include "overlay.h"
-#include "mdp_version.h"
#include "qd_utils.h"
using namespace android;
@@ -586,7 +585,7 @@
mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode = false;
- if(!qdutils::MDPVersion::getInstance().is8x26()
+ if(mHwcContext->mOverlay->isUIScalingOnExternalSupported()
&& mHwcContext->mMDPDownscaleEnabled) {
int priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
int priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 9f95667..a69e6ee 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -547,6 +547,71 @@
size = getSize(format, width, height, alignedw, alignedh);
}
+int getYUVPlaneInfo(private_handle_t* hnd, struct android_ycbcr* ycbcr)
+{
+ int err = 0;
+ size_t ystride, cstride;
+ memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
+
+ // Get the chroma offsets from the handle width/height. We take advantage
+ // of the fact the width _is_ the stride
+ switch (hnd->format) {
+ //Semiplanar
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+ 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;
+ ycbcr->y = (void*)hnd->base;
+ ycbcr->cb = (void*)(hnd->base + ystride * hnd->height);
+ ycbcr->cr = (void*)(hnd->base + ystride * hnd->height + 1);
+ ycbcr->ystride = ystride;
+ ycbcr->cstride = cstride;
+ ycbcr->chroma_step = 2;
+ break;
+
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+ 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;
+ ycbcr->y = (void*)hnd->base;
+ ycbcr->cr = (void*)(hnd->base + ystride * hnd->height);
+ ycbcr->cb = (void*)(hnd->base + ystride * hnd->height + 1);
+ ycbcr->ystride = ystride;
+ ycbcr->cstride = cstride;
+ ycbcr->chroma_step = 2;
+ break;
+
+ //Planar
+ case HAL_PIXEL_FORMAT_YV12:
+ ystride = hnd->width;
+ cstride = hnd->width/2;
+ ycbcr->y = (void*)hnd->base;
+ ycbcr->cr = (void*)(hnd->base + ystride * hnd->height);
+ ycbcr->cb = (void*)(hnd->base + ystride * hnd->height +
+ cstride * hnd->height/2);
+ ycbcr->ystride = ystride;
+ ycbcr->cstride = cstride;
+ ycbcr->chroma_step = 1;
+
+ break;
+ //Unsupported formats
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ case HAL_PIXEL_FORMAT_YCrCb_422_I:
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+ default:
+ ALOGD("%s: Invalid format passed: 0x%x", __FUNCTION__,
+ hnd->format);
+ err = -EINVAL;
+ }
+ return err;
+
+}
+
// Allocate buffer from width, height and format into a
diff --git a/libgralloc/gpu.h b/libgralloc/gpu.h
index a34ff7e..5837588 100644
--- a/libgralloc/gpu.h
+++ b/libgralloc/gpu.h
@@ -24,7 +24,6 @@
#include <string.h>
#include <cutils/log.h>
-#include <cutils/ashmem.h>
#include "gralloc_priv.h"
#include "fb_priv.h"
diff --git a/libgralloc/gr.h b/libgralloc/gr.h
index fbde8c2..32f3256 100644
--- a/libgralloc/gr.h
+++ b/libgralloc/gr.h
@@ -69,6 +69,7 @@
// It is the responsibility of the caller to free the buffer
int alloc_buffer(private_handle_t **pHnd, int w, int h, int format, int usage);
void free_buffer(private_handle_t *hnd);
+int getYUVPlaneInfo(private_handle_t* pHnd, struct android_ycbcr* ycbcr);
/*****************************************************************************/
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index b2714c5..8704354 100644
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -82,6 +82,7 @@
GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_AND_HEIGHT_FROM_HANDLE,
GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES,
GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE,
+ GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO,
};
#define GRALLOC_HEAP_MASK (GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |\
diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp
index c419da6..189d205 100644
--- a/libgralloc/mapper.cpp
+++ b/libgralloc/mapper.cpp
@@ -26,11 +26,9 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
-#include <linux/ashmem.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
-#include <cutils/ashmem.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
@@ -259,28 +257,8 @@
{
private_handle_t* hnd = (private_handle_t*)handle;
int err = gralloc_map_and_invalidate(module, handle, usage);
- size_t ystride, cstride;
- if(!err) {
- //hnd->format holds our implementation defined format
- //HAL_PIXEL_FORMAT_YCrCb_420_SP is the only one set right now.
- switch (hnd->format) {
- case HAL_PIXEL_FORMAT_YCrCb_420_SP:
- ystride = ALIGN(hnd->width, 16);
- cstride = ALIGN(hnd->width, 16)/2;
- ycbcr->y = (void*)hnd->base;
- ycbcr->cr = (void*)(hnd->base + ystride * hnd->height);
- ycbcr->cb = (void*)(hnd->base + ystride * hnd->height + 1);
- ycbcr->ystride = ystride;
- ycbcr->cstride = cstride;
- ycbcr->chroma_step = 2;
- memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
- break;
- default:
- ALOGD("%s: Invalid format passed: 0x%x", __FUNCTION__,
- hnd->format);
- err = -EINVAL;
- }
- }
+ if(!err)
+ err = getYUVPlaneInfo(hnd, ycbcr);
return err;
}
@@ -447,6 +425,15 @@
res = 0;
}
} break;
+ case GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO:
+ {
+ private_handle_t* hnd = va_arg(args, private_handle_t*);
+ android_ycbcr* ycbcr = va_arg(args, struct android_ycbcr *);
+ if (!private_handle_t::validate(hnd)) {
+ res = getYUVPlaneInfo(hnd, ycbcr);
+ }
+ } break;
+
default:
break;
}
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 48937c8..0396c91 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -101,12 +101,104 @@
init_vsync_thread(ctx);
}
-//Helper
+static void setPaddingRound(hwc_context_t *ctx, int numDisplays,
+ hwc_display_contents_1_t** displays) {
+ ctx->isPaddingRound = false;
+ for(int i = 0; i < numDisplays; i++) {
+ hwc_display_contents_1_t *list = displays[i];
+ if (LIKELY(list && list->numHwLayers > 0)) {
+ if((ctx->mPrevHwLayerCount[i] == 1 or
+ ctx->mPrevHwLayerCount[i] == 0) and
+ (list->numHwLayers > 1)) {
+ /* If the previous cycle for dpy 'i' has 0 AppLayers and the
+ * current cycle has atleast 1 AppLayer, padding round needs
+ * to be invoked in current cycle on all the active displays
+ * to free up the resources.
+ */
+ ctx->isPaddingRound = true;
+ }
+ ctx->mPrevHwLayerCount[i] = (int)list->numHwLayers;
+ } else {
+ ctx->mPrevHwLayerCount[i] = 0;
+ }
+ }
+}
+
+/* Based on certain conditions, isPaddingRound will be set
+ * to make this function self-contained */
+static void setDMAState(hwc_context_t *ctx, int numDisplays,
+ hwc_display_contents_1_t** displays) {
+
+ if(ctx->mRotMgr->getNumActiveSessions() == 0)
+ Overlay::setDMAMode(Overlay::DMA_LINE_MODE);
+
+ for(int dpy = 0; dpy < numDisplays; dpy++) {
+ hwc_display_contents_1_t *list = displays[dpy];
+ if (LIKELY(list && list->numHwLayers > 0)) {
+ for(size_t layerIndex = 0; layerIndex < list->numHwLayers;
+ layerIndex++) {
+ if(list->hwLayers[layerIndex].compositionType !=
+ HWC_FRAMEBUFFER_TARGET)
+ {
+ hwc_layer_1_t const* layer = &list->hwLayers[layerIndex];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+ /* If a video layer requires rotation, set the DMA state
+ * to BLOCK_MODE */
+
+ if (UNLIKELY(isYuvBuffer(hnd)) && canUseRotator(ctx, dpy) &&
+ (layer->transform & HWC_TRANSFORM_ROT_90)) {
+ if(not ctx->mOverlay->isDMAMultiplexingSupported()) {
+ if(ctx->mOverlay->isPipeTypeAttached(
+ overlay::utils::OV_MDP_PIPE_DMA))
+ ctx->isPaddingRound = true;
+ }
+ Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
+ }
+ }
+ }
+ if(dpy) {
+ /* Uncomment the below code for testing purpose.
+ Assuming the orientation value is in terms of HAL_TRANSFORM,
+ this needs mapping to HAL, if its in different convention */
+
+ /* char value[PROPERTY_VALUE_MAX];
+ property_get("sys.ext_orientation", value, "0");
+ ctx->mExtOrientation = atoi(value);*/
+
+ if(ctx->mExtOrientation || ctx->mBufferMirrorMode) {
+ if(ctx->mOverlay->isPipeTypeAttached(
+ overlay::utils::OV_MDP_PIPE_DMA)) {
+ ctx->isPaddingRound = true;
+ }
+ Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
+ }
+ }
+ }
+ }
+}
+
+static void setNumActiveDisplays(hwc_context_t *ctx, int numDisplays,
+ hwc_display_contents_1_t** displays) {
+
+ ctx->numActiveDisplays = 0;
+ for(int i = 0; i < numDisplays; i++) {
+ hwc_display_contents_1_t *list = displays[i];
+ if (LIKELY(list && list->numHwLayers > 0)) {
+ /* For display devices like SSD and screenrecord, we cannot
+ * rely on isActive and connected attributes of dpyAttr to
+ * determine if the displaydevice is active. Hence in case if
+ * the layer-list is non-null and numHwLayers > 0, we assume
+ * the display device to be active.
+ */
+ ctx->numActiveDisplays += 1;
+ }
+ }
+}
+
static void reset(hwc_context_t *ctx, int numDisplays,
hwc_display_contents_1_t** displays) {
- ctx->numActiveDisplays = 0;
- ctx->isPaddingRound = false;
for(int i = 0; i < numDisplays; i++) {
hwc_display_contents_1_t *list = displays[i];
@@ -120,24 +212,6 @@
list->hwLayers[j].compositionType = HWC_FRAMEBUFFER;
}
- /* For display devices like SSD and screenrecord, we cannot
- * rely on isActive and connected attributes of dpyAttr to
- * determine if the displaydevice is active. Hence in case if
- * the layer-list is non-null and numHwLayers > 0, we assume
- * the display device to be active.
- */
- ctx->numActiveDisplays += 1;
-
- if((ctx->mPrevHwLayerCount[i] == 1) and (list->numHwLayers > 1)) {
- /* If the previous cycle for dpy 'i' has 0 AppLayers and the
- * current cycle has atleast 1 AppLayer, padding round needs
- * to be invoked on current cycle to free up the resources.
- */
- ctx->isPaddingRound = true;
- }
- ctx->mPrevHwLayerCount[i] = (int)list->numHwLayers;
- } else {
- ctx->mPrevHwLayerCount[i] = 0;
}
if(ctx->mFBUpdate[i])
@@ -154,31 +228,20 @@
ctx->mHWCVirtual->destroy(ctx, numDisplays, displays);
}
-bool isEqual(float f1, float f2) {
- return ((int)(f1*100) == (int)(f2*100)) ? true : false;
-}
-
static void scaleDisplayFrame(hwc_context_t *ctx, int dpy,
hwc_display_contents_1_t *list) {
- uint32_t origXres = ctx->dpyAttr[dpy].xres_orig;
- uint32_t origYres = ctx->dpyAttr[dpy].yres_orig;
- uint32_t fakeXres = ctx->dpyAttr[dpy].xres;
- uint32_t fakeYres = ctx->dpyAttr[dpy].yres;
- float xresRatio = (float)origXres / (float)fakeXres;
- float yresRatio = (float)origYres / (float)fakeYres;
+ uint32_t origXres = ctx->dpyAttr[dpy].xres;
+ uint32_t origYres = ctx->dpyAttr[dpy].yres;
+ uint32_t newXres = ctx->dpyAttr[dpy].xres_new;
+ uint32_t newYres = ctx->dpyAttr[dpy].yres_new;
+ float xresRatio = (float)origXres / (float)newXres;
+ float yresRatio = (float)origYres / (float)newYres;
for (size_t i = 0; i < list->numHwLayers; i++) {
hwc_layer_1_t *layer = &list->hwLayers[i];
hwc_rect_t& displayFrame = layer->displayFrame;
hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
uint32_t layerWidth = displayFrame.right - displayFrame.left;
uint32_t layerHeight = displayFrame.bottom - displayFrame.top;
- uint32_t sourceWidth = sourceCrop.right - sourceCrop.left;
- uint32_t sourceHeight = sourceCrop.bottom - sourceCrop.top;
-
- if (isEqual(((float)layerWidth / (float)sourceWidth), xresRatio) &&
- isEqual(((float)layerHeight / (float)sourceHeight), yresRatio))
- break;
-
displayFrame.left = (int)(xresRatio * (float)displayFrame.left);
displayFrame.top = (int)(yresRatio * (float)displayFrame.top);
displayFrame.right = (int)((float)displayFrame.left +
@@ -197,7 +260,8 @@
if (LIKELY(list && list->numHwLayers > 1) &&
ctx->dpyAttr[dpy].isActive) {
- if (ctx->dpyAttr[dpy].customFBSize)
+ if (ctx->dpyAttr[dpy].customFBSize &&
+ list->flags & HWC_GEOMETRY_CHANGED)
scaleDisplayFrame(ctx, dpy, list);
reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
@@ -207,7 +271,10 @@
if (fbComp) {
const int fbZ = 0;
- ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
+ if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ)) {
+ ctx->mOverlay->clear(dpy);
+ ctx->mLayerRotMap[dpy]->clear();
+ }
}
if (ctx->mMDP.version < qdutils::MDP_V4_0) {
@@ -234,7 +301,11 @@
setListStats(ctx, list, dpy);
if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
const int fbZ = 0;
- ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
+ if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
+ {
+ ctx->mOverlay->clear(dpy);
+ ctx->mLayerRotMap[dpy]->clear();
+ }
}
} else {
/* External Display is in Pause state.
@@ -263,6 +334,9 @@
//Will be unlocked at the end of set
ctx->mDrawLock.lock();
+ setPaddingRound(ctx,numDisplays,displays);
+ setDMAState(ctx,numDisplays,displays);
+ setNumActiveDisplays(ctx,numDisplays,displays);
reset(ctx, (int)numDisplays, displays);
ctx->mOverlay->configBegin();
@@ -630,8 +704,6 @@
CALC_FPS();
MDPComp::resetIdleFallBack();
ctx->mVideoTransFlag = false;
- if(ctx->mRotMgr->getNumActiveSessions() == 0)
- Overlay::setDMAMode(Overlay::DMA_LINE_MODE);
//Was locked at the beginning of prepare
ctx->mDrawLock.unlock();
return ret;
@@ -696,14 +768,21 @@
values[i] = ctx->dpyAttr[disp].vsync_period;
break;
case HWC_DISPLAY_WIDTH:
- values[i] = ctx->dpyAttr[disp].xres;
+ if (ctx->dpyAttr[disp].customFBSize)
+ values[i] = ctx->dpyAttr[disp].xres_new;
+ else
+ values[i] = ctx->dpyAttr[disp].xres;
+
ALOGD("%s disp = %d, width = %d",__FUNCTION__, disp,
- ctx->dpyAttr[disp].xres);
+ values[i]);
break;
case HWC_DISPLAY_HEIGHT:
- values[i] = ctx->dpyAttr[disp].yres;
+ if (ctx->dpyAttr[disp].customFBSize)
+ values[i] = ctx->dpyAttr[disp].yres_new;
+ else
+ values[i] = ctx->dpyAttr[disp].yres;
ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp,
- ctx->dpyAttr[disp].yres);
+ values[i]);
break;
case HWC_DISPLAY_DPI_X:
values[i] = (int32_t) (ctx->dpyAttr[disp].xdpi*1000.0);
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 92aeca2..d7afa19 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -131,6 +131,83 @@
return renderArea;
}
+int CopyBit::getLayersChanging(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list,
+ int dpy){
+
+ int changingLayerIndex = -1;
+ if(mLayerCache.layerCount != ctx->listStats[dpy].numAppLayers) {
+ mLayerCache.reset();
+ mFbCache.reset();
+ mLayerCache.updateCounts(ctx,list,dpy);
+ return -1;
+ }
+
+ int updatingLayerCount = 0;
+ for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){
+ //swap rect will kick in only for single updating layer
+ if(mLayerCache.hnd[k] != list->hwLayers[k].handle){
+ updatingLayerCount ++;
+ if(updatingLayerCount == 1)
+ changingLayerIndex = k;
+ }
+ }
+ //since we are using more than one framebuffers,we have to
+ //kick in swap rect only if we are getting continuous same
+ //dirty rect for same layer at least equal of number of
+ //framebuffers
+
+ if ( updatingLayerCount == 1 ) {
+ hwc_rect_t dirtyRect = list->hwLayers[changingLayerIndex].displayFrame;
+#ifdef QCOM_BSP
+ dirtyRect = list->hwLayers[changingLayerIndex].dirtyRect;
+#endif
+
+ for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){
+ //disable swap rect for overlapping visible layer(s)
+ hwc_rect_t displayFrame = list->hwLayers[k].displayFrame;
+ hwc_rect_t result = getIntersection(displayFrame,dirtyRect);
+ if((k != changingLayerIndex) && isValidRect(result)){
+ return -1;
+ }
+ }
+ mFbCache.insertAndUpdateFbCache(dirtyRect);
+ if(mFbCache.getUnchangedFbDRCount(dirtyRect) <
+ NUM_RENDER_BUFFERS)
+ changingLayerIndex = -1;
+ }else {
+ mFbCache.reset();
+ changingLayerIndex = -1;
+ }
+ mLayerCache.updateCounts(ctx,list,dpy);
+ return changingLayerIndex;
+}
+
+int CopyBit::checkDirtyRect(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list,
+ int dpy) {
+
+ //dirty rect will enable only if
+ //1.Only single layer is updating.
+ //2.No overlapping
+ //3.No scaling
+ //4.No video layer
+ if(mSwapRectEnable == false)
+ return -1;
+ int changingLayerIndex = getLayersChanging(ctx, list, dpy);
+ //swap rect will kick in only for single updating layer
+ if(changingLayerIndex == -1){
+ return -1;
+ }
+ if(!needsScaling(&list->hwLayers[changingLayerIndex])){
+ private_handle_t *hnd =
+ (private_handle_t *)list->hwLayers[changingLayerIndex].handle;
+ if( hnd && !isYuvBuffer(hnd))
+ return changingLayerIndex;
+ }
+ return -1;
+}
+
bool CopyBit::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy) {
@@ -272,9 +349,10 @@
LayerProp *layerProp = ctx->layerProp[dpy];
private_handle_t *renderBuffer;
- if(mCopyBitDraw == false) // there is no layer marked for copybit
- return false ;
-
+ if(mCopyBitDraw == false){
+ mFbCache.reset(); // there is no layer marked for copybit
+ return false ;
+ }
//render buffer
if (ctx->mMDP.version == qdutils::MDP_V3_0_4) {
last = (uint32_t)list->numHwLayers - 1;
@@ -301,10 +379,19 @@
}
}
- //Clear the transparent or left out region on the render buffer
- hwc_rect_t clearRegion = {0,0,0,0};
- if(CBUtils::getuiClearRegion(list, clearRegion, layerProp))
- clear(renderBuffer, clearRegion);
+ mDirtyLayerIndex = checkDirtyRect(ctx, list, dpy);
+ if( mDirtyLayerIndex != -1){
+ hwc_layer_1_t *layer = &list->hwLayers[mDirtyLayerIndex];
+#ifdef QCOM_BSP
+ clear(renderBuffer,layer->dirtyRect);
+#else
+ clear(renderBuffer,layer->displayFrame);
+#endif
+ } else {
+ hwc_rect_t clearRegion = {0,0,0,0};
+ if(CBUtils::getuiClearRegion(list, clearRegion, layerProp))
+ clear(renderBuffer, clearRegion);
+ }
// numAppLayers-1, as we iterate from 0th layer index with HWC_COPYBIT flag
for (int i = 0; i <= (ctx->listStats[dpy].numAppLayers-1); i++) {
@@ -313,9 +400,9 @@
ALOGD_IF(DEBUG_COPYBIT, "%s: Not Marked for copybit", __FUNCTION__);
continue;
}
- if(layer->flags & HWC_SKIP_HWC_COMPOSITION){
+ //skip non updating layers
+ if((mDirtyLayerIndex != -1) && (mDirtyLayerIndex != i) )
continue;
- }
int ret = -1;
if (list->hwLayers[i].acquireFenceFd != -1
&& ctx->mMDP.version >= qdutils::MDP_V4_0) {
@@ -329,7 +416,7 @@
list->hwLayers[i].acquireFenceFd = -1;
}
retVal = drawLayerUsingCopybit(ctx, &(list->hwLayers[i]),
- renderBuffer, !i);
+ renderBuffer, !i);
copybitLayerCount++;
if(retVal < 0) {
ALOGE("%s : drawLayerUsingCopybit failed", __FUNCTION__);
@@ -429,7 +516,16 @@
copybit_rect_t dstRect = {displayFrame.left, displayFrame.top,
displayFrame.right,
displayFrame.bottom};
-
+#ifdef QCOM_BSP
+ //change src and dst with dirtyRect
+ if(mDirtyLayerIndex != -1) {
+ srcRect.l = layer->dirtyRect.left;
+ srcRect.t = layer->dirtyRect.top;
+ srcRect.r = layer->dirtyRect.right;
+ srcRect.b = layer->dirtyRect.bottom;
+ dstRect = srcRect;
+ }
+#endif
// Copybit dst
copybit_image_t dst;
dst.w = ALIGN(fbHandle->width,32);
@@ -733,6 +829,9 @@
property_get("debug.hwc.dynThreshold", value, "2");
mDynThreshold = atof(value);
+ property_get("debug.sf.swaprect", value, "0");
+ mSwapRectEnable = atoi(value) ? true:false ;
+ mDirtyLayerIndex = -1;
if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
if(copybit_open(module, &mEngine) < 0) {
ALOGE("FATAL ERROR: copybit open failed.");
@@ -751,4 +850,43 @@
mEngine = NULL;
}
}
+CopyBit::LayerCache::LayerCache() {
+ reset();
+}
+void CopyBit::LayerCache::reset() {
+ memset(&hnd, 0, sizeof(hnd));
+ layerCount = 0;
+}
+void CopyBit::LayerCache::updateCounts(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list, int dpy)
+{
+ layerCount = ctx->listStats[dpy].numAppLayers;
+ for (int i=0; i<ctx->listStats[dpy].numAppLayers; i++){
+ hnd[i] = list->hwLayers[i].handle;
+ }
+}
+
+CopyBit::FbCache::FbCache() {
+ reset();
+}
+void CopyBit::FbCache::reset() {
+ memset(&FbdirtyRect, 0, sizeof(FbdirtyRect));
+ FbIndex =0;
+}
+
+void CopyBit::FbCache::insertAndUpdateFbCache(hwc_rect_t dirtyRect) {
+ FbIndex = FbIndex % NUM_RENDER_BUFFERS;
+ FbdirtyRect[FbIndex] = dirtyRect;
+ FbIndex++;
+}
+
+int CopyBit::FbCache::getUnchangedFbDRCount(hwc_rect_t dirtyRect){
+ int sameDirtyCount = 0;
+ for (int i = 0 ; i < NUM_RENDER_BUFFERS ; i++ ){
+ if( FbdirtyRect[i] == dirtyRect)
+ sameDirtyCount++;
+ }
+ return sameDirtyCount;
+}
+
}; //namespace qhwc
diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h
index f7be644..14f8cfc 100644
--- a/libhwcomposer/hwc_copybit.h
+++ b/libhwcomposer/hwc_copybit.h
@@ -50,6 +50,27 @@
void setReleaseFd(int fd);
private:
+ /* cached data */
+ struct LayerCache {
+ int layerCount;
+ buffer_handle_t hnd[MAX_NUM_APP_LAYERS];
+ /* c'tor */
+ LayerCache();
+ /* clear caching info*/
+ void reset();
+ void updateCounts(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy);
+ };
+ /* framebuffer cache*/
+ struct FbCache {
+ hwc_rect_t FbdirtyRect[NUM_RENDER_BUFFERS];
+ int FbIndex;
+ FbCache();
+ void reset();
+ void insertAndUpdateFbCache(hwc_rect_t dirtyRect);
+ int getUnchangedFbDRCount(hwc_rect_t dirtyRect);
+ };
+
// holds the copybit device
struct copybit_device_t *mEngine;
// Helper functions for copybit composition
@@ -89,8 +110,16 @@
//Dynamic composition threshold for deciding copybit usage.
double mDynThreshold;
+ bool mSwapRectEnable;
int mAlignedFBWidth;
int mAlignedFBHeight;
+ int mDirtyLayerIndex;
+ LayerCache mLayerCache;
+ FbCache mFbCache;
+ int getLayersChanging(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy);
+ int checkDirtyRect(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy);
};
}; //namespace qhwc
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 74e6da4..4ab8eb8 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -38,10 +38,9 @@
namespace ovutils = overlay::utils;
IFBUpdate* IFBUpdate::getObject(hwc_context_t *ctx, const int& dpy) {
- if(isDisplaySplit(ctx, dpy)) {
- if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
- return new FBSrcSplit(ctx, dpy);
- }
+ if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
+ return new FBSrcSplit(ctx, dpy);
+ } else if(isDisplaySplit(ctx, dpy)) {
return new FBUpdateSplit(ctx, dpy);
}
return new FBUpdateNonSplit(ctx, dpy);
@@ -49,8 +48,15 @@
IFBUpdate::IFBUpdate(hwc_context_t *ctx, const int& dpy) : mDpy(dpy) {
size_t size = 0;
- getBufferAttributes(ctx->dpyAttr[mDpy].xres,
- ctx->dpyAttr[mDpy].yres,
+ uint32_t xres = ctx->dpyAttr[mDpy].xres;
+ uint32_t yres = ctx->dpyAttr[mDpy].yres;
+ if (ctx->dpyAttr[dpy].customFBSize) {
+ //GPU will render and compose at new resolution
+ //So need to have FB at new resolution
+ xres = ctx->dpyAttr[mDpy].xres_new;
+ yres = ctx->dpyAttr[mDpy].yres_new;
+ }
+ getBufferAttributes((int)xres, (int)yres,
HAL_PIXEL_FORMAT_RGBA_8888,
0,
mAlignedFBWidth,
@@ -192,7 +198,7 @@
(mDpy && !extOrient
&& !ctx->dpyAttr[mDpy].mDownScaleMode))
&& (extOnlyLayerIndex == -1)) {
- if(!qdutils::MDPVersion::getInstance().is8x26() &&
+ if(ctx->mOverlay->isUIScalingOnExternalSupported() &&
!ctx->dpyAttr[mDpy].customFBSize) {
getNonWormholeRegion(list, sourceCrop);
displayFrame = sourceCrop;
@@ -208,8 +214,6 @@
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
@@ -224,7 +228,6 @@
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;
}
}
@@ -387,10 +390,6 @@
ret = false;
}
}
-
- if(ret == false) {
- ctx->mLayerRotMap[mDpy]->clear();
- }
}
return ret;
}
@@ -425,7 +424,6 @@
bool FBSrcSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
hwc_rect_t fbUpdatingRect, int fbZorder) {
- bool ret = false;
hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
int extOnlyLayerIndex = ctx->listStats[mDpy].extOnlyLayerIndex;
// ext only layer present..
@@ -502,7 +500,6 @@
if(configMdp(ctx->mOverlay, parg, orient,
cropL, cropL, NULL /*metadata*/, destL) < 0) {
ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
- ctx->mLayerRotMap[mDpy]->clear();
return false;
}
}
@@ -512,7 +509,6 @@
if(configMdp(ctx->mOverlay, parg, orient,
cropR, cropR, NULL /*metadata*/, destR) < 0) {
ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
- ctx->mLayerRotMap[mDpy]->clear();
return false;
}
}
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 5b914d8..7c67641 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -47,12 +47,10 @@
bool MDPComp::sEnable4k2kYUVSplit = false;
bool MDPComp::sSrcSplitEnabled = false;
MDPComp* MDPComp::getObject(hwc_context_t *ctx, const int& dpy) {
-
- if(isDisplaySplit(ctx, dpy)) {
- if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
- sSrcSplitEnabled = true;
- return new MDPCompSrcSplit(dpy);
- }
+ if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
+ sSrcSplitEnabled = true;
+ return new MDPCompSrcSplit(dpy);
+ } else if(isDisplaySplit(ctx, dpy)) {
return new MDPCompSplit(dpy);
}
return new MDPCompNonSplit(dpy);
@@ -118,9 +116,13 @@
sDebugLogs = true;
}
- if(property_get("persist.hwc.partialupdate", property, NULL) > 0) {
- if((atoi(property) != 0) && ctx->mMDP.panel == MIPI_CMD_PANEL &&
- qdutils::MDPVersion::getInstance().is8x74v2())
+ // We read from drivers if panel supports partial updating
+ // and we enable partial update computations if supported.
+ // Keeping this property to disable partial update for
+ // debugging by setting below property to 0 & only 0.
+ property_get("persist.hwc.partialupdate", property, "-1");
+ if((atoi(property) != 0) &&
+ qdutils::MDPVersion::getInstance().isPartialUpdateEnabled()) {
sEnablePartialFrameUpdate = true;
}
ALOGE_IF(isDebug(), "%s: Partial Update applicable?: %d",__FUNCTION__,
@@ -399,7 +401,8 @@
if(!isEnabled()) {
ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
ret = false;
- } else if(qdutils::MDPVersion::getInstance().is8x26() &&
+ } else if((qdutils::MDPVersion::getInstance().is8x26() ||
+ qdutils::MDPVersion::getInstance().is8x16()) &&
ctx->mVideoTransFlag &&
isSecondaryConnected(ctx)) {
//1 Padding round to shift pipes across mixers
@@ -474,43 +477,44 @@
return true;
}
+bool MDPComp::canDoPartialUpdate(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list){
+ if(!qdutils::MDPVersion::getInstance().isPartialUpdateEnabled() || mDpy ||
+ isSkipPresent(ctx, mDpy) || (list->flags & HWC_GEOMETRY_CHANGED)||
+ isDisplaySplit(ctx, mDpy)) {
+ return false;
+ }
+ return true;
+}
+
void MDPComp::generateROI(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
int numAppLayers = ctx->listStats[mDpy].numAppLayers;
- if(!sEnablePartialFrameUpdate) {
- return;
- }
-
- if(mDpy || isDisplaySplit(ctx, mDpy)){
- ALOGE_IF(isDebug(), "%s: ROI not supported for"
- "the (1) external / virtual display's (2) dual DSI displays",
- __FUNCTION__);
- return;
- }
-
- if(isSkipPresent(ctx, mDpy))
- return;
-
- if(list->flags & HWC_GEOMETRY_CHANGED)
+ if(!canDoPartialUpdate(ctx, list))
return;
struct hwc_rect roi = (struct hwc_rect){0, 0, 0, 0};
for(int index = 0; index < numAppLayers; index++ ) {
- if ((mCachedFrame.hnd[index] != list->hwLayers[index].handle) ||
- isYuvBuffer((private_handle_t *)list->hwLayers[index].handle)) {
- hwc_rect_t dstRect = list->hwLayers[index].displayFrame;
- hwc_rect_t srcRect = integerizeSourceCrop(
- list->hwLayers[index].sourceCropf);
-
- /* Intersect against display boundaries */
- roi = getUnion(roi, dstRect);
+ 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;
+#ifdef QCOM_BSP
+ if(!needsScaling(layer))
+ updatingRect = layer->dirtyRect;
+#endif
+ roi = getUnion(roi, updatingRect);
}
}
- if(!validateAndApplyROI(ctx, list, roi)){
- roi = (struct hwc_rect) {0, 0,
- (int)ctx->dpyAttr[mDpy].xres, (int)ctx->dpyAttr[mDpy].yres};
- }
+ hwc_rect fullFrame = (struct hwc_rect) {0, 0,(int)ctx->dpyAttr[mDpy].xres,
+ (int)ctx->dpyAttr[mDpy].yres};
+
+ // Align ROI coordinates to panel restrictions
+ roi = sanitizeROI(roi, fullFrame);
+
+ if(!validateAndApplyROI(ctx, list, roi))
+ roi = fullFrame;
ctx->listStats[mDpy].roi.x = roi.left;
ctx->listStats[mDpy].roi.y = roi.top;
@@ -607,19 +611,11 @@
const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
for(int i = 0; i < numAppLayers; i++) {
hwc_layer_1_t* layer = &list->hwLayers[i];
- if(not isSupportedForMDPComp(ctx, layer)) {
+ if(not mCurrentFrame.drop[i] and
+ not isSupportedForMDPComp(ctx, layer)) {
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(layer))
- return false;
}
mCurrentFrame.fbCount = 0;
@@ -1407,6 +1403,7 @@
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres > 1024);
pipeSpecs.dpy = mDpy;
pipeSpecs.fb = false;
+ pipeSpecs.numActiveDisplays = ctx->numActiveDisplays;
pipe_info.index = ctx->mOverlay->getPipe(pipeSpecs);
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index beb858b..8186fff 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -213,6 +213,7 @@
bool isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer);
bool resourceCheck();
hwc_rect_t getUpdatingFBRect(hwc_display_contents_1_t* list);
+ bool canDoPartialUpdate(hwc_context_t *ctx, hwc_display_contents_1_t* list);
int mDpy;
static bool sEnabled;
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 976b23d..0bb71f0 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -108,8 +108,13 @@
Parcel* outParcel) {
int dpy = inParcel->readInt32();
outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
- outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
- outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
+ if (ctx->dpyAttr[dpy].customFBSize) {
+ outParcel->writeInt32(ctx->dpyAttr[dpy].xres_new);
+ outParcel->writeInt32(ctx->dpyAttr[dpy].yres_new);
+ } else {
+ outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
+ outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
+ }
outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
//XXX: Need to check what to return for HDMI
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 19978ad..4cc8243 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -85,20 +85,19 @@
void changeResolution(hwc_context_t *ctx, int xres_orig, int yres_orig) {
//Store original display resolution.
- ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_orig = xres_orig;
- ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_orig = yres_orig;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_orig;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_orig;
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = false;
-
char property[PROPERTY_VALUE_MAX] = {'\0'};
char *yptr = NULL;
if (property_get("debug.hwc.fbsize", property, NULL) > 0) {
yptr = strcasestr(property,"x");
- int xres = atoi(property);
- int yres = atoi(yptr + 1);
- if (isValidResolution(ctx,xres,yres) &&
- xres != xres_orig && yres != yres_orig) {
- ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres = xres;
- ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres = yres;
+ int xres_new = atoi(property);
+ int yres_new = atoi(yptr + 1);
+ if (isValidResolution(ctx,xres_new,yres_new) &&
+ xres_new != xres_orig && yres_new != yres_orig) {
+ 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;
}
}
@@ -569,7 +568,7 @@
ovutils::eTransform& orient) {
// Swap width and height when there is a 90deg transform
int extOrient = getExtOrientation(ctx);
- if(dpy && !qdutils::MDPVersion::getInstance().is8x26()) {
+ if(dpy && ctx->mOverlay->isUIScalingOnExternalSupported()) {
if(!isYuvBuffer(hnd)) {
if(extOrient & HWC_TRANSFORM_ROT_90) {
int dstWidth = ctx->dpyAttr[dpy].xres;
@@ -887,13 +886,6 @@
ctx->listStats[dpy].yuv4k2kIndices[yuv4k2kCount] = (int)i;
yuv4k2kCount++;
}
-
- if((layer->transform & HWC_TRANSFORM_ROT_90) &&
- canUseRotator(ctx, dpy)) {
- if(ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA))
- ctx->isPaddingRound = true;
- Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
- }
}
if(layer->blending == HWC_BLENDING_PREMULT)
ctx->listStats[dpy].preMultipliedAlpha = true;
@@ -916,25 +908,6 @@
}
}
}
- if(dpy) {
- //uncomment the below code for testing purpose.
- /* char value[PROPERTY_VALUE_MAX];
- property_get("sys.ext_orientation", value, "0");
- // Assuming the orientation value is in terms of HAL_TRANSFORM,
- // This needs mapping to HAL, if its in different convention
- ctx->mExtOrientation = atoi(value); */
- // Assuming the orientation value is in terms of HAL_TRANSFORM,
- // This needs mapping to HAL, if its in different convention
- if(ctx->mExtOrientation || ctx->mBufferMirrorMode) {
- ALOGD_IF(HWC_UTILS_DEBUG, "%s: ext orientation = %d"
- "BufferMirrorMode = %d", __FUNCTION__,
- ctx->mExtOrientation, ctx->mBufferMirrorMode);
- if(ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
- ctx->isPaddingRound = true;
- }
- Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
- }
- }
//The marking of video begin/end is useful on some targets where we need
//to have a padding round to be able to shift pipes across mixers.
@@ -1102,6 +1075,13 @@
return ((rect.bottom > rect.top) && (rect.right > rect.left)) ;
}
+bool operator ==(const hwc_rect_t& lhs, const hwc_rect_t& rhs) {
+ if(lhs.left == rhs.left && lhs.top == rhs.top &&
+ lhs.right == rhs.right && lhs.bottom == rhs.bottom )
+ return true ;
+ return false;
+}
+
/* computes the intersection of two rects */
hwc_rect_t getIntersection(const hwc_rect_t& rect1, const hwc_rect_t& rect2)
{
@@ -1196,6 +1176,11 @@
layer->sourceCropf.top = (float)bottomCrop.top;
layer->sourceCropf.right = (float)bottomCrop.right;
layer->sourceCropf.bottom = (float)bottomCrop.bottom;
+#ifdef QCOM_BSP
+ //Update layer dirtyRect
+ layer->dirtyRect = getIntersection(bottomCrop,
+ layer->dirtyRect);
+#endif
}
}
j--;
@@ -1290,6 +1275,9 @@
&currLayer->acquireFenceFd;
rotData.rel_fen_fd = &rotReleaseFd; //driver to populate this
rotData.session_id = currRot->getSessId();
+ if(currLayer->acquireFenceFd >= 0) {
+ rotData.acq_fen_fd_cnt = 1; //1 ioctl call per rot session
+ }
int ret = 0;
ret = ioctl(rotFd, MSMFB_BUFFER_SYNC, &rotData);
if(ret < 0) {
@@ -1962,10 +1950,10 @@
}
bool canUseRotator(hwc_context_t *ctx, int dpy) {
- if(qdutils::MDPVersion::getInstance().is8x26() &&
+ if(ctx->mOverlay->isDMAMultiplexingSupported() &&
isSecondaryConnected(ctx) &&
!ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause) {
- /* 8x26 mdss driver supports multiplexing of DMA pipe
+ /* mdss driver on certain targets support multiplexing of DMA pipe
* in LINE and BLOCK modes for writeback panels.
*/
if(dpy == HWC_DISPLAY_PRIMARY)
@@ -2176,4 +2164,58 @@
}
}
+hwc_rect_t sanitizeROI(struct hwc_rect roi, hwc_rect boundary)
+{
+ if(!isValidRect(roi))
+ return roi;
+
+ struct hwc_rect t_roi = roi;
+
+ const int LEFT_ALIGN = qdutils::MDPVersion::getInstance().getLeftAlign();
+ const int WIDTH_ALIGN = qdutils::MDPVersion::getInstance().getWidthAlign();
+ const int TOP_ALIGN = qdutils::MDPVersion::getInstance().getTopAlign();
+ const int HEIGHT_ALIGN = qdutils::MDPVersion::getInstance().getHeightAlign();
+ const int MIN_WIDTH = qdutils::MDPVersion::getInstance().getMinROIWidth();
+
+ /* Align to minimum width recommended by the panel */
+ if((t_roi.right - t_roi.left) < MIN_WIDTH) {
+ if((t_roi.left + MIN_WIDTH) > boundary.right)
+ t_roi.left = t_roi.right - MIN_WIDTH;
+ else
+ t_roi.right = t_roi.left + MIN_WIDTH;
+ }
+
+ /* Align left and width to meet panel restrictions */
+ if(WIDTH_ALIGN) {
+ int width = t_roi.right - t_roi.left;
+ width = WIDTH_ALIGN * ((width + (WIDTH_ALIGN - 1)) / WIDTH_ALIGN);
+ t_roi.right = t_roi.left + width;
+
+ if(t_roi.right > boundary.right) {
+ t_roi.right = boundary.right;
+ t_roi.left = t_roi.right - width;
+ }
+ }
+
+ if(LEFT_ALIGN)
+ t_roi.left = t_roi.left - (t_roi.left % LEFT_ALIGN);
+
+ /* Align top and height to meet panel restrictions */
+ if(HEIGHT_ALIGN) {
+ int height = t_roi.bottom - t_roi.top;
+ height = HEIGHT_ALIGN * ((height + (HEIGHT_ALIGN - 1)) / HEIGHT_ALIGN);
+ t_roi.bottom = t_roi.top + height;
+
+ if(t_roi.bottom > boundary.bottom) {
+ t_roi.bottom = boundary.bottom;
+ t_roi.top = t_roi.bottom - height;
+ }
+ }
+
+ if(TOP_ALIGN)
+ t_roi.top = t_roi.top - (t_roi.top % TOP_ALIGN);
+
+ return t_roi;
+}
+
};//namespace qhwc
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 726311b..0883a51 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -104,8 +104,8 @@
//If property fbsize set via adb shell debug.hwc.fbsize = XRESxYRES
//following fields are used.
bool customFBSize;
- uint32_t xres_orig;
- uint32_t yres_orig;
+ uint32_t xres_new;
+ uint32_t yres_new;
};
@@ -265,6 +265,7 @@
void optimizeLayerRects(const hwc_display_contents_1_t *list);
bool areLayersIntersecting(const hwc_layer_1_t* layer1,
const hwc_layer_1_t* layer2);
+bool operator ==(const hwc_rect_t& lhs, const hwc_rect_t& rhs);
// returns true if Action safe dimensions are set and target supports Actionsafe
bool isActionSafePresent(hwc_context_t *ctx, int dpy);
@@ -294,6 +295,9 @@
/* Get External State names */
const char* getExternalDisplayState(uint32_t external_state);
+// Aligns updating ROI to panel restrictions
+hwc_rect_t sanitizeROI(struct hwc_rect roi, hwc_rect boundary);
+
// Handles wfd Pause and resume events
void handle_pause(hwc_context_t *ctx, int dpy);
void handle_resume(hwc_context_t *ctx, int dpy);
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
index 10ed9d1..97b19ea 100644
--- a/libhwcomposer/hwc_virtual.cpp
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -126,7 +126,11 @@
if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
const int fbZ = 0;
- ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
+ if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
+ {
+ ctx->mOverlay->clear(dpy);
+ ctx->mLayerRotMap[dpy]->clear();
+ }
}
} else {
/* Virtual Display is in Pause state.
@@ -260,7 +264,11 @@
setListStats(ctx, list, dpy);
if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
const int fbZ = 0;
- ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
+ if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
+ {
+ ctx->mOverlay->clear(dpy);
+ ctx->mLayerRotMap[dpy]->clear();
+ }
}
} else {
/* Virtual Display is in Pause state.
diff --git a/liblight/lights.c b/liblight/lights.c
index 1aa0b58..6fd1290 100644
--- a/liblight/lights.c
+++ b/liblight/lights.c
@@ -83,7 +83,7 @@
fd = open(path, O_RDWR);
if (fd >= 0) {
char buffer[20];
- int bytes = sprintf(buffer, "%d\n", value);
+ int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
ssize_t amt = write(fd, buffer, (size_t)bytes);
close(fd);
return amt == -1 ? -errno : 0;
@@ -271,6 +271,10 @@
pthread_once(&g_init, init_globals);
struct light_device_t *dev = malloc(sizeof(struct light_device_t));
+
+ if(!dev)
+ return -ENOMEM;
+
memset(dev, 0, sizeof(*dev));
dev->common.tag = HARDWARE_DEVICE_TAG;
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index f4b0ecc..d53b46d 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -203,7 +203,9 @@
if(pipeSpecs.formatClass == FORMAT_YUV) { //video
return nextPipe(OV_MDP_PIPE_VG, pipeSpecs.dpy, pipeSpecs.mixer);
} else if(pipeSpecs.fb == false) { //RGB app layers
- if(not pipeSpecs.needsScaling) {
+ if((not pipeSpecs.needsScaling) and
+ (not (pipeSpecs.numActiveDisplays > 1 &&
+ pipeSpecs.dpy == DPY_PRIMARY))) {
dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs.dpy, pipeSpecs.mixer);
}
if(dest == OV_INVALID) {
@@ -220,7 +222,9 @@
dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs.dpy, pipeSpecs.mixer);
}
}
- if(dest == OV_INVALID and (not pipeSpecs.needsScaling)) {
+ if(dest == OV_INVALID and (not pipeSpecs.needsScaling) and
+ (not (pipeSpecs.numActiveDisplays > 1 &&
+ pipeSpecs.dpy == DPY_PRIMARY))) {
dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs.dpy, pipeSpecs.mixer);
}
}
@@ -233,23 +237,15 @@
eDest dest = OV_INVALID;
if(pipeSpecs.formatClass == FORMAT_YUV or pipeSpecs.needsScaling) {
return nextPipe(OV_MDP_PIPE_VG, pipeSpecs.dpy, pipeSpecs.mixer);
- } else if(pipeSpecs.fb == false) { //RGB app layers
+ } else {
//Since this is a specific func, we can assume stuff like RGB pipe not
//having scalar blocks
dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs.dpy, pipeSpecs.mixer);
if(dest == OV_INVALID) {
dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs.dpy, pipeSpecs.mixer);
}
- } else {
- //For 8x16 Secondary we use DMA always for FB for inline rotation
- if(pipeSpecs.dpy == DPY_PRIMARY) {
- dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs.dpy, pipeSpecs.mixer);
- if(dest == OV_INVALID) {
- dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs.dpy, pipeSpecs.mixer);
- }
- }
if(dest == OV_INVALID) {
- dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs.dpy, pipeSpecs.mixer);
+ dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs.dpy, pipeSpecs.mixer);
}
}
return dest;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index fa19dc3..455f547 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -57,12 +57,13 @@
struct PipeSpecs {
PipeSpecs() : formatClass(FORMAT_RGB), needsScaling(false), fb(false),
- dpy(DPY_PRIMARY), mixer(MIXER_DEFAULT) {}
+ dpy(DPY_PRIMARY), mixer(MIXER_DEFAULT), numActiveDisplays(1) {}
int formatClass;
bool needsScaling;
bool fb;
int dpy;
int mixer;
+ int numActiveDisplays;
};
/* dtor close */
@@ -130,6 +131,10 @@
/* Returns pipe dump. Expects a NULL terminated buffer of big enough size
* to populate.
*/
+ /* Returns if DMA pipe multiplexing is supported by the mdss driver */
+ static bool isDMAMultiplexingSupported();
+ /* Returns if UI scaling on external is supported on the targets */
+ static bool isUIScalingOnExternalSupported();
void getDump(char *buf, size_t len);
/* Reset usage and allocation bits on all pipes for given display */
void clear(int dpy);
@@ -306,6 +311,18 @@
sDMAMultiplexingSupported = true;
}
+inline bool Overlay::isDMAMultiplexingSupported() {
+ return sDMAMultiplexingSupported;
+}
+
+inline bool Overlay::isUIScalingOnExternalSupported() {
+ if(qdutils::MDPVersion::getInstance().is8x26() or
+ qdutils::MDPVersion::getInstance().is8x16()) {
+ return false;
+ }
+ return true;
+}
+
inline int Overlay::getDMAMode() {
return sDMAMode;
}
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index ce9d9d5..f7bc87a 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -37,6 +37,8 @@
namespace ovutils = overlay::utils;
namespace overlay {
+using namespace utils;
+
MdssRot::MdssRot() {
reset();
init();
@@ -265,19 +267,52 @@
// Calculate the compressed o/p buffer size for BWC
uint32_t MdssRot::calcCompressedBufSize(const ovutils::Whf& destWhf) {
uint32_t bufSize = 0;
+ //Worst case alignments
int aWidth = ovutils::align(destWhf.w, 64);
int aHeight = ovutils::align(destWhf.h, 4);
- int rau_cnt = aWidth/64;
- int stride0 = (64 * 4 * rau_cnt) + rau_cnt/8;
- int stride1 = ((64 * 2 * rau_cnt) + rau_cnt/8) * 2;
- int stride0_off = (aHeight/4);
- int stride1_off = (aHeight/2);
+ /*
+ Format | RAU size (width x height)
+ ----------------------------------------------
+ ARGB | 32 pixel x 4 line
+ RGB888 | 32 pixel x 4 line
+ Y (Luma) | 64 pixel x 4 line
+ CRCB 420 | 32 pixel x 2 line
+ CRCB 422 H2V1 | 32 pixel x 4 line
+ CRCB 422 H1V2 | 64 pixel x 2 line
- //New o/p size for BWC
- bufSize = (stride0 * stride0_off + stride1 * stride1_off) +
- (rau_cnt * 2 * (stride0_off + stride1_off));
- ALOGD_IF(DEBUG_MDSS_ROT, "%s: width = %d, height = %d raucount = %d"
- "opBufSize = %d ", __FUNCTION__, aWidth, aHeight, rau_cnt, bufSize);
+ Metadata requirements:-
+ 1 byte meta data for every 8 RAUs
+ 2 byte meta data per RAU
+ */
+
+ //These blocks attempt to allocate for the worst case in each of the
+ //respective format classes, yuv/rgb. The table above is for reference
+ if(utils::isYuv(destWhf.format)) {
+ int yRauCount = aWidth / 64; //Y
+ int cRauCount = aWidth / 32; //C
+ int yStride = (64 * 4 * yRauCount) + alignup(yRauCount, 8) / 8;
+ int cStride = ((32 * 2 * cRauCount) + alignup(cRauCount, 8) / 8) * 2;
+ int yStrideOffset = (aHeight / 4);
+ int cStrideOffset = (aHeight / 2);
+ bufSize = (yStride * yStrideOffset + cStride * cStrideOffset) +
+ (yRauCount * yStrideOffset * 2) +
+ (cRauCount * cStrideOffset * 2) * 2;
+ ALOGD_IF(DEBUG_MDSS_ROT, "%s:YUV Y RAU Count = %d C RAU Count = %d",
+ __FUNCTION__, yRauCount, cRauCount);
+ } else {
+ int rauCount = aWidth / 32;
+ //Single plane
+ int stride = (32 * 4 * rauCount) + alignup(rauCount, 8) / 8;
+ int strideOffset = (aHeight / 4);
+ bufSize = (stride * strideOffset * 4 /*bpp*/) +
+ (rauCount * strideOffset * 2);
+ ALOGD_IF(DEBUG_MDSS_ROT, "%s:RGB RAU count = %d", __FUNCTION__,
+ rauCount);
+ }
+
+ ALOGD_IF(DEBUG_MDSS_ROT, "%s: aligned width = %d, aligned height = %d "
+ "Buf Size = %d", __FUNCTION__, aWidth, aHeight, bufSize);
+
return bufSize;
}
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index 1a779cc..cace430 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -128,7 +128,10 @@
bool supportsMacroTile();
int getLeftSplit() { return mSplit.left(); }
int getRightSplit() { return mSplit.right(); }
- int isPartialUpdateEnabled() { return mPanelInfo.mPartialUpdateEnable; }
+ bool isPartialUpdateEnabled() {
+ return mPanelInfo.mPartialUpdateEnable &&
+ mPanelInfo.mType == MIPI_CMD_PANEL;
+ }
int getLeftAlign() { return mPanelInfo.mLeftAlign; }
int getWidthAlign() { return mPanelInfo.mWidthAlign; }
int getTopAlign() { return mPanelInfo.mTopAlign; }
diff --git a/libvirtual/virtual.cpp b/libvirtual/virtual.cpp
index bed5e4c..1f8e70c 100644
--- a/libvirtual/virtual.cpp
+++ b/libvirtual/virtual.cpp
@@ -47,7 +47,6 @@
#include "virtual.h"
#include "overlayUtils.h"
#include "overlay.h"
-#include "mdp_version.h"
#include "qd_utils.h"
using namespace android;
@@ -184,7 +183,7 @@
initResolution(extW, extH);
- if(!qdutils::MDPVersion::getInstance().is8x26()
+ if(mHwcContext->mOverlay->isUIScalingOnExternalSupported()
&& (mHwcContext->mMDPDownscaleEnabled || isDRC)) {
// maxArea represents the maximum resolution between