跳转到主要内容

性能

本节将讨论嵌入式图形用户界面的性能。

这里的高性能是指在获得所需图形效果和动画时实现高帧率。

我们回顾一下上一节中关于主循环如何影响用户界面帧率的内容。 再次假设有一台连接到LTDC的并行RGB显示屏和两个帧缓冲。 基本情况如下:

双帧缓冲

假设显示屏每秒刷新60次,则每次刷新之间的间隔约16 ms。 计算过程如下:1 s / 60 = 0.01667 s = 16.67 ms。

在1号帧缓冲的传输开始时,TouchGFX开始将1号帧绘制到2号帧缓冲。 如果1号帧的渲染在下一次传输开始前完成,则可以传输2号帧缓冲。 如果没有在16.67 ms内完成,则再次传输1号帧缓冲,并且显示屏的显示内容不变:

主循环时间超过16.67 ms

这种情况意味着丢帧。

采集和更新阶段的时间通常是极短的,如少于1 ms,在考虑主循环消耗的总时间时,多少有些微不足道。 因此,在下文和全文中,在考虑渲染时间时,其中包括采集和更新阶段。

如果许多帧的渲染时间超过16.67 ms的时限,显示屏上的帧率将是30帧每秒(fps)。

如果渲染时间大体上短于16.67 ms,但有一些帧超过16.67 ms,则平均帧率可能接近60 fps,但在用户看来动画可能不流畅。 动画中的某些步骤可能看起来过快而某些又过慢,具体取决于应用。 这不符合我们的期望。

渲染时间还可能更长。 如果刚好超过33 ms,由于每三次传输只有一个新帧就绪,帧率将降至20 fps。

FPS(帧率)最长渲染时间
6016.67 ms
3033.34 ms
2050.00 ms
1566.67 ms

此表显示了给定帧率可获得的最长渲染时间(包括采集和更新阶段)。

为了获得良好的用户界面性能,最好定期检查和监测帧率。 可使用两种方法:

  • 测量渲染时间
  • 丢帧计数

测量渲染时间

测量渲染时间的第一种方法提供了最详细的信息。 其理念实际上是测量从帧传输到渲染阶段结束之间的时间。 图形引擎在采集阶段开始时调用GPIO类的函数,并在渲染阶段结束时再次调用。 应用定义这些函数,并能钩子函数以便执行测量。

测量可通过两种方式来执行:

  • 使用外部计时设备,如示波器:为了使用示波器进行测量,应用应从GPIO接口实现set(GPIO_ID)clear(GPIO_ID)方法。 然后,示波器可以测量输出为高电平的持续时间,以此作为渲染时间。
  • 使用内部计时器:另一种方法是使用内部计时器,如sysTick计时器。 在调用GPIO::set(RENDER_TIME),应用可将计时器的值保存在变量中。 在进行清零调用时,应用可再次读取计时器并减去前值,从而获得渲染时间。 计时器的速度将决定测量精度。 应用必须以某种方式使渲染时间可见。 一种方式是将值保存在全局变量中,并且可以在界面上的TextArea中显示值。 也可使用调试器检查值。

丢帧计数

图形引擎对上一个采集-更新-渲染阶段中发生的传输次数进行计数。 应用可轻松地检查此值,以便了解是否丢帧以及帧率是否下降。

计数在HAL类中提供:

void handleTickEvent() {
tickCounter += 1;
if (HAL::getInstance()->getLCDRefreshCount() > 1) {
//Alert programmer somehow
...
}
}

丢帧补偿

如果丢帧且某个动画的帧率因此下降,可进行一定程度的补偿。 我们可以:

  • 等待其结束 - 让动画继续,这会导致动画持续时间变长,并且动画可能不流畅。
  • 跳过一些帧 - 通过跳帧确保整个动画的持续时间不会超过预定时间。

如果丢帧,可指示TouchGFX自动跳过一些帧。 可通过在每个实际帧将动画tick一次以上来实现。 当渲染时间不稳定时,这有助于让动画更流畅。

HAL.hpp
void setFrameRateCompensation(bool enabled)

影响渲染时间的因素有哪些?

影响渲染时间的因素有许多:更新部分的大小、分层的使用、控件的复杂度和渲染可使用的硬件支持。

界面更新了多少?

渲染时间通常与必须更新的像素数成正比。 如果动画需要的渲染时间过长,一种可能的解决办法是缩小动画面积。 例如,如果有一张旋转图像而性能不够好,则可通过缩小图像尺寸来改善性能。

通过缩小图像尺寸缩短渲染时间

记住,图形引擎会重绘应用使之无效的区域。 这意味着必须只使实际需要刷新的区域无效。

无效区域越大,渲染时间越长。

图形中的层数

在典型应用中,图形将包含彼此堆叠的不同元素。 如果更新了元素中的一个,通常必须重绘所有元素。

典型的例子是背景图像、帧和一些文本:

