普法OpenHarmony送显流程

            普法OpenHarmony送显流程

引言

  本文档主要记录OpenHarmony在渲染完成之后如何进行合成和送显流程的。这个过程牵涉的代码很多,而且流程也是比较繁琐的。所以我一定要坚持下来。千万不能半途而废,也不要想着一口气吃出一个胖子,路漫漫其修远兮吾将上下而求索!

且在该过程分析中,会牵涉到一些类之间的逻辑关系,这里我先放出一些核心关键类之间的关系,希望能对后续的源码分析有帮助:

在这里插入图片描述

注意:本篇的介绍是基于OpenHarmony 3.2 release配合phytium D2000平台为基础的,其中飞腾芯片代码平台具体地址为Phytium嵌入式软件 / Phytium-OpenHarmony-D2000-X100,其中涉及的代码路径如下:

drivers/peripheral/display/interfaces/include/
device/soc/phytium/d2000/hardware/display/
foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/
foundation/graphic/graphic_2d/rosen/modules/composer/vsync/src/
foundation/graphic/graphic_2d/frameworks/bootanimation/
foundation/graphic/graphic_2d/rosen/modules/composer/hdi_backend/src/
├── hdi_backend.cpp
├── hdi_device.cpp
├── hdi_framebuffer_surface.cpp
├── hdi_layer.cpp
├── hdi_output.cpp
└── hdi_screen.cpp

同时这块,强烈推荐OpenHarmony图形大佬亲自出马整理的开源图形驱动在OpenHarmony上的使用和落地,非常推荐对OpenHarmony图形栈感兴趣的童靴观摩!




一. 应用端发送NextVSnc请求,服务端响应

  还记得那年大明湖畔的夏雨荷吗!错了,还记得前面我们在分析OpenHarmony的buffer管理的时候,当bootamition渲染完成之后会调用flush将buffer的使用权还给render_server吗,不记得也没有关系,我们重新来看下!

RSRenderServiceListener::OnBufferAvailable(...)
		RSMainThread::Instance()->RequestNextVSync(...)//触发下次vsync
//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_main_thread.cpp
void RSMainThread::RequestNextVSync()
{
    RS_TRACE_FUNC();
    VSyncReceiver::FrameCallback fcb = {
        .userData_ = this,
        .callback_ = [this](uint64_t timestamp, void* data) { OnVsync(timestamp, data); },//回调函数
    };
    if (receiver_ != nullptr) {
        requestNextVsyncNum_++;
        if (requestNextVsyncNum_ > RUQUEST_VSYNC_NUMBER_LIMIT) {
            RS_LOGW("RSMainThread::RequestNextVSync too many times:%d", requestNextVsyncNum_);
        }
        receiver_->RequestNextVSync(fcb);//这里我们重点分析下receiver_,详见章节1.1
    }
}

void RSMainThread::OnVsync(uint64_t timestamp, void* data)
{
    ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "RSMainThread::OnVsync");
    timestamp_ = timestamp;
    requestNextVsyncNum_ = 0;
    if (isUniRender_) {
        MergeToEffectiveTransactionDataMap(cachedTransactionDataMap_);
        RSUnmarshalThread::Instance().PostTask(unmarshalBarrierTask_);
    }
    mainLoop_();
    if (handler_) {
        auto screenManager_ = CreateOrGetScreenManager();
        if (screenManager_ != nullptr) {
            PostTask([=]() { screenManager_->ProcessScreenHotPlugEvents(); });
        }
    }
    ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
}

1.1 VSyncReceiver初始化

代码分析,无需多言。直接干就完了,上代码直接开撸!

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_main_thread.cpp
void RSMainThread::Init()
{
	...
	//这套就是模仿Android做的,通过LocalSocketPair
	handler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
    	sptr<VSyncConnection> conn = new VSyncConnection(rsVSyncDistributor_, "rs");
    	rsVSyncDistributor_->AddConnection(conn);
    	receiver_ = std::make_shared<VSyncReceiver>(conn, handler_);
    	receiver_->Init();
	...

}

1.2 RequestNextVSync

//foundation/graphic/graphic_2d/rosen/modules/composer/vsync/src/vsync_receiver.cpp
VsyncError VSyncReceiver::RequestNextVSync(FrameCallback callback)
{
    std::lock_guard<std::mutex> locker(initMutex_);
    if (!init_) {
        return VSYNC_ERROR_API_FAILED;
    }
    listener_->SetCallback(callback);
    ScopedBytrace func("VSyncReceiver::RequestNextVSync_pid:" + std::to_string(GetRealPid()) + "_name:" + name_);
    return connection_->RequestNextVSync();
}

1.3 VSyncConnection::RequestNextVSync

//foundation/graphic/graphic_2d/rosen/modules/composer/vsync/src/vsync_distributor.cpp
VsyncError VSyncConnection::RequestNextVSync()
{
    ...
    return distributor->RequestNextVSync(this);
}

VsyncError VSyncDistributor::RequestNextVSync(const sptr<VSyncConnection>& connection)
{
    ...
    if (connection->rate_ < 0) {
        ...
        //此时会唤醒VSyncDistributor线程
        con_.notify_all();//notify all tasks
        ...
    }
    ...
}


void VSyncDistributor::ThreadMain()
{
    ...
    while (vsyncThreadRunning_ == true) {
        for (uint32_t i = 0; i < conns.size(); i++) {
            int32_t ret = conns[i]->PostEvent(timestamp);
        }
        ...
    }

}


int32_t VSyncConnection::PostEvent(int64_t now)
{
    //这个地方发给谁接收了,得找找找
    int32_t ret = socketPair_->SendData(&now, sizeof(int64_t));

}

//上面分析感觉没有和底层的vsync对接上,吗

1.4 遗留问题

这里有一个遗留问题就是vsync间隔时间是怎么计算出来的,这里我没有找到是怎么和底层的vblack关联起来的,还有它走的是soft vsync还是硬的。它的计算规则是怎样的!




二. 应用端响应VSync事件

这里还是以bootamition举例,其它的应用流程也基本相似(主要是我对其它的应用也不是很熟悉,所以只能重复的以bootamition举例来说明了.)

//foundation/graphic/graphic_2d/frameworks/bootanimation/src/boot_animation.cpp
std::shared_ptr<OHOS::Rosen::VSyncReceiver> receiver_ = nullptr;
void BootAnimation::Init(int32_t width, int32_t height)
{
	...
    auto& rsClient = OHOS::Rosen::RSInterfaces::GetInstance();
        /**
        	RSInterfaces &RSInterfaces::GetInstance()
        	{
            		static RSInterfaces instance;
            		return instance;
        	}
        
        	RSInterfaces::RSInterfaces() : renderServiceClient_(std::make_unique<RSRenderServiceClient>())
        	{
        	}
        **/
    while (receiver_ == nullptr) {
        receiver_ = rsClient.CreateVSyncReceiver("BootAnimation", mainHandler_);//这里获取的是代理端

    	/**
         * 
            std::shared_ptr<VSyncReceiver> RSInterfaces::CreateVSyncReceiver(
                const std::string& name,
                const std::shared_ptr<OHOS::AppExecFwk::EventHandler> &looper)
            {
                return renderServiceClient_->CreateVSyncReceiver(name, looper);
            }
            std::shared_ptr<VSyncReceiver> RSRenderServiceClient::CreateVSyncReceiver(
                const std::string& name,
                const std::shared_ptr<OHOS::AppExecFwk::EventHandler> &looper)
            {
                auto renderService = RSRenderServiceConnectHub::GetRenderService();
                if (renderService == nullptr) {
                    return nullptr;
                }
                sptr<IVSyncConnection> conn = renderService->CreateVSyncConnection(name);
                return std::make_shared<VSyncReceiver>(conn, looper, name);
            }
    	***/
    }
    VsyncError ret = receiver_->Init();


    OHOS::Rosen::VSyncReceiver::FrameCallback fcb = {
        .userData_ = this,
        .callback_ = std::bind(&BootAnimation::OnVsync, this),
    };
    int32_t changefreq = static_cast<int32_t>((1000.0 / freq_) / 16);
    ret = receiver_->SetVSyncRate(fcb, changefreq);

	...
}

  • 应用端接收和响应vsync事件,主要用于自身的绘制和渲染工作。当然也可以不干任何事情,仅仅接收。这个取决于业务逻辑,这块不是我们重点讨论的内容!



三. render_service响应VSync事件

这里注意,是render_service响应VSync事件,不是NextVsync。理解清楚了上述点,下面我们来接着分析!

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_main_thread.cpp
void RSMainThread::OnVsync(uint64_t timestamp, void* data)
{
    ...
    mainLoop_();//详见章节3.1
    if (handler_) {
        auto screenManager_ = CreateOrGetScreenManager();
        if (screenManager_ != nullptr) {
            PostTask([=]() { screenManager_->ProcessScreenHotPlugEvents(); });//这个地方后续详细分析
        }
    }
    ...
}

3.1 mainLoop_流程分析

