TGFX - 腾讯开源的轻量级 2D 渲染引擎

TGFX - 腾讯开源的轻量级 2D 渲染引擎

  • 首页
  • 下载
  • 文档
  • 案例
  • CN
  • GitHub
  • 论坛交流
  • Languages iconCN
    • EN

›绘图基础

快速开始

  • TGFX 简介
  • 平台与后端支持
  • 环境准备与编译
  • Hello2D 示例

API 参考与概述

    绘图基础

    • Canvas Overview
    • Paint Overview
    • Path Overview
    • BlendMode Overview
    • Picture 录制与回放

    几何与变换

    • 几何与变换

    图像与像素

    • Image
    • Bitmap 与像素操作
    • 图像编解码
    • 视频与外部纹理

    文本渲染

    • 文本与字体

    着色与效果

    • 着色与效果

    图层系统

    • 图层系统

    进阶主题

    • 自定义 Shader
    • 色彩管理

架构设计

  • 渲染管线
  • GPU 硬件抽象层
  • 图层渲染系统
  • 缓存系统
  • 文字图集渲染
  • GPU Hairline 极细描边
  • 广色域渲染
  • SIMD 加速

API 文档

  • API 文档

Picture 录制与回放

Picture 是 tgfx 提供的绘图命令录制与回放机制。通过 Picture,你可以将一系列绘图命令录制下来,之后在任意 Canvas 上多次回放,实现"录制一次、多次使用"的高效渲染模式。


1. 概述

1.1 什么是 Picture

Picture 是一个不可变的绘图命令集合。它捕获了在 Canvas 上执行的所有绘图操作(如 drawRect、drawPath、drawImage 等),并可以在之后的任意时刻回放这些命令。

1.2 核心价值

特性说明
命令复用复杂的绘图序列只需录制一次,可多次回放
线程安全Picture 一旦创建即不可变,可安全地在多线程间共享
延迟渲染录制时不执行实际渲染,回放时才真正绑定
转换灵活可转换为 Image 用于后续合成或缓存

1.3 典型应用场景

  • 重复元素绘制:如列表项、图标、徽章等需要多次绘制的内容
  • 复杂图形缓存:将计算开销大的绘制序列缓存为 Picture
  • 跨 Surface 复用:同一 Picture 可以在不同 Surface 的 Canvas 上回放

2. 录制流程

Picture 的录制遵循 PictureRecorder → Canvas → Picture 的流程:

Picture 录制流程

2.1 基本录制步骤

int main() {
    // 1. 创建 PictureRecorder
    PictureRecorder recorder;
    
    // 2. 开始录制,获取录制用的 Canvas
    Canvas* canvas = recorder.beginRecording();
    
    // 3. 在 Canvas 上执行绑定命令(这些命令会被录制)
    Paint paint;
    paint.setColor(Color::Blue());
    canvas->drawRect(Rect::MakeXYWH(0, 0, 100, 100), paint);
    canvas->drawCircle(50, 50, 30, paint);
    
    // 4. 结束录制,获取 Picture
    auto picture = recorder.finishRecordingAsPicture();
    
    // picture 现在包含了上述所有绘图命令
    return 0;
}

2.2 API 说明

方法说明
beginRecording()开始录制,返回用于录制的 Canvas。如果已在录制中,会清空现有命令重新开始
getRecordingCanvas()获取当前正在录制的 Canvas,如果未在录制中返回 nullptr
finishRecordingAsPicture()结束录制并返回 Picture。如果未录制任何命令,返回 nullptr

2.3 注意事项

  • 录制 Canvas 由 PictureRecorder 管理,不要手动删除
  • 录制过程中可以使用 Canvas 的所有绑定 API,包括 save()/restore()、变换、裁剪等
  • 录制的命令不会立即执行,只有在回放时才会真正渲染

3. Picture 回放

Canvas 提供两种 drawPicture 重载来回放 Picture:

Picture 回放流程

3.1 简单回放

直接将 Picture 的内容绘制到当前 Canvas,使用 Canvas 当前的裁剪区域和变换矩阵:

void drawPicture(std::shared_ptr<Picture> picture);

示例:

int main() {
    // 假设 picture 已通过 PictureRecorder 录制
    auto picture = createPicture();
    
    // 获取目标 Canvas
    auto canvas = surface->getCanvas();
    
    // 直接回放 Picture
    canvas->drawPicture(picture);
    
    return 0;
}

3.2 带变换和属性的回放

支持在回放时应用额外的变换矩阵和 Paint 属性:

void drawPicture(std::shared_ptr<Picture> picture, 
                 const Matrix* matrix, 
                 const Paint* paint);
参数说明
matrix额外的变换矩阵,与 Canvas 当前矩阵组合使用。传 nullptr 表示不额外变换
paintPaint 属性(如透明度、滤镜等)。传 nullptr 表示不应用额外属性

重要:如果提供了 paint 参数,Picture 会先绘制到一个临时图层,再应用 Paint 属性后渲染到目标 Canvas。

示例:

int main() {
    auto picture = createPicture();
    auto canvas = surface->getCanvas();
    
    // 带缩放变换回放
    Matrix scale = Matrix::MakeScale(2.0f, 2.0f);
    canvas->drawPicture(picture, &scale, nullptr);
    
    // 带半透明效果回放
    Paint paint;
    paint.setAlpha(0.5f);
    canvas->drawPicture(picture, nullptr, &paint);
    
    // 同时应用变换和透明度
    Matrix translate = Matrix::MakeTrans(100, 100);
    canvas->drawPicture(picture, &translate, &paint);
    
    return 0;
}

3.3 回放 vs playback

