模块4: 渲染管线与多后端架构

理解帧循环、脏矩形优化与多渲染器抽象

1. 渲染流程概览

@antv/g 的渲染由 RenderingService 驱动,每一帧按以下流水线执行:

  ┌─────────────┐    ┌──────────────┐    ┌─────────────┐    ┌──────────┐
  │ BeginFrame  │ -> │ Dirty Check  │ -> │ Sort & Cull │ -> │ Render   │
  │ 初始化帧     │    │ 脏矩形合并    │    │ Z排序+裁剪   │    │ 绘制图形  │
  └─────────────┘    └──────────────┘    └─────────────┘    └──────────┘
         │                                                        │
         │                  ┌──────────────┐                      │
         └──────────────────│ EndFrame     │<─────────────────────┘
                            │ 提交到屏幕    │
                            └──────────────┘

2. RenderingService 核心服务

位于 packages/g-lite/src/services/RenderingService.ts,是渲染引擎的核心调度器。

// RenderingService 核心职责
class RenderingService {
  // Hook 系统 - 插件可注册钩子
  hooks = {
    init: new SyncHook(),
    destroy: new SyncHook(),
    beginFrame: new SyncHook(),
    beforeRender: new SyncHook(),
    render: new SyncHook(),
    afterRender: new SyncHook(),
    endFrame: new SyncHook(),
  };

  // 帧循环
  render(canvasConfig, renderingContext) {
    // 1. beginFrame
    // 2. 收集脏对象
    // 3. 排序 (z-index)
    // 4. 裁剪 (culling)
    // 5. 渲染可见对象
    // 6. endFrame
  }
}

3. 脏矩形 (Dirty Rectangle) 优化

当图形属性变化时,@antv/g 不会重绘整个画布,而是只重绘变化区域:

  1. 图形属性变化时标记为 "脏" (dirty)
  2. 计算脏图形的包围盒 (AABB)
  3. 合并重叠的脏矩形
  4. 只清除和重绘脏矩形区域内的图形

脏矩形优化使得 Canvas2D 渲染器在大量静态图形+少量动态图形的场景下性能提升数十倍。

4. 视锥裁剪 (Culling)

不在视口内的图形会被跳过渲染:

// Cullable 组件 (g-lite/src/components/Cullable.ts)
class Cullable {
  visible: boolean;    // 是否通过裁剪测试
  strategy: Strategy;  // 裁剪策略
}

5. Z-Index 排序

渲染顺序由 Sortable 组件控制:

// 设置 z-index
circle.style.zIndex = 10;
rect.style.zIndex = 5;
// circle 会渲染在 rect 上方

// 同级同 zIndex 时按添加顺序渲染

6. 多渲染器后端

渲染器包名技术适用场景
Canvas2Dg-canvasCanvasRenderingContext2D通用 2D,兼容性最好
SVGg-svgSVG DOM矢量输出、无障碍、SEO
WebGLg-webglWebGLRenderingContext大规模数据、3D、GPU 加速
WebGPUg-webgpuGPUDevice API下一代 GPU,最高性能
CanvasKitg-canvaskitSkia WASM高质量文本/路径渲染

7. AbstractRenderer 抽象层

所有渲染器都实现 AbstractRenderer 接口,通过插件组合构建能力:

// 源码: packages/g-lite/src/AbstractRenderer.ts
abstract class AbstractRenderer {
  // 插件列表
  private plugins: RendererPlugin[] = [];

  // 注册插件
  registerPlugin(plugin: RendererPlugin) { ... }

  // 获取所有插件
  getPlugins(): RendererPlugin[] { ... }
}

// 切换渲染器
import { Renderer as CanvasRenderer } from '@antv/g-canvas';
import { Renderer as SVGRenderer } from '@antv/g-svg';

// 只需更换 renderer 实例,业务代码无需修改
const canvas = new Canvas({
  renderer: new CanvasRenderer(), // 或 new SVGRenderer()
});

8. Hook 系统

渲染流水线的每个阶段都暴露 Hook,插件可以注入自定义逻辑(借鉴 Webpack Tapable):

// 插件注册 Hook
renderingService.hooks.beforeRender.tap('MyPlugin', () => {
  // 每帧渲染前执行
});

renderingService.hooks.afterRender.tap('MyPlugin', () => {
  // 每帧渲染后执行
});

// 画布级事件
canvas.addEventListener('beforerender', () => {});
canvas.addEventListener('afterrender', () => {});
canvas.addEventListener('rerender', () => {});

9. 渲染器各阶段插件

每个渲染器通过插件组合完成完整的渲染能力:

插件阶段职责
ContextRegisterPlugin初始化创建渲染上下文
DirtyCheckPluginBeginFrame收集脏对象
CullingPluginCull视锥/视口裁剪
CanvasRendererPluginRenderCanvas2D 图形绘制
CanvasPickerPluginPickCanvas2D 拾取
EventPluginEvent事件分发