OpenGL -- 屏幕成像和渲染原理解析

1.CPU與GPU

CPU內部組成:web

未命名文件 (4).png

GPU內部組成:編程

截屏2021-07-18 19.40.36.png

ALU:算術邏輯單元,是能實現多組算術運算和邏輯運算的組合邏輯電路。緩存

CPUGPU由於設計之初需求就不同,因此它們的組成不一樣,在計算機中的分工也不一樣。markdown

能夠看到,GPU有更多的ALU,而CPUControl單元和Cache單元,普通的業務代碼由於邏輯複雜,數據類型複雜,跳轉複雜,依賴性高等,就更適合CPU來作。併發

GPU不擅長處理這些複雜的邏輯,它更擅長處理單一的運算,大量的算術邏輯單元能夠保證作到真正的高併發,因此大量的計算任務是適合它的工做,就好比GLSL代碼。app

關於CPUGPU的分工以下圖所示:框架

截屏2021-07-18 19.48.27.png

截屏2021-07-18 19.49.18.png

CPU更像管理者,負責調度和控制,也進行小量的計算,而GPU則是單純的打工人,負責大量的計算工做。高併發

爲了並行計算,每一個計算單元都必須獨立。意味着全部數據必須沿一個方向流動,不可能檢查另外一個計算單元的結果。GPU使計算單元一直處於忙碌狀態;一旦他們得到自由,就會接收新的信息進行處理。一個計算單元不可能知道它在前一刻在作什麼。每一個計算單元都是盲目且無記憶的。 -- 來自翻譯《The Book Of Shaders》oop

能夠很明顯看到兩者區別的是:佈局

一個OpenGL程序,若是是跑在真機上,那毫無疑問是使用GPU運行的,很是流暢。若是是跑在模擬器上,是使用電腦的CPU在運行的,複雜的特效就會出現卡段。

擴展:Metal的使用就更極端,它必須使用真機運行,而且是6s及以上的真機。

2.計算機顯示方式演變

首先須要說明的是,計算機的顯示原理離不開視覺暫留現象。

視覺暫留: 人眼在觀察景物時,光信號傳入大腦神經,需通過一段短暫的時間,光的做用結束後,視覺形象並不當即消失,這種殘留的視覺稱「後像」,視覺的這一現象則被稱爲「視覺暫留」。

物體在快速運動時, 當人眼所看到的影像消失後,人眼仍能繼續保留其影像0.1-0.4秒左右的圖像,因此當圖像的刷新幀率高於每秒16幀時,在人眼看來就是不間斷的顯示。

2.1 隨機掃描顯示

隨機掃描顯示是早期的顯示方式。CRT產生的電子束只在屏幕上顯示圖形的部分移動,電子束逐條地跟蹤圖形的組成線條,從而生成線條圖。

這就決定了隨機掃描顯示的刷新頻率依賴於顯示的線條數,和圖像的複雜度高度相關。圖形的定義是存放在稱爲刷新顯示文件存儲區的一組畫線命令。

截屏2021-07-29 10.12.57.png

好比,圖1的每幀掃描成像時間就快於圖2

當顯示的線條數不多時,則延遲每一個刷新週期,以免刷新速率超過每秒60幀。不然,線條的刷新速率過快,會燒壞熒光屏。

隨機掃描顯示的優勢在於做爲一組畫線命令來存儲而非每一個像素點的強度值,於是生成光滑的線條,而非有鋸齒的像素點。缺點是沒法顯示逼真的有陰影的場景。

2.2 光柵掃描顯示

光柵掃描顯示是目前的主流。

光柵掃描顯示中,電子束橫向掃描屏幕,一次一行,從頂到底依次進行。電子束在屏幕上逐點移動時,從被稱爲幀緩存的存儲區取出每一個像素點的強度值控制其顯示狀態。

這種實現原理決定了光柵掃描顯示的刷新頻率和圖像複雜度無關,刷新頻率能夠是恆定的。

截屏2021-07-29 14.47.54.png

好比,圖1的每幀掃描成像時間就等於圖2

光柵掃描顯示對屏幕上的每一個點都有存儲強度信息的能力(除顏色信息外,其餘的像素信息也存在幀緩存中),從而使得適用於包含陰影和彩色模式的逼真場景。