C++的语法经常会有一些牛鬼蛇神的用法,所以我们要报着见怪不怪的心态,开搞就好!

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_main_thread.cpp
  mainLoop_ = [&]() {
        RS_LOGD("RsDebug mainLoop start");
        PerfMultiWindow();
        RenderFrameTrace::GetInstance().RenderStartFrameTrace(RS_INTERVAL_NAME);
        SetRSEventDetectorLoopStartTag();
        ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "RSMainThread::DoComposition");
        ConsumeAndUpdateAllNodes();//详见章节3.2
        WaitUntilUnmarshallingTaskFinished();
        ProcessCommand();
        Animate(timestamp_);
        CheckColdStartMap();
        CheckDelayedSwitchTask();
        Render();//详见章节3.3
        ReleaseAllNodesBuffer();
        SendCommands();
        ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
        SetRSEventDetectorLoopFinishTag();
        rsEventManager_.UpdateParam();
        RS_LOGD("RsDebug mainLoop end");
    };

//在最最开始会创建DisplayRenderNode,然后添加到RootNode里面去,注意只会添加一次
01-01 08:00:14.535   670  1395 E C01400/OHOS::ROSEN: RSDisplayNode::Create, id:2877628088321
01-01 08:00:14.662   670  1395 E C01400/OHOS::ROSEN: RSDisplayNode::Create Tid:1395 comm:EventRunner#1
01-01 08:00:14.662   670  1395 E C01400/OHOS::ROSEN: #00 pc 0000000000018ff4 /system/lib64/lib_dfx_dump_catcher.z.so(OHOS::HiviewDFX::DfxDumpCatcher::DumpCatch(int, int, std::__h::basic_string<char, std::__h::char_traits<char>, std::__h::allocator<char> >&)+152)
01-01 08:00:14.662   670  1395 E C01400/OHOS::ROSEN: #01 pc 00000000000887f0 /system/lib64/librender_service_client.z.so(OHOS::Rosen::RSDisplayNode::Create(OHOS::Rosen::RSDisplayNodeConfig const&)+600)
01-01 08:00:14.662   670  1395 E C01400/OHOS::ROSEN: #02 pc 000000000003bae4 /system/lib64/libdms.z.so(OHOS::Rosen::AbstractScreen::InitRSDisplayNode(OHOS::Rosen::RSDisplayNodeConfig&, OHOS::Rosen::Point&)+88)
01-01 08:00:14.662   670  1395 E C01400/OHOS::ROSEN: #03 pc 000000000003d3dc /system/lib64/libdms.z.so(OHOS::Rosen::AbstractScreenGroup::AddChild(OHOS::sptr<OHOS::Rosen::AbstractScreen>&, OHOS::Rosen::Point&)+172)
01-01 08:00:14.662   670  1395 E C01400/OHOS::ROSEN: #04 pc 0000000000044ea4 /system/lib64/libdms.z.so(OHOS::Rosen::AbstractScreenController::AddAsFirstScreenLocked(OHOS::sptr<OHOS::Rosen::AbstractScreen>)+832)
01-01 08:00:14.662   670  1395 E C01400/OHOS::ROSEN: #05 pc 0000000000043088 /system/lib64/libdms.z.so(OHOS::Rosen::AbstractScreenController::AddToGroupLocked(OHOS::sptr<OHOS::Rosen::Abstract


01-01 08:00:14.554   690   690 E C01400/OHOS::RS: RSDisplayRenderNode create Tid:690 comm:render_service
01-01 08:00:14.554   690   690 E C01400/OHOS::RS: #00 pc 0000000000018ff4 /system/lib64/lib_dfx_dump_catcher.z.so(OHOS::HiviewDFX::DfxDumpCatcher::DumpCatch(int, int, std::__h::basic_string<char, std::__h::char_traits<char>, std::__h::allocator<char> >&)+152)
01-01 08:00:14.554   690   690 E C01400/OHOS::RS: #01 pc 00000000000d5b84 /system/lib64/librender_service_base.z.so(OHOS::Rosen::RSDisplayRenderNode::RSDisplayRenderNode(unsigned long, OHOS::Rosen::RSDisplayNodeConfig const&, std::__h::weak_ptr<OHOS::Rosen::RSContext>)+384)
01-01 08:00:14.554   690   690 E C01400/OHOS::RS: #02 pc 00000000000bd7c4 /system/lib64/librender_service_base.z.so
01-01 08:00:14.554   690   690 E C01400/OHOS::RS: #03 pc 00000000000bcf24 /system/lib64/librender_service_base.z.so(OHOS::Rosen::DisplayNodeCommandHelper::Create(OHOS::Rosen::RSContext&, unsigned long, OHOS::Rosen::RSDisplayNodeConfig const&)+108)
01-01 08:00:14.554   690   690 E C01400/OHOS::RS: #04 pc 000000000006dcd8 /system/lib64/librender_service.z.so(OHOS::Rosen::RSMainThread::ProcessCommandForDividedRender()+1796)
01-01 08:00:14.554   690   690 E C01400/OHOS::RS: #05 pc 0000000000074398 /system/lib64/librender_service.z.so
01-01 08:00:14.554   690   690 E C01400/OHOS::RS: #06 pc 000000000007187c /system/lib64/librender_service.z.so(OHOS::Rosen::RSMainT



3.2 ConsumeAndUpdateAllNodes

这个函数是一个好名字,让人一看就知道是干啥的了。我们直接撸代码,开始撸代码!

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_main_thread.cpp
void RSMainThread::ConsumeAndUpdateAllNodes()
{

    bool needRequestNextVsync = false;
    const auto& nodeMap = GetContext().GetNodeMap();
    nodeMap.TraverseSurfaceNodes(//遍历渲染完成的nodemap,此处是一个lamda表达式
        [this, &needRequestNextVsync](const std::shared_ptr<RSSurfaceRenderNode>& surfaceNode) mutable {

        auto& surfaceHandler = static_cast<RSSurfaceHandler&>(*surfaceNode);
        surfaceHandler.ResetCurrentFrameBufferConsumed();
        if (RSBaseRenderUtil::ConsumeAndUpdateBuffer(surfaceHandler)) {
            this->bufferTimestamps_[surfaceNode->GetId()] = static_cast<uint64_t>(surfaceNode->GetTimestamp());
        }

        // still have buffer(s) to consume.
        if (surfaceHandler.GetAvailableBufferCount() > 0) {
            needRequestNextVsync = true;
        }
    });

    if (needRequestNextVsync) {
        RequestNextVSync();
    }
}


//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_base_render_util.cpp
bool RSBaseRenderUtil::ConsumeAndUpdateBuffer(RSSurfaceHandler& surfaceHandler)
{
    auto availableBufferCnt = surfaceHandler.GetAvailableBufferCount();
    if (availableBufferCnt <= 0) {
        // this node has no new buffer, try use old buffer.
        return true;
    }
    auto& consumer = surfaceHandler.GetConsumer();
    if (consumer == nullptr) {
        return false;
    }

    DropFrameProcess(surfaceHandler);
    sptr<SurfaceBuffer> buffer;
    sptr<SyncFence> acquireFence = SyncFence::INVALID_FENCE;
    int64_t timestamp = 0;
    Rect damage;
    auto ret = consumer->AcquireBuffer(buffer, acquireFence, timestamp, damage);
    if (buffer == nullptr || ret != SURFACE_ERROR_OK) {
        RS_LOGE("RsDebug surfaceHandler(id: %" PRIu64 ") AcquireBuffer failed(ret: %d)!",
            surfaceHandler.GetNodeId(), ret);
        return false;
    }

    surfaceHandler.SetBuffer(buffer, acquireFence, damage, timestamp);
    surfaceHandler.SetCurrentFrameBufferConsumed();
    RS_LOGD("RsDebug surfaceHandler(id: %" PRIu64 ") AcquireBuffer success, timestamp = %" PRId64 ".",
        surfaceHandler.GetNodeId(), timestamp);
    availableBufferCnt = surfaceHandler.ReduceAvailableBuffer();
    return true;
}

上述代码的核心,可以归纳总结为如下两点:

  • 遍历所有的surfacenode,然后通过AcquireBuffer获取渲染完成的buffer
  • 判断surfacenode,是否还有需要消费的buffer,如果还有则继续调用RequestNextVSync,请求下一次VSync事件

3.3 Render

继续开撸,感觉还是一眼望不到头啊。莫停下来,继续开搞!

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_main_thread.cpp
void RSMainThread::Render()
{
    const std::shared_ptr<RSBaseRenderNode> rootNode = context_->GetGlobalRootRenderNode();
    if (rootNode == nullptr) {
        RS_LOGE("RSMainThread::Render GetGlobalRootRenderNode fail");
        return;
    }
    if (RSSystemProperties::GetRenderNodeTraceEnabled()) {
        RSPropertyTrace::GetInstance().RefreshNodeTraceInfo();
    }
    RS_LOGD("RSMainThread::Render isUni:%d", IfUseUniVisitor());

    if (IfUseUniVisitor()) {

    } else {
        auto rsVisitor = std::make_shared<RSRenderServiceVisitor>();
        rsVisitor->SetAnimateState(doWindowAnimate_);
        rootNode->Prepare(rsVisitor);
        CalcOcclusion();

        bool doParallelComposition = false;
        if (!rsVisitor->ShouldForceSerial() && RSInnovation::GetParallelCompositionEnabled()) {
            doParallelComposition = DoParallelComposition(rootNode);
        }
        if (doParallelComposition) {
            renderEngine_->ShrinkCachesIfNeeded();
            return;
        }
        rootNode->Process(rsVisitor);
    }

    renderEngine_->ShrinkCachesIfNeeded();
    PerfForBlurIfNeeded();
}

