
跨平臺(tái)圖形學(xué)前端【免費(fèi)下載鏈接】engineThe Flutter engine項(xiàng)目地址https://gitcode.com/gh_mirrors/eng/engine點(diǎn)擊查看免費(fèi)下載Flow 是 Flutter 引擎中負(fù)責(zé)合成compositing的核心模塊。它的職責(zé)非常聚焦基于 Skia 緩存已經(jīng)記錄的繪制命令recorded paint commands以及由這些記錄生成的像素pixels并運(yùn)行在獨(dú)立的 raster 線程上把合成結(jié)果上傳給 Skia 完成最終渲染。本文以倉(cāng)庫(kù)中 flow/README.md 的定義為骨架深入 flow 目錄的源碼實(shí)現(xiàn)講解 Flow 的整體架構(gòu)、兩階段渲染流水線Preroll / Paint、RasterCache 緩存機(jī)制與幀級(jí)臟區(qū)域frame damage優(yōu)化幫助你從引擎源碼層面理解 Flutter 每一幀從 layer tree 到屏幕像素的完整路徑。Flow 在 Flutter 引擎中的定位flow/README.md 對(duì) Flow 給出了精確而簡(jiǎn)潔的定義Flow is a simple compositor based on Skia that the Flutter engine uses to cache recorded paint commands and pixels generated from those recordings. Flow runs on the raster thread and uploads information to Skia.翻譯過(guò)來(lái)就是三層含義它是一個(gè)基于 Skia 的合成器compositor所有繪制最終都落到 Skia或 Impeller 后端的 canvas 上Flow 本身不負(fù)責(zé)底層圖形 API 調(diào)用。它的核心能力是緩存既緩存記錄的繪制命令即 DisplayList / picture也緩存由這些記錄生成的像素即離屏柵格化后的位圖從而避免每一幀都重復(fù)執(zhí)行昂貴的繪制指令。它運(yùn)行在 raster 線程上與 UI 線程解耦UI 線程只負(fù)責(zé)構(gòu)建 layer tree真正的柵格化與合成在 raster 線程完成。從工程目錄看flow/BUILD.gn 中定義了一個(gè)名為flow的 source_set包含 compositor_context.cc、diff_context.cc、embedded_views.cc、frame_timings.cc、raster_cache.cc、stopwatch.cc 以及l(fā)ayers/子目錄下三十余個(gè) Layer 實(shí)現(xiàn)文件這就是 Flow 模塊的全部構(gòu)成。兩階段渲染模型Preroll 與 PaintFlow 對(duì)每一幀的渲染被劃分為兩個(gè)階段對(duì)應(yīng)的核心數(shù)據(jù)結(jié)構(gòu)是 LayerTree持有根 Layer 與物理像素尺寸frame_size和 Layer所有圖層類(lèi)型的抽象基類(lèi)。Preroll布局與緩存決策階段LayerTree::Preroll 負(fù)責(zé)在整棵樹(shù)上做一次預(yù)遍歷bool LayerTree::Preroll(CompositorContext::ScopedFrame frame, bool ignore_raster_cache, DlRect cull_rect) { ... PrerollContext context { .raster_cache ignore_raster_cache ? nullptr : frame.context().raster_cache(), .gr_context frame.gr_context(), .view_embedder frame.view_embedder(), .state_stack state_stack, .dst_color_space sk_ref_spSkColorSpace(color_space), .surface_needs_readback false, .raster_time frame.context().raster_time(), .ui_time frame.context().ui_time(), .texture_registry frame.context().texture_registry(), .raster_cached_entries raster_cache_items_, }; root_layer_-Preroll(context); return context.surface_needs_readback; }從 PrerollContext 的定義可以看出Preroll 階段完成以下工作把RasterCache注入到上下文供各 Layer 決定是否、以及如何參與緩存記錄到raster_cached_entries通過(guò)LayerStateStack維護(hù)變換、裁剪等狀態(tài)并為每個(gè) Layer 計(jì)算paint_bounds繪制邊界匯總整棵樹(shù)是否需要 readback如某些濾鏡/平臺(tái)視圖需要從根 surface 讀回?cái)?shù)據(jù)返回給調(diào)用方?jīng)Q定是否需要 saveLayer統(tǒng)計(jì)has_platform_view、has_texture_layer等標(biāo)記供后續(xù)合成策略使用。Paint真正的柵格化階段LayerTree::Paint 在 Preroll 之后執(zhí)行它先做兩件與緩存相關(guān)的事再真正繪制if (cache) { cache-EvictUnusedCacheEntries(); TryToRasterCache(raster_cache_items_, context, ignore_raster_cache); } if (root_layer_-needs_painting(context)) { root_layer_-Paint(context); }即先驅(qū)逐本幀不再使用的緩存條目再嘗試為需要緩存的條目生成緩存圖最后遞歸調(diào)用各 Layer 的 Paint。needs_painting結(jié)合paint_bounds與裁剪棧做繪制剔除見(jiàn) layer.h 中Layer::needs_painting。LayerTree還提供 Flatten 方法可將整棵樹(shù)在不使用 raster cache 的情況下鋪平成單個(gè)DisplayList用于需要把場(chǎng)景導(dǎo)出為記錄的場(chǎng)景例如測(cè)試或部分嵌入場(chǎng)景。CompositorContext 與幀生命周期CompositorContext 是 Flow 的合成上下文它持有一幀合成所需的所有共享狀態(tài)RasterCache raster_cache_非 SLIMPELLER 構(gòu)建下啟用TextureRegistry外部紋理注冊(cè)表供 TextureLayer 使用兩把Stopwatchraster_time_與ui_time_用于計(jì)時(shí)與性能統(tǒng)計(jì)ScopedFrame一幀的 RAII 生命周期每一幀的合成通過(guò)CompositorContext::AcquireFrame取得一個(gè) ScopedFrame構(gòu)造時(shí)調(diào)用BeginFrame啟動(dòng)raster_time_計(jì)時(shí)析構(gòu)時(shí)調(diào)用EndFrame停止計(jì)時(shí)天然保證幀生命周期的成對(duì)性。ScopedFrame::Raster是幀柵格化的總?cè)肟赾ompositor_context.cc 中它的執(zhí)行順序是若有FrameDamage先計(jì)算本幀的裁剪矩形clip_rect部分重繪調(diào)用layer_tree.Preroll(...)傳入裁剪矩形或kGiantRect詢問(wèn)ExternalViewEmbedder的PostPrerollAction視結(jié)果決定kResubmitAndroid 上 FlutterImageView 場(chǎng)景需重提幀還是kSkipAndRetry等待 raster/platform 線程合并見(jiàn) compositor_context.h 中RasterStatus枚舉的注釋根據(jù)后端選擇PaintLayerTreeSkia或PaintLayerTreeImpeller返回RasterStatus::kSuccess。值得注意的細(xì)節(jié)在Raster中如果 Impeller 后端啟用aiks_context_非空還會(huì)調(diào)用ShouldPerformPartialRepaint判斷是否值得做部分重繪——由于 Impeller 的部分重繪需要額外的 resolve 紋理與最終 blit當(dāng)臟區(qū)域?qū)挾然蚋叨日急瘸^(guò)閾值kImpellerRepaintRatio 0.7f時(shí)放棄部分重繪見(jiàn) compositor_context.cc。幀損傷FrameDamage與臟區(qū)域計(jì)算FrameDamage 是 Flutter 實(shí)現(xiàn)只重繪變化區(qū)域的關(guān)鍵。它持有上一幀的 LayerTree通過(guò)ComputeClipRect調(diào)用 DiffContext 對(duì)比新舊兩棵樹(shù)Layer::Diff/Layer::IsReplacing/PreservePaintRegion計(jì)算出frame_damage與buffer_damage再疊加外部提供的additional_damage多緩沖累積損傷最終得到本幀實(shí)際需要重繪的矩形。Reset()則用于通知客戶端本幀不要做部分重繪例如 Impeller 認(rèn)為損傷過(guò)大時(shí)。RasterCache命令緩存與像素緩存緩存是 Flow 的靈魂。RasterCache 用「既緩存繪制命令、又緩存柵格化像素」的雙重策略避免重復(fù)繪制其生命周期在 raster_cache.h 的類(lèi)注釋中有完整描述Preroll 階段RasterCacheItem::PrerollSetup把候選緩存項(xiàng)加入PrerollContext::raster_cached_entriesRasterCacheItem::PrerollFinalize在層 Preroll 結(jié)束時(shí)把條目標(biāo)記為本幀已遇到。Paint 階段RasterCache::EvictUnusedCacheEntries驅(qū)逐不再使用的緩存LayerTree::TryToPrepareRasterCache為缺失的緩存條目生成圖像各層在 Paint 時(shí)若命中緩存則直接RasterCache::Draw繪制緩存圖RasterCache::EndFrame匯總命中數(shù)與內(nèi)存占用上報(bào)指標(biāo)RasterCacheMetrics含eviction_count、in_use_count、in_use_bytes等。命中條件與訪問(wèn)閾值緩存并不是無(wú)條件生效的。RasterCache構(gòu)造函數(shù)默認(rèn)access_threshold 3raster_cache.h即一個(gè)條目需要被連續(xù)看見(jiàn)/命中足夠次數(shù)才真正生成緩存圖避免對(duì)一幀即變的動(dòng)態(tài)內(nèi)容做無(wú)謂緩存。此外 RasterCacheUtil 定義了kDefaultPictureAndDisplayListCacheLimitPerFrame 3每幀最多新生成 3 張 picture/DisplayList 緩存把緩存生成的開(kāi)銷(xiāo)分?jǐn)偟蕉鄮乐鼓骋粠蛏纱罅烤彺娑?jank見(jiàn)GenerateNewCacheInThisFrame的實(shí)現(xiàn)邏輯kMinimumRendersBeforeCachingFilterLayer 3ImageFilterLayer 需要連續(xù)穩(wěn)定渲染若干幀后才從緩存其子層切換為緩存過(guò)濾后的輸出。緩存鍵與像素對(duì)齊緩存以RasterCacheKey為鍵raster_cache_key.h由RasterCacheKeyID唯一 ID 類(lèi)型kLayer/kDisplayList/kLayerChildren 變換矩陣組成。矩陣中只保留小數(shù)部分的平移量matrix_[kMTransX] 0后再取SkScalarFraction配合RasterCacheUtil::GetIntegralTransCTM將平移分量吸附到整數(shù)像素確保緩存紋理與物理像素精確對(duì)齊避免緩存啟用前后出現(xiàn)半像素偏移導(dǎo)致視覺(jué)抖動(dòng)。圖層級(jí)與命令級(jí)緩存DisplayList命令級(jí)DisplayListLayer以其 DisplayList 的unique_id為鍵display_list_layer.h通過(guò)DisplayListRasterCacheItem把繪制命令緩存成位圖Layer圖層級(jí)普通圖層以u(píng)nique_id為鍵layer.h 中Layer::caching_key_id通過(guò)LayerRasterCacheItem實(shí)現(xiàn)kLayerChildren類(lèi)型則用于 ImageFilterLayer 等場(chǎng)景——當(dāng)過(guò)濾層自身不穩(wěn)定時(shí)緩存其子層而不是過(guò)濾后的輸出。LayerTree::TryToRasterCachelayer_tree.cc實(shí)現(xiàn)了父子條目的協(xié)同如果父條目成功緩存則跳過(guò)其所有子條目的緩存生成若父條目緩存失敗則繼續(xù)嘗試子條目保證緩存層級(jí)不重疊、不浪費(fèi)。圖層類(lèi)型與合成能力flow/layers 目錄下的三十余個(gè) Layer 類(lèi)型覆蓋了 Flutter 場(chǎng)景的絕大部分合成需求按能力可分為幾類(lèi)類(lèi)別代表類(lèi)型用途容器/變換ContainerLayer、TransformLayer、OpacityLayer組織子樹(shù)、應(yīng)用變換與透明度裁剪ClipRectLayer、ClipRRectLayer、ClipPathLayer矩形/圓角/路徑裁剪特效ColorFilterLayer、ImageFilterLayer、BackdropFilterLayer、ShaderMaskLayer顏色/圖像/背景濾鏡與著色器遮罩內(nèi)容DisplayListLayer、TextureLayer、PlatformViewLayer繪制命令、外部紋理、平臺(tái)視圖嵌入輔助PerformanceOverlayLayer、OffscreenSurfaceLayer性能浮層、離屏 surfaceLayer 還通過(guò)renderable_state_flags機(jī)制layer.h聲明自己能獨(dú)立處理哪些狀態(tài)屬性透明度、ColorFilter、ImageFilter容器層對(duì)子層做交集計(jì)算盡量讓屬性下放到葉子層自身渲染減少不必要的 saveLayer。Clip枚舉則與 Dart 側(cè)painting.dart保持一一對(duì)應(yīng)代碼注釋明確要求exact copy保證了框架層與引擎層的語(yǔ)義一致。線程模型與外部視圖嵌入Flow 的raster 線程定位在 README 中即有說(shuō)明。CompositorContext的AcquireFrame接受fml::RefPtrfml::RasterThreadMergercompositor_context.h用于 raster 線程與 platform 線程的合并/分離管理而 EmbeddedViews 中的ExternalViewEmbedder接口則讓平臺(tái)視圖Android 的 FlutterView、iOS 的 UIView可以插入到合成流程中。在 iOS 等場(chǎng)景下遇到平臺(tái)視圖時(shí) Flow 會(huì)切換 canvas并把LayerStateStack累積的所有狀態(tài)變更重放到新 canvas 上見(jiàn) layer.h 中PaintContext的注釋保證平臺(tái)視圖兩側(cè)的繪制狀態(tài)完全一致。性能觀測(cè)與測(cè)試驗(yàn)證Flow 內(nèi)置了完整的性能觀測(cè)設(shè)施CompositorContext的raster_time_/ui_time_兩把 Stopwatch 分別統(tǒng)計(jì)柵格化與 UI 階段的耗時(shí)PerformanceOverlayLayer負(fù)責(zé)把它們可視化到屏幕上。此外 frame_timings.cc 提供幀級(jí)時(shí)間戳記錄供 DevTools 等工具分析幀節(jié)奏。測(cè)試方面Flow 有完備的單元測(cè)試覆蓋分散在各文件對(duì)應(yīng)的*_unittests.cc中例如raster_cache_unittests.cc驗(yàn)證緩存的命中、驅(qū)逐、內(nèi)存統(tǒng)計(jì)與access_threshold行為diff_context_unittests.cc 與 layer_tree_unittests.cc驗(yàn)證臟區(qū)域計(jì)算與整樹(shù) Preroll/Paint 流程flow_run_all_unittests.ccFlow 模塊測(cè)試的統(tǒng)一入口通過(guò)flutter/testing的測(cè)試框架運(yùn)行構(gòu)建配置見(jiàn) flow/BUILD.gn 中的flow_unittests目標(biāo)。這些測(cè)試連同stopwatch_unittests.cc、embedded_view_params_unittests.cc等共同保證了 Flow 合成流水線的正確性與穩(wěn)定性。小結(jié)Flow 作為 Flutter 引擎中基于 Skia 的輕量合成器用兩階段Preroll / Paint遍歷 RasterCache 雙重緩存 幀損傷計(jì)算把記錄繪制命令與復(fù)用柵格化像素這兩件事做到了極致命令緩存讓靜態(tài)場(chǎng)景免于重復(fù)構(gòu)建繪制指令像素緩存讓復(fù)雜圖層免于重復(fù)柵格化臟區(qū)域機(jī)制讓每次提交只重繪變化的部分。理解 flow 目錄的代碼組織與數(shù)據(jù)流也就理解了 Flutter 每一幀在 raster 線程上從 layer tree 到像素的完整旅程。贊分享跨平臺(tái)圖形學(xué)前端【免費(fèi)下載鏈接】engineThe Flutter engine項(xiàng)目地址https://gitcode.com/gh_mirrors/eng/engine點(diǎn)擊查看免費(fèi)下載相關(guān)推薦deck.gl CARTO RasterTileLayer 實(shí)戰(zhàn)基于 Quadbin 的柵格瓦片可視化圖層解析deck.gl CARTO RasterTileLayer 實(shí)戰(zhàn)基于 Quadbin 的柵格瓦片可視化圖層解析 RasterTileLayer 是 deck.前端數(shù)據(jù)可視化3D渲染圖形學(xué)OpenLayers 10.2.0 版本解讀Flow 粒子流圖層、WMS 1.1.1 解析與瓦片緩存優(yōu)化OpenLayers 10.2.0 版本解讀Flow 粒子流圖層、WMS 1.1.1 解析與瓦片緩存優(yōu)化 10.2.0 是 OpenLayers 在 WebG前端GIS數(shù)據(jù)可視化Docker構(gòu)建緩存優(yōu)化利用分層緩存加速CI/CD流水線Docker構(gòu)建緩存優(yōu)化利用分層緩存加速CI/CD流水線 你是否遇到過(guò)這樣的情況每次修改Dockerfile中的一行代碼整個(gè)構(gòu)建過(guò)程就需要重新下載依賴、編云原生容器運(yùn)行時(shí)虛擬化容器編排上一篇gh_mirrors/exam/examples實(shí)戰(zhàn)教程時(shí)序分類(lèi)評(píng)估指標(biāo)下一篇快速上手awesome-clothed-human10個(gè)最實(shí)用的著裝人體重建項(xiàng)目推薦創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考