/*
// Copyright (c) 2014 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/
#include <HwcTrace.h>
#include <Drm.h>
#include <HwcLayerList.h>
#include <Hwcomposer.h>
#include <GraphicBuffer.h>
#include <IDisplayDevice.h>
#include <PlaneCapabilities.h>
#include <DisplayQuery.h>
namespace android {
namespace intel {
HwcLayerList::HwcLayerList(hwc_display_contents_1_t *list, int disp)
: mList(list),
mLayerCount(0),
mLayers(),
mFBLayers(),
mStaticLayersIndex(),
mSpriteCandidates(),
mOverlayCandidates(),
mZOrderConfig(),
mFrameBufferTarget(NULL),
mDisplayIndex(disp),
mLayerSize(0)
{
initialize();
}
HwcLayerList::~HwcLayerList()
{
deinitialize();
}
bool HwcLayerList::checkSupported(int planeType, HwcLayer *hwcLayer)
{
bool valid = false;
hwc_layer_1_t& layer = *(hwcLayer->getLayer());
// if layer was forced to use FB
if (hwcLayer->getType() == HwcLayer::LAYER_FORCE_FB) {
VTRACE("layer was forced to use HWC_FRAMEBUFFER");
return false;
}
// check layer flags
if (layer.flags & HWC_SKIP_LAYER) {
VTRACE("plane type %d: (skip layer flag was set)", planeType);
return false;
}
if (layer.handle == 0) {
WTRACE("invalid buffer handle");
return false;
}
// check usage
if (!hwcLayer->getUsage() & GRALLOC_USAGE_HW_COMPOSER) {
WTRACE("not a composer layer");
return false;
}
// check layer transform
valid = PlaneCapabilities::isTransformSupported(planeType, hwcLayer);
if (!valid) {
VTRACE("plane type %d: (bad transform)", planeType);
return false;
}
// check buffer format
valid = PlaneCapabilities::isFormatSupported(planeType, hwcLayer);
if (!valid) {
VTRACE("plane type %d: (bad buffer format)", planeType);
return false;
}
// check buffer size
valid = PlaneCapabilities::isSizeSupported(planeType, hwcLayer);
if (!valid) {
VTRACE("plane type %d: (bad buffer size)", planeType);
return false;
}
// check layer blending
valid = PlaneCapabilities::isBlendingSupported(planeType, hwcLayer);
if (!valid) {
VTRACE("plane type %d: (bad blending)", planeType);
return false;
}
// check layer scaling
valid = PlaneCapabilities::isScalingSupported(planeType, hwcLayer);
if (!valid) {
VTRACE("plane type %d: (bad scaling)", planeType);
return false;
}
// TODO: check visible region?
return true;
}
bool HwcLayerList::checkCursorSupported(HwcLayer *hwcLayer)
{
hwc_layer_1_t& layer = *(hwcLayer->getLayer());
// if layer was forced to use FB
if (hwcLayer->getType() == HwcLayer::LAYER_FORCE_FB) {
VTRACE("layer was forced to use HWC_FRAMEBUFFER");
return false;
}
// check layer flags
if (layer.flags & HWC_SKIP_LAYER) {
VTRACE("skip layer flag was set");
return false;
}
if (!(layer.flags & HWC_IS_CURSOR_LAYER)) {
VTRACE("not a cursor layer");
return false;
}
if (hwcLayer->getIndex() != mLayerCount - 2) {
WTRACE("cursor layer is not on top of zorder");
return false;
}
if (layer.handle == 0) {
WTRACE("invalid buffer handle");
return false;
}
// check usage
if (!(hwcLayer->getUsage() & GRALLOC_USAGE_HW_COMPOSER)) {
WTRACE("not a composer layer");
return false;
}
uint32_t format = hwcLayer->getFormat();
if (format != HAL_PIXEL_FORMAT_BGRA_8888 &&
format != HAL_PIXEL_FORMAT_RGBA_8888) {
WTRACE("unexpected color format %u for cursor", format);
return false;
}
uint32_t trans = hwcLayer->getLayer()->transform;
if (trans != 0) {
WTRACE("unexpected transform %u for cursor", trans);
return false;
}
hwc_frect_t& src = hwcLayer->getLayer()->sourceCropf;
hwc_rect_t& dest = hwcLayer->getLayer()->displayFrame;
int srcW = (int)src.right - (int)src.left;
int srcH = (int)src.bottom - (int)src.top;
int dstW = dest.right - dest.left;
int dstH = dest.bottom - dest.top;
if (srcW != dstW || srcH != dstH) {
WTRACE("unexpected scaling for cursor: %dx%d => %dx%d",
srcW, srcH, dstW, dstH);
//return false;
}
if (srcW > 256 || srcH > 256) {
WTRACE("unexpected size %dx%d for cursor", srcW, srcH);
return false;
}
BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
if (bm) {
DataBuffer *buffer = bm->lockDataBuffer(hwcLayer->getHandle());
if (buffer) {
uint32_t w = buffer->getWidth();
uint32_t h = buffer->getHeight();
if ((w != 64 || h != 64) &&
(w != 128 || h != 128) &&
(w != 256 || h != 256)) {
bm->unlockDataBuffer(buffer);
return false;
}
}
bm->unlockDataBuffer(buffer);
}
return true;
}
bool HwcLayerList::initialize()
{
if (!mList || mList->numHwLayers == 0) {
ETRACE("invalid hwc list");
return false;
}
mLayerCount = (int)mList->numHwLayers;
mLayers.setCapacity(mLayerCount);
mFBLayers.setCapacity(mLayerCount);
mSpriteCandidates.setCapacity(mLayerCount);
mOverlayCandidates.setCapacity(mLayerCount);
mCursorCandidates.setCapacity(mLayerCount);
mZOrderConfig.setCapacity(mLayerCount);
Hwcomposer& hwc = Hwcomposer::getInstance();
for (int i = 0; i < mLayerCount; i++) {
hwc_layer_1_t *layer = &mList->hwLayers[i];
if (!layer) {
DEINIT_AND_RETURN_FALSE("layer %d is null", i);
}
HwcLayer *hwcLayer = new HwcLayer(i, layer);
if (!hwcLayer) {
DEINIT_AND_RETURN_FALSE("failed to allocate hwc layer %d", i);
}
if (layer->compositionType == HWC_FRAMEBUFFER_TARGET) {
hwcLayer->setType(HwcLayer::LAYER_FRAMEBUFFER_TARGET);
mFrameBufferTarget = hwcLayer;
} else if (layer->compositionType == HWC_OVERLAY){
// skipped layer, filtered by Display Analyzer
hwcLayer->setType(HwcLayer::LAYER_SKIPPED);
} else if (layer->compositionType == HWC_FORCE_FRAMEBUFFER) {
layer->compositionType = HWC_FRAMEBUFFER;
hwcLayer->setType(HwcLayer::LAYER_FORCE_FB);
// add layer to FB layer list for zorder check during plane assignment
mFBLayers.add(hwcLayer);
} else if (layer->compositionType == HWC_FRAMEBUFFER) {
// by default use GPU composition
hwcLayer->setType(HwcLayer::LAYER_FB);
mFBLayers.add(hwcLayer);
if (checkCursorSupported(hwcLayer)) {
mCursorCandidates.add(hwcLayer);
} else if (checkSupported(DisplayPlane::PLANE_SPRITE, hwcLayer)) {
mSpriteCandidates.add(hwcLayer);
} else if (hwc.getDisplayAnalyzer()->isOverlayAllowed() &&
checkSupported(DisplayPlane::PLANE_OVERLAY, hwcLayer)) {
mOverlayCandidates.add(hwcLayer);
} else {
// noncandidate layer
}
} else if (layer->compositionType == HWC_SIDEBAND){
hwcLayer->setType(HwcLayer::LAYER_SIDEBAND);
} else {
DEINIT_AND_RETURN_FALSE("invalid composition type %d", layer->compositionType);
}
// add layer to layer list
mLayers.add(hwcLayer);
}
if (mFrameBufferTarget == NULL) {
ETRACE("no frame buffer target?");
return false;
}
// If has layer besides of FB_Target, but no FBLayers, skip plane allocation
// Note: There is case that SF passes down a layerlist with only FB_Target
// layer; we need to have this FB_Target to be flipped as well, otherwise it
// will have the buffer queue blocked. (The buffer hold by driver cannot be
// released if new buffers' flip is skipped).
if ((mFBLayers.size() == 0) && (mLayers.size() > 1)) {
VTRACE("no FB layers, skip plane allocation");
return true;
}
allocatePlanes();
//dump();
return true;
}
void HwcLayerList::deinitialize()
{
if (mLayerCount == 0) {
return;
}
DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager();
for (int i = 0; i < mLayerCount; i++) {
HwcLayer *hwcLayer = mLayers.itemAt(i);
if (hwcLayer) {
DisplayPlane *plane = hwcLayer->detachPlane();
if (plane) {
planeManager->reclaimPlane(mDisplayIndex, *plane);
}
}
delete hwcLayer;
}
mLayers.clear();
mFBLayers.clear();
mOverlayCandidates.clear();
mSpriteCandidates.clear();
mCursorCandidates.clear();
mZOrderConfig.clear();
mFrameBufferTarget = NULL;
mLayerCount = 0;
}
bool HwcLayerList::allocatePlanes()
{
return assignCursorPlanes();
}
bool HwcLayerList::assignCursorPlanes()
{
int cursorCandidates = (int)mCursorCandidates.size();
if (cursorCandidates == 0) {
return assignOverlayPlanes();
}
DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager();
int planeNumber = planeManager->getFreePlanes(mDisplayIndex, DisplayPlane::PLANE_CURSOR);
if (planeNumber == 0) {
DTRACE("no cursor plane available. candidates %d", cursorCandidates);
return assignOverlayPlanes();
}
if (planeNumber > cursorCandidates) {
// assuming all cursor planes have the same capabilities, just
// need up to number of candidates for plane assignment
planeNumber = cursorCandidates;
}
for (int i = planeNumber; i >= 0; i--) {
// assign as many cursor planes as possible
if (assignCursorPlanes(0, i)) {
return true;
}
if (mZOrderConfig.size() != 0) {
ETRACE("ZOrder config is not cleaned up!");
}
}
return false;
}
bool HwcLayerList::assignCursorPlanes(int index, int planeNumber)
{
// index indicates position in mCursorCandidates to start plane assignment
if (planeNumber == 0) {
return assignOverlayPlanes();
}
int cursorCandidates = (int)mCursorCandidates.size();
for (int i = index; i <= cursorCandidates - planeNumber; i++) {
ZOrderLayer *zlayer = addZOrderLayer(DisplayPlane::PLANE_CURSOR, mCursorCandidates[i]);
if (assignCursorPlanes(i + 1, planeNumber - 1)) {
return true;
}
removeZOrderLayer(zlayer);
}
return false;
}
bool HwcLayerList::assignOverlayPlanes()
{
int overlayCandidates = (int)mOverlayCandidates.size();
if (overlayCandidates == 0) {
return assignSpritePlanes();
}
DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager();
int planeNumber = planeManager->getFreePlanes(mDisplayIndex, DisplayPlane::PLANE_OVERLAY);
if (planeNumber == 0) {
DTRACE("no overlay plane available. candidates %d", overlayCandidates);
return assignSpritePlanes();
}
if (planeNumber > overlayCandidates) {
// assuming all overlay planes have the same capabilities, just
// need up to number of candidates for plane assignment
planeNumber = overlayCandidates;
}
for (int i = planeNumber; i >= 0; i--) {
// assign as many overlay planes as possible
if (assignOverlayPlanes(0, i)) {
return true;
}
if (mZOrderConfig.size() != 0) {
ETRACE("ZOrder config is not cleaned up!");
}
}
return false;
}
bool HwcLayerList::assignOverlayPlanes(int index, int planeNumber)
{
// index indicates position in mOverlayCandidates to start plane assignment
if (planeNumber == 0) {
return assignSpritePlanes();
}
int overlayCandidates = (int)mOverlayCandidates.size();
for (int i = index; i <= overlayCandidates - planeNumber; i++) {
ZOrderLayer *zlayer = addZOrderLayer(DisplayPlane::PLANE_OVERLAY, mOverlayCandidates[i]);
if (assignOverlayPlanes(i + 1, planeNumber - 1)) {
return true;
}
removeZOrderLayer(zlayer);
}
return false;
}
bool HwcLayerList::assignSpritePlanes()
{
int spriteCandidates = (int)mSpriteCandidates.size();
if (spriteCandidates == 0) {
return assignPrimaryPlane();
}
// number does not include primary plane
DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager();
int planeNumber = planeManager->getFreePlanes(mDisplayIndex, DisplayPlane::PLANE_SPRITE);
if (planeNumber == 0) {
VTRACE("no sprite plane available, candidates %d", spriteCandidates);
return assignPrimaryPlane();
}
if (planeNumber > spriteCandidates) {
// assuming all sprite planes have the same capabilities, just
// need up to number of candidates for plane assignment
planeNumber = spriteCandidates;
}
for (int i = planeNumber; i >= 0; i--) {
// assign as many sprite planes as possible
if (assignSpritePlanes(0, i)) {
return true;
}
if (mOverlayCandidates.size() == 0 && mZOrderConfig.size() != 0) {
ETRACE("ZOrder config is not cleaned up!");
}
}
return false;
}
bool HwcLayerList::assignSpritePlanes(int index, int planeNumber)
{
if (planeNumber == 0) {
return assignPrimaryPlane();
}
int spriteCandidates = (int)mSpriteCandidates.size();
for (int i = index; i <= spriteCandidates - planeNumber; i++) {
ZOrderLayer *zlayer = addZOrderLayer(DisplayPlane::PLANE_SPRITE, mSpriteCandidates[i]);
if (assignSpritePlanes(i + 1, planeNumber - 1)) {
return true;
}
removeZOrderLayer(zlayer);
}
return false;
}
bool HwcLayerList::assignPrimaryPlane()
{
// find a sprit layer that is not candidate but has lower priority than candidates.
HwcLayer *spriteLayer = NULL;
for (int i = (int)mSpriteCandidates.size() - 1; i >= 0; i--) {
if (mSpriteCandidates[i]->mPlaneCandidate)
break;
spriteLayer = mSpriteCandidates[i];
}
int candidates = (int)mZOrderConfig.size();
int layers = (int)mFBLayers.size();
bool ok = false;
if (candidates == layers - 1 && spriteLayer != NULL) {
// primary plane is configured as sprite, all sprite candidates are offloaded to display planes
ok = assignPrimaryPlaneHelper(spriteLayer);
if (!ok) {
VTRACE("failed to use primary as sprite plane");
}
} else if (candidates == 0) {
// none assigned, use primary plane for frame buffer target and set zorder to 0
ok = assignPrimaryPlaneHelper(mFrameBufferTarget, 0);
if (!ok) {
ETRACE("failed to compose all layers to primary plane, should never happen");
}
} else if (candidates == layers) {
// all assigned, primary plane may be used during ZOrder config.
ok = attachPlanes();
if (!ok) {
VTRACE("failed to assign layers without primary");
}
} else {
// check if the remaining planes can be composed to frame buffer target (FBT)
// look up a legitimate Z order position to place FBT.
for (int i = 0; i < layers && !ok; i++) {
if (mFBLayers[i]->mPlaneCandidate) {
continue;
}
if (useAsFrameBufferTarget(mFBLayers[i])) {
ok = assignPrimaryPlaneHelper(mFrameBufferTarget, mFBLayers[i]->getZOrder());
if (!ok) {
VTRACE("failed to use zorder %d for frame buffer target",
mFBLayers[i]->getZOrder());
}
}
}
if (!ok) {
VTRACE("no possible zorder for frame buffer target");
}
}
return ok;
}
bool HwcLayerList::assignPrimaryPlaneHelper(HwcLayer *hwcLayer, int zorder)
{
ZOrderLayer *zlayer = addZOrderLayer(DisplayPlane::PLANE_PRIMARY, hwcLayer, zorder);
bool ok = attachPlanes();
if (!ok) {
removeZOrderLayer(zlayer);
}
return ok;
}
bool HwcLayerList::attachPlanes()
{
DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager();
if (!planeManager->isValidZOrder(mDisplayIndex, mZOrderConfig)) {
VTRACE("invalid z order, size of config %d", mZOrderConfig.size());
return false;
}
if (!planeManager->assignPlanes(mDisplayIndex, mZOrderConfig)) {
WTRACE("failed to assign planes");
return false;
}
VTRACE("============= plane assignment===================");
for (int i = 0; i < (int)mZOrderConfig.size(); i++) {
ZOrderLayer *zlayer = mZOrderConfig.itemAt(i);
if (zlayer->plane == NULL || zlayer->hwcLayer == NULL) {
ETRACE("invalid ZOrderLayer, should never happen!!");
return false;
}
zlayer->plane->setZOrder(i);
if (zlayer->plane->getType() == DisplayPlane::PLANE_CURSOR) {
zlayer->hwcLayer->setType(HwcLayer::LAYER_CURSOR_OVERLAY);
mFBLayers.remove(zlayer->hwcLayer);
} else if (zlayer->hwcLayer != mFrameBufferTarget) {
zlayer->hwcLayer->setType(HwcLayer::LAYER_OVERLAY);
// update FB layers for smart composition
mFBLayers.remove(zlayer->hwcLayer);
}
zlayer->hwcLayer->attachPlane(zlayer->plane, mDisplayIndex);
VTRACE("total %d, layer %d, type %d, index %d, zorder %d",
mLayerCount - 1,
zlayer->hwcLayer->getIndex(),
zlayer->plane->getType(),
zlayer->plane->getIndex(),
zlayer->zorder);
delete zlayer;
}
mZOrderConfig.clear();
return true;
}
bool HwcLayerList::useAsFrameBufferTarget(HwcLayer *target)
{
// check if zorder of target can be used as zorder of frame buffer target
// eligible only when all noncandidate layers can be merged to the target layer:
// 1) noncandidate layer and candidate layer below the target layer can't overlap
// if candidate layer is on top of non candidate layer, as "noncandidate layer" needs
// to be moved up to target layer in z order;
// 2) noncandidate layer and candidate layers above the target layer can't overlap
// if candidate layer is below noncandidate layer, as "noncandidate layer" needs
// to be moved down to target layer in z order.
int targetLayerIndex = target->getIndex();
// check candidate and noncandidate layers below this candidate does not overlap
for (int below = 0; below < targetLayerIndex; below++) {
if (mFBLayers[below]->mPlaneCandidate) {
continue;
} else {
// check candidate layer above this noncandidate layer does not overlap
for (int above = below + 1; above < targetLayerIndex; above++) {
if (mFBLayers[above]->mPlaneCandidate == false) {
continue;
}
if (hasIntersection(mFBLayers[above], mFBLayers[below])) {
return false;
}
}
}
}
// check candidate and noncandidate layers above this candidate does not overlap
for (int above = targetLayerIndex + 1; above < mFBLayers.size(); above++) {
if (mFBLayers[above]->mPlaneCandidate) {
continue;
} else {
// check candidate layer below this noncandidate layer does not overlap
for (int below = targetLayerIndex + 1; below < above; below++) {
if (mFBLayers[below]->mPlaneCandidate == false) {
continue;
}
if (hasIntersection(mFBLayers[above], mFBLayers[below])) {
return false;
}
}
}
}
return true;
}
bool HwcLayerList::hasIntersection(HwcLayer *la, HwcLayer *lb)
{
hwc_layer_1_t *a = la->getLayer();
hwc_layer_1_t *b = lb->getLayer();
hwc_rect_t *aRect = &a->displayFrame;
hwc_rect_t *bRect = &b->displayFrame;
if (bRect->right <= aRect->left ||
bRect->left >= aRect->right ||
bRect->top >= aRect->bottom ||
bRect->bottom <= aRect->top)
return false;
return true;
}
ZOrderLayer* HwcLayerList::addZOrderLayer(int type, HwcLayer *hwcLayer, int zorder)
{
ZOrderLayer *layer = new ZOrderLayer;
layer->planeType = type;
layer->hwcLayer = hwcLayer;
layer->zorder = (zorder != -1) ? zorder : hwcLayer->getZOrder();
layer->plane = NULL;
if (hwcLayer->mPlaneCandidate) {
ETRACE("plane is candidate!, order = %d", zorder);
}
hwcLayer->mPlaneCandidate = true;
if ((int)mZOrderConfig.indexOf(layer) >= 0) {
ETRACE("layer exists!");
}
mZOrderConfig.add(layer);
return layer;
}
void HwcLayerList::removeZOrderLayer(ZOrderLayer *layer)
{
if ((int)mZOrderConfig.indexOf(layer) < 0) {
ETRACE("layer does not exist!");
}
mZOrderConfig.remove(layer);
if (layer->hwcLayer->mPlaneCandidate == false) {
ETRACE("plane is not candidate!, order %d", layer->zorder);
}
layer->hwcLayer->mPlaneCandidate = false;
delete layer;
}
void HwcLayerList::addStaticLayerSize(HwcLayer *hwcLayer)
{
// Calculate static layer size to avoid only composition navigation bar
// and status bar etc.
hwc_layer_1_t *a = hwcLayer->getLayer();
hwc_rect_t *Rect = &a->displayFrame;
mLayerSize = mLayerSize + ((Rect->right - Rect->left) * (Rect->bottom - Rect->top));
}
bool HwcLayerList::checkStaticLayerSize()
{
// Check static layer size if over threshold: half display size
bool ret = false;
int width = 0;
int height = 0;
drmModeModeInfo mode;
Drm *drm = Hwcomposer::getInstance().getDrm();
drm->getModeInfo(mDisplayIndex, mode);
width = mode.hdisplay;
height = mode.vdisplay;
if (mLayerSize > (width * height/2))
ret = true;
return ret;
}
void HwcLayerList::setupSmartComposition()
{
uint32_t compositionType = HWC_OVERLAY;
HwcLayer *hwcLayer = NULL;
// setup smart composition only there's no update on all FB layers
for (size_t i = 0; i < mFBLayers.size(); i++) {
hwcLayer = mFBLayers.itemAt(i);
if (hwcLayer->isUpdated() ||
hwcLayer->getStaticCount() == LAYER_STATIC_THRESHOLD) {
compositionType = HWC_FRAMEBUFFER;
}
}
VTRACE("smart composition enabled %s",
(compositionType == HWC_OVERLAY) ? "TRUE" : "FALSE");
for (size_t i = 0; i < mFBLayers.size(); i++) {
hwcLayer = mFBLayers.itemAt(i);
switch (hwcLayer->getType()) {
case HwcLayer::LAYER_FB:
case HwcLayer::LAYER_FORCE_FB:
hwcLayer->setCompositionType(compositionType);
break;
default:
ETRACE("Invalid layer type %d", hwcLayer->getType());
break;
}
}
}
bool HwcLayerList::setupSmartComposition2()
{
bool ret = false;
HwcLayer *hwcLayer = NULL;
int layerIndex = 0;
int i = 0;
if (mList->flags & HWC_GEOMETRY_CHANGED) {
// clear static layers vector once geometry changed
mStaticLayersIndex.setCapacity(mLayerCount);
mStaticLayersIndex.clear();
return ret;
}
if (mStaticLayersIndex.size() > 0) {
// exit criteria: once either static layer has update
for (i = 0; i < mStaticLayersIndex.size(); i++) {
layerIndex = mStaticLayersIndex.itemAt(i);
hwcLayer = mLayers.itemAt(layerIndex);
if (hwcLayer->isUpdated()) {
ret = true;
}
}
if (ret == true) {
for (i = 0; i < mStaticLayersIndex.size(); i++) {
layerIndex = mStaticLayersIndex.itemAt(i);
hwcLayer = mLayers.itemAt(layerIndex);
hwcLayer->setCompositionType(HWC_FRAMEBUFFER);
}
DTRACE("Exit Smart Composition2 !");
mLayerSize = 0;
mStaticLayersIndex.clear();
}
} else {
// entry criteria: hwc layers has no update
if (mFBLayers.size() == 0) {
for (i = 0; i < mLayerCount - 1; i++) {
hwcLayer = mLayers.itemAt(i);
if (hwcLayer->getPlane() &&
hwcLayer->getCompositionType() == HWC_OVERLAY &&
hwcLayer->getStaticCount() >= LAYER_STATIC_THRESHOLD) {
mStaticLayersIndex.add(i);
}
}
// check if all static layers in sequence
// if all in sequence, set FORCE_FB for static layers
// TODO: optimization here
// 1. If two connected, can trigger smart composition2
// 2. Caculate layer size to see if it saves more bandwidth
// 3. Dynamically check and add new static layers
int staticLayerCount = mStaticLayersIndex.size();
if (staticLayerCount > 1 && staticLayerCount < mLayerCount-1) {
layerIndex = mStaticLayersIndex.itemAt(0);
hwcLayer = mLayers.itemAt(layerIndex);
mLayerSize = 0;
addStaticLayerSize(hwcLayer);
int preIndex = hwcLayer->getIndex();
for (i = 1; i < staticLayerCount; i++) {
layerIndex = mStaticLayersIndex.itemAt(i);
hwcLayer = mLayers.itemAt(layerIndex);
int index = hwcLayer->getIndex();
if (index == preIndex + 1) {
addStaticLayerSize(hwcLayer);
preIndex = index;
} else
break;
}
if ((i == staticLayerCount) && checkStaticLayerSize()) {
for (i =0; i < staticLayerCount; i++) {
layerIndex = mStaticLayersIndex.itemAt(i);
hwcLayer = mLayers.itemAt(layerIndex);
hwcLayer->setCompositionType(HWC_FORCE_FRAMEBUFFER);
}
DTRACE("In Smart Composition2 !");
ret = true;
} else {
mLayerSize = 0;
}
}
if (!ret)
mStaticLayersIndex.clear();
}
}
// return ture to trigger remap layers with HW plane
return ret;
}
#if 1 // support overlay fallback to GLES
bool HwcLayerList::update(hwc_display_contents_1_t *list)
{
bool ret;
// basic check to make sure the consistance
if (!list) {
ETRACE("null layer list");
return false;
}
if ((int)list->numHwLayers != mLayerCount) {
ETRACE("layer count doesn't match (%zd, %d)", list->numHwLayers, mLayerCount);
return false;
}
// update list
mList = list;
bool ok = true;
// update all layers, call each layer's update()
for (int i = 0; i < mLayerCount; i++) {
HwcLayer *hwcLayer = mLayers.itemAt(i);
if (!hwcLayer) {
ETRACE("no HWC layer for layer %d", i);
continue;
}
if (!hwcLayer->update(&list->hwLayers[i])) {
ok = false;
hwcLayer->setCompositionType(HWC_FORCE_FRAMEBUFFER);
}
}
if (!ok || setupSmartComposition2()) {
ITRACE("overlay fallback to GLES. flags: %#x", list->flags);
for (int i = 0; i < mLayerCount - 1; i++) {
HwcLayer *hwcLayer = mLayers.itemAt(i);
if (hwcLayer->getPlane() &&
(hwcLayer->getCompositionType() == HWC_OVERLAY ||
hwcLayer->getCompositionType() == HWC_CURSOR_OVERLAY)) {
hwcLayer->setCompositionType(HWC_FRAMEBUFFER);
}
}
mLayers.itemAt(mLayerCount - 1)->setCompositionType(HWC_FRAMEBUFFER_TARGET);
deinitialize();
mList = list;
initialize();
// update all layers again after plane re-allocation
for (int i = 0; i < mLayerCount; i++) {
HwcLayer *hwcLayer = mLayers.itemAt(i);
if (!hwcLayer) {
ETRACE("no HWC layer for layer %d", i);
continue;
}
if (!hwcLayer->update(&list->hwLayers[i])) {
DTRACE("fallback to GLES update failed on layer[%d]!\n", i);
}
}
}
setupSmartComposition();
return true;
}
#else
bool HwcLayerList::update(hwc_display_contents_1_t *list)
{
bool ret;
// basic check to make sure the consistance
if (!list) {
ETRACE("null layer list");
return false;
}
if ((int)list->numHwLayers != mLayerCount) {
ETRACE("layer count doesn't match (%d, %d)", list->numHwLayers, mLayerCount);
return false;
}
// update list
mList = list;
// update all layers, call each layer's update()
for (int i = 0; i < mLayerCount; i++) {
HwcLayer *hwcLayer = mLayers.itemAt(i);
if (!hwcLayer) {
ETRACE("no HWC layer for layer %d", i);
continue;
}
hwcLayer->update(&list->hwLayers[i]);
}
setupSmartComposition();
return true;
}
#endif
DisplayPlane* HwcLayerList::getPlane(uint32_t index) const
{
HwcLayer *hwcLayer;
if (index >= mLayers.size()) {
ETRACE("invalid layer index %d", index);
return 0;
}
hwcLayer = mLayers.itemAt(index);
if ((hwcLayer->getType() == HwcLayer::LAYER_FB) ||
(hwcLayer->getType() == HwcLayer::LAYER_FORCE_FB) ||
(hwcLayer->getType() == HwcLayer::LAYER_SKIPPED)) {
return 0;
}
if (hwcLayer->getHandle() == 0) {
DTRACE("plane is attached with invalid handle");
return 0;
}
return hwcLayer->getPlane();
}
void HwcLayerList::postFlip()
{
for (size_t i = 0; i < mLayers.size(); i++) {
HwcLayer *hwcLayer = mLayers.itemAt(i);
hwcLayer->postFlip();
}
}
void HwcLayerList::dump(Dump& d)
{
d.append("Layer list: (number of layers %d):\n", mLayers.size());
d.append(" LAYER | TYPE | PLANE | INDEX | Z Order \n");
d.append("-------+------------------------+----------------------------\n");
for (size_t i = 0; i < mLayers.size(); i++) {
HwcLayer *hwcLayer = mLayers.itemAt(i);
DisplayPlane *plane;
long int planeIndex = -1;
long int zorder = -1;
const char *type = "HWC_FB";
const char *planeType = "N/A";
if (hwcLayer) {
switch (hwcLayer->getType()) {
case HwcLayer::LAYER_FB:
case HwcLayer::LAYER_FORCE_FB:
type = "HWC_FB";
break;
case HwcLayer::LAYER_OVERLAY:
case HwcLayer::LAYER_SKIPPED:
type = "HWC_OVERLAY";
break;
case HwcLayer::LAYER_FRAMEBUFFER_TARGET:
type = "HWC_FRAMEBUFFER_TARGET";
break;
case HwcLayer::LAYER_SIDEBAND:
type = "HWC_SIDEBAND";
break;
case HwcLayer::LAYER_CURSOR_OVERLAY:
type = "HWC_CURSOR_OVERLAY";
break;
default:
type = "Unknown";
}
plane = hwcLayer->getPlane();
if (plane) {
planeIndex = plane->getIndex();
zorder = plane->getZOrder();
switch (plane->getType()) {
case DisplayPlane::PLANE_OVERLAY:
planeType = "OVERLAY";
break;
case DisplayPlane::PLANE_SPRITE:
planeType = "SPRITE";
break;
case DisplayPlane::PLANE_PRIMARY:
planeType = "PRIMARY";
break;
case DisplayPlane::PLANE_CURSOR:
planeType = "CURSOR";
break;
default:
planeType = "Unknown";
}
}
d.append(" %2d | %22s | %8s | %3ld | %3ld \n",
i, type, planeType, planeIndex, zorder);
}
}
}
void HwcLayerList::dump()
{
static char const* compositionTypeName[] = {
"GLES",
"HWC",
"BG",
"FBT",
"SB",
"CUR",
"N/A"};
static char const* planeTypeName[] = {
"SPRITE",
"OVERLAY",
"PRIMARY",
"CURSOR",
"UNKNOWN"};
DTRACE(" numHwLayers = %zu, flags = %08x", mList->numHwLayers, mList->flags);
DTRACE(" type | handle | hints | flags | tr | blend | alpha | format | source crop | frame | index | zorder | plane ");
DTRACE("------+----------+-------+-------+----+-------+-------+----------+-----------------------------------+---------------------------+-------+--------+---------");
for (int i = 0 ; i < mLayerCount ; i++) {
const hwc_layer_1_t&l = mList->hwLayers[i];
DisplayPlane *plane = mLayers[i]->getPlane();
int planeIndex = -1;
int zorder = -1;
const char *planeType = "N/A";
if (plane) {
planeIndex = plane->getIndex();
zorder = plane->getZOrder();
planeType = planeTypeName[plane->getType()];
}
DTRACE(
" %4s | %p | %5x | %5x | %2x | %5x | %5x | %8x | [%7.1f,%7.1f,%7.1f,%7.1f] | [%5d,%5d,%5d,%5d] | %5d | %6d | %7s ",
compositionTypeName[l.compositionType],
mLayers[i]->getHandle(), l.hints, l.flags, l.transform, l.blending, l.planeAlpha, mLayers[i]->getFormat(),
l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom,
l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
planeIndex, zorder, planeType);
}
}
} // namespace intel
} // namespace android