📱 Flutter iOS 渲染

从 Widget 到 Metal

深入理解 iOS 平台渲染机制

Surface · Impeller · LayerTree · Rasterizer

🍎 iOS 渲染概述

Flutter 在 iOS 上使用 Metal API 进行 GPU 渲染

组件技术用途
UI 框架UIKit原生 UI 集成
视图容器FlutterViewFlutter 渲染目标
图形 APIMetalGPU 渲染
图层CAMetalLayer显示层
渲染引擎Impeller/Skia2D 绘制

📈 渲染架构演进

Skia 时代

  • CPU 光栅化
  • OpenGL ES
  • 复杂的着色器编译
  • 首次帧卡顿

Impeller 时代

  • GPU 优先设计
  • Metal 原生
  • 预编译着色器
  • 流畅渲染

🏗️ 整体架构

┌─────────────────────────────────────────┐
│            Flutter Framework            │
│  Widget → Element → RenderObject        │
│                  → Layer                 │
└────────────────────┬────────────────────┘
                     │ LayerTree
┌────────────────────▼────────────────────┐
│            Flutter Engine               │
│  Animator → Rasterizer → Compositor     │
└────────────────────┬────────────────────┘
                     │
┌────────────────────▼────────────────────┐
│            Platform Embedder            │
│  FlutterViewController                  │
│  FlutterView (CAMetalLayer)             │
└────────────────────┬────────────────────┘
                     │
┌────────────────────▼────────────────────┐
│              iOS / Metal                │
│  MTLDevice → MTLCommandQueue            │
│  → MTLRenderCommandEncoder              │
└─────────────────────────────────────────┘

🎮 FlutterViewController

源码: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

👁️ FlutterView

@interface FlutterView : UIView

// Metal 图层
@property (nonatomic, strong) CAMetalLayer* metalLayer;

// 渲染目标
@property (nonatomic, weak) id<FlutterViewResolvable> resolver;

// 获取可绘制纹理
- (id<MTLTexture>)drawableTexture;

@end

FlutterView 是 UIView 的子类,使用 CAMetalLayer 作为支持层

⚙️ FlutterEngine

@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 概述

Metal 是 Apple 的低级图形和计算 API,直接访问 GPU

组件说明
MTLDeviceGPU 设备抽象
MTLCommandQueue命令队列
MTLCommandBuffer命令缓冲
MTLRenderPipelineState渲染管线
MTLTexture纹理
MTLBuffer缓冲

📺 CAMetalLayer

// 配置 CAMetalLayer
CAMetalLayer* metalLayer = [CAMetalLayer layer];
metalLayer.device = MTLCreateSystemDefaultDevice();
metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
metalLayer.framebufferOnly = YES;
metalLayer.drawableSize = view.bounds.size;

// 添加到视图
[self.layer addSublayer:metalLayer];

🎨 Surface 概念

Surface 是 Flutter 渲染的抽象输出目标

Surface 类型用途
GPUSurfaceMetalMetal GPU 渲染
GPUSurfaceGLOpenGL ES 渲染
SoftwareSurfaceCPU 软件渲染

📝 Surface 创建流程

FlutterViewController
       │
       ▼
┌─────────────────┐
│  Create View    │ 创建 FlutterView
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Create Layer   │ 配置 CAMetalLayer
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Create Surface │ 创建 GPUSurfaceMetal
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Register       │ 注册到 Engine
└─────────────────┘

🔧 GPUSurfaceMetal

源码: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();
}

📊 Surface 管理

// SurfaceDelegate 协议
@protocol FlutterSurfaceManager <NSObject>

// 获取可绘制纹理
- (FlutterDrawableSurface*)drawableSurface;

// 提交渲染结果
- (void)present;

// 调整大小
- (void)resize:(CGSize)size;

@end

🚀 Impeller 概述

Impeller 是 Flutter 的新一代渲染引擎,专为 GPU 优化

  • ✅ 预编译着色器
  • ✅ 无首次帧卡顿
  • ✅ 确定性渲染
  • ✅ Metal 原生实现

🏗️ Impeller 架构

┌─────────────────────────────────────┐
│           Flutter Engine            │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│           Impeller                   │
│  ┌─────────────────────────────┐   │
│  │  DisplayList → EntityPass   │   │
│  └───────────┬─────────────────┘   │
│              │                      │
│  ┌───────────▼─────────────────┐   │
│  │  AHAL (Abstract HAL)        │   │
│  └───────────┬─────────────────┘   │
│              │                      │
│  ┌───────────▼─────────────────┐   │
│  │  Metal Backend              │   │
│  │  - RenderPass               │   │
│  │  - PipelineState            │   │
│  │  - CommandBuffer            │   │
│  └─────────────────────────────┘   │
└─────────────────────────────────────┘

📋 AHAL 命令缓冲

Abstract HAL 是 Impeller 的硬件抽象层

class CommandBuffer {
  // 开始渲染通道
  RenderPass* CreateRenderPass(
    const RenderTarget& target
  );
  
  // 提交命令
  void Submit();
  
  // 等待完成
  void WaitUntilComplete();
}

⚡ Impeller vs Skia

特性SkiaImpeller
着色器编译运行时构建时
首次帧卡顿流畅
GPU 利用一般高效
内存使用较高优化
调试支持成熟发展中