/**
继续跟踪rootNode->Process(rsVisitor);
这里的rootNode为std::shared_ptr<RSBaseRenderNode> globalRootRenderNode_ = std::make_shared<RSBaseRenderNode>(0, true);
rsVisitor为auto rsVisitor = std::make_shared<RSRenderServiceVisitor>(),我们接着往下看
**/


RSBaseRenderNode::Process(...)
	visitor->ProcessBaseRenderNode(...)//rs_render_service_vistor.cpp
		for (auto& child : node.GetSortedChildren()) {
        		child->Process(shared_from_this());//这个地方是核心
    		}
			visitor->ProcessSurfaceRenderNode(*this);


void RSRenderServiceVisitor::ProcessSurfaceRenderNode(RSSurfaceRenderNode& node)
{
    if (!processor_) {
        RS_LOGE("RSRenderServiceVisitor::ProcessSurfaceRenderNode processor is nullptr");
        return;
    }
    if (isSecurityDisplay_ && node.GetSecurityLayer()) {
        RS_LOGI("RSRenderServiceVisitor::ProcessSurfaceRenderNode node[%" PRIu64 "] process paused because of \
            security DisplayNode.",
            node.GetId());
        return;
    }
    if (!node.ShouldPaint()) {
        RS_LOGD("RSRenderServiceVisitor::ProcessSurfaceRenderNode node : %" PRIu64 " is invisible", node.GetId());
        return;
    }
    if (!node.GetOcclusionVisible() && !doAnimate_ && RSSystemProperties::GetOcclusionEnabled()) {
        return;
    }
    if (mParallelEnable) {
        node.ParallelVisitLock();
    }
    ProcessBaseRenderNode(node);
    node.SetGlobalZOrder(globalZOrder_);
    globalZOrder_ = globalZOrder_ + 1;
    processor_->ProcessSurface(node);//核心点,在于这个函数processor_是怎么被初始化的
    RSBaseRenderUtil::WriteSurfaceRenderNodeToPng(node);//这是一个调试手段,将buffer保存成png
    if (mParallelEnable) {
        node.ParallelVisitUnlock();
    }
}
  • 这一块的逻辑主要是将前端gralloc 生成buffer,转换成为后端hdi layer,供hdi output石永红

3.4 RSProcessor processor_的创建

为了追溯这个问题,我倒腾了很久才搞明白创建的流程!首先foundatio进程会创建display_render_node,然后将其添加到root_node里面去,当root_node在进行process处理的时候,就会调用到display_render_node中的RSDisplayRenderNode::Prepare和RSDisplayRenderNode::Process,最后会调用到RSRenderServiceVisitor::ProcessDisplayRenderNode,我们对此展开分析!

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_render_service_visitor.cpp
void RSRenderServiceVisitor::ProcessDisplayRenderNode(RSDisplayRenderNode& node)
{
    //这里从打印,以及调试情况来看RSDisplayRenderNode只有一个,每次的id都木有变化
    isSecurityDisplay_ = node.GetSecurityDisplay();
    RS_LOGD("RsDebug RSRenderServiceVisitor::ProcessDisplayRenderNode: nodeid:[%" PRIu64 "] screenid:[%" PRIu64 "] \
        isSecurityDisplay:[%s] child size:[%d] total size:[%d]",
        node.GetId(), node.GetScreenId(), isSecurityDisplay_ ? "true" : "false", node.GetChildrenCount(),
        node.GetSortedChildren().size());
    globalZOrder_ = 0.0f;
    sptr<RSScreenManager> screenManager = CreateOrGetScreenManager();
    if (!screenManager) {
        RS_LOGE("RSRenderServiceVisitor::ProcessDisplayRenderNode ScreenManager is nullptr");
        return;
    }
    ScreenInfo curScreenInfo = screenManager->QueryScreenInfo(node.GetScreenId());
    RS_TRACE_NAME("ProcessDisplayRenderNode[" + std::to_string(node.GetScreenId()) + "]");
    // skip frame according to skipFrameInterval value of SetScreenSkipFrameInterval interface
    if (node.SkipFrame(curScreenInfo.skipFrameInterval)) {
        return;
    }
    //此时创建的是RSPhysicalScreenProcessor
    processor_ = RSProcessorFactory::CreateProcessor(node.GetCompositeType());
    if (processor_ == nullptr) {
        RS_LOGE("RSRenderServiceVisitor::ProcessDisplayRenderNode: RSProcessor is null!");
        return;
    }
    auto mirrorNode = node.GetMirrorSource().lock();
    //详见章节3.4.1
    if (!processor_->Init(node, node.GetDisplayOffsetX(), node.GetDisplayOffsetY(),
        mirrorNode ? mirrorNode->GetScreenId() : INVALID_SCREEN_ID)) {
        RS_LOGE("RSRenderServiceVisitor::ProcessDisplayRenderNode: processor init failed!");
        return;
    }

    if (node.IsMirrorDisplay()) {
	...
    } else {
        ProcessBaseRenderNode(node);
    }
    processor_->PostProcess();//详见3.4.2
}
3.4.1 RSPhysicalScreenProcessor::Init