Picture 还有一个 playback() 方法,它与 drawPicture() 的区别是:

方法行为
canvas->drawPicture(picture)作为单个绘制命令添加到 Canvas,Canvas 的状态不受 Picture 内容影响
picture->playback(canvas)将 Picture 中的命令逐个发送到 Canvas,如同直接在 Canvas 上执行

一般情况下推荐使用 drawPicture(),因为它会自动保护 Canvas 的状态。


4. 缓存与性能优化

4.1 录制一次、多次回放

Picture 的核心价值在于将绘图命令的构建与执行分离。对于需要重复绘制的内容,只需录制一次:

int main() {
    // 录制一个复杂的图标
    auto iconPicture = recordIcon();
    
    auto canvas = surface->getCanvas();
    
    // 在多个位置绘制同一个图标
    for (int i = 0; i < 100; i++) {
        canvas->save();
        canvas->translate(i * 50.0f, 0);
        canvas->drawPicture(iconPicture);
        canvas->restore();
    }
    
    return 0;
}

std::shared_ptr<Picture> recordIcon() {
    PictureRecorder recorder;
    auto canvas = recorder.beginRecording();
    
    // 绘制复杂图标(假设有很多绘制调用)
    Paint paint;
    paint.setColor(Color::Red());
    canvas->drawCircle(20, 20, 18, paint);
    
    paint.setColor(Color::White());
    canvas->drawRect(Rect::MakeXYWH(15, 10, 10, 20), paint);
    
    return recorder.finishRecordingAsPicture();
}

4.2 适用场景分析

场景是否推荐使用 Picture
重复绘制相同内容✅ 强烈推荐
复杂路径/形状组合✅ 推荐
动态变化的内容❌ 不推荐(每帧都需重新录制)
简单的单次绘制❌ 不推荐(增加额外开销)

4.3 内存与性能权衡

  • 内存:Picture 会持有录制时引用的资源(如 Image、Path 等)
  • 线程安全:Picture 创建后不可变,可安全跨线程使用
  • GPU 资源:Picture 本身不占用 GPU 资源,回放时才会使用

5. Picture 转 Image

通过 Image::MakeFrom() 可以将 Picture 转换为 Image,适用于需要将绘制结果作为纹理使用的场景:

static std::shared_ptr<Image> MakeFrom(
    std::shared_ptr<Picture> picture, 
    int width, 
    int height,
    const Matrix* matrix = nullptr,
    std::shared_ptr<ColorSpace> colorSpace = nullptr);

5.1 基本用法

int main() {
    // 录制 Picture
    auto picture = recordComplexGraphics();
    
    // 将 Picture 转换为 200x200 的 Image
    auto image = Image::MakeFrom(picture, 200, 200);
    
    // 现在可以像使用普通 Image 一样使用它
    auto canvas = surface->getCanvas();
    canvas->drawImage(image, 0, 0);
    
    return 0;
}

5.2 带变换的转换

可以在转换时应用变换矩阵,调整 Picture 在 Image 中的位置和大小:

int main() {
    auto picture = recordComplexGraphics();
    
    // 将 Picture 缩放 0.5 倍后转为 Image
    Matrix scale = Matrix::MakeScale(0.5f, 0.5f);
    auto image = Image::MakeFrom(picture, 100, 100, &scale);
    
    return 0;
}

5.3 应用场景

  • 纹理缓存:将复杂绘制转为 Image 后作为纹理重复使用
  • 离屏渲染:先渲染到 Picture,再转为 Image 进行后续合成
  • 截图功能:捕获绘制内容并导出

6. 高级用法

6.1 AbortCallback 中断回放

Picture 支持通过回调在回放过程中中断:

class MyAbortCallback : public Picture::AbortCallback {
public:
    bool abort() override {
        // 返回 true 会立即中断回放
        return shouldStop;
    }
    
    bool shouldStop = false;
};

int main() {
    auto picture = recordPicture();
    auto canvas = surface->getCanvas();
    
    MyAbortCallback callback;
    // 可以在另一个线程中设置 callback.shouldStop = true 来中断
    picture->playback(canvas, &callback);
    
    return 0;
}

6.2 获取边界信息

int main() {
    auto picture = recordPicture();
    
    // 获取 Picture 的边界框
    Rect bounds = picture->getBounds();
    
    // 检查是否包含无界填充(如反向路径填充)
    bool hasUnbounded = picture->hasUnboundedFill();
    
    return 0;
}

注意:getBounds() 返回的边界仅包含绘制命令的几何范围。如果 hasUnboundedFill() 返回 true,表示实际绘制可能超出此边界。

← BlendMode Overview几何与变换 →
  • 1. 概述
    • 1.1 什么是 Picture
    • 1.2 核心价值
    • 1.3 典型应用场景
  • 2. 录制流程
    • 2.1 基本录制步骤
    • 2.2 API 说明
    • 2.3 注意事项
  • 3. Picture 回放
    • 3.1 简单回放
    • 3.2 带变换和属性的回放
    • 3.3 回放 vs playback
  • 4. 缓存与性能优化
    • 4.1 录制一次、多次回放
    • 4.2 适用场景分析
    • 4.3 内存与性能权衡
  • 5. Picture 转 Image
    • 5.1 基本用法
    • 5.2 带变换的转换
    • 5.3 应用场景
  • 6. 高级用法
    • 6.1 AbortCallback 中断回放
    • 6.2 获取边界信息
公司地址:广东省深圳市南山区海天二路33号腾讯滨海大厦Copyright © 2018 - 2026 Tencent. All Rights Reserved.联系电话:0755-86013388隐私政策