与手机导航不一样,高德地图的车机版(AMAP AUTO)直接面对各大车厂和众多设备商。这些B端用户采用的硬件参数良莠不齐,提出的业务需求涉及到渲染中诸多复杂技术的应用,这对渲染性能提出了极高的要求。数组
最初车机版沿用手机版的当前屏渲染模式,每一帧都须要实时的将地图元素渲染出来。但在业务实践过程当中,咱们发如今多屏渲染和多视图渲染场景下,CPU负载急剧增高。以鹰眼图场景为例,在鹰眼图场景下,地图存在多视图渲染的状态:一张是主地图,一张是鹰眼小地图,所以渲染引擎同时渲染了两个地图实例对象,下图右下角即为鹰眼图:缓存
鹰眼图绘制后,平均帧率降低了2帧,以下图所示:性能优化
针对上述状况,除了对渲染细节、批次和纹理等进行常规优化外,咱们还须要寻找一种全局性的技术优化手段,大幅度提高引擎的渲染性能。为此,咱们深刻地研究了离屏渲染技术,并结合导航业务,提出了一种基于离屏渲染技术对特定地图的视图进行性能优化的方法。bash
在OpenGL的渲染管线中,几何数据和纹理经过一系列变换和测试,最终被渲染成屏幕上的二维像素。那些用于存储颜色值和测试结果的二维数组被称为帧缓冲区。当咱们建立了一个供OpenGL绘制用的窗体后,窗体系统会生成一个默认的帧缓冲区,这个帧缓冲区彻底由窗体系统管理,且仅用于将渲染后的图像输出到窗口的显示区域。咱们也可使用在当前屏幕缓冲区之外开辟一个缓冲区进渲染操做。前者即为当前屏渲染,后者为离屏渲染。函数
与当前屏渲染相比,离屏渲染:性能
从上述对比能够看出,在稳定场景下使用离屏渲染的优点较大。但由于地图状态随时都在变化,因此地图渲染一般处于前台动态渲染状态。那么有没有相对稳定的场景呢?答案是确定的,咱们将地图的状态分为沉浸态和非沉浸态。顾名思义,在地图处于变化状态的称为非沉浸态,进入稳定状态称为沉浸态。测试
进入沉浸态的地图,为咱们使用离屏渲染提供了条件。通过统计,地图处于前台状态的场景下,沉浸态时间基本上和非沉浸态时间至关,这样咱们采用一张纹理,便可将处于非沉浸态场景下的地图渲染出来,大大下降了系统开销。在鹰眼图,矢量路口大图等特定的视图场景下,地图基本上均处于沉浸态。因此这些视图下采用离屏渲染技术进行优化,取得的收益将是巨大的。优化
将以上的技术优化原理,代入到实际的导航应用中,流程以下:ui
离屏渲染一般使用FBO实现。FBO就是Frame Buffer Object,它可让咱们的渲染不渲染到屏幕上,而是渲染到离屏Buffer中。可是一般的离屏渲染FBO对象不具有抗锯齿能力,所以开启了全屏抗锯齿能力的OpenGL应用程序,若是采用离屏渲染FBO对象进行离屏渲染,会出现锯齿现象。而在非沉浸态地图的状态下,是开启全屏抗锯齿能力的,因此咱们必须使用具有抗锯齿能力的离屏渲染技术来进行地图渲染技术优化。spa
本节以iOS系统为例,对抗锯齿能力的离屏渲染技术进行简述。iOS系统对OpenGL进行了深度定制,其抗锯齿能力就是创建在FBO基础上的。以下图所示,IOS基于对抗锯齿的帧缓存(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);
复制代码
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, resolveFrameBuffer);
glResolveMultisampleFramebufferAPPLE();
glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, sampleFramebuffer);
复制代码
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];
复制代码
Android系统基本思路一致,须要采用gles3.0接口提供的抗锯齿能力来进行渲染,在此不作展开。
优化前的鹰眼图渲染耗时火焰图以下:
优化后的鹰眼图渲染耗时火焰图以下:
从先后对比图能够看出,鹰眼图渲染的耗时,几乎已经消失不见。
从系统的渲染帧率上进一步获得验证。从下图能够看出帧率已经恢复到与不显示鹰眼图的状况至关:
须要注意的是,全屏抗锯齿损耗资源,除了增长额外的显存空间,抗锯齿过程当中也会产生必定的耗时。因此在取得收益的同时,也须要衡量其产生的代价,须要具体问题具体分析。在本案例中,如对比结果所示,采用抗锯齿离屏渲染技术的优化产生的收益远远高于付出的代价。