您好,登錄后才能下訂單哦!
導讀
與手機導航不同,高德地圖的車機版(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 ( , , 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接口提供的抗鋸齒能力來進行渲染,在此不做展開。
優化對比
優化前的鷹眼圖渲染耗時火焰圖如下:
優化后的鷹眼圖渲染耗時火焰圖如下:
從前后對比圖可以看出,鷹眼圖渲染的耗時,幾乎已經消失不見。
從系統的渲染幀率上進一步得到驗證。從下圖可以看出幀率已經恢復到與不顯示鷹眼圖的情況相當:
需要注意的是,全屏抗鋸齒損耗資源,除了增加額外的顯存空間,抗鋸齒過程中也會產生一定的耗時。所以在取得收益的同時,也需要衡量其產生的代價,需要具體問題具體分析。在本案例中,如對比結果所示,采用抗鋸齒離屏渲染技術的優化產生的收益遠遠高于付出的代價。
關注高德技術,找到更多出行技術領域專業內容
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。