优化基于 OpenGL 的动画/可缩放 2D UI 渲染的策略

Tay*_*lor 5 gpu 2d opengl-es mipmaps

我已经为我的应用程序的 UI 构建了一个基于场景图的渲染系统(如果您好奇,请访问http://audulus.com)。该应用程序的 UI 是程序化的,其中很多都是动画的。很少有预渲染的图像。

目前,它在 mipmapped 纹理中缓存不变的可绘制组。我使用 mipmap 是因为 UI 是可缩放的。总的来说,这是一个巨大的性能胜利,但有几个缺点:

  1. 构建 mipmap(通过 glGenerateMipmap)需要时间,当 UI 的一部分从动画变为静态时会降低帧速率。

  2. 纹理缓存几何体与未缓存几何体之间的视觉差异,导致轻微闪烁。(也许可以通过更聪明地处理我的路径渲染代码来解决这个问题,但这似乎很难)

  3. 所有纹理的内存使用情况(我可以转储屏幕外的纹理,但这会加剧问题 1)

我想到的几种替代方法:

  1. 代替纹理缓存,将静态路径合并为更大的路径。我的路径已经基于 VBO/VAO,但这可以减少 GL 调用的数量。(关闭纹理缓存时,我的性能主要受 CPU 限制)。在内存使用方面大获全胜。这种方法的主要问题是:使我的路径渲染着色器复杂化(因为它必须在对 glDrawArrays 的一次调用中处理具有不同属性的路径),不处理其他基元(例如文本)的缓存,以及更多的 GPU 负担而不是简单地渲染纹理。

  2. 仍然使用纹理,但避免 mip-mapping。随着 UI 缩放,纹理可以调整大小(尽管这可能不得不推迟,因为在缩放期间重新渲染整个 UI 成本太高)。删除屏幕外几何体的纹理。缺点当然是在 UI 缩放过程中纹理放大/缩小效果不佳。

更新

我试过(2)。调整纹理的大小很慢,所以我阻止 UI 在缩放过程中调整它们的大小。这工作得相当好,但是当缩放开始很小时,放大倍数看起来很糟糕:

放大倍率不佳

请注意,某些模块没有纹理缓存,因为它们被标记为动画。

更新 2

我开始研究方法 1,所以我停用了纹理缓存。

尽管我受 CPU 限制,但实际上我所有的 GPU 端负载都来自我的路径抗锯齿片段着色器。这是它的性能:

Path-AA 着色器处于活动状态时的性能

关闭它:

禁用 Path-AA 着色器的性能

因此,进一步优化将是 GPU 方面的一大胜利。我尝试放弃它并使用 4x 超级采样,但这看起来很垃圾,提醒我为什么我花了大量时间在路径渲染着色器上。

Tay*_*lor 0

方法(1)是一个巨大的胜利。它具有与纹理缓存基本相同的性能,但没有任何视觉伪影或大量内存使用。

在此输入图像描述