Surface · Impeller · LayerTree · Rasterizer
Flutter 在 iOS 上使用 Metal API 进行 GPU 渲染
| 组件 | 技术 | 用途 |
|---|---|---|
| UI 框架 | UIKit | 原生 UI 集成 |
| 视图容器 | FlutterView | Flutter 渲染目标 |
| 图形 API | Metal | GPU 渲染 |
| 图层 | CAMetalLayer | 显示层 |
| 渲染引擎 | Impeller/Skia | 2D 绘制 |
┌─────────────────────────────────────────┐
│ Flutter Framework │
│ Widget → Element → RenderObject │
│ → Layer │
└────────────────────┬────────────────────┘
│ LayerTree
┌────────────────────▼────────────────────┐
│ Flutter Engine │
│ Animator → Rasterizer → Compositor │
└────────────────────┬────────────────────┘
│
┌────────────────────▼────────────────────┐
│ Platform Embedder │
│ FlutterViewController │
│ FlutterView (CAMetalLayer) │
└────────────────────┬────────────────────┘
│
┌────────────────────▼────────────────────┐
│ iOS / Metal │
│ MTLDevice → MTLCommandQueue │
│ → MTLRenderCommandEncoder │
└─────────────────────────────────────────┘
源码:shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
@interface FlutterViewController : UIViewController
// Flutter 引擎
@property (nonatomic, strong) FlutterEngine* engine;
// Flutter 视图
@property (nonatomic, strong) FlutterView* view;
// 初始化
- (instancetype)initWithEngine:(FlutterEngine*)engine
nibName:(NSString*)nibName
bundle:(NSBundle*)bundle;
@end
@interface FlutterView : UIView
// Metal 图层
@property (nonatomic, strong) CAMetalLayer* metalLayer;
// 渲染目标
@property (nonatomic, weak) id<FlutterViewResolvable> resolver;
// 获取可绘制纹理
- (id<MTLTexture>)drawableTexture;
@end
FlutterView 是 UIView 的子类,使用 CAMetalLayer 作为支持层
@interface FlutterEngine : NSObject
// 引擎句柄
@property (nonatomic, readonly) FlutterEngineProc* engine;
// 运行器
@property (nonatomic, readonly) FlutterTaskRunner* platformRunner;
@property (nonatomic, readonly) FlutterTaskRunner* rasterRunner;
@property (nonatomic, readonly) FlutterTaskRunner* ioRunner;
// 启动引擎
- (BOOL)runWithEntrypoint:(NSString*)entrypoint;
@end
Metal 是 Apple 的低级图形和计算 API,直接访问 GPU
| 组件 | 说明 |
|---|---|
| MTLDevice | GPU 设备抽象 |
| MTLCommandQueue | 命令队列 |
| MTLCommandBuffer | 命令缓冲 |
| MTLRenderPipelineState | 渲染管线 |
| MTLTexture | 纹理 |
| MTLBuffer | 缓冲 |
// 配置 CAMetalLayer
CAMetalLayer* metalLayer = [CAMetalLayer layer];
metalLayer.device = MTLCreateSystemDefaultDevice();
metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
metalLayer.framebufferOnly = YES;
metalLayer.drawableSize = view.bounds.size;
// 添加到视图
[self.layer addSublayer:metalLayer];
Surface 是 Flutter 渲染的抽象输出目标
| Surface 类型 | 用途 |
|---|---|
| GPUSurfaceMetal | Metal GPU 渲染 |
| GPUSurfaceGL | OpenGL ES 渲染 |
| SoftwareSurface | CPU 软件渲染 |
FlutterViewController
│
▼
┌─────────────────┐
│ Create View │ 创建 FlutterView
└────────┬────────┘
│
▼
┌─────────────────┐
│ Create Layer │ 配置 CAMetalLayer
└────────┬────────┘
│
▼
┌─────────────────┐
│ Create Surface │ 创建 GPUSurfaceMetal
└────────┬────────┘
│
▼
┌─────────────────┐
│ Register │ 注册到 Engine
└─────────────────┘
源码:shell/platform/darwin/ios/framework/Source/GPUSurfaceMetal.mm
class GPUSurfaceMetal {
id<MTLDevice> device_;
id<MTLCommandQueue> command_queue_;
CAMetalLayer* layer_;
// 获取可绘制对象
id<CAMetalDrawable> drawable_;
// 获取渲染目标纹理
id<MTLTexture> GetRenderTarget();
}
// SurfaceDelegate 协议
@protocol FlutterSurfaceManager <NSObject>
// 获取可绘制纹理
- (FlutterDrawableSurface*)drawableSurface;
// 提交渲染结果
- (void)present;
// 调整大小
- (void)resize:(CGSize)size;
@end
Impeller 是 Flutter 的新一代渲染引擎,专为 GPU 优化
┌─────────────────────────────────────┐
│ Flutter Engine │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Impeller │
│ ┌─────────────────────────────┐ │
│ │ DisplayList → EntityPass │ │
│ └───────────┬─────────────────┘ │
│ │ │
│ ┌───────────▼─────────────────┐ │
│ │ AHAL (Abstract HAL) │ │
│ └───────────┬─────────────────┘ │
│ │ │
│ ┌───────────▼─────────────────┐ │
│ │ Metal Backend │ │
│ │ - RenderPass │ │
│ │ - PipelineState │ │
│ │ - CommandBuffer │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
Abstract HAL 是 Impeller 的硬件抽象层
class CommandBuffer {
// 开始渲染通道
RenderPass* CreateRenderPass(
const RenderTarget& target
);
// 提交命令
void Submit();
// 等待完成
void WaitUntilComplete();
}
| 特性 | Skia | Impeller |
|---|---|---|
| 着色器编译 | 运行时 | 构建时 |
| 首次帧 | 卡顿 | 流畅 |
| GPU 利用 | 一般 | 高效 |
| 内存使用 | 较高 | 优化 |
| 调试支持 | 成熟 | 发展中 |
Skia 是 Flutter 默认的 2D 图形库
LayerTree 是 Flutter 渲染的中间表示
RenderObject (布局/绘制)
│
▼
PaintingContext
│
▼
LayerTree (合成树)
│
▼
SceneBuilder
│
▼
Scene (可渲染场景)
| Layer 类型 | 用途 |
|---|---|
| PictureLayer | 绘制指令 |
| ContainerLayer | 容器 |
| TransformLayer | 变换 |
| ClipLayer | 裁剪 |
| OpacityLayer | 透明度 |
| PlatformViewLayer | 平台视图 |
void Paint(PaintingContext& context) {
// 1. 创建 Layer
auto layer = ContainerLayer::Make();
// 2. 添加变换
layer->Add(TransformLayer::Make(transform));
// 3. 添加绘制内容
auto picture = recorder.endRecording();
layer->Add(PictureLayer::Make(picture));
// 4. 添加到树
context.AddLayer(layer);
}
class PictureLayer : public Layer {
sk_sp<SkPicture> picture_;
// 光栅化
void Preroll(PrerollContext* context) override {
// 计算边界
bounds_ = picture_->cullRect();
}
void Paint(PaintContext& context) override {
// 绘制到画布
context.canvas->drawPicture(picture_);
}
}
class ContainerLayer : public Layer {
std::vector<Layer*> layers_;
void Add(Layer* layer) {
layers_.push_back(layer);
}
void Preroll(PrerollContext* context) override {
for (auto layer : layers_) {
layer->Preroll(context);
}
}
}
class TransformLayer : public ContainerLayer {
SkMatrix transform_;
void Paint(PaintContext& context) override {
// 保存当前矩阵
context.canvas->save();
// 应用变换
context.canvas->concat(transform_);
// 绘制子层
ContainerLayer::Paint(context);
// 恢复矩阵
context.canvas->restore();
}
}
class ClipLayer : public ContainerLayer {
SkPath clip_path_;
void Paint(PaintContext& context) override {
// 保存并应用裁剪
context.canvas->save();
context.canvas->clipPath(clip_path_);
// 绘制子层
ContainerLayer::Paint(context);
context.canvas->restore();
}
}
源码:flow/layers/rasterizer.cc
Rasterizer 负责光栅化 LayerTree并提交到 GPU
LayerTree
│
▼
┌─────────────────┐
│ Preroll │ 预处理阶段
│ - 计算边界 │
│ - 应用裁剪 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Paint │ 绘制阶段
│ - 执行绘制指令 │
│ - 生成 Picture │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Composite │ 合成阶段
│ - 合并图层 │
│ - 应用效果 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Submit │ 提交到 GPU
└─────────────────┘
struct PrerollContext {
// 当前裁剪区域
SkRect cull_rect;
// 当前变换矩阵
SkMatrix matrix;
// 不透明度
float opacity;
// 子树边界
SkRect child_bounds;
}
struct PaintContext {
// 目标画布
SkCanvas* canvas;
// 是否光栅化缓存
bool raster_cache_enabled;
// 当前状态
void* state_stack;
}
合成阶段合并所有图层生成最终图像
// 上传纹理到 GPU
void UploadToGPU() {
// 1. 获取 Metal 命令缓冲
id<MTLCommandBuffer> cmd = [queue commandBuffer];
// 2. 创建纹理
MTLTextureDescriptor* desc = ...;
id<MTLTexture> texture = [device newTextureWithDescriptor:desc];
// 3. 上传数据
[texture replaceRegion:region
mipmapLevel:0
withBytes:data
bytesPerRow:bytesPerRow];
// 4. 提交
[cmd commit];
}
| 格式 | 说明 | 使用场景 |
|---|---|---|
| BGRA8 | 32位颜色 | 默认帧缓冲 |
| RGBA8 | 32位颜色 | 纹理 |
| R8 | 8位灰度 | 遮罩 |
| ASTC | 压缩格式 | 图片纹理 |
// 创建帧缓冲
id<CAMetalDrawable> drawable = [metalLayer nextDrawable];
id<MTLTexture> texture = drawable.texture;
// 配置渲染通道
MTLRenderPassDescriptor* desc = [MTLRenderPassDescriptor new];
desc.colorAttachments[0].texture = texture;
desc.colorAttachments[0].loadAction = MTLLoadActionClear;
desc.colorAttachments[0].storeAction = MTLStoreActionStore;
// 渲染
id<MTLRenderCommandEncoder> encoder = [cmd renderCommandEncoderWithDescriptor:desc];
VSync 是垂直同步信号,控制帧渲染时机
// 创建 DisplayLink
CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:self
selector:@selector(displayLinkCallback:)];
// 配置
displayLink.preferredFramesPerSecond = 60; // 60 FPS
// 添加到 RunLoop
[displayLink addToRunLoop:[NSRunLoop mainRunLoop]
forMode:NSRunLoopCommonModes];
// 回调
- (void)displayLinkCallback:(CADisplayLink*)link {
// VSync 信号到达,开始渲染
[self renderFrame];
}
VSync 信号
│
▼
┌─────────────────┐
│ BeginFrame │ 开始帧
└────────┬────────┘
│
▼
┌─────────────────┐
│ Build LayerTree│ 构建 LayerTree
└────────┬────────┘
│
▼
┌─────────────────┐
│ Rasterize │ 光栅化
└────────┬────────┘
│
▼
┌─────────────────┐
│ Present │ 提交显示
└─────────────────┘
│
▼
等待下一个 VSync
源码:shell/platform/darwin/ios/vsync_waiter_ios.mm
class VsyncWaiterIOS : public VsyncWaiter {
CADisplayLink* display_link_;
void AwaitVSync() override {
// 等待 VSync 信号
// 信号到达后调用回调
}
}
// VSync 回调链
void OnVsync(uint64_t frame_start_ns, uint64_t frame_target_ns) {
// 1. 通知 Animator
animator_->BeginFrame(frame_start_ns, frame_target_ns);
// 2. Animator 通知 Engine
engine_->BeginFrame();
// 3. Engine 执行 Dart 代码
// 4. Dart 构建 Widget 树
// 5. 生成 LayerTree
// 6. 提交到 Rasterizer
}
class RasterCache {
// 缓存光栅化结果
std::map<Layer*, CachedImage> cache_;
// 获取缓存
CachedImage* Get(Layer* layer) {
if (cache_.count(layer)) {
return &cache_[layer];
}
return nullptr;
}
// 缓存图层
void Cache(Layer* layer, SkImage* image);
}
RepaintBoundary 创建独立的图层缓存
// 使用 RepaintBoundary
RepaintBoundary(
child: ExpensiveWidget(),
)
适用于:
iOS 平台视图集成:
// 使用 UIKitView
UIKitView(
viewType: 'native-view',
creationParams: {...},
creationParamsCodec: StandardMessageCodec(),
)
平台视图使用 PlatformViewLayer 渲染
flutter/engine/ ├── shell/platform/darwin/ios/ │ ├── framework/Source/ │ │ ├── FlutterViewController.mm │ │ ├── FlutterView.mm │ │ ├── FlutterEngine.mm │ │ └── GPUSurfaceMetal.mm │ └── ... │ ├── flow/ │ ├── layers/ # Layer 实现 │ ├── rasterizer.cc # 光栅化 │ └── compositor.cc # 合成 │ └── impeller/ ├── entity/ # 实体系统 ├── renderer/ # 渲染器 └── aiks/ # 2D API
| 类名 | 职责 |
|---|---|
| FlutterViewController | iOS 视图控制器 |
| FlutterView | Flutter 渲染视图 |
| GPUSurfaceMetal | Metal Surface |
| Rasterizer | 光栅化引擎 |
| LayerTree | 图层树 |
# 启用性能叠加
MaterialApp(
showPerformanceOverlay: true,
)
# 检查渲染模式
flutter doctor -v
# Xcode GPU 报告
Debug → Navigator → GPU Capture
Widget → RenderObject → LayerTree → Rasterizer → Metal → Screen
| 阶段 | 组件 |
|---|---|
| 构建 | Widget → Element → RenderObject |
| 合成 | LayerTree |
| 光栅化 | Impeller/Skia |
| 显示 | Metal → CAMetalLayer |
1. VSync 信号 └─▶ CADisplayLink 触发 2. 构建帧 └─▶ Widget → RenderObject → LayerTree 3. 光栅化 └─▶ Rasterizer → Impeller/Skia 4. GPU 渲染 └─▶ Metal → CAMetalLayer 5. 显示 └─▶ presentDrawable
📱 Happy Rendering!