概述這里所說的GPU硬件加速是指應(yīng)用GPU的圖形性能對(duì)chromium中的一些圖形操作交給GPU來完成,因?yàn)镚PU是專門為處理圖形而設(shè)計(jì),所以它在速度和能耗上更有效率。但是,使用GPU加速有些額外開銷,并且某些圖形操作CPU完成的會(huì)更快,因而不是所有的操作都合適交給GPU來做。 Chromium中,GPU加速可以不僅應(yīng)用于3D,而且也可以應(yīng)用于2D。這里,GPU加速通常包括以下幾個(gè)部分:Canvas2D,布局合成(Layout Compositing), CSS3轉(zhuǎn)換(transitions),CSS3 3D變換(transforms),WebGL和視頻(video)。目前chromium對(duì)這些的支持已經(jīng)越來越充分,只是某些方面可能還存在些正確性和性能問題。 Chromium除了對(duì)以上采用GPU硬件加速之外,在新的views框架中,引入了對(duì)瀏覽器主界面采用硬件加速的機(jī)制。 它可以把瀏覽器主界面上的各種工具欄等和網(wǎng)頁(yè)通過GPU合成(compositing)起來。因?yàn)橹熬W(wǎng)頁(yè)布局也用到合成器,目前兩個(gè)合成器各自為戰(zhàn),所以chromium會(huì)實(shí)現(xiàn)一個(gè)新的合成器叫chrome compositor,關(guān)于它的細(xì)節(jié),我會(huì)在專門的章節(jié)來做介紹。 本章主要介紹GPU進(jìn)程相關(guān)的內(nèi)容,但是不涉及各個(gè)部分的加速實(shí)現(xiàn)。具體的各個(gè)加速實(shí)現(xiàn)及WebKit對(duì)GPU硬件加速的支持,后面會(huì)有分別的章節(jié)來介紹。 啟用GPU加速如果想使用Chromium的GPU硬件加速功能,首先需要你的GPU驅(qū)動(dòng)程序不在chromium的黑名單中。因?yàn)楹芏嗟腉PU驅(qū)動(dòng)程序存在很多的錯(cuò)誤,這些錯(cuò)誤可能會(huì)比較嚴(yán)重的影響了chromium的穩(wěn)定,例如導(dǎo)致程序崩潰,所以這些GPU被列在黑名單中。一個(gè)檢測(cè)的簡(jiǎn)單辦法是在地址欄里輸入“about:gpu”查看相關(guān)GPU的信息,檢查相關(guān)加速是否已經(jīng)打開。 如果你的GPU驅(qū)動(dòng)不幸在黑名單中,首先的辦法是升級(jí)你的驅(qū)動(dòng),然后重新啟動(dòng)chromium。如果還是解決不了問題,可以通過在chromium的啟動(dòng)參數(shù)中加入“--ingore-gpu-blacklist”來關(guān)閉黑名單功能,這樣你就開啟了你的GPU加速功能。但是,如前所說,這種方法可能會(huì)造成chromium的不穩(wěn)定,因而只是權(quán)宜之計(jì)。 進(jìn)程模型由于chromium的安全模型和穩(wěn)定性考慮,GPU加速也采用多進(jìn)程模型來實(shí)現(xiàn)。所以的GPU加速相關(guān)的操作均有一個(gè)獨(dú)立的進(jìn)程來完成,這就是GPU進(jìn)程。詳見下圖所示GPU進(jìn)程和Browser,Renderer進(jìn)程。
GPU進(jìn)程由Browser進(jìn)程來創(chuàng)建和銷毀,這類似于對(duì)plugin進(jìn)程的管理。它們之間的通信是通過chromium的IPC消息機(jī)制實(shí)現(xiàn)的。Chromium只會(huì)創(chuàng)建一個(gè)GPU進(jìn)程,該進(jìn)程被所有的Renderer進(jìn)程和Pepper plugin進(jìn)程所共享,但是GPU進(jìn)程會(huì)為不同的進(jìn)程創(chuàng)建不同的command buffer的示例。對(duì)于一個(gè)Renderer進(jìn)程,GPU進(jìn)程也可以為其創(chuàng)建多個(gè)示例,這取決于Renderer進(jìn)程的需求。 下面主要介紹以下GPU進(jìn)程和客戶進(jìn)程(以Renderer進(jìn)程示例)之間是如何工作的。下圖描述了以WebGL為示例的主要模塊(類)及它們之間的聯(lián)系。
首先來看一看Renderer進(jìn)程的模塊類: WebGraphicsContext3DCommandBufferImpl:繼承自WebKit::WebGraphicsContext3D類, 具體的實(shí)現(xiàn)類,主要是轉(zhuǎn)接自WebKit的調(diào)用到chromium的具體實(shí)現(xiàn)。主要包括一個(gè)RenderGLContext對(duì)象。 RendererGLContext: Renderer進(jìn)程對(duì)GLContext的一個(gè)封裝,包括所有用于跟GPU進(jìn)程交互的類,有一個(gè)GLES2Implementation對(duì)象,一個(gè)CommandBufferProxy對(duì)象和一個(gè)GPUChannelHost對(duì)象。 GLES2Implementation:該類模擬GLES2,但是不直接調(diào)用GLES2的實(shí)現(xiàn),而是將這些調(diào)用轉(zhuǎn)換成特定格式的命令存入CommandBuffer中。 CommandBufferHelper: 該類是一個(gè)輔助類,包括一個(gè)CommandBuffer代理類和一個(gè)共享內(nèi)存 CommandBufferProxy:CommandBuffer的一個(gè)代理類,實(shí)現(xiàn)CommandBuffer的接口,用于和CommandBufferStub之間的通信 GPUChannelHost:用于IPC消息的通信類 接著再挨個(gè)了解一下GPU進(jìn)程中的模塊類: GPUChannel:用于GPU進(jìn)程中的IPC消息的通信類 GPUCommandBufferStub:CommandBuffer的樁,接受來自于CommandBufferProxy的消息,將請(qǐng)求交給CommandBufferService處理 CommandBufferService:具體的CommandBuffer的實(shí)現(xiàn)類,但是其實(shí)它并不具體解析和執(zhí)行這些命令,而是當(dāng)有新的命令時(shí),觸發(fā)給注冊(cè)的回調(diào)函數(shù)來處理 GPUScheduler:負(fù)責(zé)調(diào)度執(zhí)行commandbuffer的命令,它會(huì)檢查該commandbuffer是否應(yīng)該被執(zhí)行,并適時(shí)將命令交給CommandParser的來處理 CommandParser:僅檢查CommandBuffer中的命令的頭部,其余交給具體的decoder來做 GLES2DecoderImpl:解析每條具體的命令并執(zhí)行調(diào)用GL相應(yīng)的函數(shù) GLImplementation Wrapper: 一組GL相關(guān)的函數(shù)指針,通過用戶的設(shè)定來讀取相應(yīng)gl庫(kù)的函數(shù)地址來設(shè)置自己 GLLibraries: 具體的函數(shù)庫(kù),可以是opengl,opengles,mesagl,mock等 通過上面每個(gè)模塊類的具體介紹,相信你已經(jīng)大概知道它們的工作過程。那么,它們是如何同步的呢?因?yàn)镽enderer進(jìn)程需要等待GPU進(jìn)程做好某些操作之后才繼續(xù)執(zhí)行。答案是,GPU進(jìn)程處理一些命令后,會(huì)向Renderer進(jìn)程報(bào)告當(dāng)前自己當(dāng)前的狀態(tài),Renderer進(jìn)程通過檢查狀態(tài)信息和自己的期望結(jié)果來確定是否滿足自己的條件。 GPU進(jìn)程最終繪制的結(jié)果不再像軟件渲染那樣通過共享內(nèi)存?zhèn)鬟f給Browser進(jìn)程,而是直接將頁(yè)面的內(nèi)容繪制在瀏覽器的標(biāo)簽窗口內(nèi)。 Command BufferCommand Buffer主要用于GPU進(jìn)程(且稱為GPU 服務(wù)端)和GPU的調(diào)用者進(jìn)程(且稱GPU客戶端, 如Renderer進(jìn)程, Pepperplugin進(jìn)程)傳遞GPU操作命令。從接口上來,它只提供一些基本的接口來對(duì)buffer進(jìn)行管理,它沒有對(duì)buffer的具體方式和命令的格式進(jìn)行任何限制。 現(xiàn)有實(shí)現(xiàn)是基于共享內(nèi)存的方式來完成,因而命令是基于gles編碼成特定的格式存儲(chǔ)在共享內(nèi)存中。共享內(nèi)存方式采用了ring buffer的方式來管理,這表示內(nèi)存可以循環(huán)使用,舊的命令會(huì)被新的命令所覆蓋。基于gles的編碼格式,因?yàn)閃ebGL是基于gles的JavaScript綁定,所以簡(jiǎn)單直觀。 命令基本格式一條命令可以分成兩個(gè)部分:命令頭和命令體。命令頭包含兩個(gè)部分,一個(gè)是命令的長(zhǎng)度,一個(gè)是命令的ID。命令體包含該命令所需要的其他信息,例如命令的立即操作數(shù)。命令是可以固定長(zhǎng)度的,也可以是變長(zhǎng)的,一起取決于該命令。具體的結(jié)構(gòu)如下圖所示。
基于GLES2的命令上面說到,本身Command Buffer是沒有定義具體的命令,所以GLES2可以根據(jù)需要自己來定義。命令大概可以分成兩類,第一類是公共的命令,主要用來操作桶(bucket),跳轉(zhuǎn),調(diào)用和返回。第二類是跟GLES2的函數(shù)相關(guān)的命令,主要用來操作GLES2的函數(shù)。 IPC機(jī)制前面提到,命令本身是保存在共享內(nèi)存中的,而且每條命令的長(zhǎng)度不能超過(1<<21 -1),而且共享內(nèi)存的大小也是固定的,如果命令太長(zhǎng),可存儲(chǔ)的命令很少。那么問題就出來了,如何解決需要傳輸較大數(shù)據(jù)的命令呢?對(duì)于這樣類型的數(shù)據(jù),可以對(duì)它們利用獨(dú)立的共享內(nèi)存來實(shí)現(xiàn),例如TexImage2D。但是,當(dāng)共享內(nèi)存大小超過系統(tǒng)的限制時(shí),這種方式就行不通。chromium提供了一種新的機(jī)制來解決這個(gè)問題。 這個(gè)機(jī)制就是桶(bucket)機(jī)制。其解決問題的原理是,通過共享內(nèi)存機(jī)制來分塊傳輸,而后把分塊的數(shù)據(jù)保存在本地的桶內(nèi),從而避免了申請(qǐng)大塊的共享內(nèi)存。前面提到的公共的命令就是用來處理桶相關(guān)的數(shù)據(jù)。當(dāng)數(shù)據(jù)傳輸完成之后,對(duì)該數(shù)據(jù)進(jìn)行操作的命令就可以執(zhí)行了。 桶機(jī)制也可用來傳輸string類型的變長(zhǎng)數(shù)據(jù)。接受端首先獲取桶內(nèi)string的長(zhǎng)度,然后通過共享內(nèi)存方式來分塊傳輸,最后合成在自己的桶內(nèi)。 GPU加速的后端GPU加速雖然是基于opengles的接口來設(shè)計(jì)commandbuffer的,但是這不意味著系統(tǒng)的gl的后端庫(kù)必須是egl/opengles庫(kù),這是因?yàn)閏hromium提供了一層轉(zhuǎn)接。 這層轉(zhuǎn)接如何實(shí)現(xiàn)的呢?原理其實(shí)并不復(fù)雜。Chromium首先定義了一組gl相關(guān)的函數(shù)指針,然后chromium根據(jù)設(shè)置或者命令行參數(shù)來加載相應(yīng)的庫(kù),并從這些庫(kù)中讀取相應(yīng)的函數(shù)地址,并把這些地址賦值給這些函數(shù)指針。這樣一來,GPU加速部分的代碼調(diào)用的是這一組函數(shù)指針,從而避免直接使用opengles的庫(kù)。詳細(xì)代碼參考源文件目錄” ui/gfx/gl”。 源代碼目錄gpu/ 該目錄包含GPU相關(guān)的文件,主要包括commandbuffer的實(shí)現(xiàn),工具,GPU涉及的IPC等 gpu/command_buffer 該目錄存放CommandBuffer相關(guān)的類,主要包括client端,service端和公共的基礎(chǔ)類 gpu/command_buffer/client 該目錄存放GPU客戶端所使用到的與CommandBuffer相關(guān)的類 gpu/command_buffer/service 該目錄存放GPU進(jìn)程端所使用到的與CommandBuffer相關(guān)和GLES2具體實(shí)現(xiàn)相關(guān)的類 content/gpu 該目錄存放GPU進(jìn)程所涉及使用的基礎(chǔ)類,包括進(jìn)程入口函數(shù),IPC,進(jìn)程和線程管理等相關(guān)類 content/common/gpu/ 該目錄存放GPU進(jìn)程使用的與GPU相關(guān)的類 content/Renderer/gpu/ 該目錄存放Renderer進(jìn)程使用GPU加速所涉及的類,主要包括IPCchannel, CommandBuffer代理等類 content/browser/gpu/ 該目錄存放Browser進(jìn)程和GPU、Renderer進(jìn)程交互相關(guān)的類,如GPUProcessHost。還包括GPU黑名單的實(shí)現(xiàn) ui/gfx/gl/ 該目錄存放與具體的opengl,opengles庫(kù)相關(guān)類,包括根據(jù)命令行參數(shù)讀取所需要的gl的庫(kù)類型,庫(kù)的函數(shù)地址的讀取和管理等等 參考文獻(xiàn) |
|