分析源码,就是烦啊!只能fuck you!我草草!

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_physical_screen_processor.cpp
bool RSPhysicalScreenProcessor::Init(RSDisplayRenderNode& node, int32_t offsetX, int32_t offsetY, ScreenId mirroredId)
{
    if (!RSProcessor::Init(node, offsetX, offsetY, mirroredId)) {
        return false;
    }

    if (mirroredId != INVALID_SCREEN_ID) {
        SetMirrorScreenSwap(node);
    }

    //注意这个地方的回调Redraw很重要,当进行GPU合成的时候,会调用该回调,并且应用到屏幕上面
    return composerAdapter_->Init(screenInfo_, offsetX, offsetY, mirrorAdaptiveCoefficient_,
        [this](const auto& surface, const auto& layers) { Redraw(surface, layers); });
}

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_composer_adapter.cpp
bool RSComposerAdapter::Init(const ScreenInfo& screenInfo, int32_t offsetX, int32_t offsetY,
    float mirrorAdaptiveCoefficient, const FallbackCallback& cb)
{
    hdiBackend_ = HdiBackend::GetInstance();
    if (hdiBackend_ == nullptr) {
        RS_LOGE("RSComposerAdapter::Init: hdiBackend is nullptr");
        return false;
    }
    auto screenManager = CreateOrGetScreenManager();
    if (screenManager == nullptr) {
        RS_LOGE("RSComposerAdapter::Init: ScreenManager is nullptr");
        return false;
    }
    //获取一个output,这个地方得又牵涉到output怎么来的了
    //screenManager_最开始的初始化是在RsRenderService里面
    //这里的output表示输出设备
    output_ = screenManager->GetOutput(ToScreenPhysicalId(screenInfo.id));
    /**
    bool RSScreenManager::Init() noexcept
    {
        //这个地方又牵涉到HdiBackend这个类的实现它的调用逻辑如下:
        // HdiBackend ---> HdiDevice 
        composer_ = HdiBackend::GetInstance();
        if (composer_ == nullptr) {
            RS_LOGE("RSScreenManager %s: Failed to get composer.", __func__);
            return false;
        }
        //它的调用逻辑如下:
        //  HdiBackend::RegScreenHotplug
        //  HdiBackend::InitDevice
        //device_->RegHotPlugCallback(HdiBackend::OnHdiBackendHotPlugEvent, this);
        // 其中HdiDevice.RegHotPlugCallback
            // deviceFuncs_->RegHotPlugCallback
                //HdiSession::GetInstance().RegHotPlugCallback(callback, data);
                  // 主要是drm中的connector
        //这里的compser搞了忽悠人的名字,其实它是HdiBackend
        if (composer_->RegScreenHotplug(&RSScreenManager::OnHotPlug, this) == -1) {
            RS_LOGE("RSScreenManager %s: Failed to register OnHotPlug Func to composer.", __func__);
            return false;
        }

        // call ProcessScreenHotPlugEvents() for primary screen immediately in main thread.
        ProcessScreenHotPlugEvents();

        return true;
    }

    //foundation/graphic/graphic_2d/rosen/modules/composer/hdi_backend/src/hdi_backend.cpp
    RosenError HdiBackend::InitDevice()
    {
        if (device_ != nullptr) {
            return ROSEN_ERROR_OK;
        }

        device_ = HdiDevice::GetInstance();
        if (device_ == nullptr) {
            HLOGE("Get HdiDevice failed");
            return ROSEN_ERROR_NOT_INIT;
        }

        int32_t ret = device_->RegHotPlugCallback(HdiBackend::OnHdiBackendHotPlugEvent, this);
        if (ret != DISPLAY_SUCCESS) {
            HLOGE("RegHotPlugCallback failed, ret is %{public}d", ret);
            return ROSEN_ERROR_API_FAILED;
        }

        HLOGI("Init device succeed");

        return ROSEN_ERROR_OK;
    }

    RosenError HdiBackend::RegScreenHotplug(OnScreenHotplugFunc func, void* data)
    {
        if (func == nullptr) {
            HLOGE("OnScreenHotplugFunc is null");
            return ROSEN_ERROR_INVALID_ARGUMENTS;
        }

        onScreenHotplugCb_ = func;
        onHotPlugCbData_ = data;

        return InitDevice();
    }

    RosenError HdiBackend::InitDevice()
    {
        if (device_ != nullptr) {
            return ROSEN_ERROR_OK;
        }

        device_ = HdiDevice::GetInstance();
        if (device_ == nullptr) {
            HLOGE("Get HdiDevice failed");
            return ROSEN_ERROR_NOT_INIT;
        }

        int32_t ret = device_->RegHotPlugCallback(HdiBackend::OnHdiBackendHotPlugEvent, this);
        if (ret != DISPLAY_SUCCESS) {
            HLOGE("RegHotPlugCallback failed, ret is %{public}d", ret);
            return ROSEN_ERROR_API_FAILED;
        }

        HLOGI("Init device succeed");

        return ROSEN_ERROR_OK;
    }

    void HdiBackend::OnHdiBackendHotPlugEvent(uint32_t screenId, bool connected, void *data)
    {
        HLOGI("HotPlugEvent, screenId is %{public}u, connected is %{public}u", screenId, connected);
        HdiBackend *hdiBackend = nullptr;
        if (data != nullptr) {
            hdiBackend = static_cast<HdiBackend *>(data);
        } else {
            hdiBackend = HdiBackend::GetInstance();
        }

        hdiBackend->OnHdiBackendConnected(screenId, connected);
    }

    void HdiBackend::OnHdiBackendConnected(uint32_t screenId, bool connected)
    {
        if (connected) {
            CreateHdiOutput(screenId);
        }

        OnScreenHotplug(screenId, connected);
    }

    void HdiBackend::CreateHdiOutput(uint32_t screenId)
    {
        OutputPtr newOutput = HdiOutput::CreateHdiOutput(screenId);
        newOutput->Init();
        outputs_.emplace(screenId, newOutput);
    }

    //foundation/graphic/graphic_2d/rosen/modules/composer/hdi_backend/src/hdi_output.cpp
    std::shared_ptr<HdiOutput> RSScreenManager::GetOutput(ScreenId id) const
    {
        std::lock_guard<std::mutex> lock(mutex_);

        // assert screens_.count(id) == 1
        if (screens_.count(id) == 0) {
            RS_LOGW("RSScreenManager::GetOutput: There is no screen for id %" PRIu64 ".", id);
            return nullptr;
        }
        //其中screens_调用逻辑老复杂了,通过层层回调
        /** HdiBackend::OnHdiBackendHotPlugEvent
         *   HdiBackend::OnHdiBackendConnectedHdiBackend::OnHdiBackendConnected
         *    HdiBackend::CreateHdiOutput
         *       OutputPtr newOutput = HdiOutput::CreateHdiOutput(screenId);
         *       newOutput->Init();
         *       outputs_.emplace(screenId, newOutput);
         *    HdiBackend::OnScreenHotplug  OnScreenHidlConnected(screenId, connected);
         *       onScreenHotplugCb_(...)
         *          RSScreenManager::OnHotPlug(...)
         *            screenManager->OnHotPlugEvent(output, connected)
         *               pendingHotPlugEvents_.emplace_back(ScreenHotPlugEvent{output, connected});
         *               mainThread->RequestNextVSync();//此处会调用ProcessScreenHotPlugEvents()
         *                 RSScreenManager::ProcessScreenHotPlugEvents(...)
         *                   RSScreenManager::ProcessScreenConnectedLocked(...)
         *                     screens_[id] = std::make_unique<RSScreen>(id, isVirtual, output, nullptr);
         ** /
        return screens_.at(id)->GetOutput();
    }
    **/
    if (output_ == nullptr) {
        RS_LOGE("RSComposerAdapter::Init: output_ is nullptr");
        return false;
    }

    fallbackCb_ = cb;
    auto onPrepareCompleteFunc = [this](auto& surface, const auto& param, void* data) {
        OnPrepareComplete(surface, param, data);
    };
    hdiBackend_->RegPrepareComplete(onPrepareCompleteFunc, this);

    offsetX_ = offsetX;
    offsetY_ = offsetY;
    mirrorAdaptiveCoefficient_ = mirrorAdaptiveCoefficient;
    screenInfo_ = screenInfo;

    IRect damageRect {0, 0, static_cast<int32_t>(screenInfo_.width), static_cast<int32_t>(screenInfo_.height)};
    output_->SetOutputDamage(1, damageRect);
    bool directClientCompEnableStatus = RSSystemProperties::GetDirectClientCompEnableStatus();
    output_->SetDirectClientCompEnableStatus(directClientCompEnableStatus);

#if (defined RS_ENABLE_GL) && (defined RS_ENABLE_EGLIMAGE)
    // enable direct GPU composition.
    output_->SetLayerCompCapacity(LAYER_COMPOSITION_CAPACITY);
#else // (defined RS_ENABLE_GL) && (defined RS_ENABLE_EGLIMAGE)
    output_->SetLayerCompCapacity(LAYER_COMPOSITION_CAPACITY_INVALID);
#endif // (defined RS_ENABLE_GL) && (defined RS_ENABLE_EGLIMAGE)

    return true;
}

3.4.2 RSPhysicalScreenProcessor::PostProcess

跟踪代码,有点搞谍报工作似的。稍微一不留声,代码就不知道溜到那里去了!

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_physical_screen_processor.cpp
void RSPhysicalScreenProcessor::PostProcess()
{
    //这里的核心是这些layers_是怎么来的,当然是RSSurfaceRenderNode
    composerAdapter_->CommitLayers(layers_);//详见章节3.5
    MultiLayersPerf(layers_.size());
}


void RSPhysicalScreenProcessor::ProcessSurface(RSSurfaceRenderNode &node)
{
    auto layer = composerAdapter_->CreateLayer(node);
    if (layer == nullptr) {
        RS_LOGD(
            "RSPhysicalScreenProcessor::ProcessSurface: failed to createLayer for node(id: %" PRIu64 ")", node.GetId());
        return;
    }

    layers_.emplace_back(layer);
}

3.5 RSComposerAdapter::CommitLayers

历经磨难,我们来到了这里。但是取经的道路还远没有结束,战斗还在继续,药不能听,让我们继续手撕代码!

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_composer_adapter.cpp
void RSComposerAdapter::CommitLayers(const std::vector<LayerInfoPtr>& layers)
{
    // do composition.
    //layers里面只有surfacenode,没有displaynode
    //它接着会调用CreateLayer()
    output_->SetLayerInfo(layers);
    std::vector<std::shared_ptr<HdiOutput>> outputs {output_};
    hdiBackend_->Repaint(outputs);//详见章节3.7
}

//foundation/graphic/graphic_2d/rosen/modules/composer/hdi_backend/src/hdi_output.cpp
int32_t HdiOutput::CreateLayer(uint64_t surfaceId, const LayerInfoPtr &layerInfo)
{
    LayerPtr layer = HdiLayer::CreateHdiLayer(screenId_);
    /**
     * HdiLayer::Init
     *  CreateLayer   //hdi_output.cpp
     *   InitDevice()
     *     device_->CreateLayer //hdi_device.cpp
     *      HdiSession::GetInstance().CallDisplayFunction(devId, &HdiDisplay::CreateLayer, layerInfo, layerId);//hdi_session.cpp
     *       HdiDisplay::CreateLayer//hdi_display.cpp
     *    
     **/
    if (!layer->Init(layerInfo)) {
        HLOGE("Init hdiLayer failed");
        return DISPLAY_FAILURE;
    }

    layer->UpdateLayerInfo(layerInfo);
    uint32_t layerId = layer->GetLayerId();
    layerIdMap_[layerId] = layer;
    surfaceIdMap_[surfaceId] = layer;

    return DISPLAY_SUCCESS;
}

void HdiOutput::SetLayerInfo(const std::vector<LayerInfoPtr> &layerInfos)
{
    for (auto &layerInfo : layerInfos) {
        if (layerInfo == nullptr || layerInfo->GetSurface() == nullptr) {
            HLOGE("current layerInfo or layerInfo's cSurface is null");
            continue;
        }
        uint64_t surfaceId = layerInfo->GetSurface()->GetUniqueId();
        auto iter = surfaceIdMap_.find(surfaceId);
        if (iter != surfaceIdMap_.end()) {
            const LayerPtr &layer = iter->second;
            const LayerInfoPtr &info = layer->GetLayerInfo();
            if (info->GetLayerSize().w == layerInfo->GetLayerSize().w &&
                info->GetLayerSize().h == layerInfo->GetLayerSize().h)
            {
                layer->UpdateLayerInfo(layerInfo);
                continue;
            }
        }

        int32_t ret = CreateLayer(surfaceId, layerInfo);
        if (ret != DISPLAY_SUCCESS) {
            return;
        }
    }

    DeletePrevLayers();
    ResetLayerStatus();
}



