與手機導航不一樣,高德地圖的車機版(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接口提供的抗鋸齒能力來進行渲染,在此不作展開。
優化前的鷹眼圖渲染耗時火焰圖以下:
優化後的鷹眼圖渲染耗時火焰圖以下:
從先後對比圖能夠看出,鷹眼圖渲染的耗時,幾乎已經消失不見。
從系統的渲染幀率上進一步獲得驗證。從下圖能夠看出幀率已經恢復到與不顯示鷹眼圖的狀況至關:
須要注意的是,全屏抗鋸齒損耗資源,除了增長額外的顯存空間,抗鋸齒過程當中也會產生必定的耗時。因此在取得收益的同時,也須要衡量其產生的代價,須要具體問題具體分析。在本案例中,如對比結果所示,採用抗鋸齒離屏渲染技術的優化產生的收益遠遠高於付出的代價。