在某些光柵掃描系統中,採用了隔行掃描刷新的方式來顯示每一幀。第一次從頂到底掃描奇數行,第二次從頂到底掃描偶數行。隔行掃描使得掃描時間只須要原先的一半就能看到屏幕的顯示。不過隔行掃描技術主要應用於較慢刷新頻率的場景。

2.4 光柵掃描顯示系統組成

光柵掃描系統除了使用CPU以外,還用視頻控制器來控制顯示設備的操做。

2.4.1 簡單光柵掃描顯示系統結構

截屏2021-07-29 13.39.37.png

簡單的光柵掃描系統如上圖所示。其中,幀緩存能夠在系統存儲器中的任意位置,視頻控制器經過系統總線訪問幀緩存來刷新屏幕。

2.4.2 經常使用光柵掃描顯示系統結構

截屏2021-07-29 14.03.43.png

與簡單結構的相比,這個結構明顯提高了顯示效率,緣由在於:

幀緩存使用了系統主存中的固定區域來存儲,且由視頻控制器直接訪問。

2.4.3 高級光柵顯示系統結構

截屏2021-07-29 14.14.30.png

高級的光柵顯示系統包含獨立的顯示處理器,也就是獨立顯卡。顯示處理器使CPU從圖形的複雜處理中解脫出來,還提供獨立的顯示處理器存儲區域。

2.4.4 視頻控制器的工做流程

不管何種結構,都存在視頻控制器,說明它是必不可少的。那它是如何工做的呢?

截屏2021-07-29 14.30.24.png

視頻控制器使用兩個寄存器來存放屏幕像素的座標,而屏幕像素座標和幀緩存的位置都使用笛卡爾座標系

開始時,將x寄存器置爲0,將y寄存器置爲頂部掃描行號。存儲在幀緩存中該像素對應位置的值被取出,並用來設置CRT電子束的強度值。而後,x寄存器加1,並沿該掃描線對每一個像素重複執行。在處理完頂部掃描線的最後一個像素後,x寄存器復位爲0,y寄存器減1,指向頂部掃描行的下一行。而後,沿該行依次掃描各像素,而且該過程對每條後繼的掃描線重複執行。當循環處理完底部掃描線的全部像素後,視頻控制器寄存器復位爲最高行掃描線上的第一個像素,刷新過程重複開始。

爲了加速圖像處理,視頻控制器每次從刷新緩存中取出多個像素值。這些像素強度存放在單獨的像素寄存器中,用來爲一組相鄰的像素控制CRT電子束的強度。當處理完改組像素後,從幀緩存取出下一塊像素值。

因爲多數設備都提供多緩衝的機制,視頻控制器取像素強度值時還會在每一個緩衝之間作切換。

2.4.5 總結

GPU的渲染流程大概以下:

GPU進行渲染時,會把數據先存儲在幀緩衝區裏,而後視頻控制器讀取幀緩衝區裏的數據,完成數模轉化,逐行掃描顯示畫面。

理論上,完美狀況時,每掃描一張圖,就顯示一張,而後下一張也掃描完成等待刷新。

依次反覆,屏幕就會保持流暢,那爲何有些時候屏幕還會出現不流暢的現象,不流暢現象產生的原理是什麼?

3.撕裂與掉幀

u=4019473518,1749902772&fm=26&fmt=auto&gp=0.webp

畫面撕裂是比較影響用戶體驗的異常。畫面撕裂產生的緣由以下:

視頻控制器讀取讀取完一幀畫面顯示後,會去幀緩存讀取下一幀,若是幀緩存依然保持着上一幀的數據沒有被刷新,視頻控制器照常工做讀取幀緩存中的數據。當寄存器工做到某一行時,幀緩存的數據被更新爲下一幀,視頻控制器就讀取到新的數據,而此時已經顯示的畫面是上一幀的數據,後續將要顯示的是下一幀的數據,撕裂也就產生了。

因此,撕裂的產生是由於幀緩存的刷新頻率沒有跟上屏幕的刷新頻率,根本緣由就是CPUGPU工做超時。

爲了解決撕裂的問題,蘋果宣佈iOS一直會使用垂直同步Vsync + 雙緩衝的機制

截屏2021-07-29 16.04.10.png

VSync信號到來後,會在CPU中計算顯示內容,好比視圖的建立、佈局計算、圖片解碼、文本繪製等。而後CPU會將計算好的數據提交到GPU,由GPU進行變換、合成、渲染。而後GPU會把渲染結果提交到幀緩存,等待下一次VSync信號到來時顯示到屏幕上。

