日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

超详解析Flutter渲染引擎|业务想创新,不了解底层原理怎么行?

發(fā)布時(shí)間:2024/9/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 超详解析Flutter渲染引擎|业务想创新,不了解底层原理怎么行? 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

簡(jiǎn)介:?Flutter 作為一個(gè)跨平臺(tái)的應(yīng)用框架,誕生之后,就被高度關(guān)注。它通過(guò)自繪 UI ,解決了之前 RN 和 weex 方案難以解決的多端一致性問(wèn)題。Dart AOT 和精減的渲染管線,相對(duì)與 JavaScript 和 webview 的組合,具備更高的性能體驗(yàn)。 本文的分析主要以 Android 平臺(tái)為例,IOS 上原理大致類似,相關(guān)的參考代碼基于 stable/v1.12.13+hotfix.8 。


作者|萬(wàn)紅波(遠(yuǎn)湖)
出品|阿里巴巴新零售淘系技術(shù)部

前言

Flutter 作為一個(gè)跨平臺(tái)的應(yīng)用框架,誕生之后,就被高度關(guān)注。它通過(guò)自繪 UI ,解決了之前 RN 和 weex 方案難以解決的多端一致性問(wèn)題。Dart AOT 和精減的渲染管線,相對(duì)與 JavaScript 和 webview 的組合,具備更高的性能體驗(yàn)。

目前在集團(tuán)內(nèi)也有很多的 BU 在使用和探索。了解底層引擎的工作原理可以幫助我們更深入地結(jié)合具體的業(yè)務(wù)來(lái)對(duì)引擎進(jìn)行定制和優(yōu)化,更好的去創(chuàng)新和支撐業(yè)務(wù)。在淘寶,我們也基于 Flutter engine 進(jìn)行了自繪UI的渲染引擎的探索。本文先對(duì) Flutter 的底層渲染引擎做一下深入分析和整理,以理清 Flutter 的渲染的機(jī)制及思路,之后分享一下我們基于Flutter引擎一些探索,供大家參考。

本文的分析主要以 Android 平臺(tái)為例,IOS 上原理大致類似,相關(guān)的參考代碼基于 stable/v1.12.13+hotfix.8 。

渲染引擎分析

? 渲染流水線

整個(gè) Flutter 的 UI 生成以及渲染完成主要分下面幾個(gè)步驟:

其中 1-6 在收到系統(tǒng) vsync 信號(hào)后,在 UI 線程中執(zhí)行,主要是涉及在 Dart framework 中 Widget/Element/RenderObject 三顆樹(shù)的生成以及承載繪制指令的 LayerTree 的創(chuàng)建,7-8 在 GPU 線程中執(zhí)行,主要涉及光柵化合成上屏。

  • 1-4跟渲染沒(méi)有直接關(guān)系,主要就是管理UI組件生命周期,頁(yè)面結(jié)構(gòu)以及Flex layout等相關(guān)實(shí)現(xiàn),本文不作深入分析。
  • 5-8為渲染相關(guān)流程,其中5-6在UI線程中執(zhí)行,產(chǎn)物為包含了渲染指令的Layer tree,在Dart層生成,可以認(rèn)為是整個(gè)渲染流程的前半部,屬于生產(chǎn)者角色。
  • 7-8把dart層生成的Layer Tree,通過(guò)window透?jìng)鞯紽lutter engine的C++代碼中,通過(guò)flow模塊來(lái)實(shí)現(xiàn)光柵化并合成輸出。可以認(rèn)為是整個(gè)渲染流程的后半部,屬于消費(fèi)者角色。

下圖為 Android 平臺(tái)上渲染一幀 Flutter UI 的運(yùn)行時(shí)序圖:

