2. TouchGFX基础回顾

在进入资源与内存优化之前,必须先建立一张清晰的“全局地图”:TouchGFX 到底由哪些部分组成、一帧画面是怎样被渲染出来的、工程里有哪些资源类型、它们分别被放在哪块内存区域。只有把这条链路看清楚,后续的裁剪、压缩、缓存与搬运策略才有依据。

一、TouchGFX 的整体架构

TouchGFX 采用典型的“分层 + 生成代码”架构,自上而下大致分为四层:

  • 应用层(Application):由你在 TouchGFX Designer 中搭建的 Screen、View、Presenter 以及自定义 Widget 组成,负责界面逻辑与交互。
  • 框架层(Framework):包含 Model-View-Presenter(MVP)机制、Screen 管理器、事件分发、动画与过渡(Transition)、Timer、Easing 等。
  • 渲染层(Renderer):负责把 Widget 树绘制成像素,包含 Canvas Widget Renderer(CWR)、LCD24bpp、LCD16bpp 等不同渲染器,以及位图缓存(Bitmap Cache)与脏矩形(Dirty Rectangle)机制。
  • 硬件抽象层(HAL / OSAL):包括 LCD 驱动、DMA2D/GPU 加速接口、触摸驱动、OS 抽象层(FreeRTOS 或裸机),由开发者按板级实现。

关键点在于:TouchGFX Designer 生成的代码与手写代码是分离的。Designer 生成 generated/ 目录下的 Screen 基类、资源描述与字体/图片索引,而你的业务逻辑写在 gui/ 目录中。理解这一点,才能判断哪些资源是“自动生成、可被优化”的,哪些是“手写、需自行管理”的。

二、一帧画面的渲染流程

TouchGFX 不是每帧全屏重绘,而是基于“脏矩形 + 位图缓存”的增量渲染。典型流程如下:

  1. 主循环调用 handleTickEvent(),推进动画与定时器。
  2. 框架收集本帧需要重绘的区域,合并为脏矩形列表。
  3. 对每个脏矩形,遍历覆盖它的 Widget 树,按 Z 序从底到顶绘制。
  4. 若 Widget 是图片或文字,优先从位图缓存中取已渲染好的位图;未命中则调用渲染器绘制并写回缓存。
  5. 渲染结果写入帧缓冲区(Frame Buffer),再由 LCD 驱动或 DMA2D 搬运到屏幕。

因此,位图缓存大小、脏矩形数量、是否启用 DMA2D 会直接决定 CPU 占用与帧率。缓存越大,重复绘制越少,但 RAM 消耗越高——这正是后续优化的核心矛盾之一。

TouchGFX 架构与一帧渲染数据流 应用层 Screen / View Presenter / Widget 框架层 MVP / Screen 管理 事件 / 动画 / 过渡 渲染层 CWR / LCD16bpp 脏矩形 / 位图缓存 HAL / OSAL LCD / DMA2D 触摸 / FreeRTOS 一帧渲染流程 handleTick 推进动画 收集脏矩形 合并区域 遍历 Widget 按 Z 序绘制 位图缓存 命中/回写 帧缓冲 → LCD DMA2D 搬运 典型内存区域划分 Flash:代码 + 常量资源 字体 / 图片 / 文本 内部 SRAM:栈/堆 帧缓冲 / 位图缓存 外部 SDRAM/PSRAM 大图 / 多帧缓冲 外部 Flash / QSPI 压缩资源 / 字库

三、资源类型与内存区域划分

TouchGFX 工程中的资源大致可分为四类,它们对内存的诉求完全不同:

资源类型 典型内容 默认存放区域 优化关注点
图片资源 PNG/JPG 转换后的位图、Alpha 通道 Flash(常量)→ 运行时可能解压到 RAM 色深、压缩格式、是否常驻缓存
字体资源 点阵字库、字符映射表 Flash 字符集裁剪、字号数量、是否启用压缩
文本资源 多语言字符串表 Flash 语言数量、是否按需加载
运行时缓冲 帧缓冲、位图缓存、Widget 对象 内部 SRAM / 外部 SDRAM 缓存大小、双缓冲策略、对象生命周期

需要特别注意的是:“资源放在 Flash”并不等于“不占 RAM”。很多图片在绘制时需要先解压到 RAM 中的位图缓存,字体在渲染时也要生成字形位图。因此,Flash 占用与 RAM 占用必须分开评估。

四、典型应用场景与常见误区

TouchGFX 常见于以下场景:

  • 家电 HMI:屏幕小、资源少,重点在 Flash 裁剪与低 RAM 占用。
  • 工业控制面板:多语言、多状态图标,重点在字体与图片的按需加载。
  • 智能穿戴:分辨率高但 RAM 极小,必须依赖外部 Flash 与压缩资源。
  • 汽车仪表:高帧率、多图层,重点在 DMA2D 加速与双帧缓冲。
常见误区:很多开发者只关注 Flash 占用,却忽略了位图缓存和帧缓冲对 RAM 的消耗。实际项目中,RAM 往往比 Flash 更早成为瓶颈。另一个误区是盲目增大位图缓存,导致内部 SRAM 被占满,反而引发栈溢出或分配失败。
复盘建议:在优化前,先用 TouchGFX Designer 的“资源报告”和链接脚本的 .map 文件,分别统计 Flash 与 RAM 的实际占用。把资源按“常驻 / 按需 / 可压缩”三类标记,再决定哪些放内部 SRAM、哪些放外部 SDRAM、哪些保留在 Flash 中按需解压。
// 典型链接脚本片段:把 TouchGFX 资源与缓冲分区
MEMORY
{
  FLASH  (rx)  : ORIGIN = 0x08000000, LENGTH = 1024K
  SRAM   (rwx) : ORIGIN = 0x20000000, LENGTH = 256K
  SDRAM  (rwx) : ORIGIN = 0xC0000000, LENGTH = 8M
}

SECTIONS
{
  .touchgfx_res : { *(.touchgfx_res*) } > FLASH
  .framebuffer  : { *(.framebuffer*)  } > SDRAM
  .bitmap_cache : { *(.bitmap_cache*) } > SDRAM
}

理解架构、渲染流程、资源类型与内存区域划分,是后续所有优化动作的起点。只有先明确“谁在什么时候、从哪块内存、取什么资源、画到哪里”,才能有针对性地做减法与搬运。