1893 lines
66 KiB
C++
1893 lines
66 KiB
C++
/*
|
|||
|
|
* Copyright (c) 2018 Amlogic, Inc. All rights reserved.
|
||
|
|
*
|
||
|
|
* This source code is subject to the terms and conditions defined in the
|
||
|
|
* file 'LICENSE' which is part of this source code package.
|
||
|
|
*
|
||
|
|
* Description:
|
||
|
|
*/
|
||
|
|
#define LOG_NDEBUG 1
|
||
|
|
#include <algorithm>
|
||
|
|
|
||
|
|
#include "CompositionStrategyBase.h"
|
||
|
|
#include <DrmTypes.h>
|
||
|
|
#include <fcntl.h>
|
||
|
|
#include <DebugHelper.h>
|
||
|
|
|
||
|
|
/* Constructor function */
|
||
|
|
CompositionStrategyBase::CompositionStrategyBase() {
|
||
|
|
init();
|
||
|
|
mOsdPlaneNum = 0;
|
||
|
|
mVideoPlaneNum = 0;
|
||
|
|
mVideoComposerNum = 0;
|
||
|
|
mScaleValue = 0;
|
||
|
|
mCompositionFlag = 0;
|
||
|
|
memset(&mOsdDisplayFrame, 0, sizeof(mOsdDisplayFrame));
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Clean FrameBuffer, Composer and Plane. */
|
||
|
|
void CompositionStrategyBase::init() {
|
||
|
|
/* Reset Flags */
|
||
|
|
mHDRMode = false;
|
||
|
|
mHideSecureLayer = false;
|
||
|
|
mForceClientComposer = false;
|
||
|
|
mForceVideoComposer = false;
|
||
|
|
mHaveClient = false;
|
||
|
|
mInsideVideoFbsFlag = false;
|
||
|
|
mIsSideBandDisable = false;
|
||
|
|
mMosaicEnabled = false;
|
||
|
|
m4Mosaic = false;
|
||
|
|
mIsVideoComposerV2D = false;
|
||
|
|
mHideVideoForHdcpDev = false;
|
||
|
|
|
||
|
|
/*crtc scale info.*/
|
||
|
|
mDisplayRefFb.reset();
|
||
|
|
//memset(&mOsdDisplayFrame, 0, sizeof(mOsdDisplayFrame));
|
||
|
|
mCrtc.reset();
|
||
|
|
|
||
|
|
/* Clean FrameBuffer */
|
||
|
|
mFramebuffers.clear();
|
||
|
|
|
||
|
|
/* Clean Composer */
|
||
|
|
mDummyComposer.reset();
|
||
|
|
mClientComposer.reset();
|
||
|
|
mVideoComposers.clear();
|
||
|
|
mOtherComposers.clear();
|
||
|
|
|
||
|
|
/* Clean Plane */
|
||
|
|
mOsdPlanes.clear();
|
||
|
|
mHwcVideoPlanes.clear();
|
||
|
|
mOtherPlanes.clear();
|
||
|
|
|
||
|
|
/* Clean Composition members */
|
||
|
|
mComposer.reset();
|
||
|
|
mOverlayFbs.clear();
|
||
|
|
mComposerFbs.clear();
|
||
|
|
mVideoComposerFbs.clear();
|
||
|
|
mDisplayPairs.clear();
|
||
|
|
|
||
|
|
mMinComposerZorder = INVALID_ZORDER;
|
||
|
|
mMaxComposerZorder = INVALID_ZORDER;
|
||
|
|
mMinVideoZorder = INVALID_ZORDER;
|
||
|
|
mMaxVideoZorder = INVALID_ZORDER;
|
||
|
|
|
||
|
|
mDumpStr.clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
int CompositionStrategyBase::deleteFbFromVectorFbs(
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> & inputFbs,
|
||
|
|
std::shared_ptr<DrmFramebufferBase> & fb) {
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>>::iterator itErase;
|
||
|
|
|
||
|
|
if (!fb.get())
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
/* remove from list */
|
||
|
|
itErase = std::find(inputFbs.begin(), inputFbs.end(), fb);
|
||
|
|
if (itErase != inputFbs.end()) {
|
||
|
|
inputFbs.erase(itErase);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CompositionStrategyBase::chooseVideoFbsBaseNoOverlap(
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> & inputVideoFbs,
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> & outputVideoFbs) {
|
||
|
|
drm_rect_t dispFrame, dispFrame1;
|
||
|
|
bool is_overlap;
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb, fb1;
|
||
|
|
|
||
|
|
for (auto it = inputVideoFbs.begin(); it != inputVideoFbs.end(); it++) {
|
||
|
|
fb = *it;
|
||
|
|
is_overlap = false;
|
||
|
|
|
||
|
|
/* find one that did not overlap with others */
|
||
|
|
dispFrame = fb->getDisplayFrame();
|
||
|
|
for (auto it1 = it; it1 != inputVideoFbs.end(); it1++) {
|
||
|
|
fb1 = *it1;
|
||
|
|
if (fb == fb1)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
dispFrame1 = fb1->getDisplayFrame();
|
||
|
|
if (std::max(0, std::min(dispFrame.right, dispFrame1.right) -
|
||
|
|
std::max(dispFrame.left, dispFrame1.left)) *
|
||
|
|
std::max(0, std::min(dispFrame.bottom, dispFrame1.bottom) -
|
||
|
|
std::max(dispFrame.top, dispFrame1.top)) != 0) {
|
||
|
|
is_overlap = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!is_overlap) {
|
||
|
|
MESON_LOGV("[%s] Layer(%s) buffer is not overlap with others",
|
||
|
|
__func__, fb->getDebugInfo());
|
||
|
|
outputVideoFbs.push_back(fb);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CompositionStrategyBase::chooseOneVideoFbBaseBiggestWindow(
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> & inputVideoFbs,
|
||
|
|
std::shared_ptr<DrmFramebufferBase> & outputVideoFb) {
|
||
|
|
drm_rect_t dispFrame;
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb = nullptr;
|
||
|
|
std::shared_ptr<DrmFramebufferBase> large_fb = nullptr;
|
||
|
|
int region = 0, max_region = 0;
|
||
|
|
|
||
|
|
outputVideoFb.reset();
|
||
|
|
|
||
|
|
if (inputVideoFbs.empty())
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
for (auto it = inputVideoFbs.begin(); it != inputVideoFbs.end(); it++) {
|
||
|
|
fb = *it;
|
||
|
|
|
||
|
|
dispFrame = fb->getDisplayFrame();
|
||
|
|
region = (dispFrame.right - dispFrame.left) * (dispFrame.bottom - dispFrame.top);
|
||
|
|
|
||
|
|
if (!large_fb) {
|
||
|
|
large_fb = fb;
|
||
|
|
max_region = region;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* find the largest the frame */
|
||
|
|
if (region > max_region) {
|
||
|
|
large_fb = fb;
|
||
|
|
max_region = region;
|
||
|
|
} else if (region == max_region) {
|
||
|
|
if (fb->getZorder() > large_fb->getZorder())
|
||
|
|
large_fb = fb;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
outputVideoFb = large_fb;
|
||
|
|
dispFrame = large_fb->getDisplayFrame();
|
||
|
|
MESON_LOGV("[%s] Layer(%s) return large region buffer (%d %d %d %d)",
|
||
|
|
__func__, large_fb->getDebugInfo(),
|
||
|
|
dispFrame.left, dispFrame.top, dispFrame.right, dispFrame.bottom);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CompositionStrategyBase::chooseOneVideoFbBaseVideoType(
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> & inputVideoFbs,
|
||
|
|
std::shared_ptr<DrmFramebufferBase> & outputVideoFb) {
|
||
|
|
int video_type;
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> fbs;
|
||
|
|
|
||
|
|
std::vector<MESON_VIDEO_TYPE> video_types {MESON_VIDEO_8K, MESON_VIDEO_DI_POST,
|
||
|
|
MESON_VIDEO_SECURE, MESON_VIDEO_DV, MESON_VIDEO_4K, MESON_VIDEO_AFBC,
|
||
|
|
MESON_VIDEO_HDR, MESON_VIDEO_HDR10_PLUS, MESON_VIDEO_HLG};
|
||
|
|
|
||
|
|
for (auto it = inputVideoFbs.begin(); it != inputVideoFbs.end(); it++) {
|
||
|
|
video_type = (*it)->getVideoType();
|
||
|
|
if (video_type > 0) fbs.push_back(*it);
|
||
|
|
|
||
|
|
MESON_LOGV("[%s] Layer(%s) videoType:0x%x",
|
||
|
|
__func__, (*it)->getDebugInfo(), video_type);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!fbs.empty()) {
|
||
|
|
auto type_it = video_types.begin();
|
||
|
|
for (; type_it != video_types.end(); type_it++) {
|
||
|
|
bool have_type = false;
|
||
|
|
for (auto fbIt = fbs.begin(); fbIt != fbs.end(); fbIt++) {
|
||
|
|
video_type = (*fbIt)->getVideoType();
|
||
|
|
if ((video_type & *type_it) == *type_it) {
|
||
|
|
have_type = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (have_type) {
|
||
|
|
for (auto fbIt = fbs.begin(); fbIt != fbs.end();) {
|
||
|
|
video_type = (*fbIt)->getVideoType();
|
||
|
|
if ((video_type & *type_it) == *type_it)
|
||
|
|
fbIt++;
|
||
|
|
else
|
||
|
|
fbs.erase(fbIt);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (fbs.size() == 1)
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
outputVideoFb.reset();
|
||
|
|
if (fbs.size() == 1) {
|
||
|
|
outputVideoFb = fbs[0];
|
||
|
|
} else if (fbs.size() >= 1) {
|
||
|
|
chooseOneVideoFbBaseBiggestWindow(fbs, outputVideoFb);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (outputVideoFb.get())
|
||
|
|
MESON_LOGV("[%s] choose the fb (%s), videoType:0x%x",
|
||
|
|
__func__, outputVideoFb->getDebugInfo(),
|
||
|
|
outputVideoFb->getVideoType());
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CompositionStrategyBase::chooseOneVideoFbBasePriority(
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> & inputVideoFbs,
|
||
|
|
std::shared_ptr<DrmFramebufferBase> & outputVideoFb) {
|
||
|
|
std::vector<uint32_t> videoPrioritys;
|
||
|
|
|
||
|
|
if (inputVideoFbs.empty())
|
||
|
|
return false;
|
||
|
|
|
||
|
|
for (auto it = inputVideoFbs.begin(); it != inputVideoFbs.end(); it ++) {
|
||
|
|
videoPrioritys.push_back((*it)->getVideoPriority() & 0xFFFF);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (videoPrioritys.size() <= 1)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
std::sort(videoPrioritys.begin(), videoPrioritys.end());
|
||
|
|
if (std::find((++videoPrioritys.begin()), videoPrioritys.end(),
|
||
|
|
*(videoPrioritys.begin())) != videoPrioritys.end()) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::map<uint32_t, std::shared_ptr<DrmFramebufferBase>, std::less<uint32_t>> bufferPrioritys;
|
||
|
|
for (auto it = inputVideoFbs.begin(); it != inputVideoFbs.end(); it ++) {
|
||
|
|
bufferPrioritys.insert(make_pair((*it)->getVideoPriority(), *it));
|
||
|
|
}
|
||
|
|
|
||
|
|
outputVideoFb = bufferPrioritys.begin()->second;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CompositionStrategyBase::chooseOneVideoFb(
|
||
|
|
std::shared_ptr<DrmFramebufferBase> & outputVideoFb,
|
||
|
|
bool bVideoCompose) {
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> noOverlayFbs;
|
||
|
|
outputVideoFb.reset();
|
||
|
|
|
||
|
|
// no Video Fbs
|
||
|
|
if (mVideoComposerFbs.empty())
|
||
|
|
return -EINVAL;
|
||
|
|
|
||
|
|
if (!bVideoCompose) {
|
||
|
|
chooseOneVideoFbBaseVideoType(mVideoComposerFbs, outputVideoFb);
|
||
|
|
if (!outputVideoFb.get())
|
||
|
|
chooseOneVideoFbBaseBiggestWindow(mVideoComposerFbs, outputVideoFb);
|
||
|
|
} else {
|
||
|
|
bool bHavePriority = chooseOneVideoFbBasePriority(mVideoComposerFbs, outputVideoFb);
|
||
|
|
if (!bHavePriority) {
|
||
|
|
chooseVideoFbsBaseNoOverlap(mVideoComposerFbs, noOverlayFbs);
|
||
|
|
/* at least one buffer in noOverlayFbs vector */
|
||
|
|
|
||
|
|
if (noOverlayFbs.size() == 1) {
|
||
|
|
outputVideoFb = *noOverlayFbs.begin();
|
||
|
|
} else {
|
||
|
|
chooseOneVideoFbBaseVideoType(noOverlayFbs, outputVideoFb);
|
||
|
|
if (!outputVideoFb.get()) {
|
||
|
|
chooseOneVideoFbBaseBiggestWindow(noOverlayFbs, outputVideoFb);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (outputVideoFb.get()) {
|
||
|
|
MESON_LOGV("[%s]: choose the fb (%s)", __func__, outputVideoFb->getDebugInfo());
|
||
|
|
deleteFbFromVectorFbs(mVideoComposerFbs, outputVideoFb);
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*TODO: only one legacy sideband supported now if hw support sideband video */
|
||
|
|
int CompositionStrategyBase::chooseVideoFbFromLegacySideband(
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> & sidebandFbs,
|
||
|
|
std::shared_ptr<DrmFramebufferBase> & outputVideoFb) {
|
||
|
|
outputVideoFb = nullptr;
|
||
|
|
|
||
|
|
if (sidebandFbs.empty())
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
auto it = sidebandFbs.begin();
|
||
|
|
if (!mIsSideBandDisable) {
|
||
|
|
outputVideoFb = (*it);
|
||
|
|
it ++;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (; it != sidebandFbs.end(); it ++) {
|
||
|
|
MESON_LOGD("%s, too many legacy sideband, skip (%s)",
|
||
|
|
__func__, (*it)->getDebugInfo());
|
||
|
|
(*it)->setCompositionType(MESON_COMPOSITION_DUMMY);
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* If all the 4 video meet the following requirements, then all of then can send to vd1.
|
||
|
|
* 1. each video is within its own 1/4 window
|
||
|
|
* 2. The horizontal border distance from each video to its 1/4 window must be equal
|
||
|
|
* 3. 4 video must be all afbc
|
||
|
|
* 4. The distance to the border must be a multiple of 8
|
||
|
|
* 5. only support when refresh rate <= 60hz
|
||
|
|
*/
|
||
|
|
bool CompositionStrategyBase::checkAndHandle4Mosaic(uint32_t videoZorder) {
|
||
|
|
if (!mMosaicEnabled)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
// first check if hwc video plane (VD1) support mosaic feature
|
||
|
|
HwDisplayPlaneBase *plane = (HwDisplayPlaneBase *)(mHwcVideoPlanes[0].get());
|
||
|
|
if (!plane)
|
||
|
|
return false;
|
||
|
|
if (plane->isSupportMosaic() == false)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
// mosaic need disable when output refresh rate > 60hz
|
||
|
|
if (mDisplayMode.refreshRate > DEFAULT_REFRESH_RATE)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
// check 4 video playback
|
||
|
|
if (mVideoComposerFbs.empty() || mVideoComposerFbs.size() != 4)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb;
|
||
|
|
uint32_t halfWidth = mDisplayMode.pixelW/2;
|
||
|
|
uint32_t halfHeight = mDisplayMode.pixelH/2;
|
||
|
|
|
||
|
|
// 2*2 mosaic check
|
||
|
|
int leftWindow = 0;
|
||
|
|
int topWindow = 0;
|
||
|
|
for (auto it = mVideoComposerFbs.begin(); it != mVideoComposerFbs.end(); it++) {
|
||
|
|
fb = *it;
|
||
|
|
drm_rect_t displayFrame = fb->getDisplayFrame();
|
||
|
|
uint32_t frameWidth = displayFrame.right - displayFrame.left;
|
||
|
|
uint32_t frameHeight = displayFrame.bottom - displayFrame.top;
|
||
|
|
|
||
|
|
// check all afbc
|
||
|
|
if (!(fb->getVideoType() & MESON_VIDEO_AFBC))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
// check if the width and height <= 1/2 vinfo */
|
||
|
|
if (frameWidth > halfWidth || frameHeight > halfHeight)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
// check the border distance
|
||
|
|
if (displayFrame.left < halfWidth) {
|
||
|
|
leftWindow++;
|
||
|
|
if (displayFrame.left != halfWidth - displayFrame.right)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
// check border distance
|
||
|
|
if (displayFrame.left % 8 != 0)
|
||
|
|
return false;
|
||
|
|
} else {
|
||
|
|
if (displayFrame.left - halfWidth != mDisplayMode.pixelW - displayFrame.right)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
// check border distance
|
||
|
|
if ((displayFrame.left - halfWidth) % 8 != 0)
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (displayFrame.top < halfHeight) {
|
||
|
|
topWindow++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// check each video within its own 1/4 window
|
||
|
|
if (topWindow != leftWindow)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
m4Mosaic = true;
|
||
|
|
|
||
|
|
|
||
|
|
/*set video composer*/
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> nofbs;
|
||
|
|
auto composer = mVideoComposers[0];
|
||
|
|
composer->prepare();
|
||
|
|
composer->addInputs(mVideoComposerFbs, nofbs, 0);
|
||
|
|
/*-----set buffer to displaypair------*/
|
||
|
|
mDisplayPairs.push_back(DisplayPair{
|
||
|
|
(uint32_t)mOsdPlaneNum, videoZorder, composer, mVideoComposerFbs, mHwcVideoPlanes[0]});
|
||
|
|
|
||
|
|
mHwcVideoPlanes.erase(mHwcVideoPlanes.begin());
|
||
|
|
mVideoComposers.erase(mVideoComposers.begin());
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CompositionStrategyBase:: processVideoFbs() {
|
||
|
|
bool bVideoCompose = false;
|
||
|
|
|
||
|
|
int videoFbNum = 0;
|
||
|
|
uint32_t usedPlanes = 0;
|
||
|
|
uint32_t minVideoZ = INVALID_ZORDER;
|
||
|
|
uint32_t maxVideoZ = INVALID_ZORDER;
|
||
|
|
uint32_t fbZorder = INVALID_ZORDER;
|
||
|
|
|
||
|
|
meson_composition_t compositionType = MESON_COMPOSITION_DUMMY;
|
||
|
|
drm_fb_type_t fbType = DRM_FB_UNDEFINED;
|
||
|
|
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb = nullptr;
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> sidebandFbs;
|
||
|
|
|
||
|
|
for (auto fbIt = mFramebuffers.begin(); fbIt != mFramebuffers.end(); ++fbIt) {
|
||
|
|
bool bSideband = false;
|
||
|
|
fb = fbIt->second;
|
||
|
|
|
||
|
|
/* skip dummy */
|
||
|
|
compositionType = (meson_composition_t)fb->getCompositionType();
|
||
|
|
if (compositionType == MESON_COMPOSITION_DUMMY)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
fbType = fb->getFbType();
|
||
|
|
fbZorder = fb->getZorder();
|
||
|
|
|
||
|
|
switch (fbType) {
|
||
|
|
case DRM_FB_VIDEO_OVERLAY:
|
||
|
|
case DRM_FB_VIDEO_SIDEBAND:
|
||
|
|
case DRM_FB_VIDEO_SIDEBAND_TV:
|
||
|
|
bSideband = true;
|
||
|
|
[[clang::fallthrough]];
|
||
|
|
case DRM_FB_VIDEO_DMABUF:
|
||
|
|
case DRM_FB_VIDEO_UVM_DMA:
|
||
|
|
case DRM_FB_VIDEO_TUNNEL_SIDEBAND:
|
||
|
|
if (mHideVideoForHdcpDev) {
|
||
|
|
fb->setCompositionType(MESON_COMPOSITION_DUMMY);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (mVideoPlaneNum != 0) {
|
||
|
|
if (bSideband) {
|
||
|
|
sidebandFbs.push_back(fb);
|
||
|
|
} else if (fb->isBufferValidate()) {
|
||
|
|
mVideoComposerFbs.push_back(fb);
|
||
|
|
} else {
|
||
|
|
fb->setCompositionType(MESON_COMPOSITION_DUMMY);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
fb->setCompositionType(MESON_COMPOSITION_DUMMY);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
videoFbNum++;
|
||
|
|
if (minVideoZ == INVALID_ZORDER || fbZorder < minVideoZ)
|
||
|
|
minVideoZ = fbZorder;
|
||
|
|
|
||
|
|
if (maxVideoZ == INVALID_ZORDER || fbZorder > maxVideoZ)
|
||
|
|
maxVideoZ = fbZorder;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Composition: only 1 + .. + N mode now
|
||
|
|
* For vd1:
|
||
|
|
* 1. sideband.
|
||
|
|
* 2. special video types: AFBC/DV/HDR/HDR10/HLG/SECURE/DIPOST.
|
||
|
|
* 3. no overlap & biggest one.
|
||
|
|
* For the last vd:
|
||
|
|
* 1. compose always happened on the last vd.
|
||
|
|
* 2. the last vd compose always output fullscreen buffer.
|
||
|
|
* 3. vd1 should on top of vd2 when have video composed.
|
||
|
|
*/
|
||
|
|
videoFbNum = (sidebandFbs.size() > 0 ? 1 : 0) + (videoFbNum - sidebandFbs.size());
|
||
|
|
bVideoCompose = videoFbNum > mVideoPlaneNum ? true : false;
|
||
|
|
|
||
|
|
if (!bVideoCompose) {
|
||
|
|
/*clear hold buffer resource*/
|
||
|
|
auto it = mVideoComposers.begin();
|
||
|
|
for (; it != mVideoComposers.end(); it++)
|
||
|
|
(*it)->prepare();
|
||
|
|
|
||
|
|
/* do not disable composer in here,
|
||
|
|
* disable composer need after disable video plane */
|
||
|
|
}
|
||
|
|
|
||
|
|
if (videoFbNum == 0) return 0;
|
||
|
|
|
||
|
|
fb.reset();
|
||
|
|
chooseVideoFbFromLegacySideband(sidebandFbs, fb);
|
||
|
|
sidebandFbs.clear();
|
||
|
|
|
||
|
|
if (fb.get()) {
|
||
|
|
/* have legacy sideband video need to display */
|
||
|
|
if (mVideoPlaneNum == 1) {
|
||
|
|
mDisplayPairs.push_back(DisplayPair{
|
||
|
|
(uint32_t)mOsdPlaneNum, fb->getZorder(), nullptr, {fb}, mHwcVideoPlanes[0]});
|
||
|
|
fb->setCompositionType(MESON_COMPOSITION_PLANE_HWCVIDEO);
|
||
|
|
|
||
|
|
if (mVideoComposerFbs.size() > 0) {
|
||
|
|
for (auto it = mVideoComposerFbs.begin(); it != mVideoComposerFbs.end(); it++)
|
||
|
|
(*it)->setCompositionType(MESON_COMPOSITION_DUMMY);
|
||
|
|
}
|
||
|
|
|
||
|
|
mHwcVideoPlanes.erase(mHwcVideoPlanes.begin());
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
} else if (checkAndHandle4Mosaic(minVideoZ)) {
|
||
|
|
/* there are no legacy sideband video */
|
||
|
|
return 0;
|
||
|
|
} else if (mForceVideoComposer) {
|
||
|
|
/*set video to composer, only support V2D composer */
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> nofbs;
|
||
|
|
auto composer = mVideoComposers[0];
|
||
|
|
composer->prepare();
|
||
|
|
composer->addInputs(mVideoComposerFbs, nofbs, 1);
|
||
|
|
/*-----set buffer to displaypair------*/
|
||
|
|
mDisplayPairs.push_back(DisplayPair{(uint32_t)mOsdPlaneNum,
|
||
|
|
minVideoZ, composer, mVideoComposerFbs, mHwcVideoPlanes[0]});
|
||
|
|
|
||
|
|
mHwcVideoPlanes.erase(mHwcVideoPlanes.begin());
|
||
|
|
mVideoComposers.erase(mVideoComposers.begin());
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < videoFbNum; i++) {
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> nofbs;
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> inputFbs;
|
||
|
|
std::shared_ptr<IComposer> composer = nullptr;
|
||
|
|
if (mIsVideoComposerV2D) {
|
||
|
|
composer = mVideoComposers[usedPlanes];
|
||
|
|
composer->prepare();
|
||
|
|
}
|
||
|
|
|
||
|
|
usedPlanes++;
|
||
|
|
|
||
|
|
/* Fbs set to the last hwcVideoPlane */
|
||
|
|
if (i >= mVideoPlaneNum - 1) {
|
||
|
|
if (mVideoComposerFbs.size() > 0) {
|
||
|
|
if (bVideoCompose) {
|
||
|
|
/* make sure Z-Order of the last VD is the minimum */
|
||
|
|
fbZorder = minVideoZ;
|
||
|
|
if (!composer.get()) {
|
||
|
|
/* composer is MESON_COMPOSITION_DI*/
|
||
|
|
composer = mVideoComposers[0];
|
||
|
|
composer->prepare();
|
||
|
|
}
|
||
|
|
|
||
|
|
/*set dicomposer and get output video.*/
|
||
|
|
composer->addInputs(mVideoComposerFbs, nofbs, i);
|
||
|
|
/*-----set buffer to displaypair------*/
|
||
|
|
mDisplayPairs.push_back(DisplayPair{(uint32_t)mOsdPlaneNum + i,
|
||
|
|
fbZorder, composer, mVideoComposerFbs, mHwcVideoPlanes[i]});
|
||
|
|
} else {
|
||
|
|
fb = *mVideoComposerFbs.begin();
|
||
|
|
fbZorder = fb->getZorder();
|
||
|
|
fb->setCompositionType(MESON_COMPOSITION_PLANE_HWCVIDEO);
|
||
|
|
inputFbs.push_back(fb);
|
||
|
|
|
||
|
|
if (composer.get())
|
||
|
|
composer->addInputs(inputFbs, nofbs);
|
||
|
|
|
||
|
|
/*-----set buffer to displaypair------*/
|
||
|
|
mDisplayPairs.push_back(DisplayPair{(uint32_t)mOsdPlaneNum + i,
|
||
|
|
fbZorder, composer, inputFbs, mHwcVideoPlanes[i]});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!fb.get()) {
|
||
|
|
chooseOneVideoFb(fb, bVideoCompose);
|
||
|
|
if (!fb.get())
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
fb->setCompositionType(MESON_COMPOSITION_PLANE_HWCVIDEO);
|
||
|
|
|
||
|
|
if (bVideoCompose) {
|
||
|
|
/* make sure Z-Order of the last VD is the minimum */
|
||
|
|
fbZorder = fb->getZorder() + 1;
|
||
|
|
} else {
|
||
|
|
fbZorder = fb->getZorder();
|
||
|
|
}
|
||
|
|
|
||
|
|
inputFbs.push_back(fb);
|
||
|
|
if (composer.get())
|
||
|
|
composer->addInputs(inputFbs, nofbs);
|
||
|
|
|
||
|
|
mDisplayPairs.push_back(DisplayPair{
|
||
|
|
(uint32_t)mOsdPlaneNum + i, fbZorder, composer, inputFbs, mHwcVideoPlanes[i]});
|
||
|
|
fb.reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
/* removed used planes from mHwcVideoPlanes */
|
||
|
|
for (uint32_t i = 0; i < usedPlanes; i++)
|
||
|
|
mHwcVideoPlanes.erase(mHwcVideoPlanes.begin());
|
||
|
|
|
||
|
|
/* removed used videoComposer from mVideoComposers */
|
||
|
|
if (mIsVideoComposerV2D) {
|
||
|
|
for (uint32_t i = 0; i < usedPlanes; i++)
|
||
|
|
mVideoComposers.erase(mVideoComposers.begin());
|
||
|
|
} else if (bVideoCompose) {
|
||
|
|
mVideoComposers.clear();
|
||
|
|
} else {
|
||
|
|
// nothing to do;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Apply flag with secure and forceClient Fbs. */
|
||
|
|
int CompositionStrategyBase::applyCompositionFlags() {
|
||
|
|
if (!mHideSecureLayer && !mForceClientComposer) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb;
|
||
|
|
auto fbIt = mFramebuffers.begin();
|
||
|
|
for (; fbIt != mFramebuffers.end(); ++fbIt) {
|
||
|
|
fb = fbIt->second;
|
||
|
|
if (fb->getCompositionType() == MESON_COMPOSITION_UNDETERMINED) {
|
||
|
|
if (mHideSecureLayer && fb->getSecureFlag()) {
|
||
|
|
fb->setCompositionType(MESON_COMPOSITION_DUMMY);
|
||
|
|
} else if (mForceClientComposer) {
|
||
|
|
fb->setCompositionType(MESON_COMPOSITION_CLIENT);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CompositionStrategyBase::processGfxFbs() {
|
||
|
|
/* Remove dummy and video Fbs for later osd composition.
|
||
|
|
* Pickout OSD Fbs.
|
||
|
|
* Save client flag.
|
||
|
|
*/
|
||
|
|
pickoutOsdFbs();
|
||
|
|
|
||
|
|
if (!mInsideVideoFbsFlag) {
|
||
|
|
handleOsdComposition();
|
||
|
|
} else {
|
||
|
|
handleOsdCompositionWithVideo();
|
||
|
|
}
|
||
|
|
|
||
|
|
/* record overlayFbs and start to compose */
|
||
|
|
if (mComposer.get()) {
|
||
|
|
mComposer->prepare();
|
||
|
|
mComposer->addInputs(mComposerFbs, mOverlayFbs);
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Delete dummy and video Fbs, then pickout OSD Fbs. */
|
||
|
|
int CompositionStrategyBase::pickoutOsdFbs() {
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb;
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> dummyFbs;
|
||
|
|
bool bRemove = false;
|
||
|
|
bool bClientLayer = false;
|
||
|
|
bool mHaveVirLayer = false;
|
||
|
|
uint32_t fbZorder = -1;
|
||
|
|
meson_composition_t compositionType = MESON_COMPOSITION_DUMMY;
|
||
|
|
|
||
|
|
auto fbIt = mFramebuffers.begin();
|
||
|
|
for (; fbIt != mFramebuffers.end(); ) {
|
||
|
|
fb = fbIt->second;
|
||
|
|
bRemove = false;
|
||
|
|
bClientLayer = false;
|
||
|
|
|
||
|
|
if (!fb->isBufferValidate())
|
||
|
|
fb->setCompositionType(MESON_COMPOSITION_DUMMY);
|
||
|
|
|
||
|
|
compositionType = (meson_composition_t)fb->getCompositionType();
|
||
|
|
fbZorder = fb->getZorder();
|
||
|
|
|
||
|
|
switch (compositionType) {
|
||
|
|
case MESON_COMPOSITION_DUMMY:
|
||
|
|
dummyFbs.push_back(fb);
|
||
|
|
bRemove = true;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MESON_COMPOSITION_PLANE_HWCVIDEO:
|
||
|
|
case MESON_COMPOSITION_DI:
|
||
|
|
case MESON_COMPOSITION_V2D:
|
||
|
|
MESON_LOGV("collect overlay fb (%s)", fb->getDebugInfo());
|
||
|
|
mOverlayFbs.push_back(fb);
|
||
|
|
bRemove = true;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MESON_COMPOSITION_CLIENT:
|
||
|
|
mHaveClient = true;
|
||
|
|
bClientLayer = true;
|
||
|
|
[[clang::fallthrough]];
|
||
|
|
case MESON_COMPOSITION_UNDETERMINED:
|
||
|
|
{
|
||
|
|
if (mOsdPlaneNum == 0) {
|
||
|
|
fb->setCompositionType(MESON_COMPOSITION_DUMMY);
|
||
|
|
dummyFbs.push_back(fb);
|
||
|
|
bRemove = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (bClientLayer || !hasPlaneSupport(fb)) {
|
||
|
|
if (mMinComposerZorder == INVALID_ZORDER ||
|
||
|
|
mMaxComposerZorder == INVALID_ZORDER) {
|
||
|
|
mMinComposerZorder = fbZorder;
|
||
|
|
mMaxComposerZorder = fbZorder;
|
||
|
|
} else {
|
||
|
|
if (mMinComposerZorder > fbZorder)
|
||
|
|
mMinComposerZorder = fbZorder;
|
||
|
|
if (mMaxComposerZorder < fbZorder)
|
||
|
|
mMaxComposerZorder = fbZorder;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
MESON_LOGE("Unknown composition type %s",
|
||
|
|
compositionTypeToString(fb->getCompositionType()));
|
||
|
|
bRemove = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (bRemove)
|
||
|
|
fbIt = mFramebuffers.erase(fbIt);
|
||
|
|
else
|
||
|
|
++ fbIt;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (dummyFbs.size() > 0) {
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> dummyOverlayFbs;
|
||
|
|
if (mDummyComposer.get())
|
||
|
|
mDummyComposer->addInputs(dummyFbs, dummyOverlayFbs);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Only support one legacy video in current times. */
|
||
|
|
#if ENABLE_LEGACY_VIDEO
|
||
|
|
if (!mOverlayFbs.empty() && !mFramebuffers.empty()) {
|
||
|
|
auto osdFbIt = mFramebuffers.begin();
|
||
|
|
uint32_t minOsdFbZorder = osdFbIt->second->getZorder();
|
||
|
|
|
||
|
|
/* Current only input one Legacy video fb. */
|
||
|
|
std::shared_ptr<DrmFramebufferBase> legacyVideoFb = *(mOverlayFbs.begin());
|
||
|
|
if (legacyVideoFb->getZorder() > minOsdFbZorder) {
|
||
|
|
mMinComposerZorder = mFramebuffers.begin()->second->getZorder();
|
||
|
|
/* Legacy video is always on the bottom.
|
||
|
|
* SO, all fbs below legacyVideo zorder need to compose.
|
||
|
|
* Set maxClientZorder = legacyVideoZorder
|
||
|
|
*/
|
||
|
|
if (mMaxComposerZorder == INVALID_ZORDER || legacyVideoFb->getZorder() > mMaxComposerZorder) {
|
||
|
|
mMaxComposerZorder = legacyVideoFb->getZorder();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#else // If only one legacy video in current times, don't need to check inside video flag.
|
||
|
|
|
||
|
|
/* 1. check mInsideVideoFbsFlag = false
|
||
|
|
* 2. for HDR mode, adjust compose range.
|
||
|
|
*/
|
||
|
|
if (!mOverlayFbs.empty() && !mFramebuffers.empty()) {
|
||
|
|
bool bVideoCompose = mOverlayFbs.size() > 2 ? true : false;
|
||
|
|
auto uiFbIt = mFramebuffers.begin();
|
||
|
|
uint32_t uiFbMinZorder = uiFbIt->second->getZorder();
|
||
|
|
uiFbIt = mFramebuffers.end();
|
||
|
|
uiFbIt --;
|
||
|
|
uint32_t uiFbMaxZorder = uiFbIt->second->getZorder();
|
||
|
|
int videoOnTop = 0;
|
||
|
|
|
||
|
|
for (auto videoFbIt = mOverlayFbs.begin(); videoFbIt != mOverlayFbs.end(); ) {
|
||
|
|
std::shared_ptr<DrmFramebufferBase> videoFb = *videoFbIt;
|
||
|
|
fbZorder = videoFb->getZorder();
|
||
|
|
|
||
|
|
if (fbZorder >= uiFbMinZorder && fbZorder <= uiFbMaxZorder) {
|
||
|
|
if (mHDRMode || bVideoCompose) {
|
||
|
|
/* For hdr composition: it's hw limit.
|
||
|
|
* video should top or bottom.
|
||
|
|
* when video layer is not top, make all the lower framebuffers composed.
|
||
|
|
* For fixed planemode, video is always bottom.
|
||
|
|
*/
|
||
|
|
mMinComposerZorder = mFramebuffers.begin()->second->getZorder();
|
||
|
|
if (mMaxComposerZorder == INVALID_ZORDER || fbZorder > mMaxComposerZorder) {
|
||
|
|
mMaxComposerZorder = fbZorder;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
mInsideVideoFbsFlag = true;
|
||
|
|
}
|
||
|
|
++videoFbIt;
|
||
|
|
} else {
|
||
|
|
/*only one video on top of ui */
|
||
|
|
if (fbZorder > uiFbMaxZorder) {
|
||
|
|
if (videoOnTop >= 1 || bVideoCompose) {
|
||
|
|
++videoFbIt;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
videoOnTop ++;
|
||
|
|
}
|
||
|
|
|
||
|
|
MESON_LOGV("%s remove overlay fb (%s)", __func__, videoFb->getDebugInfo());
|
||
|
|
videoFbIt = mOverlayFbs.erase(videoFbIt);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CompositionStrategyBase::hasPlaneSupport(std::shared_ptr<DrmFramebufferBase> fb) {
|
||
|
|
for (const auto& plane : mOsdPlanes) {
|
||
|
|
if (plane && plane->isFbSupport(fb)) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CompositionStrategyBase::tryAllocate(int idx, const std::vector<std::shared_ptr<DrmFramebufferBase>>& layers,
|
||
|
|
std::vector<std::shared_ptr<HwDisplayPlaneBase>>& planes, std::vector<bool>& usablePlanes,
|
||
|
|
std::unordered_map<uint32_t, uint32_t>& results) {
|
||
|
|
if (idx == layers.size()) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
const auto& curLayer = layers[idx];
|
||
|
|
|
||
|
|
for (int i = 0; i < planes.size(); ++i) {
|
||
|
|
if (!usablePlanes[i] && planes[i]->isFbSupport(curLayer)) {
|
||
|
|
usablePlanes[i] = true;
|
||
|
|
results[curLayer->getZorder()] = planes[i]->getId();
|
||
|
|
if (tryAllocate(idx + 1, layers, planes, usablePlanes, results)) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
results.erase(curLayer->getZorder());
|
||
|
|
usablePlanes[i] = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CompositionStrategyBase::decidePlaneAssignment() {
|
||
|
|
mLayerAssignment.clear();
|
||
|
|
if (mFramebuffers.empty()) {
|
||
|
|
MESON_LOGV("%s No framebuffers available for plane assignment", __func__);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
while (true) {
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> targetLayers;
|
||
|
|
std::vector<std::shared_ptr<HwDisplayPlaneBase>> availablePlanes;
|
||
|
|
|
||
|
|
//Step1: Collect layers that require device composition into targetLayers.
|
||
|
|
if (mMinComposerZorder == INVALID_ZORDER && mMaxComposerZorder == INVALID_ZORDER) {
|
||
|
|
targetLayers.reserve(mFramebuffers.size());
|
||
|
|
for (const auto& [zorder, buf] : mFramebuffers) {
|
||
|
|
targetLayers.push_back(buf);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
for (const auto& [zorder, buf] : mFramebuffers) {
|
||
|
|
if (zorder < mMinComposerZorder || zorder > mMaxComposerZorder) {
|
||
|
|
targetLayers.push_back(buf);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//Step2: Collect available planes based on whether client composition is required;
|
||
|
|
//if client composition is involved, reserve the primary plane.
|
||
|
|
bool hasClient = mMinComposerZorder != INVALID_ZORDER && mMaxComposerZorder != INVALID_ZORDER;
|
||
|
|
for (const auto& plane : mOsdPlanes) {
|
||
|
|
if (hasClient) {
|
||
|
|
if (!(plane->getCapabilities() & PLANE_PRIMARY)) {
|
||
|
|
availablePlanes.push_back(plane);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
availablePlanes.push_back(plane);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//Step3: Attempt to assign the layer to a plane. If successful, break the loop;
|
||
|
|
//otherwise, expand the search scope and retry.
|
||
|
|
std::vector<bool> usablePlanes(availablePlanes.size(), false);
|
||
|
|
if (tryAllocate(0, targetLayers, availablePlanes, usablePlanes, mLayerAssignment)) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
//Step4 :Fall back to client composition for more layers if plane assignment fails.
|
||
|
|
bool expanded = false;
|
||
|
|
if (mMinComposerZorder == INVALID_ZORDER || mMaxComposerZorder == INVALID_ZORDER) {
|
||
|
|
mMinComposerZorder = mFramebuffers.begin()->first;
|
||
|
|
mMaxComposerZorder = mFramebuffers.begin()->first;
|
||
|
|
expanded = true;
|
||
|
|
} else {
|
||
|
|
auto itUpper = mFramebuffers.upper_bound(mMaxComposerZorder);
|
||
|
|
auto itLower = mFramebuffers.lower_bound(mMinComposerZorder);
|
||
|
|
//Since the whiteboard layer is on top, prioritize expanding
|
||
|
|
//the client-side compositing range downward.
|
||
|
|
if (itLower != mFramebuffers.begin()) {
|
||
|
|
--itLower;
|
||
|
|
mMinComposerZorder = itLower->first;
|
||
|
|
expanded = true;
|
||
|
|
} else if (itUpper != mFramebuffers.end()){
|
||
|
|
mMaxComposerZorder = itUpper->first;
|
||
|
|
expanded = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!expanded) {
|
||
|
|
// Fallback solution: full GPU composition.
|
||
|
|
mMinComposerZorder = mFramebuffers.begin()->first;
|
||
|
|
mMaxComposerZorder = mFramebuffers.rbegin()->first;
|
||
|
|
mLayerAssignment.clear();
|
||
|
|
MESON_LOGV("%s: Final fallback to full GPU composition", __func__);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mMaxComposerZorder != INVALID_ZORDER &&
|
||
|
|
mMinComposerZorder != INVALID_ZORDER) {
|
||
|
|
/*will use compose fb as reffb.*/
|
||
|
|
return ;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*select base fb and set base scale info.*/
|
||
|
|
int32_t minXOffset = -1, minYOffset = -1;
|
||
|
|
int32_t compositionTargetW = 0, compositionTargetH = 0;
|
||
|
|
for (auto it = mFramebuffers.begin(); it != mFramebuffers.end(); it++) {
|
||
|
|
drm_rect_t dispFrame = it->second->getDisplayFrame();
|
||
|
|
if (minXOffset == -1 || minXOffset > dispFrame.left)
|
||
|
|
minXOffset = dispFrame.left;
|
||
|
|
if (minYOffset == -1 || minYOffset > dispFrame.top)
|
||
|
|
minYOffset = dispFrame.top;
|
||
|
|
|
||
|
|
if (dispFrame.right > compositionTargetW)
|
||
|
|
compositionTargetW = dispFrame.right;
|
||
|
|
if (dispFrame.bottom > compositionTargetH)
|
||
|
|
compositionTargetH = dispFrame.bottom;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*choose base fb, the scale is smallest bigger.*/
|
||
|
|
compositionTargetW = compositionTargetW - minXOffset;
|
||
|
|
compositionTargetH = compositionTargetH - minYOffset;
|
||
|
|
|
||
|
|
drm_rect_t scaleInput = {0, 0,
|
||
|
|
OSD_SCALER_INPUT_MAX_WIDTH, OSD_SCALER_INPUT_MAX_HEIGHT};
|
||
|
|
drm_rect_t scaleOutput = {0, 0, compositionTargetW, compositionTargetH};
|
||
|
|
|
||
|
|
if (1 == mFramebuffers.size()) {
|
||
|
|
if (!mDisplayRefFb)
|
||
|
|
mDisplayRefFb = mFramebuffers.begin()->second;
|
||
|
|
} else {
|
||
|
|
/*choose the scale > targetW/MAX_INPUT*/
|
||
|
|
for (auto it = mFramebuffers.begin(); it != mFramebuffers.end(); it++) {
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb = it->second;
|
||
|
|
drm_rect_t dispFrame = fb->getDisplayFrame();
|
||
|
|
drm_rect_t sourceCrop = fb->getSourceCrop();
|
||
|
|
drm_rect_t refDispFrame;
|
||
|
|
drm_rect_t refSourceCrop;
|
||
|
|
int32_t ret = compareFbScale(sourceCrop, dispFrame, scaleInput, scaleOutput);
|
||
|
|
if (0 == ret) {
|
||
|
|
mDisplayRefFb = fb;
|
||
|
|
break;
|
||
|
|
} else if (1 == ret) {
|
||
|
|
if (!mDisplayRefFb)
|
||
|
|
mDisplayRefFb = fb;
|
||
|
|
else {
|
||
|
|
refDispFrame = mDisplayRefFb->getDisplayFrame();
|
||
|
|
refSourceCrop = mDisplayRefFb->getSourceCrop();
|
||
|
|
if (-1 == compareFbScale(sourceCrop, dispFrame,
|
||
|
|
refSourceCrop, refDispFrame)) {
|
||
|
|
mDisplayRefFb = fb;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*no suitable fb, we need do composition*/
|
||
|
|
if (!mDisplayRefFb) {
|
||
|
|
/* All Scale Fbs and no default composer range, select begin Fbs to composer. */
|
||
|
|
mMinComposerZorder = mFramebuffers.begin()->second->getZorder();
|
||
|
|
mMaxComposerZorder = mMinComposerZorder;
|
||
|
|
} else {
|
||
|
|
/*set display offset, the offset will be updated when commit() if reffb is composed*/
|
||
|
|
mOsdDisplayFrame.crtc_display_x = minXOffset;
|
||
|
|
mOsdDisplayFrame.crtc_display_y = minYOffset;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*Count below, inside and up client Fbs number.
|
||
|
|
********************************************************************
|
||
|
|
** *
|
||
|
|
** |----------------------- *
|
||
|
|
** upClientNum--{----------------------- *
|
||
|
|
** |----------------------- *
|
||
|
|
** ----maxClientZorder----| *
|
||
|
|
** -----------------------} --insideClientNum *
|
||
|
|
** ----minClientZorder----| *
|
||
|
|
** |----------------------- *
|
||
|
|
** belowClientNum--{----------------------- *
|
||
|
|
** |----------------------- *
|
||
|
|
** *
|
||
|
|
********************************************************************
|
||
|
|
*/
|
||
|
|
int CompositionStrategyBase::countComposerFbs(int &belowClientNum, int &upClientNum, int &insideClientNum) {
|
||
|
|
uint32_t fbZorder = -1;
|
||
|
|
if (mMinComposerZorder == INVALID_ZORDER) {
|
||
|
|
belowClientNum = 0;
|
||
|
|
upClientNum = 0;
|
||
|
|
insideClientNum = 0;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb;
|
||
|
|
auto fbIt = mFramebuffers.begin();
|
||
|
|
for (; fbIt != mFramebuffers.end(); ++fbIt) {
|
||
|
|
fb = fbIt->second;
|
||
|
|
fbZorder = fb->getZorder();
|
||
|
|
if (fbZorder < mMinComposerZorder)
|
||
|
|
belowClientNum++;
|
||
|
|
else if (fbZorder > mMaxComposerZorder)
|
||
|
|
upClientNum++;
|
||
|
|
else
|
||
|
|
insideClientNum++;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CompositionStrategyBase::confirmComposerRange() {
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb;
|
||
|
|
uint32_t osdFbsNum = mFramebuffers.size();
|
||
|
|
uint32_t osdPlanesNum = mOsdPlanes.size();
|
||
|
|
int belowClientNum = 0;
|
||
|
|
int upClientNum = 0;
|
||
|
|
int insideClientNum = 0;
|
||
|
|
if (osdFbsNum == 0 || osdPlanesNum == 0) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
int ret = countComposerFbs(belowClientNum, upClientNum, insideClientNum);
|
||
|
|
UNUSED(ret);
|
||
|
|
if (osdFbsNum > osdPlanesNum) { // CASE 1: osdFbsNum > osdPlanesNum , need compose more fbs.*/
|
||
|
|
/* CASE 1_1: mMinComposerZorder != INVALID_ZORDER, need do compose. */
|
||
|
|
int minNeedComposedFbs = osdFbsNum - insideClientNum - osdPlanesNum + 1; // minimum OSD Fbs need to be composered
|
||
|
|
if (mMinComposerZorder != INVALID_ZORDER) {
|
||
|
|
/* If minNeedComposedFbs = 0, use client range to compose */
|
||
|
|
if (minNeedComposedFbs > 0) {
|
||
|
|
/* compose more fbs from minimum zorder first. */
|
||
|
|
auto fbIt = mFramebuffers.begin();
|
||
|
|
if (belowClientNum > 0 && minNeedComposedFbs <= belowClientNum) {
|
||
|
|
int noComposedFbs = belowClientNum - minNeedComposedFbs;
|
||
|
|
if (noComposedFbs > 0) {
|
||
|
|
for (; fbIt != mFramebuffers.end(); ++fbIt) {
|
||
|
|
noComposedFbs -- ;
|
||
|
|
if (noComposedFbs < 0)
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
minNeedComposedFbs = 0;
|
||
|
|
} else {
|
||
|
|
minNeedComposedFbs -= belowClientNum;
|
||
|
|
}
|
||
|
|
/* confirm the minimum zorder value. */
|
||
|
|
if (fbIt != mFramebuffers.end())
|
||
|
|
mMinComposerZorder = fbIt->second->getZorder();
|
||
|
|
|
||
|
|
/* compose fb from maximum zorder. */
|
||
|
|
if (minNeedComposedFbs > 0) {
|
||
|
|
MESON_ASSERT(upClientNum > 0, "upClientNum should > 0.");
|
||
|
|
fbIt = mFramebuffers.upper_bound(mMaxComposerZorder);
|
||
|
|
for (; fbIt != mFramebuffers.end(); ++ fbIt) {
|
||
|
|
minNeedComposedFbs --;
|
||
|
|
if (minNeedComposedFbs <= 0)
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* we can confirm the maximum zorder value. */
|
||
|
|
if (fbIt != mFramebuffers.end())
|
||
|
|
mMaxComposerZorder = fbIt->second->getZorder();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
/* CASE 1_2: no fb set to compose before, free to choose new fbs to compose */
|
||
|
|
int countComposerFbs = 0;
|
||
|
|
for (auto it = mFramebuffers.begin(); it != mFramebuffers.end(); ++it) {
|
||
|
|
fb = it->second;
|
||
|
|
countComposerFbs++;
|
||
|
|
if (countComposerFbs == minNeedComposedFbs) {
|
||
|
|
mMaxComposerZorder = fb->getZorder();
|
||
|
|
mMinComposerZorder = (mFramebuffers.begin()->second)->getZorder();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t CompositionStrategyBase::compareFbScale(
|
||
|
|
drm_rect_t & aSrc,
|
||
|
|
drm_rect_t & aDst,
|
||
|
|
drm_rect_t & bSrc,
|
||
|
|
drm_rect_t & bDst) {
|
||
|
|
int32_t aDisplayWidth = aDst.right - aDst.left;
|
||
|
|
int32_t aDisplayHeight = aDst.bottom - aDst.top;
|
||
|
|
int32_t aSrcWidth = aSrc.right - aSrc.left;
|
||
|
|
int32_t aSrcHeight = aSrc.bottom - aSrc.top;
|
||
|
|
int32_t bDisplayWidth = bDst.right - bDst.left;
|
||
|
|
int32_t bDisplayHeight = bDst.bottom - bDst.top;
|
||
|
|
int32_t bSrcWidth = bSrc.right - bSrc.left;
|
||
|
|
int32_t bSrcHeight = bSrc.bottom - bSrc.top;
|
||
|
|
|
||
|
|
int widthCompare = aDisplayWidth*bSrcWidth - bDisplayWidth*aSrcWidth;
|
||
|
|
int heightCompare = aDisplayHeight *bSrcHeight - bDisplayHeight * aSrcHeight;
|
||
|
|
if (widthCompare == 0 && heightCompare == 0)
|
||
|
|
return 0;
|
||
|
|
else if (widthCompare > 0 && heightCompare > 0)
|
||
|
|
return 1;
|
||
|
|
else {
|
||
|
|
//MESON_LOGW("compareFbScale failed %d ,%d, %d, %d",
|
||
|
|
//widthCompare, heightCompare,
|
||
|
|
//bDisplayWidth, bDisplayHeight);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Set DisplayPairs between UI(OSD) Fbs with plane. */
|
||
|
|
int CompositionStrategyBase::setOsdFbs2PlanePairs() {
|
||
|
|
if (mFramebuffers.size() == 0)
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
std::shared_ptr<HwDisplayPlaneBase> osdTemp;
|
||
|
|
for (uint32_t i = 1; i < mOsdPlanes.size(); i++) {
|
||
|
|
if (mOsdPlanes[i]->getCapabilities() & PLANE_PRIMARY) {
|
||
|
|
osdTemp = mOsdPlanes[0];
|
||
|
|
mOsdPlanes[0] = mOsdPlanes[i];
|
||
|
|
mOsdPlanes[i] = osdTemp;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
uint32_t usedPlanes = 0;
|
||
|
|
|
||
|
|
if (mDisplayRefFb.get()) {
|
||
|
|
/*baseFb always post to din0*/
|
||
|
|
mDisplayPairs.push_back(
|
||
|
|
DisplayPair{usedPlanes, mDisplayRefFb->getZorder(), nullptr, {mDisplayRefFb}, mOsdPlanes[usedPlanes]});
|
||
|
|
/* Not composed fb, set to osd composition. */
|
||
|
|
if (mDisplayRefFb->getCompositionType() == MESON_COMPOSITION_UNDETERMINED)
|
||
|
|
mDisplayRefFb->setCompositionType(MESON_COMPOSITION_PLANE_OSD);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (auto fbIt = mFramebuffers.begin(); fbIt != mFramebuffers.end(); ++fbIt) {
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb = fbIt->second;
|
||
|
|
if (fb == mDisplayRefFb)
|
||
|
|
continue;
|
||
|
|
/* fb is unscaled or is represent of composer output,
|
||
|
|
* we pick primary display.
|
||
|
|
*/
|
||
|
|
/* Pick any available plane */
|
||
|
|
if (usedPlanes != mOsdPlanes.size() - 1) {
|
||
|
|
usedPlanes++;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::shared_ptr<HwDisplayPlaneBase> targetPlane = nullptr;
|
||
|
|
auto it = mLayerAssignment.find(fb->getZorder());
|
||
|
|
if (it != mLayerAssignment.end()) {
|
||
|
|
uint32_t targetId = it->second;
|
||
|
|
auto planeIt = std::find_if(mOsdPlanes.begin(), mOsdPlanes.end(),
|
||
|
|
[targetId](const auto& p) { return p->getId() == targetId; });
|
||
|
|
|
||
|
|
if (planeIt != mOsdPlanes.end()) {
|
||
|
|
targetPlane = *planeIt;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (targetPlane != nullptr) {
|
||
|
|
mDisplayPairs.push_back(
|
||
|
|
DisplayPair{usedPlanes, fb->getZorder(), nullptr, {fb}, targetPlane});
|
||
|
|
} else {
|
||
|
|
MESON_LOGD("%s: Skip adding FB (Zorder: %u) to DisplayPairs", __func__, fb->getZorder());
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Not composed fb, set to osd composition. */
|
||
|
|
if (fb->getCompositionType() == MESON_COMPOSITION_UNDETERMINED)
|
||
|
|
fb->setCompositionType(MESON_COMPOSITION_PLANE_OSD);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* removed used planes from mOsdPlanes */
|
||
|
|
for (uint32_t i = 0; i <= usedPlanes; i++) {
|
||
|
|
mOsdPlanes.erase(mOsdPlanes.begin());
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Select composer */
|
||
|
|
int CompositionStrategyBase::selectComposer() {
|
||
|
|
if (mComposerFbs.size() == 0) {
|
||
|
|
if (mClientComposer.get())
|
||
|
|
mClientComposer->prepare();
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!mHaveClient) {
|
||
|
|
auto composerIt = mOtherComposers.begin();
|
||
|
|
for (; composerIt != mOtherComposers.end(); ++composerIt) {
|
||
|
|
if ((*composerIt)->isFbsSupport(mComposerFbs, mOverlayFbs)) {
|
||
|
|
mComposer = *composerIt;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (mComposer.get() == NULL)
|
||
|
|
mComposer = mClientComposer;
|
||
|
|
|
||
|
|
if (!mComposer.get())
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
/* set composed fb composition type */
|
||
|
|
for (auto it = mComposerFbs.begin(); it != mComposerFbs.end(); ++it) {
|
||
|
|
(*it)->setCompositionType(mComposer->getType());
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Find out which fb need to compose and push DisplayPair */
|
||
|
|
int CompositionStrategyBase::fillComposerFbs() {
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb;
|
||
|
|
if (mMaxComposerZorder != INVALID_ZORDER &&
|
||
|
|
mMinComposerZorder != INVALID_ZORDER) {
|
||
|
|
auto fbIt = mFramebuffers.begin();
|
||
|
|
auto lastComposeFbIt = mFramebuffers.end();
|
||
|
|
while (fbIt != mFramebuffers.end()) {
|
||
|
|
fb = fbIt->second;
|
||
|
|
if (IS_FB_COMPOSED(fb)) {
|
||
|
|
mComposerFbs.push_back(fb);
|
||
|
|
if (lastComposeFbIt != mFramebuffers.end()) {
|
||
|
|
mFramebuffers.erase(lastComposeFbIt);
|
||
|
|
}
|
||
|
|
lastComposeFbIt = fbIt;
|
||
|
|
}
|
||
|
|
++ fbIt;
|
||
|
|
}
|
||
|
|
|
||
|
|
MESON_ASSERT(lastComposeFbIt != mFramebuffers.end(), "no last composer fb !");
|
||
|
|
MESON_ASSERT(mDisplayRefFb.get() == NULL, "reffb should be NULL.");
|
||
|
|
mDisplayRefFb = lastComposeFbIt->second;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (auto videoFbIt = mOverlayFbs.begin(); videoFbIt != mOverlayFbs.end();) {
|
||
|
|
std::shared_ptr<DrmFramebufferBase> videoFb = *videoFbIt;
|
||
|
|
if (IS_FB_COMPOSED(videoFb)) {
|
||
|
|
++videoFbIt;
|
||
|
|
} else {
|
||
|
|
MESON_LOGV("%s remove overlay fb (%s)", __func__, videoFb->getDebugInfo());
|
||
|
|
videoFbIt = mOverlayFbs.erase(videoFbIt);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Update present zorder.
|
||
|
|
* If videoZ ~ (mMinComposerZorder, mMaxComposerZorder), set maxVideoZ = maxVideoZ - 1
|
||
|
|
*/
|
||
|
|
void CompositionStrategyBase::handleOverlayVideoZorder() {
|
||
|
|
auto it = mDisplayPairs.begin();
|
||
|
|
for (; it != mDisplayPairs.end(); ++it) {
|
||
|
|
auto fbIt = it->fbs.begin();
|
||
|
|
for (; fbIt != it->fbs.end(); fbIt++) {
|
||
|
|
if (IS_FB_COMPOSED((*fbIt))) {
|
||
|
|
it->presentZorder = it->presentZorder - 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CompositionStrategyBase::handleVPUOddScaleLimit() {
|
||
|
|
drm_rect_t sourceCrop = {0, 0, 0,0};
|
||
|
|
uint32_t fbZorder = 0;
|
||
|
|
if (!(mCrtc->getWrFlag() & (1 << (int32_t) MesonDrmWrId::GFCD_ODD_SIZE))) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mFramebuffers.size() <= 1) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
int deviceNum = 0;
|
||
|
|
int clientNum = 0;
|
||
|
|
bool oddInput = false;
|
||
|
|
std::shared_ptr<DrmFramebufferBase> scaleFb;
|
||
|
|
for (auto fbIt = mFramebuffers.begin(); fbIt != mFramebuffers.end(); ++fbIt) {
|
||
|
|
auto fb = fbIt->second;
|
||
|
|
sourceCrop = fb->getSourceCrop();
|
||
|
|
if ((sourceCrop.right - sourceCrop.left) % 2 != 0) {
|
||
|
|
oddInput = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// osdComposed layers
|
||
|
|
fbZorder = fb->getZorder();
|
||
|
|
if (fbZorder < mMinComposerZorder || fbZorder > mMaxComposerZorder) {
|
||
|
|
scaleFb = fb;
|
||
|
|
deviceNum++;
|
||
|
|
} else {
|
||
|
|
clientNum++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// no device Composition or no odd input , no need check
|
||
|
|
if (deviceNum == 0 || !oddInput) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
drm_rect_t scaleInput = {0,0,0,0};
|
||
|
|
drm_rect_t scaleOutput = {0, 0, 0,0};
|
||
|
|
// has Client composition
|
||
|
|
if (clientNum != 0) {
|
||
|
|
// input width is not odd
|
||
|
|
if (!scaleFb) {
|
||
|
|
sourceCrop = scaleFb->getSourceCrop();
|
||
|
|
if ((sourceCrop.right - sourceCrop.left) % 2 == 0) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
scaleInput = {0, 0, mOsdDisplayFrame.framebuffer_w, mOsdDisplayFrame.framebuffer_h};
|
||
|
|
scaleOutput = {mOsdDisplayFrame.crtc_display_x, mOsdDisplayFrame.crtc_display_y,
|
||
|
|
mOsdDisplayFrame.crtc_display_w, mOsdDisplayFrame.crtc_display_h};
|
||
|
|
// all device compostion
|
||
|
|
} else {
|
||
|
|
auto firstIt = mFramebuffers.begin();
|
||
|
|
auto secondIt = std::next(firstIt);
|
||
|
|
if (secondIt == mFramebuffers.end()) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
scaleInput = secondIt->second->getSourceCrop();
|
||
|
|
scaleOutput = secondIt->second->getDisplayFrame();
|
||
|
|
scaleFb = firstIt->second;
|
||
|
|
}
|
||
|
|
|
||
|
|
// need check the scale limit
|
||
|
|
drm_rect_t scaleDispFrame = scaleFb->getDisplayFrame();
|
||
|
|
sourceCrop = scaleFb->getSourceCrop();
|
||
|
|
auto scaleRet = compareFbScale(sourceCrop, scaleDispFrame, scaleInput, scaleOutput);
|
||
|
|
|
||
|
|
// force to Client compose
|
||
|
|
if (scaleRet != 0) {
|
||
|
|
for (auto fbIt = mFramebuffers.begin(); fbIt != mFramebuffers.end(); ++fbIt) {
|
||
|
|
auto fb = fbIt->second;
|
||
|
|
fbZorder = fb->getZorder();
|
||
|
|
if (mMinComposerZorder == INVALID_ZORDER || mMinComposerZorder > fbZorder) {
|
||
|
|
mMinComposerZorder = fbZorder;
|
||
|
|
}
|
||
|
|
if (mMaxComposerZorder == INVALID_ZORDER || mMaxComposerZorder < fbZorder) {
|
||
|
|
mMaxComposerZorder = fbZorder;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Scale Limitation:
|
||
|
|
* 1. VPU only support composed 2 non afbc osd layers
|
||
|
|
* 2. For afbc layers, exp_h = SourceFrame_height * 1/3 * 1.1;
|
||
|
|
* when DisplayFrame_height < exp_h then only support two layers.
|
||
|
|
*/
|
||
|
|
void CompositionStrategyBase::handleVPUScaleLimit() {
|
||
|
|
uint32_t nonAfbcFbsNumb = 0;
|
||
|
|
uint32_t limitCount = 0;
|
||
|
|
|
||
|
|
int belowClientNum = 0;
|
||
|
|
int upClientNum = 0;
|
||
|
|
int insideClientNum = 0;
|
||
|
|
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb;
|
||
|
|
for (auto fbIt = mFramebuffers.begin(); fbIt != mFramebuffers.end(); ++fbIt) {
|
||
|
|
fb = fbIt->second;
|
||
|
|
float scaleLimit = DebugHelper::getInstance().getScaleLimit();
|
||
|
|
if (scaleLimit == 0)
|
||
|
|
scaleLimit = OSD_SCALER_INPUT_MARGIN / OSD_SCALER_INPUT_FACTOR;
|
||
|
|
|
||
|
|
drm_rect_t dispFrame = fb->getDisplayFrame();
|
||
|
|
drm_rect_t sourceCrop = fb->getSourceCrop();
|
||
|
|
uint32_t fbZorder = fb->getZorder();
|
||
|
|
float expHeight = (sourceCrop.bottom - sourceCrop.top) * scaleLimit;
|
||
|
|
float dispHeight = (dispFrame.bottom - dispFrame.top) * mScaleValue;
|
||
|
|
|
||
|
|
/* osdComposed layers */
|
||
|
|
if (fbZorder < mMinComposerZorder || fbZorder > mMaxComposerZorder) {
|
||
|
|
/* it is non afbc layer */
|
||
|
|
if (!fb->isAfbcBuffer()) {
|
||
|
|
nonAfbcFbsNumb++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (expHeight > dispHeight) {
|
||
|
|
limitCount++;
|
||
|
|
|
||
|
|
if (fbZorder > mMaxComposerZorder)
|
||
|
|
upClientNum++;
|
||
|
|
else
|
||
|
|
belowClientNum++;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
insideClientNum++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* minus one layer for VPU composer */
|
||
|
|
if (limitCount >= 1 || nonAfbcFbsNumb > 2) {
|
||
|
|
if (upClientNum > 0) {
|
||
|
|
auto fbIt = mFramebuffers.upper_bound(mMaxComposerZorder);
|
||
|
|
if (fbIt != mFramebuffers.end())
|
||
|
|
mMaxComposerZorder = fbIt->second->getZorder();
|
||
|
|
} else if (belowClientNum > 0) {
|
||
|
|
if (mMinComposerZorder == INVALID_ZORDER) {
|
||
|
|
/* free to select one */
|
||
|
|
mMinComposerZorder = mFramebuffers.begin()->second->getZorder();
|
||
|
|
mMaxComposerZorder = mMinComposerZorder;
|
||
|
|
} else {
|
||
|
|
auto fbIt = mFramebuffers.lower_bound(mMinComposerZorder);
|
||
|
|
if (fbIt != mFramebuffers.begin() && fbIt != mFramebuffers.end()) {
|
||
|
|
fbIt--;
|
||
|
|
mMinComposerZorder = fbIt->second->getZorder();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Limitation:
|
||
|
|
1. scale input should smaller than 1080P.
|
||
|
|
2. din0 should input the base fb.
|
||
|
|
*/
|
||
|
|
void CompositionStrategyBase::handleVPULimit(bool video) {
|
||
|
|
UNUSED(video);
|
||
|
|
//MESON_ASSERT(video == false, "handleVPULimit havenot support video");
|
||
|
|
|
||
|
|
if (mFramebuffers.size() == 0)
|
||
|
|
return ;
|
||
|
|
|
||
|
|
handleVPUScaleLimit();
|
||
|
|
handleVPUOddScaleLimit();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CompositionStrategyBase::handleDisplayLayerZorder() {
|
||
|
|
int topVideoNum = 0;
|
||
|
|
uint32_t maxOsdZorder = INVALID_ZORDER;
|
||
|
|
for (auto it = mDisplayPairs.begin(); it != mDisplayPairs.end(); ++it) {
|
||
|
|
std::shared_ptr<HwDisplayPlaneBase> plane = it->plane;
|
||
|
|
if (OSD_PLANE == plane->getType()) {
|
||
|
|
if (maxOsdZorder == INVALID_ZORDER) {
|
||
|
|
maxOsdZorder = it->presentZorder;
|
||
|
|
} else {
|
||
|
|
if (maxOsdZorder < it->presentZorder)
|
||
|
|
maxOsdZorder = it->presentZorder;
|
||
|
|
}
|
||
|
|
it->presentZorder = it->presentZorder + OSD_FB_BEGIN_ZORDER; // osd zorder: 65 - 128
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
for (auto it = mDisplayPairs.begin(); it != mDisplayPairs.end(); ++it) {
|
||
|
|
std::shared_ptr<HwDisplayPlaneBase> plane = it->plane;
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb = *(it->fbs.begin());
|
||
|
|
if (HWC_VIDEO_PLANE == plane->getType() ||
|
||
|
|
DRM_VIDEO_PLANE == plane->getType()) {
|
||
|
|
if (fb->getZorder() > maxOsdZorder && topVideoNum != 1) {
|
||
|
|
it->presentZorder = it->presentZorder + TOP_VIDEO_FB_BEGIN_ZORDER; // top video zorder: 129 - 192
|
||
|
|
topVideoNum++;
|
||
|
|
} else {
|
||
|
|
it->presentZorder = it->presentZorder + BOTTOM_VIDEO_FB_BEGIN_ZORDER; // bottom video zorder: 1 - 64
|
||
|
|
}
|
||
|
|
#if ENABLE_LEGACY_VIDEO
|
||
|
|
/* legacy video need on bottom */
|
||
|
|
if (it->presentZorder >= TOP_VIDEO_FB_BEGIN_ZORDER)
|
||
|
|
it->presentZorder -= (TOP_VIDEO_FB_BEGIN_ZORDER - BOTTOM_VIDEO_FB_BEGIN_ZORDER);
|
||
|
|
#else
|
||
|
|
/* keep top video when only one video commit
|
||
|
|
* tmp solution for SWPL-116333
|
||
|
|
* */
|
||
|
|
if (mDisplayPairs.size() == 1)
|
||
|
|
it->presentZorder = it->presentZorder + TOP_VIDEO_FB_BEGIN_ZORDER;
|
||
|
|
|
||
|
|
#if KEEP_VIDEO_BOTTOM
|
||
|
|
if (it->presentZorder >= TOP_VIDEO_FB_BEGIN_ZORDER)
|
||
|
|
it->presentZorder -= (TOP_VIDEO_FB_BEGIN_ZORDER - BOTTOM_VIDEO_FB_BEGIN_ZORDER);
|
||
|
|
#endif
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Handle OSD Fbs and set OsdFbs2Plane pairs. */
|
||
|
|
int CompositionStrategyBase::handleOsdComposition() {
|
||
|
|
/* Step 1:
|
||
|
|
* Judge whether compose or not.
|
||
|
|
* If need to compose, confirm max/min client zorder.
|
||
|
|
*/
|
||
|
|
confirmComposerRange();
|
||
|
|
handleVPULimit(false);
|
||
|
|
decidePlaneAssignment();
|
||
|
|
|
||
|
|
/* Step 2:
|
||
|
|
* Push composers to cache mComposerFbs to build OSD2Plane pair.
|
||
|
|
*/
|
||
|
|
fillComposerFbs();
|
||
|
|
|
||
|
|
/* Step 3:
|
||
|
|
* Select composer.
|
||
|
|
*/
|
||
|
|
selectComposer();
|
||
|
|
|
||
|
|
/* Step 4:
|
||
|
|
* Set DisplayPairs between OSD Fbs with plane.
|
||
|
|
*/
|
||
|
|
setOsdFbs2PlanePairs();
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CompositionStrategyBase::handleOsdCompositionWithVideo() {
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb;
|
||
|
|
|
||
|
|
/* STEP 1: handle two video fbs. */
|
||
|
|
if (mOverlayFbs.size() > 1) {
|
||
|
|
MESON_ASSERT(mOverlayFbs.size() <= 3, "Only support 3 video layers now.");
|
||
|
|
/* CASE VIDEO_1: have two video fbs between ui fbs. */
|
||
|
|
/* Calculate max/min video zorder. */
|
||
|
|
mMinVideoZorder = INVALID_ZORDER;
|
||
|
|
mMaxVideoZorder = INVALID_ZORDER;
|
||
|
|
auto videoIt = mOverlayFbs.begin();
|
||
|
|
for (; videoIt != mOverlayFbs.end(); ++ videoIt) {
|
||
|
|
fb = *videoIt;
|
||
|
|
uint32_t fbZorder = fb->getZorder();
|
||
|
|
if (mMinVideoZorder == INVALID_ZORDER) {
|
||
|
|
mMinVideoZorder = fbZorder;
|
||
|
|
mMaxVideoZorder = fbZorder;
|
||
|
|
} else {
|
||
|
|
if (mMinVideoZorder > fbZorder)
|
||
|
|
mMinVideoZorder = fbZorder;
|
||
|
|
if (mMaxVideoZorder < fbZorder)
|
||
|
|
mMaxVideoZorder = fbZorder;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Judge whether double video are neighbour or not */
|
||
|
|
bool bNeighbourVideo = true;
|
||
|
|
auto fbIt = mFramebuffers.lower_bound(mMinVideoZorder);
|
||
|
|
for (; fbIt != mFramebuffers.end(); ++ fbIt) {
|
||
|
|
if (fbIt->second->getZorder() > mMinVideoZorder && fbIt->second->getZorder() < mMaxVideoZorder) {
|
||
|
|
bNeighbourVideo = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!bNeighbourVideo) {
|
||
|
|
/* CASE VIDEO_1_1: two video fbs are not neighbour. */
|
||
|
|
if (mMinComposerZorder != INVALID_ZORDER) {
|
||
|
|
/* CASE VIDEO_1_1_1: have default compose range */
|
||
|
|
/* Change compose range to cover two video fbs. */
|
||
|
|
/*
|
||
|
|
case 1: Both up and below client has video |case 2_1: Only up client has video |case 2_2: Only below client has video
|
||
|
|
maxClientZorder from 5-->7 | maxClientZorder from 5-->7 | maxClientZorder not change
|
||
|
|
minClientZorder from 4-->3 | minClientZorder not change | minClientZorder from 4-->3
|
||
|
|
zorder: 8 -- osd --------- | 8 -- osd --------- | 8 -- osd ---------
|
||
|
|
7 -- maxVideo ---- maxClient(composer) | 7 -- maxVideo ---- maxClient(composer) | 7 -- client osd -- maxClient(composer)
|
||
|
|
6 -- osd --------- | 6 -- osd --------- | 6 -- maxVideo ----
|
||
|
|
5 -- client osd -- | 5 -- client osd -- | 5 -- client osd --
|
||
|
|
4 -- client osd -- | 4 -- client osd -- | 4 -- client osd --
|
||
|
|
3 -- osd --------- minClient(composer) | 3 -- minVideo ---- | 3 -- osd --------- minClient(composer)
|
||
|
|
2 -- minVideo ---- | 2 -- client osd -- minClient(composer) | 2 -- minVideo ----
|
||
|
|
1 -- osd --------- | 1 -- osd --------- | 1 -- osd ---------
|
||
|
|
*/
|
||
|
|
if (mMinComposerZorder > mMinVideoZorder) {
|
||
|
|
mMinComposerZorder = mMinVideoZorder + 1; // +1 to not compose the video
|
||
|
|
}
|
||
|
|
if (mMaxComposerZorder < mMaxVideoZorder) {
|
||
|
|
mMaxComposerZorder = mMaxVideoZorder;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
/* CASE VIDEO_1_1_2:no default compose range
|
||
|
|
* Compose the fbs below minVideoZ, so the minVideoZ will be bottom.
|
||
|
|
* CASE: two video inside osd ui without client(default) range
|
||
|
|
* set maxClientZorder = 2
|
||
|
|
* set minClientZorder = 1
|
||
|
|
* zorder: 5 -- osd -------
|
||
|
|
* 4 -- maxVideo --
|
||
|
|
* 3 -- osd -------
|
||
|
|
* 2 -- minVideo -- maxClient(composer)
|
||
|
|
* 1 -- osd ------- minClient(composer)
|
||
|
|
*/
|
||
|
|
mMaxComposerZorder = mMinVideoZorder;
|
||
|
|
mMinComposerZorder = mFramebuffers.begin()->first;
|
||
|
|
}
|
||
|
|
/* goto case VIDEO_2 */
|
||
|
|
} else {
|
||
|
|
/* CASE VIDEO_1_2: two video fbs are neighbour, treat as one video. */
|
||
|
|
/* goto case VIDEO_2 */
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* STEP 2: now only one video fb or two neighbour video fbs.
|
||
|
|
* pick ui fbs to compose.
|
||
|
|
*/
|
||
|
|
confirmComposerRange();
|
||
|
|
handleVPULimit(true);
|
||
|
|
decidePlaneAssignment();
|
||
|
|
|
||
|
|
/* Push composers to cache mComposerFbs to build OSD2Plane pair. */
|
||
|
|
fillComposerFbs();
|
||
|
|
|
||
|
|
/* Step 3:
|
||
|
|
* Select composer.
|
||
|
|
*/
|
||
|
|
selectComposer();
|
||
|
|
|
||
|
|
setOsdFbs2PlanePairs();
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* The public setup interface.
|
||
|
|
* layers: UI(include OSD and VIDEO) layer from SurfaceFlinger.
|
||
|
|
* composers: Composer style.
|
||
|
|
* planes: Get OSD and VIDEO planes from HwDisplayManager.
|
||
|
|
*/
|
||
|
|
void CompositionStrategyBase::setup(
|
||
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> & layers,
|
||
|
|
std::vector<std::shared_ptr<IComposer>> & composers,
|
||
|
|
std::vector<std::shared_ptr<HwDisplayPlaneBase>> & planes,
|
||
|
|
std::shared_ptr<HwDisplayCrtcBase> & crtc,
|
||
|
|
uint32_t reqFlag,
|
||
|
|
float scaleValue,
|
||
|
|
drm_mode_info_t mode) {
|
||
|
|
|
||
|
|
init();
|
||
|
|
|
||
|
|
mCrtc = crtc;
|
||
|
|
mCompositionFlag = reqFlag;
|
||
|
|
mScaleValue = scaleValue;
|
||
|
|
mDisplayMode = mode;
|
||
|
|
#if OSD_OUTPUT_ONE_CHANNEL
|
||
|
|
mHDRMode = true;
|
||
|
|
#else
|
||
|
|
if (reqFlag & COMPOSE_WITH_HDR_VIDEO) {
|
||
|
|
mHDRMode = true;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
if (reqFlag & COMPOSE_HIDE_SECURE_FB) {
|
||
|
|
mHideSecureLayer = true;
|
||
|
|
}
|
||
|
|
if (reqFlag & COMPOSE_FORCE_CLIENT) {
|
||
|
|
mForceClientComposer = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
#if ENABLE_GFX_HRR
|
||
|
|
if (mDisplayMode.refreshRate > 165.0f) {
|
||
|
|
mForceClientComposer = true;
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
if (mDisplayMode.refreshRate > DEFAULT_REFRESH_RATE) {
|
||
|
|
mForceClientComposer = true;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if (reqFlag & COMPOSE_DISABLE_SIDEBAND) {
|
||
|
|
mIsSideBandDisable = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (reqFlag & COMPOSE_ENABLE_MOSAIC_MODE) {
|
||
|
|
mMosaicEnabled = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (reqFlag & COMPOSE_FORCE_VIDEO) {
|
||
|
|
mForceVideoComposer = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mCompositionFlag & COMPOSE_HIDE_VIDEO_FOR_HDCP_DEV) {
|
||
|
|
mHideVideoForHdcpDev = true;
|
||
|
|
}
|
||
|
|
/* add layers */
|
||
|
|
auto layerIt = layers.begin();
|
||
|
|
for (; layerIt != layers.end(); ++layerIt) {
|
||
|
|
std::shared_ptr<DrmFramebufferBase> layer = *layerIt;
|
||
|
|
mFramebuffers.insert(make_pair(layer->getZorder(), layer));
|
||
|
|
}
|
||
|
|
|
||
|
|
/* collect composers */
|
||
|
|
auto composerIt = composers.begin();
|
||
|
|
for (; composerIt != composers.end(); ++composerIt) {
|
||
|
|
std::shared_ptr<IComposer> composer = *composerIt;
|
||
|
|
switch (composer->getType()) {
|
||
|
|
case MESON_COMPOSITION_DUMMY:
|
||
|
|
if (mDummyComposer == NULL)
|
||
|
|
mDummyComposer = composer;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MESON_COMPOSITION_CLIENT:
|
||
|
|
if (mClientComposer == NULL)
|
||
|
|
mClientComposer = composer;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MESON_COMPOSITION_DI:
|
||
|
|
if (mVideoComposers.empty())
|
||
|
|
mVideoComposers.push_back(composer);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MESON_COMPOSITION_V2D:
|
||
|
|
mIsVideoComposerV2D = true;
|
||
|
|
mVideoComposers.push_back(composer);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
mOtherComposers.push_back(composer);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* collect planes */
|
||
|
|
auto planeIt = planes.begin();
|
||
|
|
for (; planeIt != planes.end(); ++planeIt) {
|
||
|
|
std::shared_ptr<HwDisplayPlaneBase> plane = *planeIt;
|
||
|
|
|
||
|
|
if (!plane->isAvailable()) {
|
||
|
|
mOtherPlanes.push_back(plane);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (plane->getType()) {
|
||
|
|
case OSD_PLANE:
|
||
|
|
mOsdPlanes.push_back(plane);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case DRM_VIDEO_PLANE:
|
||
|
|
case HWC_VIDEO_PLANE:
|
||
|
|
mHwcVideoPlanes.push_back(plane);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
mOtherPlanes.push_back(plane);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
mVideoPlaneNum = mHwcVideoPlanes.size();
|
||
|
|
mVideoComposerNum = mVideoComposers.size();
|
||
|
|
mOsdPlaneNum = mOsdPlanes.size();
|
||
|
|
|
||
|
|
if (mIsVideoComposerV2D)
|
||
|
|
MESON_ASSERT(mVideoPlaneNum == mVideoComposerNum, "video composer count error !!!");
|
||
|
|
}
|
||
|
|
|
||
|
|
void CompositionStrategyBase::updateComposition() {
|
||
|
|
mDumpStr.clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Decide to choose which Fbs and how to build OsdFbs2Plane pairs. */
|
||
|
|
int CompositionStrategyBase::decideComposition() {
|
||
|
|
int ret = 0;
|
||
|
|
if (mFramebuffers.empty()) {
|
||
|
|
MESON_LOGV("No layers to compose, exit.");
|
||
|
|
if (mClientComposer != NULL) {
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb = nullptr;
|
||
|
|
|
||
|
|
mClientComposer->prepare();
|
||
|
|
mClientComposer->setOutput(fb, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
fillDebugInfoStr();
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* handle VIDEO fbs. */
|
||
|
|
processVideoFbs();
|
||
|
|
|
||
|
|
/* handle HDR mode, hide secure layer, and force client. */
|
||
|
|
applyCompositionFlags();
|
||
|
|
/* handle graphic fbs.*/
|
||
|
|
processGfxFbs();
|
||
|
|
|
||
|
|
mDisplayPairs.sort();
|
||
|
|
|
||
|
|
handleOverlayVideoZorder();
|
||
|
|
handleDisplayLayerZorder();
|
||
|
|
|
||
|
|
fillDebugInfoStr();
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* debug info for composition strategy */
|
||
|
|
void CompositionStrategyBase::fillDebugInfoStr() {
|
||
|
|
/* replace composer output with din0 Pair. */
|
||
|
|
std::shared_ptr<DrmFramebufferBase> composerOutput;
|
||
|
|
|
||
|
|
if (mComposer.get()) {
|
||
|
|
mComposer->start();
|
||
|
|
composerOutput = mComposer->getOutput();
|
||
|
|
}
|
||
|
|
|
||
|
|
for (auto displayIt = mDisplayPairs.begin(); displayIt != mDisplayPairs.end(); ++displayIt) {
|
||
|
|
uint32_t presentZorder = displayIt->presentZorder;
|
||
|
|
std::shared_ptr<DrmFramebufferBase> fb = *(displayIt->fbs.begin());
|
||
|
|
std::shared_ptr<HwDisplayPlaneBase> plane = displayIt->plane;
|
||
|
|
int blankFlag = (mHideSecureLayer && fb->getSecureFlag()) ?
|
||
|
|
BLANK_FOR_SECURE_CONTENT : UNBLANK;
|
||
|
|
meson_composition_t compType = fb->getCompositionType();
|
||
|
|
|
||
|
|
if (composerOutput.get() &&
|
||
|
|
compType == mComposer->getType()) {
|
||
|
|
presentZorder = mMaxComposerZorder + OSD_FB_BEGIN_ZORDER;
|
||
|
|
bool bDumpPlane = true;
|
||
|
|
for (auto it = mComposerFbs.begin(); it != mComposerFbs.end(); ++it) {
|
||
|
|
if (bDumpPlane) {
|
||
|
|
dumpFbAndPlane(*it, plane, presentZorder, blankFlag);
|
||
|
|
bDumpPlane = false;
|
||
|
|
} else {
|
||
|
|
dumpComposedFb(*it);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else if (compType == MESON_COMPOSITION_DI || compType == MESON_COMPOSITION_V2D) {
|
||
|
|
bool bDumpVideoComposerBuffer = false;
|
||
|
|
for (auto it = displayIt->fbs.begin(); it != displayIt->fbs.end(); ++it) {
|
||
|
|
if (!bDumpVideoComposerBuffer) {
|
||
|
|
dumpFbAndPlane(*it, plane, presentZorder, blankFlag);
|
||
|
|
bDumpVideoComposerBuffer = true;
|
||
|
|
} else {
|
||
|
|
dumpComposedFb(*it);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
dumpFbAndPlane(fb, plane, presentZorder, blankFlag);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Blank un-used plane. */
|
||
|
|
auto planeIt = mHwcVideoPlanes.begin();
|
||
|
|
for (; planeIt != mHwcVideoPlanes.end(); ++planeIt)
|
||
|
|
mOtherPlanes.push_back(*planeIt);
|
||
|
|
|
||
|
|
planeIt = mOsdPlanes.begin();
|
||
|
|
for (; planeIt != mOsdPlanes.end(); ++planeIt)
|
||
|
|
mOtherPlanes.push_back(*planeIt);
|
||
|
|
|
||
|
|
planeIt = mOtherPlanes.begin();
|
||
|
|
for (; planeIt != mOtherPlanes.end(); ++planeIt)
|
||
|
|
dumpUnusedPlane(*planeIt, BLANK_FOR_NO_CONTENT);
|
||
|
|
}
|
||
|
|
|
||
|
|
int CompositionStrategyBase::getDisplayPair(std::list<DisplayPair> & displayPairs) {
|
||
|
|
displayPairs = mDisplayPairs;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CompositionStrategyBase::dump(std::string & dumpstr) {
|
||
|
|
char str[64] = {0};
|
||
|
|
snprintf(str, 63, "Composition (%s):(0x%x)\n", getName(), mCompositionFlag);
|
||
|
|
dumpstr.append(str);
|
||
|
|
dumpstr.append("--------------------------------------------------------------\n");
|
||
|
|
dumpstr.append("| FbZ | Comp Type | Plane | PlaneZ | BlankStat |\n");
|
||
|
|
dumpstr.append(mDumpStr);
|
||
|
|
dumpstr.append("--------------------------------------------------------------\n");
|
||
|
|
}
|