具體的運(yùn)行時(shí)步驟:

  • flutter 引擎啟動(dòng)時(shí),向系統(tǒng)的 Choreographer 實(shí)例注冊(cè)接收 Vsync 的回調(diào)。
  • 平臺(tái)發(fā)出 Vsync 信號(hào)后,上一步注冊(cè)的回調(diào)被調(diào)用,一系列調(diào)用后,執(zhí)行到 VsyncWaiter::fireCallback。
  • VsyncWaiter::fireCallback實(shí)際上會(huì)執(zhí)行Animator類的成員函數(shù)BeginFrame。
  • BeginFrame 經(jīng)過(guò)一系列調(diào)用執(zhí)行到 Window 的 BeginFrame,Window 實(shí)例是連接底層 Engine 和 Dart framework 的重要橋梁,基本上所以跟平臺(tái)相關(guān)的操作都會(huì)由 Window 實(shí)例來(lái)串聯(lián),包括事件,渲染,無(wú)障礙等。
  • 通過(guò) Window 的 BeginFrame 調(diào)用到 Dart Framework的RenderBinding 類,其有一個(gè)方法叫 drawFrame ,這個(gè)方法會(huì)去驅(qū)動(dòng) UI 上的 dirty 節(jié)點(diǎn)進(jìn)行重排和繪制,如果遇到圖片的顯示,會(huì)丟到 IO 線程以及去 worker 線程去執(zhí)行圖片加載和解碼,解碼完成后,再次丟到 IO 線程去生成圖片紋理,由于 IO 線程和 GPU 線程是 share GL context 的,所以在 IO 線程生成的圖片紋理在 GPU 線程可以直接被 GPU 所處理和顯示。
  • Dart 層繪制所產(chǎn)生的繪制指令以及相關(guān)的渲染屬性配置都會(huì)存儲(chǔ)在 LayerTree 中,通過(guò) Animator::RenderFrame 把 LayerTree 提交到 GPU 線程,GPU 線程拿到 LayerTree 后,進(jìn)行光柵化并做上屏操作(關(guān)于LayerTree我們后面會(huì)詳細(xì)講解)。之后通過(guò) Animator::RequestFrame 請(qǐng)求接收系統(tǒng)下一次的Vsync信號(hào),這樣又會(huì)從第1步開(kāi)始,循環(huán)往復(fù),驅(qū)動(dòng) UI 界面不斷的更新。
  • 分析了整個(gè) Flutter 底層引擎總體運(yùn)行流程,下面會(huì)相對(duì)詳細(xì)的分析上述渲染流水線中涉及到的相關(guān)概念以及細(xì)節(jié)知識(shí),大家可以根據(jù)自己的情況選擇性的閱讀。

    ? 線程模型

    要了解 Flutter 的渲染管線,必須要先了解 Flutter 的線程模型。從渲染引擎的視角來(lái)看,Flutter 的四個(gè)線程的職責(zé)如下:

    • Platform 線程:負(fù)責(zé)提供Native窗口,作為GPU渲染的目標(biāo)。接受平臺(tái)的VSync信號(hào)并發(fā)送到UI線程,驅(qū)動(dòng)渲染管線運(yùn)行。
    • UI 線程:負(fù)責(zé)UI組件管理,維護(hù)3顆樹(shù),Dart VM管理,UI渲染指令生成。同時(shí)負(fù)責(zé)把承載渲染指令的LayerTree提交給GPU線程去光柵化。
    • GPU線程:通過(guò)flow模塊完成光柵化,并調(diào)用底層渲染API(opengl/vulkan/meta),合成并輸出到屏幕。
    • IO 線程:包括若干worker線程會(huì)去請(qǐng)求圖片資源并完成圖片解碼,之后在 IO 線程中生成紋理并上傳 GPU ,由于通過(guò)和 GPU 線程共享 EGL Context,在 GPU 線程中可以直接使用 IO 線程上傳的紋理,通過(guò)并行化,提高渲染的性能

    后面介紹的概念都會(huì)貫穿在這四個(gè)線程當(dāng)中,關(guān)于線程模型的更多信息可以參考下面兩篇文章:

    《深入了解 Flutter 引擎線程模型》
    《The Engine architecture》

    ? VSync

    Flutter引擎啟動(dòng)時(shí),向系統(tǒng)的Choreographer實(shí)例注冊(cè)接收Vsync的回調(diào)函數(shù),GPU硬件發(fā)出Vsync后,系統(tǒng)會(huì)觸發(fā)該回調(diào)函數(shù),并驅(qū)動(dòng)UI線程進(jìn)行l(wèi)ayout和繪制。

    @ shell/platform/android/io/flutter/view/VsyncWaiter.java private final FlutterJNI.AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate = new FlutterJNI.AsyncWaitForVsyncDelegate() {@Overridepublic void asyncWaitForVsync(long cookie) {Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {@Overridepublic void doFrame(long frameTimeNanos) {float fps = windowManager.getDefaultDisplay().getRefreshRate();long refreshPeriodNanos = (long) (1000000000.0 / fps);FlutterJNI.nativeOnVsync(frameTimeNanos, frameTimeNanos + refreshPeriodNanos, cookie);}});}};

    下圖為Vsync觸發(fā)時(shí)的調(diào)用棧:

    在Android上,Java層收到系統(tǒng)的Vsync的回調(diào)后通過(guò)JNI發(fā)給Flutter engine,之后通過(guò)Animator,Engine以及Window等對(duì)象路由調(diào)回dart層,驅(qū)動(dòng)dart層進(jìn)行drawFrame的操作。在Dart framework的RenderingBinding::drawFrame函數(shù)中會(huì)觸發(fā)對(duì)所有dirty節(jié)點(diǎn)的layout/paint/compositor相關(guān)的操作,之后生成LayerTree,再交由Flutter engine光柵化并合成。

    void drawFrame() {assert(renderView != null);pipelineOwner.flushLayout();pipelineOwner.flushCompositingBits();pipelineOwner.flushPaint();renderView.compositeFrame(); // this sends the bits to the GPUpipelineOwner.flushSemantics(); // this also sends the semantics to the OS.}

    ? 圖層

    在Dart層進(jìn)行drawFrame對(duì)dirty節(jié)點(diǎn)進(jìn)行排版后,就會(huì)對(duì)需要重新繪制的節(jié)點(diǎn)進(jìn)行繪制操作。而我們知道Flutter中widget是一個(gè)UI元素的抽象描述,繪制時(shí),需要先將其inflate成為Element,之后生成對(duì)應(yīng)的RenderObject來(lái)負(fù)責(zé)驅(qū)動(dòng)渲染。通常來(lái)講,一個(gè)頁(yè)面的所有的RenderObject都屬于一個(gè)圖層,Flutter本身沒(méi)有圖層的概念,這里所說(shuō)的圖層可以粗暴理解成一塊內(nèi)存buffer,所有屬于圖層的RenderObject都應(yīng)該被繪制在這個(gè)圖層對(duì)應(yīng)的buffer中去。

    如果這個(gè)RenderObject的RepaintBoundary屬性為true時(shí),就會(huì)額外生成一個(gè)圖層,其所有的子節(jié)點(diǎn)都會(huì)被繪制在這個(gè)新的圖層上,最后所有圖層有GPU來(lái)負(fù)責(zé)合成并上屏。

    Flutter中使用Layer的概念來(lái)表示一個(gè)層次上的所有RenderObject,Layer和圖層存在N:1的對(duì)應(yīng)關(guān)系。根節(jié)點(diǎn)RenderView會(huì)創(chuàng)建root Layer,一般是一個(gè)Transform Layer,并包含多個(gè)子Layer,每個(gè)子Layer又會(huì)包含若干RenderObject,每個(gè)RenderObject繪制時(shí),會(huì)產(chǎn)生相關(guān)的繪制指令和繪制參數(shù),并存儲(chǔ)在對(duì)應(yīng)的Layer上。

    可以參考下面Layer的類圖,Layer實(shí)際上主要用來(lái)組織和存儲(chǔ)渲染相關(guān)的指令和參數(shù),比如Transform Layer用來(lái)保存圖層變換的矩陣,ClipRectLayer包含圖層的剪切域大小,PlatformViewLayer包含同層渲染組件的紋理id,PictureLayer包含SkPicture(SkPicture記錄了SkCanvas繪制的指令,在GPU線程的光柵化過(guò)程中會(huì)用它來(lái)做光柵化)

    ? 渲染指令

    當(dāng)渲染第一幀的時(shí)候,會(huì)從根節(jié)點(diǎn)RenderView開(kāi)始,逐個(gè)遍歷所有的子節(jié)點(diǎn)進(jìn)行繪制操作。

    //@rendering/view.dart //繪制入口,從view根節(jié)點(diǎn)開(kāi)始,逐個(gè)繪制所有子節(jié)點(diǎn) @overridevoid paint(PaintingContext context, Offset offset) {if (child != null)context.paintChild(child, offset);}

    我們可以具體看看一個(gè)節(jié)點(diǎn)如何繪制的:

  • 創(chuàng)建Canvas。繪制時(shí)會(huì)通過(guò)PaintContex獲取的Canvas進(jìn)行,其內(nèi)部會(huì)去創(chuàng)建一個(gè)PictureLayer,并通過(guò)ui.PictrureRecorder調(diào)用到C++層來(lái)創(chuàng)建一個(gè)Skia的SkPictureRecorder實(shí)例,再通過(guò)SkPictureRecorder創(chuàng)建SkCanvas,最后把這個(gè)SkCanvas返回給Dart層去使用.
  • //@rendering/object.dart @overrideCanvas get canvas {if (_canvas == null)_startRecording();return _canvas;}void _startRecording() {assert(!_isRecording);_currentLayer = PictureLayer(estimatedBounds);_recorder = ui.PictureRecorder();_canvas = Canvas(_recorder);_containerLayer.append(_currentLayer);}

    2.通過(guò)Canvas執(zhí)行具體繪制。Dart層拿到綁定了底層SkCanvas的對(duì)象后,用這個(gè)Canvas進(jìn)行具體的繪制操作,這些繪制命令會(huì)被底層的SkPictureRecorder記錄下來(lái)。

    3.結(jié)束繪制,準(zhǔn)備上屏。繪制完畢時(shí),會(huì)調(diào)用Canvas對(duì)象的stopRecordingIfNeeded函數(shù),它會(huì)最后會(huì)去調(diào)用到C++的SkPictureRecorder的endRecording接口來(lái)生成一個(gè)Picture對(duì)象,存儲(chǔ)在PictureLayer中。

    //@rendering/object.dart void stopRecordingIfNeeded() {if (!_isRecording)return;_currentLayer.picture = _recorder.endRecording();_currentLayer = null;_recorder = null;_canvas = null;}

    這個(gè)Picture對(duì)象對(duì)應(yīng)Skia的SkPicture對(duì)象,存儲(chǔ)這所有的繪制指令。有興趣可以看一下SkPicture的官方說(shuō)明。

    所有的Layer繪制完成形成LayerTree,在renderView.compositeFrame()中通過(guò)SceneBuilder把Dart Layer映射為flutter engine中的flow::Layer,同時(shí)也會(huì)生成一顆C++的flow::LayerTree,存儲(chǔ)在Scene對(duì)象中,最后通過(guò)Window的render接口提交給Flutter engine。

    //@rendering/view.dart void compositeFrame() {...final ui.SceneBuilder builder = ui.SceneBuilder();final ui.Scene scene = layer.buildScene(builder);_window.render(scene);scene.dispose();}

    在全部繪制操作完成后,在Flutter engine中就形成了一顆flow::LayerTree,應(yīng)該是像下面的樣子:

    這顆包含了所有繪制信息以及繪制指令的flow::LayerTree會(huì)通過(guò)window實(shí)例調(diào)用到Animator::Render后,最后在Shell::OnAnimatorDraw中提交給GPU線程,并進(jìn)行光柵化操作,代碼可以參考:

    @shell/common/animator.cc/Animator::Render
    @shell/common/shell.cc/Shell::OnAnimatorDraw

    這里提一下flow這個(gè)模塊,flow是一個(gè)基于skia的合成器,它可以基于渲染指令來(lái)生成像素?cái)?shù)據(jù)。Flutter基于flow模塊來(lái)操作Skia,進(jìn)行光柵化以及合成。

    ? 圖片紋理

    前面講線程模型的時(shí)候,我們提到過(guò)IO線程負(fù)責(zé)圖片加載以及解碼并且把解碼后的數(shù)據(jù)上傳到GPU生成紋理,這個(gè)紋理在后面光柵化過(guò)程中會(huì)用到,我們來(lái)看一下這部分的內(nèi)容。

    UI線程加載圖片的時(shí)候,會(huì)在IO線程調(diào)用InstantiateImageCodec*函數(shù)調(diào)用到C++層來(lái)初始化圖片解碼庫(kù),通過(guò)skia的自帶的解碼庫(kù)解碼生成bitmap數(shù)據(jù)后,調(diào)用SkImage::MakeCrossContextFromPixmap來(lái)生成可以在多個(gè)線程共享的SkImage,在IO線程中用它來(lái)生成GPU紋理。

    //@flutter/lib/ui/painting/codec.cc sk_sp<SkImage> MultiFrameCodec::GetNextFrameImage(fml::WeakPtr<GrContext> resourceContext) {...// 如果resourceContext不為空,就會(huì)去創(chuàng)建一個(gè)SkImage,// 并且這個(gè)SkImage是在resouceContext中的,if (resourceContext) {SkPixmap pixmap(bitmap.info(), bitmap.pixelRef()->pixels(),bitmap.pixelRef()->rowBytes());// This indicates that we do not want a "linear blending" decode.sk_sp<SkColorSpace> dstColorSpace = nullptr;return SkImage::MakeCrossContextFromPixmap(resourceContext.get(), pixmap,false, dstColorSpace.get());} else {// Defer decoding until time of draw later on the GPU thread. Can happen// when GL operations are currently forbidden such as in the background// on iOS.return SkImage::MakeFromBitmap(bitmap);} }

    我們知道,OpenGL的環(huán)境是線程不安全的,在一個(gè)線程生成的圖片紋理,在另外一個(gè)線程里面是不能直接使用的。但由于上傳紋理操作比較耗時(shí),都放在GPU線程操作,會(huì)減低渲染性能。目前OpenGL中可以通過(guò)share context來(lái)支持這種多線程紋理上傳的,所以目前flutter中是由IO線程做紋理上傳,GPU線程負(fù)責(zé)使用紋理。

    基本的操作就是在GPU線程創(chuàng)建一個(gè)EGLContextA,之后把EGLContextA傳給IO線程,IO線程在通過(guò)EGLCreateContext在創(chuàng)建EGLContextB的時(shí)候,把EGLContextA作為shareContext的參數(shù),這樣EGLContextA和EGLContextB就可以共享紋理數(shù)據(jù)了。

    具體相關(guān)的代碼不一一列舉了,可以參考:

    @shell/platform/android/platform_view_android.cc/CreateResourceContext
    @shell/platform/android/android_surface_gl.cc/ResourceContextMakeCurrent
    @shell/platform/android/android_surface_gl.cc/AndroidSurfaceGL
    @shell/platform/android/android_surface_gl.cc/SetNativeWindow

    關(guān)于圖片加載相關(guān)流程,可以參考這篇文章:TODO

    ? 光柵化與合成

    把繪制指令轉(zhuǎn)化為像素?cái)?shù)據(jù)的過(guò)程稱為光柵化,把各圖層光柵化后的數(shù)據(jù)進(jìn)行相關(guān)的疊加與特效相關(guān)的處理成為合成這是渲染后半段的主要工作。

    前面也提到過(guò),生成LayerTree后,會(huì)通過(guò)Window的Render接口把它提交到GPU線程去執(zhí)行光柵化操作,大體流程如下:

    1-4步,在UI線程執(zhí)行,主要是通過(guò)Animator類把LayerTree提交到Pipeline對(duì)象的渲染隊(duì)列,之后通過(guò)Shell把pipeline對(duì)象提交給GPU線程進(jìn)行光柵化,不具體展開(kāi),代碼在animator.cc&pipeline.h

    5-6步,在GPU線程執(zhí)行具體的光柵化操作。這部分主要分為兩大塊,一塊是Surface的管理。一塊是如何把Layer Tree里面的渲染指令繪制到之前創(chuàng)建的Surface中。

    可以通過(guò)下圖了解一下Flutter中的Surface,不同類型的Surface,對(duì)應(yīng)不同的底層渲染API。


    我們以GPUSurfaceGL為例,在Flutter中,GPUSurfaceGL是對(duì)Skia GrContext的一個(gè)管理和封裝,而GrContext是Skia用來(lái)管理GPU繪制的一個(gè)上下文,最終都是借助它來(lái)操作OpenGL的API進(jìn)行相關(guān)的上屏操作。在引擎初始化時(shí),當(dāng)FlutterViewAndroid創(chuàng)建后,就會(huì)創(chuàng)建GPUSurfaceGL,在其構(gòu)造函數(shù)中會(huì)同步創(chuàng)建Skia的GrContext。

    光柵化主要是在函數(shù)Rasterizer::DrawToSurface中實(shí)現(xiàn)的:

    //@shell/rasterizer.cc RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {FML_DCHECK(surface_);... if (compositor_frame) {//1.執(zhí)行光柵化RasterStatus raster_status = compositor_frame->Raster(layer_tree, false);if (raster_status == RasterStatus::kFailed) {return raster_status;}//2.合成frame->Submit();if (external_view_embedder != nullptr) {external_view_embedder->SubmitFrame(surface_->GetContext());}//3.上屏FireNextFrameCallbackIfPresent();if (surface_->GetContext()) {surface_->GetContext()->performDeferredCleanup(kSkiaCleanupExpiration);}return raster_status;}return RasterStatus::kFailed; }

    光柵化完成后,執(zhí)行frame->Submit()進(jìn)行合成。這會(huì)調(diào)用到下面的PresentSurface,來(lái)把offscreen_surface中的內(nèi)容轉(zhuǎn)移到onscreen_canvas中,最后通過(guò)GLContextPresent()上屏。

    //@shell/GPU/gpu_surface_gl.cc bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) { ...if (offscreen_surface_ != nullptr) {SkPaint paint;SkCanvas* onscreen_canvas = onscreen_surface_->getCanvas();onscreen_canvas->clear(SK_ColorTRANSPARENT);// 1.轉(zhuǎn)移offscreen surface的內(nèi)容到onscreen canvas中onscreen_canvas->drawImage(offscreen_surface_->makeImageSnapshot(), 0, 0,&paint);}{//2. flush 所有繪制命令onscreen_surface_->getCanvas()->flush();}//3 上屏if (!delegate_->GLContextPresent()) {return false;}...return true; }

    GLContextPresent接口代碼如下,實(shí)際上是調(diào)用的EGL的eglSwapBuffers接口去顯示圖形緩沖區(qū)的內(nèi)容。

    //@shell/platform/android/android_surface_gl.cc
    bool AndroidSurfaceGL::GLContextPresent() {
    FML_DCHECK(onscreen_context_ && onscreen_context_->IsValid());
    return onscreen_context_->SwapBuffers();
    }

    上面代碼段中的onscreen_context是Flutter引擎初始化的時(shí)候,通過(guò)setNativeWindow獲得。主要是把一個(gè)Android的SurfaceView組件對(duì)應(yīng)的ANativeWindow指針傳給EGL,EGL根據(jù)這個(gè)窗口,調(diào)用eglCreateWindowSurface和顯示系統(tǒng)建立關(guān)聯(lián),之后通過(guò)這個(gè)窗口把渲染內(nèi)容顯示到屏幕上。

    代碼可以參考:
    @shell/platform/android/android_surface_gl.cc/AndroidSurfaceGL::SetNativeWindow

    總結(jié)以上渲染后半段流程,就可以看到LayerTree中的渲染指令被光柵化,并繪制到SkSurface對(duì)應(yīng)的Surface中。這個(gè)Surface是由AndroidSurfaceGL創(chuàng)建的一個(gè)offscreen_surface。再通過(guò)PresentSurface操作,把offscreen_surface的內(nèi)容,交換到onscreen_surface中去,之后調(diào)用eglSwapSurfaces上屏,結(jié)束一幀的渲染。

    探索

    深入了解了Flutter引擎的渲染機(jī)制后,基于業(yè)務(wù)的訴求,我們也做了一些相關(guān)的探索,這里簡(jiǎn)單分享一下。

    ? 小程序渲染引擎

    基于Flutter engine,我們?nèi)コ嗽膁art引擎,引入js引擎,用C++重寫了Flutter Framework中的rendering,painting以及widget的核心邏輯,繼續(xù)向上封裝基礎(chǔ)組件,實(shí)現(xiàn)cssom以及C++版的響應(yīng)式框架,對(duì)外提供統(tǒng)一的JS Binding API,再向上對(duì)接小程序的DSL,供小程序業(yè)務(wù)方使用。對(duì)于性能要求比較高的小程序,可以選擇使用這條鏈路進(jìn)行渲染,線下我們跑通了星巴克小程序的UI渲染,并具備了很好的性能體驗(yàn)。

    ? 小程序互動(dòng)渲染引擎

    受限于小程序worker/render的架構(gòu),互動(dòng)業(yè)務(wù)中頻繁的繪制操作需要經(jīng)過(guò)序列化/反序列化并把消息從worker發(fā)送到render去執(zhí)行渲染命令。基于flutter engine,我們提供了一套獨(dú)立的2d渲染引擎,引入canvas的渲染管線,提供標(biāo)準(zhǔn)的canvas API供業(yè)務(wù)直接在worker線程中使用,縮短渲染鏈路,提高性能。目前已經(jīng)支持了相關(guān)的互動(dòng)業(yè)務(wù)在線上運(yùn)行,性能和穩(wěn)定性表現(xiàn)很好。

    總結(jié)與思考

    本文著重分析了flutter engine的渲染流水線及其相關(guān)概念并簡(jiǎn)單分享了我們的一些探索。熟悉和了解渲染引擎的工作原來(lái)可以幫助我們?cè)贏ndroid和IOS雙端快速去構(gòu)建一個(gè)差異化高效的渲染鏈路。這在目前雙端主要以web作為跨平臺(tái)渲染的主要形式下,提供了一個(gè)更容易定制和優(yōu)化的方案。

    總結(jié)

    以上是生活随笔為你收集整理的超详解析Flutter渲染引擎|业务想创新,不了解底层原理怎么行?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。