3.6 HdiDevice的初始化

本来后续分析的好好的,尼玛但是发现这个地方还是跳不过。还是得回来把这个地方分析明白了,后续才好继续分析。尼玛!

//打印的关于该初始化的相关逻辑
01-01 08:00:10.908   782   782 E C01400/Composer: Init: HdiDevice::Init Tid:782 comm:render_service
01-01 08:00:10.908   782   782 E C01400/Composer: #00 pc 0000000000018ff4 /system/lib64/lib_dfx_dump_catcher.z.so(OHOS::HiviewDFX::DfxDumpCatcher::DumpCatch(int, int, std::__h::basic_string<char, std::__h::char_traits<char>, std::__h::allocator<char> >&)+152)
01-01 08:00:10.908   782   782 E C01400/Composer: #01 pc 0000000000017fd8 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiDevice::Init()+100)
01-01 08:00:10.908   782   782 E C01400/Composer: #02 pc 0000000000017eb4 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiDevice::GetInstance()+72)
01-01 08:00:10.908   782   782 E C01400/Composer: #03 pc 0000000000013b64 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiBackend::RegScreenHotplug(std::__h::function<void (std::__h::shared_ptr<OHOS::Rosen::HdiOutput>&, bool, void*)>, void*)+268)
01-01 08:00:10.908   782   782 E C01400/Composer: #04 pc 00000000000ce50c /system/lib64/librender_service.z.so(OHOS::Rosen::impl::RSScreenManager::Init()+88)
01-01 08:00:10.908   782   782 E C01400/Composer: #05 pc 000000000008a6f8 /system/lib64/librender_service.z.so(OHOS::Rosen::RSRenderService::Init()+92)
01-01 08:00:10.908   782   782 E C01400/Composer: #06 pc 0000000000006f28 /system/bin/render_service
01-01 08:00:10.908   782   782 E C01400/Composer: #07 pc 00000000000da6f4 /system/lib/ld-musl-aarch64.so.1
01-01 08:00:11.002   782   782 I C01400/Composer: OnHdiBackendHotPlugEvent: HotPlugEvent, screenId is 2, connected is 1
01-01 08:00:11.004   782   782 I C01400/Composer: InitDevice: Init device succeed
01-01 08:00:11.004   782   782 I C01400/Composer: HdiScreen: Create screen, screenId is 2
01-01 08:00:11.026   782   782 E C01400/Composer: Init: HdiDevice::Init Tid:782 comm:render_service
01-01 08:00:11.026   782   782 E C01400/Composer: #00 pc 0000000000018ff4 /system/lib64/lib_dfx_dump_catcher.z.so(OHOS::HiviewDFX::DfxDumpCatcher::DumpCatch(int, int, std::__h::basic_string<char, std::__h::char_traits<char>, std::__h::allocator<char> >&)+152)
01-01 08:00:11.026   782   782 E C01400/Composer: #01 pc 0000000000017fd8 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiDevice::Init()+100)
01-01 08:00:11.026   782   782 E C01400/Composer: #02 pc 0000000000017eb4 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiDevice::GetInstance()+72)
01-01 08:00:11.026   782   782 E C01400/Composer: #03 pc 000000000002d5fc /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiScreen::Init()+60)
01-01 08:00:11.026   782   782 E C01400/Composer: #04 pc 00000000000c9644 /system/lib64/librender_service.z.so(OHOS::Rosen::impl::RSScreen::PhysicalScreenInit()+116)
01-01 08:00:11.026   782   782 E C01400/Composer: #05 pc 00000000000c959c /system/lib64/librender_service.z.so(OHOS::Rosen::impl::RSScreen::RSScreen(unsigned long, bool, std::__h::shared_ptr<OHOS::Rosen::HdiOutput>, OHOS::sptr<OHOS::Surface>)+376)
01-01 08:00:11.026   782   782 E C01400/Composer: #06 pc 00000000000ceb48 /system/lib64/librender_service.z.so(OHOS::Rosen::impl::RSScreenManager::ProcessScreenConnectedLocked(std::__h::shared_ptr<OHOS::Rosen::HdiOutput>&
01-01 08:00:11.026   782   782 I C01400/Composer: Init: Init hdiScreen succeed
01-01 08:00:14.504   782   782 I C01400/Composer: Repaint: layer map is empty, drop this frame
01-01 08:00:17.519   782   782 I C01400/Composer: Repaint: layer map is empty, drop this frame
01-01 08:00:20.435   782   782 E C01400/Composer: Init: HdiDevice::Init Tid:782 comm:render_service
01-01 08:00:20.435   782   782 E C01400/Composer: #00 pc 0000000000018ff4 /system/lib64/lib_dfx_dump_catcher.z.so(OHOS::HiviewDFX::DfxDumpCatcher::DumpCatch(int, int, std::__h::basic_string<char, std::__h::char_traits<char>, std::__h::allocator<char> >&)+152)
01-01 08:00:20.435   782   782 E C01400/Composer: #01 pc 0000000000017fd8 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiDevice::Init()+100)
01-01 08:00:20.435   782   782 E C01400/Composer: #02 pc 0000000000017eb4 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiDevice::GetInstance()+72)
01-01 08:00:20.435   782   782 E C01400/Composer: #03 pc 0000000000022674 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiLayer::CreateLayer(std::__h::shared_ptr<OHOS::Rosen::HdiLayerInfo> const&)+68)
01-01 08:00:20.435   782   782 E C01400/Composer: #04 pc 0000000000022610 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiLayer::Init(std::__h::shared_ptr<OHOS::Rosen::HdiLayerInfo> const&)+16)
01-01 08:00:20.435   782   782 E C01400/Composer: #05 pc 0000000000026c88 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiOutput::CreateLayer(unsigned long, std::__h::shared_ptr<OHOS::Rosen::HdiLayerInfo> const&)+68)
01-01 08:00:20.435   782   782 E C01400/Composer: #06 pc 0000000000026bdc /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiOutput::SetLayerInfo(std::__h::vector<std::__
01-01 08:00:30.950   782   782 E C01400/Composer: Init: HdiDevice::Init Tid:782 comm:render_service
01-01 08:00:30.950   782   782 E C01400/Composer: #00 pc 0000000000018ff4 /system/lib64/lib_dfx_dump_catcher.z.so(OHOS::HiviewDFX::DfxDumpCatcher::DumpCatch(int, int, std::__h::basic_string<char, std::__h::char_traits<char>, std::__h::allocator<char> >&)+152)
01-01 08:00:30.950   782   782 E C01400/Composer: #01 pc 0000000000017fd8 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiDevice::Init()+100)
01-01 08:00:30.950   782   782 E C01400/Composer: #02 pc 0000000000017eb4 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiDevice::GetInstance()+72)
01-01 08:00:30.950   782   782 E C01400/Composer: #03 pc 0000000000022674 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiLayer::CreateLayer(std::__h::shared_ptr<OHOS::Rosen::HdiLayerInfo> const&)+68)
01-01 08:00:30.950   782   782 E C01400/Composer: #04 pc 0000000000022610 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiLayer::Init(std::__h::shared_ptr<OHOS::Rosen::HdiLayerInfo> const&)+16)
01-01 08:00:30.950   782   782 E C01400/Composer: #05 pc 0000000000026c88 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiOutput::CreateLayer(unsigned long, std::__h::shared_ptr<OHOS::Rosen::HdiLayerInfo> const&)+68)
01-01 08:00:30.950   782   782 E C01400/Composer: #06 pc 0000000000026bdc /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiOutput::SetLayerInfo(std::__h::vector<std::__
01-01 08:00:41.683   782   782 E C01400/Composer: Init: HdiDevice::Init Tid:782 comm:render_service
01-01 08:00:41.683   782   782 E C01400/Composer: #00 pc 0000000000018ff4 /system/lib64/lib_dfx_dump_catcher.z.so(OHOS::HiviewDFX::DfxDumpCatcher::DumpCatch(int, int, std::__h::basic_string<char, std::__h::char_traits<char>, std::__h::allocator<char> >&)+152)
01-01 08:00:41.683   782   782 E C01400/Composer: #01 pc 0000000000017fd8 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiDevice::Init()+100)
01-01 08:00:41.683   782   782 E C01400/Composer: #02 pc 0000000000017eb4 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiDevice::GetInstance()+72)
01-01 08:00:41.683   782   782 E C01400/Composer: #03 pc 0000000000022674 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiLayer::CreateLayer(std::__h::shared_ptr<OHOS::Rosen::HdiLayerInfo> const&)+68)
01-01 08:00:41.683   782   782 E C01400/Composer: #04 pc 0000000000022610 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiLayer::Init(std::__h::shared_ptr<OHOS::Rosen::HdiLayerInfo> const&)+16)
01-01 08:00:41.683   782   782 E C01400/Composer: #05 pc 0000000000026c88 /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiOutput::CreateLayer(unsigned long, std::__h::shared_ptr<OHOS::Rosen::HdiLayerInfo> const&)+68)
01-01 08:00:41.683   782   782 E C01400/Composer: #06 pc 0000000000026bdc /system/lib64/libcomposer.z.so(OHOS::Rosen::HdiOutput::SetLayerInfo(std::__h::vector<std::__


