HWC/Copybit :: Add swap rect feature in HAL for MDP3
We brings all swap rect level checks in HAL from surfaceflinger
for MDP3.
swap rect kicks in case of
1 Only one layer is updating.
2 No overlaypping layers.
3.Both src and dst has same value.(no scaling)
4.No video layer
Change-Id: I881958994e80b53d4969beaaf51518b727a8de78
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 92aeca2..0843da4 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -131,6 +131,80 @@
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].dirtyRect;
+
+ 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 +346,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 +376,15 @@
}
}
- //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];
+ clear(renderBuffer,layer->dirtyRect);
+ } 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 +393,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 +409,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 +509,14 @@
copybit_rect_t dstRect = {displayFrame.left, displayFrame.top,
displayFrame.right,
displayFrame.bottom};
-
+ //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;
+ }
// Copybit dst
copybit_image_t dst;
dst.w = ALIGN(fbHandle->width,32);
@@ -733,6 +820,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 +841,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_utils.cpp b/libhwcomposer/hwc_utils.cpp
index ceb09ea..1670803 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -1080,6 +1080,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)
{
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index ed68988..a33df8d 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -254,6 +254,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);