操作系統是如何管理GPU等計算資源的?
傳統操作系統的書籍以及內核代碼的分析似乎非常少提及圖像顯示(從最簡單的像素點,線,圖形,字體)的管理,而一般只是引用諸如OpenGL等庫,想問一下計算機的顯示資源與操作系統是如何的管理關係?
不論移動還是桌面,桌面的集成還是獨立顯卡,拿來render還是compute,GPU上的資源無外乎包括:video memory,render/compute/multimedia engine/node,display controller。以下用桌面卡在WDDM 1.x (Vista~Win8.1) 上的行為進行描述,會單獨描述XP和Win10的情況:
(題外話:真要說清楚,render和display各自至少可以寫本書了~)
1. Video Memory:
- 顯存的存在主要是為了提高性能。在大多數情況下,顯存的效率和帶寬總是大於系統內存。舉例:DDR3, GDDR5。反例: PS4全系統用GDDR5作為內存/顯存,大部分集成顯卡的系統內存和顯存共享DDRx系統內存。
- 從物理介質上看,獨顯的video memory一般指卡上的顯存; 集顯的video memory一般從系統內存上保留或者分配出的一塊系統內存。
- 從使用屬性上看,凡是能被GPU使用的memory都可以稱為video memory (包括顯存及系統內存),但根據情況不同有所區別。Windows上的劃分很清晰,可參考:Calculating Graphics Memory (Windows Drivers)
- 以上兩點容易混用,需要根據使用場合明確具體所指。
- 從訪問的物理路徑上看:獨立顯卡訪問本地顯存不需要過匯流排,訪問系統內存需要經過匯流排;集成顯卡的顯存雖然共享系統內存,但在晶元內部的訪問路徑仍有可能不同;有些集顯還可以增加一塊小的external RAM來在沒有顯存只有內存的情況下來取得一定的性能提升,比如xbox one,當然獨顯也可以增加eRAM,不過已經有GDDRx了所以意義不大。
- 根據CPU/GPU的訪問方式,可以被GPU訪問的memory分visible,invisible, GART(page table remapping)。前兩者物理上屬於顯存,GPU直接訪問,CPU會根據有沒有地址映射而有所區別,invisible的部分無法直接訪問到,同時受PCI-e及設備限制,visible/invisible大小也不可任意調整;後者物理上是系統內存,通過page table被GPU間接訪問,CPU可以直接訪問。除了GART,還有GPU virtual memory,區別主要在於GPU virtual memory通常會去映射顯存而非系統內存。
- 以下描述Video Memory的訪問。總的來說,所有的video memory是由dxgkrnl/dxgmms中的vidmm管理和分配、user mode driver和kernel mode driver參與、runtime協調,共同完成的。
application/runtime/os/driver之間的調用關係參見: Windows Display Driver Model (WDDM) Architecture (Windows Drivers)
- 對於應用程序來說,能看到的就是D3D/OpenGL提供的函數,所以app開發者無法直接分配video memory,能做的只是通過DX/OpenGL準備好你的xx buffer。
- 對於runtime來說,協調user mode driver和dxgkrnl/dxgmms,處理符合pipeline設計的vendor無關的部分。
- 對於User mode driver,根據vendor自家的設計,從kernel mode driver獲得顯卡處理能力,選擇分配的buffer的格式(memory format, 主要是tiling等),分配在哪裡(visible, invisible,local,non-local等等)等問題。
- 對於kernel mode driver,綁定好video memory的物理地址和CPU分配的virtual address,把memory劃分成不同的segment後report給OS,建立及更新GART/GPU virtual memory的page table,記錄handle和physical/virtual地址的對應關係,處理GPU地址空間里的GPU physical address等等。
- 對於dxgkrnl/dxgmms,vidmm模塊會對所有分配的memory(以allocation表示)進行管理。
- 關於XP的XDDM的部分,memory管理最主要的區別在於XDDM是由各家vendor自己的driver完成,WDDM也是吸收了這種設計做出的dxgkrnl/dxgmms模塊。
- 關於Win10的WDDM2.0,最大的區別之一在於引入了GPU virtual memory的管理,簡單說就是dxgkrnl+dxgmms/user mode driver/kernel mode driver扔給GPU的memory可以用virtual address, 通過GPU上自己的page table完成定址。在WDDM 1.x時代,雖然各家vendor的GPU從硬體上早已支持了virtual address通過page table去定址,但Windows的設計是讓GPU直接通過GPU的physical address去定址的,並沒有提供直接的DDI去控制,所以各家vendor通過自己的做法使用GPU virtual address. Win10等於將這種實現從vendor自己搬到了OS中進行。
2. render/compute/multimedia engine node
最複雜的部分,但不準備用很多語言描述,因為太少說不清,太長又會真的太長。。。- 對於render,computer,video decoding/encoding這些不同類型的操作, WDDM都是通過抽象的engine node的模型來實現的。比如現在的一張主流顯卡,上面通常會有用於render,用於DMA,用於decoding/encoding的node各一個。
- application層,這些不可見,能控制的就是D3D/OpenGL的call,比如draw。
- Runtime層,會知道調用合適的user mode driver去完成,處理vendor/硬體無關的操作。對於原生OS不支持的一些功能,則要藉助SDK來完成和user mode driver的通信。
- User mode driver層,一般不同的功能都有各自的driver,比如用於render的DX9/10/11/12driver,用於multimedia的,用於CUDA/OpenCL的等等。在這一層,user mode driver知道該用什麼engine做什麼樣的事情。另外,需要根據vendor自己的顯卡架構情況,進行command的建立。command就是GPU中的相應模塊可以執行的一系列操作的抽象。在有shader的情況下,還要對shader進行編譯。
- dxgkrnl/dxgmms,vidsh模塊對所有的engine以及command submission進行管理,提交command給kernel mode driver, 調度來自不同應用程序的context切換,高優先順序搶佔操作,處理長時間不能完成的command submission等。MSDN上有詳細說明不再展開。
- kernel mode driver層,根據顯卡的能力report給OS有多少個engine,每個engine都有什麼capability,編號是多少等等。當command從dxgkrnl下來的時候,要根據和user mode driver之間的私有定義,把每個command解析並打包封裝成更小的單位,並對其中涉及地址訪問的操作(包括memory,register等)賦予正確的地址。然後吧這些command真正提交到GPU上。各家vendor實現均有不同。user mode driver和kernel mode driver可以看作是GPU的HAL。
- 對於compute(CUDA, OpenCL)的情況,因為Windows定義的engine type並沒有專門用於compute的,所以需要vendor自己的SDK以及對應的compute-purpose driver, 來完成類似render情況下dxgkrnl/dxgmms的功能。
Memory Mangemen和Command Submission的部分詳見這裡:Video Memory Management and GPU Scheduling (Windows Drivers)
3. Display Controller
真要以為display很簡單就錯了。雖然看起來"只不過是"點個顯示器"而已",要做的事情仍然很多很複雜。- 各種user mode模塊,基本不用操心,需要用到的差不多隻要知道窗口在桌面上的坐標,當前顯示屬性,以及能通過一些API切換display mode就差不多了。
- dxgkrnl, 需要管理被稱為Video Present Network的topology。有機會看過最初搞的設計文檔,雖然後來各種詬病甚多,不過從數學角度講,設計真的非常非常非常嚴謹。詳細見這裡:VidPN Objects and Interfaces (Windows Drivers)
- Kernel Mode Driver,需要處理各類顯示器的capability,按照某種局部最優演算法匹配桌面(desktop view)和顯示信號(display timing),處理標準化協議定義的操作(HDMI, DisplayPort)。在render部分完工的內容只是以memory的形式存在,為了能最終顯示出來,kernel mode driver需要讓display controller能夠正確的從memory中scan出這些內容、轉化為對應的timing信號(analog)或者packet(digital)、進行layer間composite(desktop view, stereoscopic, overlay, underlay, hardware cursor, hardware icon都可以各自作為一個layer),這些都屬於display的範疇。
綜上。其實這是一個非常複雜而又小眾的細分領域,如果搞應用層開發,雖然這些內容可以幫助你深入了解整個GPU在hardware和software上是怎麼工作的,但對於開發本身的實質幫助十分有限。而且很多資料都不公開,除非你在相應的公司相應的項目上工作,不然很難深入學習。
禁止一切形式的轉載。菜鳥回答下,操作系統對顯卡和對網卡沒什麼兩樣,都是IO讀寫,中斷這些的。管理顯卡和管理其它pci設備一樣。點線面什麼的還是openGL才關心的。打個不太好的比方,操作系統和網卡驅動只知道數據進出,不關心這些數據是TCP.udp還是arp,這是更上層關心的。
為了表示圖像,計算機的顯示屏上的每個像素都一定位元組的數據表示,想想RGB和ARGB這些表示。 我們可以試想下(沒有驗證過,有錯請指正),這些數據要顯示到顯示屏上,那麼顯示屏必須有塊內存來存放這些數據。顯示屏最簡單的設計就是按照一定頻率把它背後的那塊內存的數據解釋並顯示出來。我們的圖像,可以通過一些圖形變換繪製(cpu gpu 用上opengl或者其他圖形庫的演算法)修改 應該 顯示到 顯示屏上的內存緩衝的內容,最後把些處理後的數據放到顯示屏背後(我的意思是默默工作那塊內存,不是背面哦)的內存上,讓顯示屏顯示出來。 好了,到這裡差不多可以理解了吧。 有錯誤,請指正。
推薦閱讀:
※光照和陰影演算法該如何優化?
※圖形渲染中關於CPU和GPU的一些問題?
※對多重採樣(MSAA)原理的一些疑問?
※如何用OpenGL封裝一個2D引擎?
※如果做一個GIS渲染引擎,圖形API應當選擇OpenGL還是DirectX?