//foundation/graphic/graphic_2d/rosen/modules/composer/hdi_backend/src/hdi_device.cpp
RosenError HdiDevice::Init()
{

    /**
     * 
     * 这里我们可以看出HdiDevice有两个比较重要的钩子
     * deviceFuncs_和layerFuncs_
     * 它们的头文件分别是:
     * drivers/peripheral/display/interfaces/include/display_device.h
     * drivers/peripheral/display/interfaces/include/display_layer.h
     * 且这一块的代码,都是device或者vendor厂家自己实现了,和OpenHarmony关系不大了
     * 
    **/
    if (deviceFuncs_ == nullptr) {
        int32_t ret = DeviceInitialize(&deviceFuncs_);
        if (ret != DISPLAY_SUCCESS || deviceFuncs_ == nullptr) {
            HLOGE("DeviceInitialize failed, ret is %{public}d", ret);
            return ROSEN_ERROR_NOT_INIT;
        }
    }

    if (layerFuncs_ == nullptr) {
        int32_t ret = LayerInitialize(&layerFuncs_);
        if (ret != DISPLAY_SUCCESS || layerFuncs_ == nullptr) {
            Destroy();
            HLOGE("LayerInitialize failed, ret is %{public}d", ret);
            return ROSEN_ERROR_NOT_INIT;
        }
    }

    return ROSEN_ERROR_OK;
}



extern "C" {
int32_t DeviceInitialize(DeviceFuncs **funcs)
{
    DISPLAY_CHK_RETURN((funcs == nullptr), DISPLAY_NULL_PTR, DISPLAY_LOGE("in funcs is null"));
    DeviceFuncs *dFuncs = (DeviceFuncs *)calloc(1, sizeof(DeviceFuncs));
    DISPLAY_CHK_RETURN((dFuncs == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("can not calloc"));

    dFuncs->RegHotPlugCallback = RegHotPlugCallback;
    dFuncs->GetDisplayCapability = GetDisplayCapability;
    dFuncs->GetDisplaySupportedModes = GetDisplaySupportedModes;
    dFuncs->GetDisplayMode = GetDisplayMode;
    dFuncs->SetDisplayMode = SetDisplayMode;
    dFuncs->GetDisplayPowerStatus = GetDisplayPowerStatus;
    dFuncs->SetDisplayPowerStatus = SetDisplayPowerStatus;
    dFuncs->PrepareDisplayLayers = PrepareDisplayLayers;
    dFuncs->GetDisplayBacklight = GetDisplayBacklight;
    dFuncs->SetDisplayBacklight = SetDisplayBacklight;
    dFuncs->GetDisplayProperty = GetDisplayProperty;
    dFuncs->GetDisplayCompChange = GetDisplayCompChange;
    dFuncs->SetDisplayClientCrop = SetDisplayClientCrop;
    dFuncs->SetDisplayClientDestRect = SetDisplayClientDestRect;
    dFuncs->SetDisplayClientBuffer = SetDisplayClientBuffer;
    dFuncs->SetDisplayClientDamage = SetDisplayClientDamage;
    dFuncs->SetDisplayVsyncEnabled = SetDisplayVsyncEnabled;
    dFuncs->RegDisplayVBlankCallback = RegDisplayVBlankCallback;
    dFuncs->GetDisplayReleaseFence = GetDisplayReleaseFence;
    dFuncs->CreateVirtualDisplay = CreateVirtualDisplay;
    dFuncs->DestroyVirtualDisplay = DestroyVirtualDisplay;
    dFuncs->SetVirtualDisplayBuffer = SetVirtualDisplayBuffer;
    dFuncs->SetDisplayProperty = SetDisplayProperty;
    dFuncs->Commit = Commit;
    *funcs = dFuncs;

    HdiSession::GetInstance();//详见章节3.6.1
    return DISPLAY_SUCCESS;
}



int32_t LayerInitialize(LayerFuncs **funcs)
{
    DISPLAY_CHK_RETURN((funcs == nullptr), DISPLAY_NULL_PTR, DISPLAY_LOGE("the in funcs is nullptr"));
    LayerFuncs *lFuncs = (LayerFuncs *)calloc(1, sizeof(LayerFuncs));
    DISPLAY_CHK_RETURN((lFuncs == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("can not calloc errno: %{public}d", errno));
    lFuncs->SetLayerAlpha = SetLayerAlpha;
    lFuncs->CreateLayer = CreateLayer;
    lFuncs->CloseLayer = CloseLayer;
    lFuncs->SetLayerSize = SetLayerSize;
    lFuncs->SetLayerCrop = SetLayerCrop;
    lFuncs->SetLayerZorder = SetLayerZorder;
    lFuncs->SetLayerPreMulti = SetLayerPreMulti;
    lFuncs->SetTransformMode = SetTransformMode;
    lFuncs->SetLayerDirtyRegion = SetLayerDirtyRegion;
    lFuncs->SetLayerVisibleRegion = SetLayerVisibleRegion;
    lFuncs->SetLayerBuffer = SetLayerBuffer;
    lFuncs->SetLayerCompositionType = SetLayerCompositionType;
    lFuncs->SetLayerBlendType = SetLayerBlendType;
    lFuncs->SetLayerVisible = SetLayerVisible;

    *funcs = lFuncs;
    DISPLAY_LOGD("layer initialize success");
    return DISPLAY_SUCCESS;
}

}
3.6.1 HdiSession::GetInstance

干到这里,只能一个字形容累。但是,累也得继续搞,搞搞搞!

//device/soc/phytium/d2000/hardware/display/src/display_device/hdi_session.cpp
HdiSession &HdiSession::GetInstance()
{
    static HdiSession instance;
    static std::once_flag once;
    std::call_once(once, [&]() { instance.Init(); });
    return instance;
}

void HdiSession::Init()
{
    DISPLAY_LOGD();
    //获取一个drmDevice
    mHdiDevices = HdiDeviceInterface::DiscoveryDevice();
    DISPLAY_LOGD("devices size %{public}zd", mHdiDevices.size());
    mHdiDisplays.clear();
    for (auto device : mHdiDevices) {
        auto displays = device->DiscoveryDisplay();
        mHdiDisplays.insert(displays.begin(), displays.end());
    }
}

//KMS的一些常规操作,主要通过libdrm库的API调用来实现。
//drm_device.cpp
std::unordered_map<uint32_t, std::shared_ptr<HdiDisplay>> DrmDevice::DiscoveryDisplay()
{
    mDisplays.clear();
    drmModeResPtr res = drmModeGetResources(GetDrmFd());
    DISPLAY_CHK_RETURN((res == nullptr), mDisplays, DISPLAY_LOGE("can not get drm resource"));
    // discovery all drm resource
    FindAllCrtc(res);
    FindAllEncoder(res);
    FindAllConnector(res);
    FindAllPlane();
    DISPLAY_LOGD();
    // travel all connector
    for (auto &connectorPair : mConnectors) {
        auto connector = connectorPair.second;
        uint32_t crtcId = 0; 
	int32_t ret;
	ret = connector->PickIdleCrtcId(mEncoders, mCrtcs, crtcId);
        if (ret != DISPLAY_SUCCESS) {
            continue;
        }
        DISPLAY_LOGD();

        auto crtcIter = mCrtcs.find(crtcId);
        if (crtcIter == mCrtcs.end()) {
            DISPLAY_LOGE("can not find crtc for the id %{public}d", connector->GetId());
            continue;
        }
        DISPLAY_LOGD();
        auto crtc = crtcIter->second;
        DISPLAY_LOGD("crtc %{public}p", crtc.get());
        // create the display
        std::shared_ptr<HdiDisplay> display = std::make_shared<DrmDisplay>(connector, crtc, mInstance);
        DISPLAY_LOGD();
        display->Init();//详见章节3.6.2
        mDisplays.emplace(display->GetId(), std::move(display));
    }
    return mDisplays;
}

3.6.2 DrmDisplay::init

猴子的快乐你不懂,而我们程序员的快乐你也不懂。但是我懂!因为我也是一个!

/**
 * 在源码开始分析前,这里我们要知道DrmDisplay继承于HdiDisplay
 **/
 //device/soc/phytium/d2000/hardware/display/src/display_device/drm_display.cpp
int32_t DrmDisplay::Init()
{
    int ret;
    DISPLAY_CHK_RETURN((mCrtc == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("crtc is null"));
    DISPLAY_CHK_RETURN((mConnector == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("connector is null"));
    DISPLAY_CHK_RETURN((mDrmDevice == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("drmDevice is null"));
    ret = HdiDisplay::Init();
    DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE("init failed"));
    DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE("can not init HdiGfxComposition"));

    auto postComp = std::make_unique<HdiDrmComposition>(mConnector, mCrtc, mDrmDevice);
    DISPLAY_CHK_RETURN((postComp == nullptr), DISPLAY_FAILURE,
        DISPLAY_LOGE("can not new HdiDrmComposition errno %{public}d", errno));
    ret = postComp->Init();
    DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE("can not init HdiDrmComposition"));
    /**
     * HdiDrmComposition继承于HdiComposer
     * 这里的HdiComposer里的mComposer指向了HdiDrmComposition
    **/
    mComposer = std::make_unique<HdiComposer>(std::move(postComp));
    ret = mCrtc->BindToDisplay(GetId());
    DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE("bind crtc failed"));

    ret = ChosePreferenceMode();
    DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE("choose preference mode fialed"));
    return DISPLAY_SUCCESS;
}
3.6.3 小结

