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

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

导读

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

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

1

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

2_jpeg

3_jpeg

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

优化原理

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

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

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

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

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

工程实践

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

4

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

抗锯齿离屏渲染技术简述

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

5

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

优化对比

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

7

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

8

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

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

9

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

相关文章
|
5月前
|
人工智能 API Python
办公Agent如何真正提效?用数据对比说明:介入前后团队时间消耗变化
这是一份真实办公提效实验报告:20人团队引入办公Agent后,事务与沟通时间骤降56%,人均每周多出9小时有效工作时间。数据揭示——AI不替代人,而是接管填表、催办、写纪要等低价值衔接工作,让人回归核心创造。(239字)
488 7
|
JavaScript
56Vue - Props(camelCase vs. kebab-case)
56Vue - Props(camelCase vs. kebab-case)
165 0
|
存储
电感器的作用及其应用
一、电感器的基本原理 电感器是一种用于存储和释放电能的 passive 设备,它的基本原理是利用线圈中的电流产生磁场,从而储存电能。电感器由一个或多个线圈组成,线圈中的导线环绕在一个或多个磁性材料的芯上。当电流通过线圈时,磁场会在芯中产生,这个磁场会储存电能。 二、电感器的类型 根据电感器的结构和特性,可以将电感器分为多种类型。常见的电感器包括固定电感器、可变电感器和互感器。 1. 固定电感器:固定电感器是指电感值不可调节的电感器。它通常由线圈和磁性芯组成,线圈中的导线匝数和磁性芯的材料和形状决定了电感器的电感值。 2. 可变电感器:可变电感器是指电感值可调节的电感器。它通常由线圈和可移动的磁
562 0
|
9月前
|
人工智能 监控 架构师
AI Agent 职业路线体系化指南:从入门到资深的能力构建与跃迁路径
AI Agent时代正重塑技术职业路径:逻辑架构师、插件工程师、环境设计师成为新核心角色;需掌握长程任务设计、鲁棒容错、Token成本优化三大工程能力;分入门→行业落地→多Agent协同三阶段跃迁。拥抱阿里云生态,做AI的统筹者而非执行者。(239字)
621 0
|
自然语言处理 Java 编译器
语言处理程序
一、语言处理程序 语言处理程序是一种用于处理程序设计语言的软件工具。它们可以根据语言的语法和语义规则对程序进行解析、分析、优化和生成代码。常见的语言处理程序包括编译器、解释器和语法分析器。 1. 编译器:编译器是一种将高级程序设计语言(如C、C++、Java)编写的源代码转换为机器语言的语言处理程序。编译器通常包括以下几个阶段:词法分析、语法分析、语义分析、优化和代码生成。编译器将源代码转换为可执行文件,使得程序可以在计算机上直接运行。 2. 解释器:解释器是一种逐行解释和执行程序的语言处理程序。解释器将程序设计语言的源代码逐行解析并执行,而不需要将其转换为机器语言。解释器通常会在运行时进行解
715 1
|
监控 API 数据安全/隐私保护
小红书详情API接口的获取与应用
在互联网信息爆炸的时代,小红书凭借丰富的用户生成内容(UGC)和精准的推荐系统迅速崛起,成为重要的社区电商平台。为了帮助开发者高效利用平台数据,小红书开放平台提供了多种API接口,涵盖商品详情和笔记详情等。本文详细介绍了如何注册、申请权限、构建请求、处理响应及应用这些API接口,旨在为开发者提供全面的指南,助力数据驱动的决策与创新。
8049 1
|
Linux 开发者 异构计算
英特尔显卡+魔搭社区,一行命令快速部署本地大模型
近期,Intel和魔搭合作,在魔搭社区上线了Ollama 英特尔优化版镜像,该镜像提供基于 IPEX-LLM 的 Ollama 英特尔优化版,开发者可在英特尔GPU (如搭载集成显卡的个人电脑,Arc 独立显卡等) 上直接免安装运行 Ollama。
3752 3
|
供应链 搜索推荐 算法
淘宝电商运营的小秘籍,看完血赚。
在淘宝电商竞争激烈的环境中,掌握实用运营技巧是成功的关键。本文深入剖析了淘宝电商运营的五大核心策略:精准市场定位与选品、引人入胜的店铺装修、优质客户服务、灵活营销推广及数据驱动决策。通过这些技巧,你可以在淘宝平台上打造独具魅力的店铺,吸引更多流量和客户,实现销售业绩稳步增长,最终脱颖而出,成为知名品牌。
2049 10
|
存储 Linux Docker
Docker【部署 04】Docker Compose下载安装及实例Milvus Docker compose(CPU)使用说明分享
Docker【部署 04】Docker Compose下载安装及实例Milvus Docker compose(CPU)使用说明分享
3067 0
|
小程序
扫雷小游戏详解
扫雷小游戏详解
267 0

热门文章

最新文章