离屏渲染在车载导航中的应用

作者 : 开心源码 本文共3370个字,预计阅读时间需要9分钟 发布时间: 2022-05-13 共216人阅读

导读

与手机导航不同,高德地图的车机版(AMAP AUTO)直接面对各大车厂和众多设施商。这些B端客户采用的硬件参数参差不齐,提出的业务需求涉及到渲染中诸多复杂技术的应用,这对渲染性能提出了极高的要求。

最初车机版沿用手机版的当前屏渲染模式,每一帧都需要实时的将地图元素渲染出来。但在业务实践过程中,我们发现在多屏渲染和多视图渲染场景下,CPU负载急剧增高。以鹰眼图场景为例,在鹰眼图场景下,地图存在多视图渲染的状态:一张是主地图,一张是鹰眼小地图,因而渲染引擎同时渲染了两个地图实例对象,下图右下角即为鹰眼图:

鹰眼图绘制后,平均帧率下降了2帧,如下图所示:

针对上述情况,除了对渲染细节、批次和纹理等进行常规优化外,我们还需要寻觅一种全局性的技术优化手段,大幅度提升引擎的渲染性能。为此,我们深入地研究了离屏渲染技术,并结合导航业务,提出了一种基于离屏渲染技术对特定地图的视图进行性能优化的方法。

优化原理

在OpenGL的渲染管线中,几何数据和纹理通过一系列变换和测试,最终被渲染成屏幕上的二维像素。那些用于存储颜色值和测试结果的二维数组被称为帧缓冲区。当我们创立了一个供OpenGL绘制用的窗体后,窗体系统会生成一个默认的帧缓冲区,这个帧缓冲区完全由窗体系统管理,且仅用于将渲染后的图像输出到窗口的显示区域。我们也可以使用在当前屏幕缓冲区以外开拓一个缓冲区进渲染操作。前者即为当前屏渲染,后者为离屏渲染。

与当前屏渲染相比,离屏渲染:

  • 在变化的场景下,由于离屏渲染需要创立一个新的缓冲区,且需要屡次切换上下文环境,所以代价很高;
  • 在稳固的场景下,离屏渲染可以采用一张纹理进行渲染,所以性能较当前屏渲染有较大提升。

从上述比照可以看出,在稳固场景下使用离屏渲染的优势较大。但由于地图状态随时都在变化,所以地图渲染通常处于前端动态渲染状态。那么有没有相对稳固的场景呢?答案是一定的,我们将地图的状态分为沉迷态和非沉迷态。顾名思义,在地图处于变化状态的称为非沉迷态,进入稳固状态称为沉迷态。

进入沉迷态的地图,为我们使用离屏渲染提供了条件。经过统计,地图处于前端状态的场景下,沉迷态时间基本上和非沉迷态时间相当,这样我们采用一张纹理,就可将处于非沉迷态场景下的地图渲染出来,大大降低了系统开销。在鹰眼图,矢量路口大图等特定的视图场景下,地图基本上均处于沉迷态。所以这些视图下采用离屏渲染技术进行优化,获得的收益将是巨大的。

工程实践

将以上的技术优化原理,代入到实际的导航应用中,流程如下:

离屏渲染通常使用FBO实现。FBO就是Frame Buffer Object,它可以让我们的渲染不渲染到屏幕上,而是渲染到离屏Buffer中。但是通常的离屏渲染FBO对象不具有抗锯齿能力,因而开启了全屏抗锯齿能力的OpenGL应用程序,假如采用离屏渲染FBO对象进行离屏渲染,会出现锯齿现象。而在非沉迷态地图的状态下,是开启全屏抗锯齿能力的,所以我们必需使用具有抗锯齿能力的离屏渲染技术来进行地图渲染技术优化。

抗锯齿离屏渲染技术简述

本节以iOS系统为例,对抗锯齿能力的离屏渲染技术进行简述。iOS系统对OpenGL进行了深度定制,其抗锯齿能力就是建立在FBO基础上的。如下图所示,IOS基于对抗锯齿的帧缓存(FBO)对象进行操作,从而达到全屏抗锯齿的目的:

接下来具体详情抗锯齿FBO的创立步骤:

  • 创立FBO并绑定:
GLuint sampleFramebuffer;glGenFramebuffers(1, &sampleFramebuffer);glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);
  • 创立一个颜色帧缓冲区,在显存中开拓一个具备抗锯齿能力的对象,并将颜色缓冲区挂载到开拓的对象上。创立一个深度模版渲染缓冲区,开拓具备抗锯齿能力的显存空间,并和帧缓冲区进行绑定:
GLuint sampleColorRenderbuffer, sampleDepthRenderbuffer;glGenRenderbuffers(1, &sampleColorRenderbuffer);glBindRenderbuffer(GL_RENDERBUFFER, sampleColorRenderbuffer);glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, width, height);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sampleColorRenderbuffer);glGenRenderbuffers(1, &sampleDepthRenderbuffer);glBindRenderbuffer(GL_RENDERBUFFER, sampleDepthRenderbuffer);glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, sampleDepthRenderbuffer);
  • 测试创立的环境能否正确,避免如显存空间不足等造成创立失败的可能:
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;if(status != GL_FRAMEBUFFER_COMPLETE) {  return false;}

至此,一个具有抗锯齿能力的离屏FBO已创立好,下面将应用这个FBO,步骤如下:

  • 先清理抗锯齿帧缓存空间重的内容:
glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glViewport(0, 0, framebufferWidth, framebufferHeight);
  • 开始进行一系列的渲染函数操作,比方准备顶点数据,纹理数据,VBO,IBO,矩阵,状态等,并执行一系列的渲染指令,选择指定的shader,及其传输数据状态;
  • FBO不是一个具有直接渲染能力的帧缓存空间,在执行完2的操作之后,需要将抗锯齿的FBO内渲染的内容通过合并每个像素,转换到屏幕渲染所在的帧缓存空间去。原理如下图所示:

代码如下:

glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, resolveFrameBuffer);glResolveMultisampleFramebufferAPPLE();glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, sampleFramebuffer);
  • 以上操作完成后,需要进行少量Discard步骤, 将少量原价在当前帧缓存中的内容忽略掉:
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);[context presentRenderbuffer:GL_RENDERBUFFER];

Android系统基本思路一致,需要采用gles3.0接口提供的抗锯齿能力来进行渲染,在此不做开展。

优化比照

优化前的鹰眼图渲染耗时火焰图如下:

优化后的鹰眼图渲染耗时火焰图如下:

从前后比照图可以看出,鹰眼图渲染的耗时,几乎已经消失不见。

从系统的渲染帧率上进一步得到验证。从下图可以看出帧率已经恢复到与不显示鹰眼图的情况相当:

需要注意的是,全屏抗锯齿损耗资源,除了添加额外的显存空间,抗锯齿过程中也会产生肯定的耗时。所以在获得收益的同时,也需要衡量其产生的代价,需要具体问题具体分析。在本案例中,如比照结果所示,采用抗锯齿离屏渲染技术的优化产生的收益远远高于付出的代价。


本文作者:高德技术小哥

阅读原文

本文为云栖社区原创内容,未经允许不得转载。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 离屏渲染在车载导航中的应用

发表回复