通过前面的分析可知,我们可以把hdibackend理解为后端,其调用逻辑我们可以使用如下的伪代码来表示:

    HdiBackend --->HdiSession-------->HdiDisplay

3.7 HdiBackend::Repaint

前途是光明的,道路是曲折的。狭路相逢勇者胜,木有啥好说的,继续撸起袖子干就是了!

//foundation/graphic/graphic_2d/rosen/modules/composer/hdi_backend/src/hdi_backend.cpp
void HdiBackend::Repaint(std::vector<OutputPtr> &outputs)
{
    ...
    int32_t ret = DISPLAY_SUCCESS;
    for (auto &output : outputs) {//遍历output,通常只有一个输出实例
        ...
        //获取所有已知ID的Layer
        const std::unordered_map<uint32_t, LayerPtr> &layersMap = output->GetLayers();
        ...
        bool needFlush = false;
        ret = PreProcessLayersComp(output, layersMap, needFlush);//详见章节3.8
        ...
        uint32_t screenId = output->GetScreenId();
        std::vector<LayerPtr> compClientLayers;
        std::vector<LayerInfoPtr> newLayerInfos;
        for (auto iter = layersMap.begin(); iter != layersMap.end(); ++iter) {
            const LayerPtr &layer = iter->second;
            newLayerInfos.emplace_back(layer->GetLayerInfo());
            if (layer->GetLayerInfo()->GetCompositionType() == GraphicCompositionType::GRAPHIC_COMPOSITION_CLIENT) {
                compClientLayers.emplace_back(layer);
            }
        }

        if (compClientLayers.size() > 0) {
            needFlush = true;
            HLOGD("Need flush framebuffer, client composition layer num is %{public}zu", compClientLayers.size());
        }
        /**
         * 此时的needFlush为true
         * 
        **/
        OnPrepareComplete(needFlush, output, newLayerInfos);//详见章节3.9
        sptr<SurfaceBuffer> frameBuffer = nullptr;
        if (needFlush) {
            /**
             * 此时的needFlush为true,compClientLayers表示需要通过GPU合成的layers
            **/
            if (FlushScreen(output, compClientLayers, frameBuffer) != DISPLAY_SUCCESS) {//详见章节3.10
                // return
            }
        }

        sptr<SyncFence> fbFence = SyncFence::INVALID_FENCE;
        ret = device_->Commit(screenId, fbFence);//详见章节3.11
        ...
        output->UpdatePrevLayerInfo();//交换output中前后buffer
        ...
        //释放framebuffer
        ReleaseFramebuffer(output, fbFence, frameBuffer);
        lastPresentFence_ = fbFence;
        HLOGD("%{public}s: end", __func__);
    }
}

3.8 HdiDevice::PrepareScreenLayers

辛亏老子以前分析过,Android的逻辑代码。不然OpenHarmony里面的各种弯弯绕绕,不得搞死人去啊。

//foundation/graphic/graphic_2d/rosen/modules/composer/hdi_backend/src/hdi_device.cpp
int32_t HdiDevice::PrepareScreenLayers(uint32_t screenId, bool &needFlush)
{
    CHECK_FUNC(deviceFuncs_, deviceFuncs_->PrepareDisplayLayers);
    return deviceFuncs_->PrepareDisplayLayers(screenId, &needFlush);
}
//此时的needFlushFb为false
//device/soc/phytium/d2000/hardware/display/src/display_device/hdi_session.cpp
HdiSession::GetInstance().CallDisplayFunction(devId, &HdiDisplay::PrepareDisplayLayers, needFlushFb);  //hdi_session.cpp
    HdiDisplay::PrepareDisplayLayers(...)
        /**
         * 其中mClientLayer是在HdiDisplay::Init被初始化的
         * auto layer = CreateHdiLayer(LAYER_TYPE_GRAPHIC);
         * mClientLayer = std::move(layer);
        **/
        mComposer->Prepare(layers, *mClientLayer)//其中mComposer指向HdiComposer,layers为前面章节3.5 layer->Init传递过来的
            mPostComp->SetLayers(layers, clientLayer);//hdi_composer.cpp,其中mPostComp指向HdiDrmComposition
                HdiDrmComposition::SetLayers(...)
                    for (auto &layer : layers) {
                        layer->SetDeviceSelect(COMPOSITION_CLIENT);
                    }
                    mCompLayers.push_back(&clientLayer);                       


  • PrepareScreenLayers函数的核心功能,一句话概括就是对要进行合成的buffer做一些预处理

3.9 HdiBackend::OnPrepareComplete

分析代码,真是累啊。搞了一天,还没有分析完。革命尚未成功,同志还需努力!OnPrepareComplete的核心功能为:

  • 主要是对渲染完成的layer,进行GPU合成操作,并将其写入到FBO中。
  • 在合成完成后,将FBO写入到屏幕上。
//hdi_backend.cpp
void HdiBackend::OnPrepareComplete(bool needFlush, OutputPtr &output, std::vector<LayerInfoPtr> &newLayerInfos)
{
    if (needFlush) {
        ReorderLayerInfo(newLayerInfos);
    }

    struct PrepareCompleteParam param = {
        .needFlushFramebuffer = needFlush,
        .layers = newLayerInfos,
    };

    /**
     * 这个地方获取的是Surface
     * 此处的fbSurface_ = HdiFramebufferSurface::CreateFramebufferSurface();
    **/

   /**
    * 
    SurfaceError HdiFramebufferSurface::CreateSurface(sptr<HdiFramebufferSurface> &fbSurface)
    {
        consumerSurface_ = Surface::CreateSurfaceAsConsumer("FrameBuffer");

        sptr<IBufferProducer> producer = consumerSurface_->GetProducer();
        producerSurface_ = Surface::CreateSurfaceAsProducer(producer);

        sptr<IBufferConsumerListener> listener = fbSurface;
        SurfaceError ret = consumerSurface_->RegisterConsumerListener(listener);
        if (ret != SURFACE_ERROR_OK) {
            return SURFACE_ERROR_NO_CONSUMER;
        }

        return SURFACE_ERROR_OK;
    }
    sptr<HdiFramebufferSurface> HdiFramebufferSurface::CreateFramebufferSurface()
    {
        sptr<HdiFramebufferSurface> fbSurface = new HdiFramebufferSurface();

        SurfaceError ret = fbSurface->CreateSurface(fbSurface);
        if (ret != SURFACE_ERROR_OK) {
            HLOGE("FramebufferSurface CreateSurface failed, ret is %{public}d", ret);
            return nullptr;
        }

        ret = fbSurface->SetBufferQueueSize(MAX_BUFFER_SIZE);
        if (ret != SURFACE_ERROR_OK) {
            HLOGE("FramebufferSurface SetBufferQueueSize failed, ret is %{public}d", ret);
            return nullptr;
        }

        return fbSurface;
    }
   **/

    auto fbSurface = output->GetFrameBufferSurface();
    if (onPrepareCompleteCb_ != nullptr) {
        //这个地方是个回调函数,它的执行逻辑如下
        /**onPrepareCompleteCb_(...)//hdi_backend.cpp
         *   RSComposerAdapter::OnPrepareComplete(...)//rs_composer_adapter.cpp
         *      RSPhysicalScreenProcessor::Redraw(...)//rs_physical_screen_processor.cpp,详见章节3.9.1
        **/
        onPrepareCompleteCb_(fbSurface, param, onPrepareCompleteCbData_);
    }
}

3.9.1 RSPhysicalScreenProcessor::Redraw

