1.adb shell dumpsys SurfaceFlinger
dump時會打印出是HWC合成還是GPU合成,androidO開始HWC換成了Device伟骨,GPU換成了Client饮潦。
2.問題場景
打開 Settings -> Accessibility -> Color inversion 后冷啟動應(yīng)用會出現(xiàn)閃白屏。
在androidO上該問題是原生問題继蜡,但是在androidP上不再是原生問題逛腿。
通過dump SurfaceFlinger發(fā)現(xiàn)問題場景下為Client合成方式,而正常時為Device合成方式单默。
google原生解釋理由:
The reason is that the surface of the app has been created, but the app does not send the data that needs to be displayed to the surfaceflinger in time, and waits for a few frames before starting to update. In this case, the surfaceflinger has no valid data, and it shows black surface. If it is a reverse color(using Invert colours option), we will see a white surface twinkling.
3.分析CompositionType
1) 在prepare的時候會去設(shè)置frame data到hwc hal中,會傳入compositionType殴俱,根據(jù)下面的代碼可以看出默認是有四種方式的:Sideband、Cursor线欲、Device汽摹、SolidColor李丰。
frameworks/native/services/surfaceflinger/BufferLayer.cpp
618void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
...
641 // Sideband layers
642 if (getBE().compositionInfo.hwc.sidebandStream.get()) {
643 setCompositionType(hwcId, HWC2::Composition::Sideband);
644 ALOGV("[%s] Requesting Sideband composition", mName.string());
645 error = hwcLayer->setSidebandStream(getBE().compositionInfo.hwc.sidebandStream->handle());
646 if (error != HWC2::Error::None) {
647 ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
648 getBE().compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(),
649 static_cast<int32_t>(error));
650 }
651 return;
652 }
653
654 // Device or Cursor layers
655 if (mPotentialCursor) {
656 ALOGV("[%s] Requesting Cursor composition", mName.string());
657 setCompositionType(hwcId, HWC2::Composition::Cursor);
658 } else {
659 ALOGV("[%s] Requesting Device composition", mName.string());
660 setCompositionType(hwcId, HWC2::Composition::Device);
661 }
frameworks/native/services/surfaceflinger/ColorLayer.cpp
64void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
...
78 setCompositionType(hwcId, HWC2::Composition::SolidColor);
還有一個地方會強制設(shè)置compositionType為Client趴泌。
hwc Hal層的layer創(chuàng)建失斃嗜憔;禁用HWC氏仗;打開debugRegion;layer的一些特殊屬性等會設(shè)置compositionType為Client到hwc hal中呐舔。
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1959void SurfaceFlinger::setUpHWComposer() {
...
2003 if (!layer->hasHwcLayer(hwcId)) {
2004 if (!layer->createHwcLayer(getBE().mHwc.get(), hwcId)) {
2005 layer->forceClientComposition(hwcId);
2006 continue;
2007 }
2008 }
2009
2010 layer->setGeometry(displayDevice, i);
2011 if (mDebugDisableHWC || mDebugRegion) {
2012 layer->forceClientComposition(hwcId);
2013 }
...
2033 for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
2034 if (layer->isHdrY410()) {
2035 layer->forceClientComposition(hwcId);
2036 } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
2037 layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
2038 !displayDevice->hasHDR10Support()) {
2039 layer->forceClientComposition(hwcId);
2040 } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
2041 layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
2042 !displayDevice->hasHLGSupport()) {
2043 layer->forceClientComposition(hwcId);
2044 }
2045
2046 if (layer->getForceClientComposition(hwcId)) {
2047 ALOGV("[%s] Requesting Client composition", layer->getName().string());
2048 layer->setCompositionType(hwcId, HWC2::Composition::Client);
2049 continue;
2050 }
那么我們分析下Layer的setCompositionType珊拼,會根據(jù)callIntoHwc去決定是否將compositionType設(shè)置到hwc hal中食呻,surfaceflinger第一次會向hwc hal中設(shè)置compositionType(callIntoHwc為true)澎现,hwc hal會返回給surfaceflinger側(cè)compositionType改變的值(androidO上新增mChangeType),如果有改變的話只需要改變surfaceflinger側(cè)即可饼问,無需往hwc hal再設(shè)置compositionType(callIntoHwc為false)揭斧,這個后面會分析莱革。
frameworks/native/services/surfaceflinger/Layer.cpp
730void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc) {
731 if (getBE().mHwcLayers.count(hwcId) == 0) {
732 ALOGE("setCompositionType called without a valid HWC layer");
733 return;
734 }
735 auto& hwcInfo = getBE().mHwcLayers[hwcId];
736 auto& hwcLayer = hwcInfo.layer;
737 ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", hwcLayer->getId(), to_string(type).c_str(),
738 static_cast<int>(callIntoHwc));
739 if (hwcInfo.compositionType != type) {
740 ALOGV(" actually setting");
741 hwcInfo.compositionType = type;
742 if (callIntoHwc) {
743 auto error = hwcLayer->setCompositionType(type);
744 ALOGE_IF(error != HWC2::Error::None,
745 "[%s] Failed to set "
746 "composition type %s: %s (%d)",
747 mName.string(), to_string(type).c_str(), to_string(error).c_str(),
748 static_cast<int32_t>(error));
749 }
750 }
751}
最后盅视,分析下hwc hal返回的結(jié)果旦万。
在hwc hal層結(jié)束了prepare操作后闹击,surfaceflinger側(cè)會調(diào)用getChangedCompositionTypes得到底層更改后的compositionType成艘,hwc hal層會實現(xiàn)getChangedCompositionTypes方法,當(dāng)有改變的話changedTypes.count(hwcLayer)不為0断箫,這樣的話會向layer中重新設(shè)置compositionType秋冰,但是此時的callIntoHwc為false仲义,即不向hwc hal層中設(shè)置剑勾。
同時,HWComposer中通過DisplayDate保存compositionType暂刘,注意只有兩種:hasClientComposition洲赵、hasDeviceComposition鸳惯。
frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
406status_t HWComposer::prepare(DisplayDevice& displayDevice) {
...
456 error = hwcDisplay->validate(&numTypes, &numRequests);
463 std::unordered_map<HWC2::Layer*, HWC2::Composition> changedTypes;
464 changedTypes.reserve(numTypes);
465 error = hwcDisplay->getChangedCompositionTypes(&changedTypes);
477 for (auto& layer : displayDevice.getVisibleLayersSortedByZ()) {
478 auto hwcLayer = layer->getHwcLayer(displayId);
479
480 if (changedTypes.count(hwcLayer) != 0) {
481 // We pass false so we only update our state and don't call back
482 // into the HWC device
483 validateChange(layer->getCompositionType(displayId),
484 changedTypes[hwcLayer]);
485 layer->setCompositionType(displayId, changedTypes[hwcLayer], false);
486 }
488 switch (layer->getCompositionType(displayId)) {
489 case HWC2::Composition::Client:
490 displayData.hasClientComposition = true;
491 break;
492 case HWC2::Composition::Device:
493 case HWC2::Composition::SolidColor:
494 case HWC2::Composition::Cursor:
495 case HWC2::Composition::Sideband:
496 displayData.hasDeviceComposition = true;
497 break;
498 default:
499 break;
500 }
4.結(jié)論
有些平臺hwc可以很好的支持這種場景的合成芝发,而有些平臺不支持的話就出現(xiàn)了問題苛谷。
至于底層如何實現(xiàn)的,這里就不方便貼出來了腹殿,自行研究~