因爲垂直同步的機制,若是在一個VSync時間內,CPU或者GPU沒有完成內容提交,則那一幀就會被丟棄,等待下一次機會再顯示,而這時屏幕會刷新顯示上一幀的內容。

經過這種機制,就解決了撕裂的問題,但同時引入了新的問題 -- 掉幀

CPUGPU渲染流⽔線耗時過⻓,先後顯示同一幀時,也就出現了掉幀現象(因此掉幀不是不渲染數據,而是重複渲染同一幀數據)。

至於掉幀沒法被徹底解決,由於CPUGPU的工做是不可預估的。只能儘可能合理的使用CPUGPU減小掉幀次數。

這裏引入三緩衝機制的概念:

開闢三個幀緩衝區,儘量保證總有個緩衝區中有下一幀須要的內容。不過這也是治標不治本的手段。

總結:

撕裂是因爲CPUGPU耗時過⻓而產生的,iOS解決的方式是引入垂直同步Vsync + 雙緩衝的機制,而解決撕裂是以掉幀做爲代價的,掉幀不能徹底被解決。

4.iOS下的渲染框架和流程

截屏2021-07-29 17.28.49.png

App經過調用Core GraphicsCore AnimationCore Image等框架的接口觸發圖形渲染,這些框架在經過 OpenGL/Metal 來調用GPU進行繪製,最終將內容顯示到屏幕之上.

固然,APP也能直接使用OpenGL/Metal提供的接口進行繪製。

總結:

  1. UIKit:經過UIKit提供的街交口進行佈局和繪製界面,UIKit自己不具有顯示能力,是經過底層的layer實現的。

  2. CoreAnimation:本質上是一個複合引擎,主要職責在於渲染,構建和動畫。CAlayer屬於CoreAnimation,是界面可視化的承載。

  3. CoreGraphics:基於Quartz的高級繪圖引擎,提供了輕量級的2d渲染能力,主要是用於運行時繪圖的。CG開頭的類都屬於CoreGraphics

  4. CoreImage:一個高性能的圖像處理分析的框架,運行前繪製圖形,主要提供圖形的濾鏡功能。

  5. OpenGL ES:針對嵌入式設備,是OpenGL的子集。直接操做硬件服務,是跨平臺的。

  6. Metal:蘋果自研的針對自家設備的圖形渲染標準,在蘋果設備上性能最優。

5.CPU和GPU的渲染流水線

截屏2021-07-29 18.39.17.png

總的來講,圖形的渲染分爲兩個部分:CPU部分,GPU部分

CPU部分主要作了3步操做:

1.Handle Event 接收事件,包括點擊事件,佈局的改變等。

2.Commit transcation 提交事務,經過CPU完成顯示內容的計算,而後對圖層樹進行打包,在下一個runloop時提交到Render server進程

3.Render Server 將收到的包進行解碼,處理完數據後,再傳遞至 GPU

須要注意的是,app自己的進程並不負責渲染,渲染是由一個獨立的進程負責,就是Render Server進程

GPU部分主要就是渲染管線的內容:

這部分的內容在OpenGL初探 - 專有名詞解析中的最後總結已說明。

最後,GPU的渲染管線結束後,須要在等下一個runloop來時顯示幀緩衝區內的內容。

以上渲染流水線舉個具體的例子以下:

若是一張圖片被設置爲imageview的屬性時會發生什麼?

首先,CATransaction捕獲到圖層樹的變化,在下一個runloop週期到來時,Core Animation會提交這個隱式動畫,會對圖片作如下操做:

  • 分配內存緩衝區用於管理文件IO和解壓縮操做
  • 將文件從磁盤讀到內存
  • 將壓縮的圖片數據解壓成未壓縮的位圖數據,這一步操做比較耗時,且在主線程
  • CPU計算好frame等數據,對圖片解壓後,交給GPU作圖片渲染
  • Calayer使用原始數據進行繪製Content

6.寫在最後

OpenGL或者shader的編程都是面向過程的,大部分是面向GPU的,這和麪向CPU編程的思想是有所不一樣的。之前總以爲圖形的變換老是在第一幀的基礎上進行是費時費力的,若是在上一幀的基礎上變換豈不是更省事,理解了屏幕成像和渲染原理以後對這個問題,或者說對圖形學纔有了初步的理解。

相關文章
相關標籤/搜索