| /* |
| // 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 |