hwc: cache layers on framebuffer

In the cases where all the layers that are marked as HWC_FRAMEBUFFER did not
change, we can mark them as HWC_OVERLAY since their contents are already on the
framebuffer and do not need any additional processing.

This optimization shows power improvement for video playback.

Bug: 7623741
Change-Id: Ia178a926e6f56a3ec9291250a22a66f212c30b14
Signed-off-by: Iliyan Malchev <malchev@google.com>
This commit is contained in:
Naseer Ahmed
2012-10-17 00:32:50 -04:00
parent 09549f6d75
commit b1c7632ec5
3 changed files with 109 additions and 4 deletions

View File

@@ -77,11 +77,23 @@ static void hwc_registerProcs(struct hwc_composer_device_1* dev,
} }
//Helper //Helper
static void reset(hwc_context_t *ctx, int numDisplays) { static void reset(hwc_context_t *ctx, int numDisplays,
hwc_display_contents_1_t** displays) {
memset(ctx->listStats, 0, sizeof(ctx->listStats)); memset(ctx->listStats, 0, sizeof(ctx->listStats));
for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++){ for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++){
ctx->overlayInUse[i] = false; ctx->overlayInUse[i] = false;
ctx->listStats[i].yuvIndex = -1; ctx->listStats[i].yuvIndex = -1;
hwc_display_contents_1_t *list = displays[i];
// XXX:SurfaceFlinger no longer guarantees that this
// value is reset on every prepare. However, for the layer
// cache we need to reset it.
// We can probably rethink that later on
if (LIKELY(list && list->numHwLayers > 1)) {
for(uint32_t j = 0; j < list->numHwLayers; j++) {
if(list->hwLayers[j].compositionType != HWC_FRAMEBUFFER_TARGET)
list->hwLayers[j].compositionType = HWC_FRAMEBUFFER;
}
}
} }
} }
@@ -103,6 +115,7 @@ static int hwc_prepare_primary(hwc_composer_device_1 *dev,
} else { } else {
ctx->overlayInUse[HWC_DISPLAY_PRIMARY] = false; ctx->overlayInUse[HWC_DISPLAY_PRIMARY] = false;
} }
ctx->mLayerCache->updateLayerCache(list);
} }
} }
return 0; return 0;
@@ -141,7 +154,7 @@ static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays,
{ {
int ret = 0; int ret = 0;
hwc_context_t* ctx = (hwc_context_t*)(dev); hwc_context_t* ctx = (hwc_context_t*)(dev);
reset(ctx, numDisplays); reset(ctx, numDisplays, displays);
//If securing of h/w in progress skip comp using overlay. //If securing of h/w in progress skip comp using overlay.
if(ctx->mSecuring == true) return 0; if(ctx->mSecuring == true) return 0;

View File

@@ -60,6 +60,7 @@ void initContext(hwc_context_t *ctx)
ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay(); ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay();
ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType(); ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType();
ctx->mExtDisplay = new ExternalDisplay(ctx); ctx->mExtDisplay = new ExternalDisplay(ctx);
ctx->mLayerCache = new LayerCache();
MDPComp::init(ctx); MDPComp::init(ctx);
pthread_mutex_init(&(ctx->vstate.lock), NULL); pthread_mutex_init(&(ctx->vstate.lock), NULL);
@@ -208,7 +209,7 @@ int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy) {
int ret = 0; int ret = 0;
#ifdef USE_FENCE_SYNC #ifdef USE_FENCE_SYNC
struct mdp_buf_sync data; struct mdp_buf_sync data;
int acquireFd[4]; int acquireFd[MAX_NUM_LAYERS];
int count = 0; int count = 0;
int releaseFd = -1; int releaseFd = -1;
int fbFd = -1; int fbFd = -1;
@@ -219,7 +220,8 @@ int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy) {
for(uint32_t i = 0; i < list->numHwLayers; i++) { for(uint32_t i = 0; i < list->numHwLayers; i++) {
if((list->hwLayers[i].compositionType == HWC_OVERLAY || if((list->hwLayers[i].compositionType == HWC_OVERLAY ||
list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) && list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) &&
list->hwLayers[i].acquireFenceFd != -1) { list->hwLayers[i].acquireFenceFd != -1 &&
(list->hwLayers[i].flags & HWC_MDPCOMP)) {
acquireFd[count++] = list->hwLayers[i].acquireFenceFd; acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
} }
} }
@@ -251,4 +253,71 @@ int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy) {
return ret; return ret;
} }
void LayerCache::resetLayerCache(int num) {
for(uint32_t i = 0; i < MAX_NUM_LAYERS; i++) {
hnd[i] = NULL;
}
numHwLayers = num;
}
void LayerCache::updateLayerCache(hwc_display_contents_1_t* list) {
int numFbLayers = 0;
int numCacheableLayers = 0;
canUseLayerCache = false;
//Bail if geometry changed or num of layers changed
if(list->flags & HWC_GEOMETRY_CHANGED ||
list->numHwLayers != numHwLayers ) {
resetLayerCache(list->numHwLayers);
return;
}
for(uint32_t i = 0; i < list->numHwLayers; i++) {
//Bail on skip layers
if(list->hwLayers[i].flags & HWC_SKIP_LAYER) {
resetLayerCache(list->numHwLayers);
return;
}
if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER) {
numFbLayers++;
if(hnd[i] == NULL) {
hnd[i] = list->hwLayers[i].handle;
} else if (hnd[i] ==
list->hwLayers[i].handle) {
numCacheableLayers++;
} else {
hnd[i] = NULL;
return;
}
} else {
hnd[i] = NULL;
}
}
if(numFbLayers == numCacheableLayers)
canUseLayerCache = true;
//XXX: The marking part is separate, if MDP comp wants
// to use it in the future. Right now getting MDP comp
// to use this is more trouble than it is worth.
markCachedLayersAsOverlay(list);
}
void LayerCache::markCachedLayersAsOverlay(hwc_display_contents_1_t* list) {
//This optimization only works if ALL the layer handles
//that were on the framebuffer didn't change.
if(canUseLayerCache){
for(uint32_t i = 0; i < list->numHwLayers; i++) {
if (list->hwLayers[i].handle &&
list->hwLayers[i].handle == hnd[i] &&
list->hwLayers[i].compositionType != HWC_FRAMEBUFFER_TARGET)
{
list->hwLayers[i].compositionType = HWC_OVERLAY;
}
}
}
}
};//namespace };//namespace

