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

2019 年 8 月 15 日

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

1. 导读


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


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



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




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


2. 优化原理


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


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


  • 在变化的场景下,因为离屏渲染需要创建一个新的缓冲区,且需要多次切换上下文环境,所以代价很高;

  • 在稳定的场景下,离屏渲染可以采用一张纹理进行渲染,所以性能较当前屏渲染有较大提升。


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


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


3. 工程实践


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



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


4. 抗锯齿离屏渲染技术简述


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



接下来具体介绍抗锯齿 FBO 的创建步骤:


  • 创建FBO并绑定:


GLuint sampleFramebuffer;glGenFramebuffers(1, &sampleFramebuffer);glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);
复制代码


<ulclass=“list-paddingleft-2"style=”">


  • 创建一个颜色帧缓冲区,在显存中开辟一个具有抗锯齿能力的对象,并将颜色缓冲区挂载到开辟的对象上。创建一个深度模版渲染缓冲区,开辟具有抗锯齿能力的显存空间,并和帧缓冲区进行绑定:


  • 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,
    

  • 测试创建的环境是否正确,避免如显存空间不足等造成创建失败的可能:


  • 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接口提供的抗锯齿能力来进行渲染,在此不做展开。


  • 5. 优化对比



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




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




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


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




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


  • 本文转载自公众号高德技术(ID:amap_tech)


  • 原文链接


  • https://mp.weixin.qq.com/s/0Va3RXx5Pv0H9gX3d3Tp1w


  • 2019 年 8 月 15 日 08:00799

    评论

    发布
    暂无评论
    发现更多内容

    HTML5+CSS3前端入门教程---从0开始通过一个商城实例手把手教你学习PC端和移动端页面开发第7章定位

    Geek_8dbdc1

    超市趣味游戏关卡设计

    孙志平

    面经手册 · 第4篇《HashMap数据插入、查找、删除、遍历,源码分析》

    小傅哥

    Java 小傅哥 hashmap 面经 红黑树

    哈希算法的设计要点、应用场景

    多选参数

    哈希 hash 哈希算法

    为什么需要企业架构师?

    周金根

    React TypeScript项目基本构建

    JackWangGeek

    合约跟单软件开发app,跟单系统开发功能和优势

    WX13823153201

    区块链 数字货币

    微服务框架 Dubbo

    莫莫大人

    极客大学架构师训练营

    安卓移动应用代码安全加固系统设计及实现

    几维安全

    android 安全评估 移动应用安全

    192.168.52.165/25是啥意思?

    书旅

    IP 网络 CIDR

    架构师0期第十周命题作业

    何伟敏

    libuv 异步网络编程之 TCP 源码分析

    Huayra

    网络编程 libuv libuv 源码分析

    工业互联网网络安全渗透测试技术研究

    几维安全

    网络安全 数据安全;工业互联网 移动应用安全 渗透测试

    如何让“哑”终端进化,你知道吗?

    华为云开发者社区

    操作系统 物联网 IoT 华为云 LiteOS

    HTML5+CSS3前端入门教程---从0开始通过一个商城实例手把手教你学习PC端和移动端页面开发第8章FlexBox布局

    Geek_8dbdc1

    OpenTSDB 数据存储详解

    vivo互联网技术

    数据库 时序数据库

    Week10作业1

    熊威

    巴黎世家土味病毒营销,B端创业初期,如何用营销壮大种子用户?

    北柯

    创业 营销 tob

    肯耐珂萨D1轮融资资方阵营揭晓,跟投方为中南资本、青发集团

    人称T客

    React TypeScript 项目基本构建2

    JackWangGeek

    React

    HTML5+CSS3前端入门教程---从0开始通过一个商城实例手把手教你学习PC端和移动端页面开发第6章表格与表单

    Geek_8dbdc1

    前端科普系列(1):前端简史

    vivo互联网技术

    html 前端 Web

    拼多多员工曝离职黑幕:要走可以,要离职证明,没有!

    程序员生活志

    职场 互联网公司

    HTML5+CSS3前端入门教程---从0开始通过一个商城实例手把手教你学习PC端和移动端页面开发第9章FlexBox实战有路网

    Geek_8dbdc1

    全民加速节:全站加速在游戏行业的最佳实践

    巨侠说

    CDN 动态加速

    Week10总结

    熊威

    智能汽车安全风险及防护技术分析

    几维安全

    移动应用安全

    易观方舟70秒可视化埋点SDK全部开源!

    易观大数据

    埋点

    怎么写一个超棒的 README 文档

    程序员生活志

    经验总结 文档

    第十周学习总结

    菲尼克斯

    Spark优化之小文件是否需要合并?

    华为云开发者社区

    spark 数据 cpu 内存 Spark调优

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