继续执行RSComposerAdapter::OnPrepareComplete函数,将其传递到rs_physical_screen_processor.cpp中。
在rs_physical_screen_processor.cpp中执行RSPhysicalScreenProcessor::Redraw函数。

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_physical_screen_processor.cpp
void RSPhysicalScreenProcessor::Redraw(const sptr<Surface>& surface, const std::vector<LayerInfoPtr>& layers)
{
    RS_TRACE_NAME("Redraw");
    //此处的流程和bootamition中的何其相似
    RS_LOGD("RsDebug RSPhysicalScreenProcessor::Redraw flush frame buffer start");
    bool forceCPU = RSBaseRenderEngine::NeedForceCPU(layers);
    auto renderFrame = renderEngine_->RequestFrame(surface, renderFrameConfig_, forceCPU);

    auto canvas = renderFrame->GetCanvas();
    if (canvas == nullptr) {
        RS_LOGE("RsDebug RSPhysicalScreenProcessor::Redraw:canvas is nullptr.");
        return;
    }
    canvas->concat(screenTransformMatrix_);
    //此处的forceCPU为false,renderEngine_为rs_render_engine.cpp中的一个引用
    renderEngine_->DrawLayers(*canvas, layers, forceCPU, mirrorAdaptiveCoefficient_);
    /**
     * 此处调用surface的flaush,然后触发HdiFramebufferSurface::OnBufferAvailable()
     * 详见章节3.9.2
    **/
    renderFrame->Flush();
    RS_LOGD("RsDebug RSPhysicalScreenProcessor::Redraw flush frame buffer end");
}
3.9.2 HdiFramebufferSurface::OnBufferAvailable

兜兜转转,一路走来。不容易,既然选择了,那就干就是了。坚信自己是最牛逼的!

//foundation/graphic/graphic_2d/rosen/modules/composer/hdi_backend/src/hdi_framebuffer_surface.cpp
void HdiFramebufferSurface::OnBufferAvailable()
{
    sptr<SurfaceBuffer> buffer;
    int64_t timestamp = 0;
    Rect damage = {0};
    sptr<SyncFence> acquireFence = SyncFence::INVALID_FENCE;
    //获取可用buffer
    SurfaceError ret = consumerSurface_->AcquireBuffer(buffer, acquireFence,
                                                       timestamp, damage);
    if (ret != SURFACE_ERROR_OK || buffer == nullptr) {
        HLOGE("AcquireBuffer failed, ret is %{public}d", ret);
        return;
    }

    std::lock_guard<std::mutex> lock(mutex_);
    //放入
    availableBuffers_.push(std::make_unique<FrameBufferEntry>(buffer, acquireFence, timestamp, damage));
    bufferCond_.notify_one();//唤醒等待
}

总结上述代码的核心逻辑就是:

  • 消费前面的合成后图层的buffer并放入AvailableBuffers_中
  • 然后唤醒bufferCond_等待事件

3.10 HdiBackend::FlushScreen

离成功越来越近了,再坚持一把,冲一冲,前途是美好的,未来是光明的,道路是曲折的。此时不拼搏,更待何时!

//foundation/graphic/graphic_2d/rosen/modules/composer/hdi_backend/src/hdi_backend.cpp
int32_t HdiBackend::FlushScreen(
    const OutputPtr &output, std::vector<LayerPtr> &compClientLayers, sptr<SurfaceBuffer> &buffer)
{
    //获取前面合成好的图层buffer
    auto fbEntry = output->GetFramebuffer();

    const auto& fbAcquireFence = fbEntry->acquireFence;
    for (auto &layer : compClientLayers) {
        layer->MergeWithFramebufferFence(fbAcquireFence);//这个地方,没有看出来有啥用
    }

    buffer = fbEntry->buffer;
    return SetScreenClientInfo(*fbEntry, output);//继续接着往下看3.10.1
}
3.10.1 HdiBackend::SetScreenClientInfo

别人说见色起意,这里我们见名思意。这个函数是干嘛的呢,我们一道来分析!

//foundation/graphic/graphic_2d/rosen/modules/composer/hdi_backend/src/hdi_backend.cpp
int32_t HdiBackend::SetScreenClientInfo(const OutputPtr &output, const OutputPtr &clientOutput)
{
    if (buffer == nullptr) {
        return;
    }
    if (lastFrameBuffers_.find(output->GetScreenId()) != lastFrameBuffers_.end()) {
        // wrong check
        (void)output->ReleaseFramebuffer(lastFrameBuffers_[output->GetScreenId()], presentFence);
    }
    lastFrameBuffers_[output->GetScreenId()] = buffer;
}

int32_t HdiBackend::SetScreenClientInfo(const FrameBufferEntry &fbEntry, const OutputPtr &output)
{
    ...
    /**
     * 设置上屏buffer,它的调用逻辑如下:
     *  HdiDevice::SetScreenClientBuffer
     *   SetDisplayClientBuffer(...)//hdi_session.cpp
     *      HdiDisplay::SetDisplayClientBuffer()//hdi_display.cpp
     *           mClientLayer->SetLayerBuffer(buffer, fence)//这里的mClientLayer是在hdi_display在init中被初始化的,但是没有提供buffer实质性的内容
     *                  std::unique_ptr<HdiLayerBuffer> layerbuffer = std::make_unique<HdiLayerBuffer>(*buffer);
     *                  mHdiBuffer = std::move(layerbuffer)
    **/
    int ret = device_->SetScreenClientBuffer(output->GetScreenId(),
        fbEntry.buffer->GetBufferHandle(), fbEntry.acquireFence);

    //这个函数毛都木有做
    ret = device_->SetScreenClientDamage(output->GetScreenId(), output->GetOutputDamageNum(),
                                         output->GetOutputDamage());
    ...
    return DISPLAY_SUCCESS;    
}
3.10.2 小结

FlushScreen的核心功能可以概括为:

  • 将合成OK之后的图层送到hdioupt,接着送往hdidisplay等待显示

3.11 HdiDevice::Commit

前面的铺垫,都是为了最后将图层应用到屏幕上,而此处便是最后一搏了,单车能否变摩托!

//foundation/graphic/graphic_2d/rosen/modules/composer/hdi_backend/src/hdi_device.cpp
int32_t HdiDevice::Commit(uint32_t screenId, sptr<SyncFence> &fence)
{
    ...
    int32_t ret = deviceFuncs_->Commit(screenId, &fenceFd);
    ...
    return ret;
}


    /**
     * 其中deviceFuncs_->Commit的调用逻辑如下:
     *  Commit(...)//hdi_session.cpp
     *     HdiSession::GetInstance().CallDisplayFunction(devId, &HdiDisplay::Commit, fence)
     *       HdiDisplay::Commit(...)//hdi_display.cpp
     *          mComposer->Commit(false)//hdi_composer.cpp
     *              mPostComp->Apply(modeSet)//hdi_drm_composition.cpp
     *                  接下来就是一番drm送显示的一番常规操作了
    **/




四.重新回过头来看

基本流程虽然理了一篇,但是还不是很透彻,很多东西只是走了一下,还是得重新回过头来重新梳理梳理下。这里我将重点梳理几个核心关键点:


4.1 RSSurfaceRenderNode到HdiLayer的转变

其实这块我们在前面的代码里面已经有分析到了,只是由于没有系统归纳,这里我们重新梳理下!

//foundation/graphic/graphic_2d/rosen/modules/render_service/core/pipeline/rs_physical_screen_processor.cpp
//using LayerInfoPtr = std::shared_ptr<HdiLayerInfo>
//using LayerPtr = std::shared_ptr<HdiLayer>;
void RSPhysicalScreenProcessor::ProcessSurface(RSSurfaceRenderNode &node)//这块详见章节3.3
{
    auto layer = composerAdapter_->CreateLayer(node);
    layers_.emplace_back(layer);
}

void RSPhysicalScreenProcessor::PostProcess()
{
    composerAdapter_->CommitLayers(layers_);
}
RSComposerAdapter::CommitLayers
    output_->SetLayerInfo(layers)
        for (auto &layerInfo : layerInfos) {
             CreateLayer(surfaceId, layerInfo)
                 LayerPtr layer = HdiLayer::CreateHdiLayer(screenId_);
                 layer->UpdateLayerInfo(layerInfo)
        }

4.2 对HdiBackend HdiLayer HdiOutput HdiDisplay的理解

对这几个类来说,如果能有一个类图或者关联图能归纳起来他们之间的联系是最好的了。但是把,有了它们之间的联系也是比较松散的。这里我就简单的就我个人的理解,来简单描述下。可能理解的不是很准确,勿喷!

  • HdiBackend:这里我把它理解为处理显示的后端,譬如处理合成,处理相关送显示流程等都是由它进行负责的
  • HdiLayer:这里我们可以把它理解为和前端RSSurfaceRenderNode对应的后端处理显示buffer的类
  • HdiOutput:这里的HdiOutput为后端对所有需要输出显示layer的总管家,包括各种应用的layer,以及相关layer合成后的framebuffer
  • HdiDisplay:这里我把它理解为对显示设备的抽象




写在最后

到这里,OpenHarmony送显流程分析介绍就告一段落了!编写该文档的过程我也是小心再小心,谨慎再谨慎!但是难免其中可能会有一些概念或者理论不对,这个希望各位能多多指针!就我分析个人感觉,OpenHarmony的很多理念都是和Android非常相似,基本只是换了一套实现而已。看来OpenHarmony还有很长的路要走大!路漫漫其修,吾将上下而求索,总之,青山不改绿水长流先到这里了,各位江湖见!

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值