🎨 Skia 渲染

Skia 是 Flutter 默认的 2D 图形库

  • CPU 光栅化到位图
  • 上传到 GPU 纹理
  • 使用 Metal/OpenGL 绘制
  • 着色器运行时编译

🌳 LayerTree 概述

LayerTree 是 Flutter 渲染的中间表示

RenderObject (布局/绘制)
       │
       ▼
PaintingContext
       │
       ▼
LayerTree (合成树)
       │
       ▼
SceneBuilder
       │
       ▼
Scene (可渲染场景)

📦 Layer 类型

Layer 类型用途
PictureLayer绘制指令
ContainerLayer容器
TransformLayer变换
ClipLayer裁剪
OpacityLayer透明度
PlatformViewLayer平台视图

🔨 LayerTree 构建

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);
}

🖼️ PictureLayer

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_);
  }
}

📦 ContainerLayer

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);
    }
  }
}

🔄 TransformLayer

class TransformLayer : public ContainerLayer {
  SkMatrix transform_;
  
  void Paint(PaintContext& context) override {
    // 保存当前矩阵
    context.canvas->save();
    
    // 应用变换
    context.canvas->concat(transform_);
    
    // 绘制子层
    ContainerLayer::Paint(context);
    
    // 恢复矩阵
    context.canvas->restore();
  }
}

✂️ ClipLayer

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();
  }
}

🎨 Rasterizer 概述

源码:flow/layers/rasterizer.cc

Rasterizer 负责光栅化 LayerTree并提交到 GPU

  • 接收 LayerTree
  • 执行 Preroll 阶段
  • 执行 Paint 阶段
  • 合成最终图像

🔄 光栅化流程

LayerTree
     │
     ▼
┌─────────────────┐
│  Preroll        │ 预处理阶段
│  - 计算边界      │
│  - 应用裁剪      │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Paint          │ 绘制阶段
│  - 执行绘制指令  │
│  - 生成 Picture │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Composite      │ 合成阶段
│  - 合并图层      │
│  - 应用效果      │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Submit         │ 提交到 GPU
└─────────────────┘

📋 Preroll 阶段

struct PrerollContext {
  // 当前裁剪区域
  SkRect cull_rect;
  
  // 当前变换矩阵
  SkMatrix matrix;
  
  // 不透明度
  float opacity;
  
  // 子树边界
  SkRect child_bounds;
}

🎨 Paint 阶段

struct PaintContext {
  // 目标画布
  SkCanvas* canvas;
  
  // 是否光栅化缓存
  bool raster_cache_enabled;
  
  // 当前状态
  void* state_stack;
}

🔀 合成阶段

合成阶段合并所有图层生成最终图像

  • 从后往前遍历 LayerTree
  • 应用变换和裁剪
  • 合并透明度
  • 生成最终纹理

📤 GPU 上传

// 上传纹理到 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];
}

🖼️ 纹理上传

格式说明使用场景
BGRA832位颜色默认帧缓冲
RGBA832位颜色纹理
R88位灰度遮罩
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 机制

VSync 是垂直同步信号,控制帧渲染时机

  • iOS 屏幕刷新率:60Hz / 120Hz
  • 每帧时间:16.67ms / 8.33ms
  • VSync 信号触发渲染
  • 避免撕裂和卡顿

📺 CADisplayLink

// 创建 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

⏰ VsyncWaiter

源码: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
}

⚡ 性能优化

渲染优化

  • 减少重绘区域
  • 使用 RepaintBoundary
  • 避免过度绘制

内存优化

  • 释放不可见资源
  • 使用纹理缓存
  • 压缩图片

💾 光栅化缓存

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(),
)

适用于:

  • 复杂但很少变化的 Widget
  • 动画中的静态部分
  • 列表项

🖼️ 平台视图

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

📄 关键类

类名职责
FlutterViewControlleriOS 视图控制器
FlutterViewFlutter 渲染视图
GPUSurfaceMetalMetal Surface
Rasterizer光栅化引擎
LayerTree图层树

🔧 调试技巧

# 启用性能叠加
MaterialApp(
  showPerformanceOverlay: true,
)

# 检查渲染模式
flutter doctor -v

# Xcode GPU 报告
Debug → Navigator → GPU Capture

❓ 常见问题

卡顿

  • 检查是否在主线程执行耗时操作
  • 使用 Performance Overlay 定位
  • 添加 RepaintBoundary

内存泄漏

  • 检查图片是否正确释放
  • 使用 Xcode Instruments 分析

📝 总结

渲染流程

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

🎯 关键要点

  • 📱 iOS 使用 Metal 进行 GPU 渲染
  • 🎮 CAMetalLayer 是 Flutter 的显示层
  • 🚀 Impeller 是新一代渲染引擎
  • 🌳 LayerTree 是渲染中间表示
  • ⏱️ VSync 控制帧渲染时机
  • 💾 光栅化缓存 提升性能

📚 参考资料

  • 🔗 Flutter Engine: github.com/flutter/engine
  • 🔗 Impeller: github.com/flutter/engine/tree/main/impeller
  • 🔗 Metal: developer.apple.com/metal
  • 🔗 Flutter iOS: docs.flutter.dev/platform-integration/ios

📱 Happy Rendering!