blob: a6326fcae4632ff85576c011d7850eadb7e19355 [file] [log] [blame]
/*
// 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 <common/utils/HwcTrace.h>
#include <common/base/Drm.h>
#include <common/base/HwcLayerList.h>
#include <Hwcomposer.h>
#include <GraphicBuffer.h>
#include <IDisplayDevice.h>
#include <PlaneCapabilities.h>
#include <DisplayQuery.h>
#include <hal_public.h>
namespace android {
namespace intel {
HwcLayerList::HwcLayerList(hwc_display_contents_1_t *list, int disp)
: mList(list),
mLayerCount(0),
mLayers(),
mFBLayers(),
mSpriteCandidates(),
mOverlayCandidates(),
mZOrderConfig(),
mFrameBufferTarget(NULL),
mDisplayIndex(disp)
{
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) {
VLOGTRACE("layer was forced to use HWC_FRAMEBUFFER");
return false;
}
// check layer flags
if (layer.flags & HWC_SKIP_LAYER) {
VLOGTRACE("plane type %d: (skip layer flag was set)", planeType);
return false;
}
if (layer.handle == 0) {
WLOGTRACE("invalid buffer handle");
return false;
}
// check usage
if (!hwcLayer->getUsage() & GRALLOC_USAGE_HW_COMPOSER) {
WLOGTRACE("not a composer layer");
return false;
}
// check layer transform
valid = PlaneCapabilities::isTransformSupported(planeType, hwcLayer);
if (!valid) {
VLOGTRACE("plane type %d: (bad transform)", planeType);
return false;
}
// check buffer format
valid = PlaneCapabilities::isFormatSupported(planeType, hwcLayer);
if (!valid) {
VLOGTRACE("plane type %d: (bad buffer format)", planeType);
return false;
}
// check buffer size
valid = PlaneCapabilities::isSizeSupported(planeType, hwcLayer);
if (!valid) {
VLOGTRACE("plane type %d: (bad buffer size)", planeType);
return false;
}
// check layer blending
valid = PlaneCapabilities::isBlendingSupported(planeType, hwcLayer);
if (!valid) {
VLOGTRACE("plane type %d: (bad blending)", planeType);
return false;
}
// check layer scaling
valid = PlaneCapabilities::isScalingSupported(planeType, hwcLayer);
if (!valid) {
VLOGTRACE("plane type %d: (bad scaling)", planeType);
return false;
}
// TODO: check visible region?
return true;
}
bool HwcLayerList::checkRgbOverlaySupported(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) {
VLOGTRACE("layer was forced to use HWC_FRAMEBUFFER");
return false;
}
// check layer flags
if (layer.flags & HWC_SKIP_LAYER) {
VLOGTRACE("skip layer flag was set");
return false;
}
if (layer.handle == 0) {
WLOGTRACE("invalid buffer handle");
return false;
}
// check usage
if (!hwcLayer->getUsage() & GRALLOC_USAGE_HW_COMPOSER) {
WLOGTRACE("not a composer layer");
return false;
}
uint32_t format = hwcLayer->getFormat();
if (format != HAL_PIXEL_FORMAT_BGRA_8888 &&
format != HAL_PIXEL_FORMAT_BGRX_8888) {
return false;
}
uint32_t h = hwcLayer->getBufferHeight();
const stride_t& stride = hwcLayer->getBufferStride();
if (stride.rgb.stride > 4096) {
return false;
}
uint32_t blending = (uint32_t)hwcLayer->getLayer()->blending;
if (blending != HWC_BLENDING_NONE) {
return false;
}
uint32_t trans = hwcLayer->getLayer()->transform;
if (trans != 0) {
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) {
return false;
}
return true;
}
bool HwcLayerList::checkCursorSupported(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) {
VLOGTRACE("layer was forced to use HWC_FRAMEBUFFER");
return false;
}
// check layer flags
if (layer.flags & HWC_SKIP_LAYER) {
VLOGTRACE("skip layer flag was set");
return false;
}
if (!(layer.flags & HWC_IS_CURSOR_LAYER)) {
VLOGTRACE("not a cursor layer");
return false;
}
if (hwcLayer->getIndex() != mLayerCount - 2) {
WLOGTRACE("cursor layer is not on top of zorder");
return false;
}
if (layer.handle == 0) {
WLOGTRACE("invalid buffer handle");
return false;
}
// check usage
if (!hwcLayer->getUsage() & GRALLOC_USAGE_HW_COMPOSER) {
WLOGTRACE("not a composer layer");
return false;
}
uint32_t format = hwcLayer->getFormat();
if (format != HAL_PIXEL_FORMAT_BGRA_8888 &&
format != HAL_PIXEL_FORMAT_RGBA_8888) {
WLOGTRACE("unexpected color format %u for cursor", format);
return false;
}
uint32_t trans = hwcLayer->getLayer()->transform;
if (trans != 0) {
WLOGTRACE("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) {
WLOGTRACE("unexpected scaling for cursor: %dx%d => %dx%d",
srcW, srcH, dstW, dstH);
//return false;
}
if (srcW > 256 || srcH > 256) {
WLOGTRACE("unexpected size %dx%d for cursor", srcW, srcH);
return false;
}
return true;
}
bool HwcLayerList::initialize()
{
if (!mList || mList->numHwLayers == 0) {
ELOGTRACE("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();
PriorityVector rgbOverlayLayers;
rgbOverlayLayers.setCapacity(mLayerCount);
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 (checkRgbOverlaySupported(hwcLayer)) {
rgbOverlayLayers.add(hwcLayer);
} else if (checkSupported(DisplayPlane::PLANE_SPRITE, hwcLayer)) {
mSpriteCandidates.add(hwcLayer);
} else if (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) {
ELOGTRACE("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)) {
VLOGTRACE("no FB layers, skip plane allocation");
return true;
}
bool hasOverlay = mOverlayCandidates.size() != 0;
while (rgbOverlayLayers.size()) {
HwcLayer *hwcLayer = rgbOverlayLayers.top();
if (hasOverlay) {
mSpriteCandidates.add(hwcLayer);
} else {
mOverlayCandidates.add(hwcLayer);
}
rgbOverlayLayers.removeItemsAt(0);
}
if (!DisplayQuery::forceFbScaling(mDisplayIndex)) {
allocatePlanes();
} else {
// force GLES composition on all layers, then use GPU or hardware
// overlay to scale buffer to match display resolution
assignPrimaryPlane();
}
//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) {
DLOGTRACE("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) {
ELOGTRACE("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) {
DLOGTRACE("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) {
ELOGTRACE("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) {
VLOGTRACE("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) {
ELOGTRACE("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) {
VLOGTRACE("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) {
ELOGTRACE("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) {
VLOGTRACE("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) {
VLOGTRACE("failed to use zorder %d for frame buffer target",
mFBLayers[i]->getZOrder());
}
}
}
if (!ok) {
VLOGTRACE("no possible zorder for frame buffer target");
}
}
return ok;
}
bool HwcLayerList::assignPrimaryPlaneHelper(HwcLayer *hwcLayer, int zorder)
{
int type = DisplayPlane::PLANE_PRIMARY;
if (DisplayQuery::forceFbScaling(mDisplayIndex)) {
type = DisplayPlane::PLANE_OVERLAY;
// use overlay plane as primary plane. Color is converted to NV12 first then overlay
// hardware will perform scaling to display resolution.
// can use primary plane as well, but frame buffer needs to be scaled to match display resolution,
// (primary plane does not support RGB scaling). There is issue in DDK blit function (RGB scaling
// yields corrupt output)
}
ZOrderLayer *zlayer = addZOrderLayer(type, hwcLayer, zorder);
bool ok = attachPlanes();
if (!ok) {
removeZOrderLayer(zlayer);
}
return ok;
}
bool HwcLayerList::attachPlanes()
{
DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager();
if (!planeManager->isValidZOrder(mDisplayIndex, mZOrderConfig)) {
VLOGTRACE("invalid z order, size of config %d", mZOrderConfig.size());
return false;
}
if (!planeManager->assignPlanes(mDisplayIndex, mZOrderConfig)) {
WLOGTRACE("failed to assign planes");
return false;
}
VLOGTRACE("============= plane assignment===================");
for (int i = 0; i < (int)mZOrderConfig.size(); i++) {
ZOrderLayer *zlayer = mZOrderConfig.itemAt(i);
if (zlayer->plane == NULL || zlayer->hwcLayer == NULL) {
ELOGTRACE("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);
VLOGTRACE("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 (unsigned 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 (unsigned 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) {
ELOGTRACE("plane is candidate!, order = %d", zorder);
}
hwcLayer->mPlaneCandidate = true;
if ((int)mZOrderConfig.indexOf(layer) >= 0) {
ELOGTRACE("layer exists!");
}
mZOrderConfig.add(layer);
return layer;
}
void HwcLayerList::removeZOrderLayer(ZOrderLayer *layer)
{
if ((int)mZOrderConfig.indexOf(layer) < 0) {
ELOGTRACE("layer does not exist!");
}
mZOrderConfig.remove(layer);
if (layer->hwcLayer->mPlaneCandidate == false) {
ELOGTRACE("plane is not candidate!, order %d", layer->zorder);
}
layer->hwcLayer->mPlaneCandidate = false;
delete layer;
}
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()) {
compositionType = HWC_FRAMEBUFFER;
}
}
VLOGTRACE("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:
ELOGTRACE("Invalid layer type %d", hwcLayer->getType());
break;
}
}
}
#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) {
ELOGTRACE("null layer list");
return false;
}
if ((int)list->numHwLayers != mLayerCount) {
ELOGTRACE("layer count doesn't match (%d, %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) {
ELOGTRACE("no HWC layer for layer %d", i);
continue;
}
if (!hwcLayer->update(&list->hwLayers[i])) {
ok = false;
hwcLayer->setCompositionType(HWC_FORCE_FRAMEBUFFER);
}
}
if (!ok) {
ILOGTRACE("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) {
ELOGTRACE("no HWC layer for layer %d", i);
continue;
}
if (!hwcLayer->update(&list->hwLayers[i])) {
DLOGTRACE("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) {
ELOGTRACE("null layer list");
return false;
}
if ((int)list->numHwLayers != mLayerCount) {
ELOGTRACE("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) {
ELOGTRACE("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()) {
ELOGTRACE("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) {
DLOGTRACE("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;
int planeIndex = -1;
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 | %3D | %3D \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"};
DLOGTRACE(" numHwLayers = %u, flags = %08x", mList->numHwLayers, mList->flags);
DLOGTRACE(" type | handle | hints | flags | tr | blend | alpha | format | source crop | frame | index | zorder | plane ");
DLOGTRACE("------+----------+-------+-------+----+-------+-------+----------+-----------------------------------+---------------------------+-------+--------+---------");
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()];
}
DLOGTRACE(
" %4s | %8x | %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