分层图形元素

此用户界面的创建方法是将TextArea控件放在显示了一个透明帧的Image控件上方。 二者都在背景图像上层:

TouchGFX Designer中的分层图形元素

此解决方案在应用中经常用到。 这是一种十分简单的解决方案,具有高度的灵活性,例如,可以在运行时间更改帧或在背景上移动帧和文本。

关于渲染时间的问题是如果在运行时间更新了文本且需要重绘,图形引擎还需要重绘背景和帧,然后是新的文本。 这会显著增加文本的渲染时间。

无效区域的层数越多,渲染时间就越长。

渲染像素的复杂度

将每个像素渲染到帧缓冲的难度并不一致。 在所有类型的渲染中,图形引擎必须将最终的像素写入帧缓冲。 但是,要写入像素的计算需要的消耗并不相同。

固定色彩(如Box Widget中使用的色彩)的消耗最低,只需计算一个像素并将结果重复用于所有像素。 这意味着使用许多Box可获得非常高的性能。 由于这会导致用户界面质量不高,因此不建议这样做。

第二低的是图像的像素计算消耗,这是因为像素均以可直接使用的格式存储在位图中。 计算要写入帧缓冲的像素关系到从位图中的正确位置加载色彩值。

文本的消耗与图像相当,每个字母实际上都是一幅小图像。 事实上,由于大量小图像导致了相当高的“开始-停止”消耗,因此文本的消耗更高。 例如,每个字母的位置计算。 为了让文本看起来尽可能美观,会将文本显示为具有透明度的小图像,请参见下文关于透明的注释。

旋转或缩放后的图像消耗更高。 任务同样是从位图加载像素值,但由于图形引擎必须包含缩放和旋转,因此这时的计算更耗时。

几何元素(如圆)的消耗比之更高。 这时我们不能从位图加载像素色彩,而是必须计算圆的形状和圆中每个像素的色彩。

透明度增加了元素的绘制消耗。 如果一些像素不是实心的,那么元素是透明的。 图形引擎首先必须绘制透明元素后方的元素(如“帧中的文本”部分所述),这会增加绘制的消耗。 其次,图形引擎随后必须将背景像素与透明元素的像素进行组合,并将结果写入帧缓冲。 此类计算的耗时显著多于只写入计算过的像素的场景。

Box、Image、旋转Image和圆。 实心元素位于第一行。 透明元素在下方。

透明总是需要多出一层。 但是,将实心像素放在其他实心像素的上方并不一定会增加层数。 图形引擎尽量不绘制被其他实心像素覆盖的像素,因为这是在浪费宝贵的时间。

无效区域中元素的复杂度越高,渲染时间就越长。

记住,只有无效区域中的元素才会增加渲染时间。 无效区域之外的元素对渲染时间无影响。

点击此处阅读关于UI组件和性能的更多内容。

渲染的硬件支持

一些STM32微控制器包含图形加速器Chrom-ART(或DMA2D)。 此加速器可缩短渲染时间。 由于加速器与微控制器核心并行运行,微控制器可以在加速器渲染图形时自由地运行其他任务。

Chrom-ART主要用于图像和文本。 如果有,图形引擎会自动使用它。

何时应考虑渲染时间

渲染时间并非总是那么重要。 当低帧率可被用户观察到时,应注意渲染时间。 当动画在屏幕的一部分上运行(如旋转的图标)或您在界面上移动或滑动某元素时,通常就属于这种情况。 如果更新频率低,那么在用户看来,动画将呈现出分步显示而非流畅的状态。 如果是这样,应检查渲染时间。

另一方面,如果用新界面替代整个界面,当更换期间帧率显著下降时,用户通常注意不到。 这是因为用户看不到渲染何时开始,只能看到它何时结束。

这两条规则意味着对于动画元素(如移动元素)而言,应使用较少的层数,避免使用复杂元素和许多层数。 对于界面的其余部分,这些不是问题。

模拟时钟和滚动列表

在本例中,左侧有一个模拟时钟。 通过旋转三幅细长的图像渲染三根指针。 这通常不难实现,因为指针并非总是在移动。 但如果我们要让时钟在界面上到处移动,将会在每一帧中重绘指针,由于绘制旋转图像通常比较耗时,因此会比较复杂。

右侧是一个滚动列表。 用户可以上下移动此数字列表,为了让用户界面显示出高响应性,需要高帧率。 因此,必须考虑滚动列表中元素的渲染时间,或者缩小滚动列表的尺寸。

通过使内容无效来优化性能

通常整个控件均无效,但图形引擎只能使控件的内容无效,而不能使整个控件无效。 通过减少无效区域,渲染时间一般会明显缩短。 渲染时间的改进取决于:

  • 控件内容覆盖的区域相对于整个控件的大小。
  • 背景控件部分或全部被控件覆盖。