View File

@@ -29,6 +29,7 @@
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
#define FINAL_TRANSFORM_MASK 0x000F #define FINAL_TRANSFORM_MASK 0x000F
#define MAX_NUM_DISPLAYS 4 //Yes, this is ambitious #define MAX_NUM_DISPLAYS 4 //Yes, this is ambitious
#define MAX_NUM_LAYERS 32
//Fwrd decls //Fwrd decls
struct hwc_context_t; struct hwc_context_t;
@@ -81,6 +82,26 @@ enum {
HWC_LAYER_RESERVED_1 = 0x00000008 HWC_LAYER_RESERVED_1 = 0x00000008
}; };
class LayerCache {
public:
LayerCache() {
canUseLayerCache = false;
numHwLayers = 0;
for(uint32_t i = 0; i < MAX_NUM_LAYERS; i++) {
hnd[i] = NULL;
}
}
//LayerCache optimization
void updateLayerCache(hwc_display_contents_1_t* list);
void resetLayerCache(int num);
void markCachedLayersAsOverlay(hwc_display_contents_1_t* list);
private:
uint32_t numHwLayers;
bool canUseLayerCache;
buffer_handle_t hnd[MAX_NUM_LAYERS];
};
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Utility functions - implemented in hwc_utils.cpp // Utility functions - implemented in hwc_utils.cpp
@@ -196,6 +217,8 @@ struct hwc_context_t {
qhwc::ListStats listStats[HWC_NUM_DISPLAY_TYPES]; qhwc::ListStats listStats[HWC_NUM_DISPLAY_TYPES];
qhwc::LayerCache *mLayerCache;
//Securing in progress indicator //Securing in progress indicator
bool mSecuring; bool mSecuring;