其實你可以把顯示卡想象成另外一臺機器。那麼控制另外一臺機器的辦法,就是往它的記憶體裡面寫指令和資料。往一塊記憶體裡面寫東西的辦法無非就幾種,1, 用CPU去做,那麼就是用MMIO(Memory Mapped IO)把"視訊記憶體" map到CPU定址空間,然後去讀寫,2, 用DMA控制器去做,這裡面有系統自帶的DMA控制器或者顯示卡帶的,不管哪種你可以把DMA控制器再一次看作另外一臺機器,那麼其實就是向DMA控制器寫指令讓它幫你傳一些東西到視訊記憶體去,傳的這些東西就是顯示卡要執行的命令和資料。顯示卡上的記憶體控制器,原來AGP的時候叫GART,現在不知道叫啥名了,另外SoC裡面也有類似的概念,不過大多數SoC只有一個記憶體控制器,所以不分視訊記憶體和記憶體。把顯示卡想象成另外一臺機器。它要工作,無非也是“程式儲存”原理,上電之後,從特定的記憶體(視訊記憶體)地址去取指,然後執行指令。顯示卡的工作邏輯比CPU簡單多了,它一般就從一個環形buffer不斷的取指令,然後執行,CPU就不斷的去往環形buffer填指令。很多時候同一個動作既可以用MMIO,也可以用DMA,比如flip framebuffer。只要把flip framebuffer的指令正確傳到環形buffer就好了。但是MMIO需要CPU參與,傳大資料的時候,打亂CPU GPU並行性,划不來。驅動程式其實也是圍繞著這件事情來做的,Vista以前,顯示卡的驅動全都是kernel mode執行的,因為只有kernel mode才能訪問的物理地址,但是kernel mode的壞處是一旦有問題,系統就崩潰,而且kernel mode有很多侷限性,比如沒有C庫支援,浮點運算很難,代價很大等等。所以Vista之後,顯示卡驅動都分兩部分,kmd負責需要訪問物理地址的動作,其他事情都放到umd去做,包括API支援等等。所以一個3D程式執行的過程是這樣的,app generate command, call D3D runtime,D3D runtime call driver umd, driver umd system call driver kmd, kmd send command to ring buffer, graphic card exeute.至於顯示卡驅動要完成什麼部分,這個就是所謂HAL(hardware abstraction layer)層,也就是說HAL以下由廠商提供,以上就是作業系統自帶,在HAL層以上,所有的操作都是統一的,比如畫一個點,畫一條線,驅動來對應具體的某一款晶片生成真正的命令,比如畫點,需要0x9指令,把絕對座標放到地址0x12345678(舉例)。微軟管的比較寬,umd, kmd都有HAL層,意思是即使kmd你也不能亂寫,能統一的儘量統一,比如CPU GPU external fence讀寫同步機制就是微軟統一做的。流處理器就是說,那些處理器可以執行很多的指令,而不是就幾個固定的功能,比如原來我把幾個矩陣的乘法固定成一個操作(比如T&L單元),現在我把這個操作拆了,改成更基本的指令,比如,取矩陣元素,加乘,這樣更靈活。不過你就得多費心思去組合這些指令了,組合這些指令有個高大上的名字,shader。至於為什麼叫shader,越來越長了,不說了。
其實你可以把顯示卡想象成另外一臺機器。那麼控制另外一臺機器的辦法,就是往它的記憶體裡面寫指令和資料。往一塊記憶體裡面寫東西的辦法無非就幾種,1, 用CPU去做,那麼就是用MMIO(Memory Mapped IO)把"視訊記憶體" map到CPU定址空間,然後去讀寫,2, 用DMA控制器去做,這裡面有系統自帶的DMA控制器或者顯示卡帶的,不管哪種你可以把DMA控制器再一次看作另外一臺機器,那麼其實就是向DMA控制器寫指令讓它幫你傳一些東西到視訊記憶體去,傳的這些東西就是顯示卡要執行的命令和資料。顯示卡上的記憶體控制器,原來AGP的時候叫GART,現在不知道叫啥名了,另外SoC裡面也有類似的概念,不過大多數SoC只有一個記憶體控制器,所以不分視訊記憶體和記憶體。把顯示卡想象成另外一臺機器。它要工作,無非也是“程式儲存”原理,上電之後,從特定的記憶體(視訊記憶體)地址去取指,然後執行指令。顯示卡的工作邏輯比CPU簡單多了,它一般就從一個環形buffer不斷的取指令,然後執行,CPU就不斷的去往環形buffer填指令。很多時候同一個動作既可以用MMIO,也可以用DMA,比如flip framebuffer。只要把flip framebuffer的指令正確傳到環形buffer就好了。但是MMIO需要CPU參與,傳大資料的時候,打亂CPU GPU並行性,划不來。驅動程式其實也是圍繞著這件事情來做的,Vista以前,顯示卡的驅動全都是kernel mode執行的,因為只有kernel mode才能訪問的物理地址,但是kernel mode的壞處是一旦有問題,系統就崩潰,而且kernel mode有很多侷限性,比如沒有C庫支援,浮點運算很難,代價很大等等。所以Vista之後,顯示卡驅動都分兩部分,kmd負責需要訪問物理地址的動作,其他事情都放到umd去做,包括API支援等等。所以一個3D程式執行的過程是這樣的,app generate command, call D3D runtime,D3D runtime call driver umd, driver umd system call driver kmd, kmd send command to ring buffer, graphic card exeute.至於顯示卡驅動要完成什麼部分,這個就是所謂HAL(hardware abstraction layer)層,也就是說HAL以下由廠商提供,以上就是作業系統自帶,在HAL層以上,所有的操作都是統一的,比如畫一個點,畫一條線,驅動來對應具體的某一款晶片生成真正的命令,比如畫點,需要0x9指令,把絕對座標放到地址0x12345678(舉例)。微軟管的比較寬,umd, kmd都有HAL層,意思是即使kmd你也不能亂寫,能統一的儘量統一,比如CPU GPU external fence讀寫同步機制就是微軟統一做的。流處理器就是說,那些處理器可以執行很多的指令,而不是就幾個固定的功能,比如原來我把幾個矩陣的乘法固定成一個操作(比如T&L單元),現在我把這個操作拆了,改成更基本的指令,比如,取矩陣元素,加乘,這樣更靈活。不過你就得多費心思去組合這些指令了,組合這些指令有個高大上的名字,shader。至於為什麼叫shader,越來越長了,不說了。