下图以TextArea控件为例说明了内容无效的概念。 图1显示了控件的整个区域。 图2显示了使用TextArea::invalidate()时的无效区域。 图3显示了使用TextArea::invalidate()时的无效区域。

图1. 横跨整个屏幕宽度的文本区域

图2. 使用TextArea::invalidate()时无效的区域(红色)

图3. 使用TextArea::invalidateContent()时无效的区域(绿色)

使用TextArea::invalidateContent()的示例

在控件与其他控件重叠的情况下,使用TextArea::invalidate()使整个TextArea无效时,需要重新绘制其他控件。 通过改用TextArea::invalidateContent(),我们将不必要的无效和重绘控件的风险降至最低。 这对于昂贵的控件尤其如此,例如:圆、仪表等。

下图说明了如何避免使用TextArea::invalidateContent()使背景控件(图像-意法半导体标志)无效。 如果我们使用TextArea::invalidate(),将会使后台控件无效并重新绘制。

使用TextArea::invalidateContent()的示例

获得良好性能的建议

我们总结了获得良好性能的建议,以结束本节内容:

  • 不要重绘未更改的部分 确保没有误操作将界面上不必要的部分失效。 这会降低性能且无任何益处。
  • 在质量与速度之间寻求平衡 降低元素的复杂度有助于提高性能。 复杂度与性能之间的良好平衡通常极为关键。
  • 利用硬件能力 具有硬件加速(Chrom-ART)的微控制器的能力通常高于没有硬件加速的微控制器。 考虑使用具有Chrom-ART的微控制器。
  • 用图像替代计算图形 计算得到的圆比圆图像慢。 一般而言,图像可替代许多静态元素。
  • 调整显示屏刷新率 如本节开头所述,刷新率是渲染时间的硬性限制。 如果渲染时间超过刷新率,帧率将下降。 如果渲染时间只超过刷新率一点点,也许能够将显示屏的刷新率降至如55 Hz(相当于18.2 ms)这样的水平,并维持高帧率。

Graphics Accelerators

A common way to achieve high performance is to use an STM32 MCU with a graphics accelerator. The STM32 MCU family uses two graphics accelerators: DMA2D and GPU2D. The DMA2D IP is also called ChromART. The GPU2D IP is also called NeoChrom.

The DMA2D accelerator is capable of copying and blending images between the image storage and the frame buffer. The GPU2D can do the same, but is also capable of texture mapping and vector graphics.

DMA2D comes in 3 versions. DMA2D version 1 is available in many STM32 MCUs. The version 2 included in the STM32H7 family is capable of converting YCbCr data to RGB. This improves the JPEG decoding performance. DMA2D version 3 supports more image formats and down-scaling.

Compared to the DMA2D graphics accelerator NeoChrom is capable of accelerating more graphical operations and has a richer feature set:

Graphic featureDMA2DDMA2D v3GPU2D
Supported formats (with TouchGFX)ARGB8888, RGB888, RGB565, A8, A4, L8-888, L8-8888ARGB8888, RGB888, RGB565, A8, A4, A2, A1, L8-565, L8-888, L8-8888ARGB8888, RGB888, RGB565, A8, A4, A2, A1
Command list basedNoYesYes
DrawingRectanglesRectanglesRectangles, Pixels, Line, Triangle, Quadrilaterals with multi-sample anti-aliasing (MSAA)
BlittingCopy, alpha blending, pixel format conversionCopy, alpha blending, pixel format conversionCopy, alpha blending, pixel format conversion, color keying
ScalingNoYes (nearest neighbor)Yes
Texture MappingNoNoYes
Vector GraphicsNoNoNo*

* Vector Graphics are partially hardware-accelerated with NeoChrom when using TouchGFX. Full hardware acceleration for Vector Graphics is available with NeoChromVG.

With these capabilities available many TouchGFX Widgets are accelerated:

WidgetDMA2DDMA2D v3GPU2D
Box, BoxWithBorderYesYesYes
Image, AnimatedImage, TiledImage, SnapshotWidgetYesYesYes
Button, ButtonWithIcon, ButtonWithLabel, ToggleButtonYesYesYes
RadioButton, RepeatButtonYesYesYes
PixelDataWidgetYesYesYes
TextArea, TextAreaWithWildcard, KeyboardPartlyYesYes
ScalableImageNoPartlyYes
TextureMapper, AnimatedTextureMapperNoNoYes
Circle, Line, Graph, GaugeNo*No*No*
SVGNo*No*No**

* The drawing/blending of pixels to the framebuffer is done by DMA2D, but the shape calculations are done in software.
** Hardware accelerated SVG drawing is available with NeoChromVG.

The operations that are not hardware accelerated are software rendered (implying a higher CPU-load, and lower performance). As the table above shows, NeoChrom can accelerate widgets like ScalableImage and TextureMapper. This means that we can use those widgets to a greater extent while keeping a high performance.

Read more about TouchGFX with NeoChrom here.