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:
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user