通過DWM的桌面合成
應用程序的顯示不再是直接畫到屏幕上,而是一個顯示内存中的一個離屏Surface。然後由DWM将這些Surface合成顯示到屏幕之上。
桌面合成
在Vista之前,Windows要求應用程序畫自己的可見區域,它們可以直接畫在顯卡的視頻緩沖裡面。而在Vista,系統要求應用程序把整個表面畫到離屏Surface當中。然後由DWM控制所有的離屏表面,并把它們合成到一起顯示到真正的屏幕上。
現在計算機的圖形芯片飛速發展,具有了很強的處理能力,現在它們主要用于遊戲等方面。DWM的主要目标就是利用圖形芯片的處理能力也給非遊戲用戶帶來盡可能好的體驗。因此DWM是基于DirectX,特别是Direct3D。更準備是說,DWM是直接建立在一個稱為Milcore的層次之上。Milcore又建立在DirectX之上。最終是用Direct3D紋理來表示窗口内容和窗口框架。
DWM/Milcore調用适當的Direct3D函數把所有的Direct3D紋理合成為最終的桌面。Vista或Win7桌面就可以理解為一個全屏幕的Direct3D應用程序。
優點
帶來的便利
從窗口系統的顯示角度上看,這可以給我們帶來很大的方便,幫助實現更高質量的視覺效果,比如:
1、訪問窗口:現在所有的窗口都顯示到離屏表面,這些離屏表面就可以用于其他的地方了。例如前面提到的Alt-Tab組合鍵所看到的縮略圖,用戶還可以據此實現一些其他需求。
2、窗口操作中不再涉及到背景應用程序:在Vista之前,如果隐藏的窗口變得重新可見,這部分區域隻有在應用程序醒來後并響應了WM_PAINT才能被重畫,這就引起了很多難看的效果。在Vista中,背景窗口不會收到WM_PAINT,也不會被要求提交,因為他們的内容已經在離屏表面當中了,可以被直接拿來進行重新合成。
3、更炫的用戶體驗,這個不用多說了,大家可以有自己的體驗感受。
4、高分辨率支持:大部分應用程序不知道它所運行的顯示器的分辨率。随着高分辨率顯示器的普及,這會使應用程序在物理空間看起來越來越小,效果很差。由于DWM訪問了窗口的離屏表面,其特殊的位置可以調整應用程序的顯示分辨率,使它在高分辨率顯示器上有更好的效果。
在DWM中,我們的每個窗口都用一個Surface表示,都可以看到為是3D的網格。雖然每個窗口還是一個矩形,但它們都位于一個3D空間之中。窗口的操作,比如最大化,還原等等,都發生了變化,它們都是對網格進行3D變換實現的。與以往有了很大的區别。
在WindowsVista或Windows7中窗口的毛玻璃效果非常絢麗。在窗口的邊界,我們可以看到窗口下面的内容。這其中同時具有一個的透明和模糊效果。但是,在實現毛玻璃時,為了不讓下面的窗口内容過于清晰影響上面的窗口,DWM組還對下面的窗口實現了模糊效果。
其中的實現要點有
1、模糊下面的内容,這是由自定義的象素Shader實現,這個Shader是一個完全運行在GPU的小程序,它可以并行處理多個象素。
2、模糊隻是針對窗口邊界下的部分内容。這些内容需要從不同的緩沖提取出來。
3、摸索的方法類似于平均值處理:一個象素的值等于其鄰居象素的平局值。
衆所周知,Direct3D支持多個Surface,最後顯示不同Surface時是通過Flip(翻轉)實現的,DWM也是如此。這樣實現的結果就是不會在出現以前的Tearing。使得桌面變得更平滑。
現在,我們的桌面雖然稱得上是一個全屏幕的Direct3D應用程序。不管是老式隻支持帖圖加速的圖形處理器還是新型的高速圖形處理器,我們都需要操作圖形處理器的存儲系統。這就出現了兩個重要的問題:
1、在窗口很多時,運行DWM需要的内存将是一個問題,它随着用戶的窗口數增加而增加。
2、DWM會與其它的應用程序共享内存資源。比如DirectX應用程序、視頻回放和WPF應用程序等等。
解決這些問題,微軟提出了Windows顯示驅動模型(DisplayDriverModel)。WDDM是Vista及以後操作系統的新的DirectX驅動模型。WDDM主要提供三項功能:1、虛拟化視頻内存。2、允許與GPU的交互。3、允許DirectX表面可以跨進程共享。
在WDDM中,顯示内容是虛拟化的。這就表示顯示内容與系統内存一樣。我們知道,在系統内存中如果内存分配完畢,此時還有新的分配要求,就會産生第二存儲頁面,然後由系統管理存儲頁面和主存儲的頁面算法和機制。現在,主存儲是顯示内存,而第二存儲頁面是系統内存。在顯示存儲和系統内存都分配完後,将使用磁盤作為視頻内存表面。
當然,這種情況比較少見。但是這樣的設計使得WDDM足夠的健壯,應用程序的可靠性也得到增強。在WDDM而言,它将實現非常關鍵的功能:執行内存的分配、實現分配内存和真正的顯示内存的控制。WDDM本身也在不斷的改進中。
既然WDDM已經實現了顯示内存的虛拟化,那麼這就意味着WDDM具有調整應用程序的GPU命令優先級的功能。這種功能通常是由WDDM調度程序實現。因此WDDM必須能中斷GPU的某些操作,并保存操作的上下文,以備在必要時恢複操作繼續運行。基于這項功能,WDDM提供了兩種級别的調度支持:
1、基本調度。它是基于DirectX9的WDDM驅動和硬件所支持的調度粒度。也就是說單獨的Primitive和Shader程序不能被中斷,上下文交換必須在它們完成後進行。
2、高級調度。它是基于DirectX10的WDDM驅動和硬件所支持的調度粒度。這種調用支持比Primitive和Shader更細粒度的中斷。注意,雖然DirectX10支持高級調度,但是它并不是DirecX10所必須的。也就是說,隻有部分硬件支持高級調度。桌面窗口管理器使用DirectX9,因此它是支持基本調度。
前面曾經提到過,通過WDDM可以支持Surface的跨進程共享。共享DirectX表面對于重定向DirectX應用程序非常重要。因為Vista必須要和以前的應用程序兼容,就必須支持以前用GDI、、DirectX編寫的應用程序。WDM必須把這些應用程序的窗口重定向到Surface,然後由WDM統一合成、最後顯示一個單一的Surface。
需要注意的一點是:WDM隻重定向Top-level的窗口。而對于MDI應用程序,它的所有Top-level窗口、子窗口會被合成為單獨的一個Surface,然後交給DWM合成。根據以前的Windows圖形系統。重定向主要分為以下三類:
1、隻用GDI顯示的窗口
毫無疑問,GDI應用程序在當今任是主流。WDM在重定向基于GDI的應用程序時,基本過程如下:
A、在系統内存中分配一個和窗口大小一樣的内存塊,然後和窗口關聯。
B、顯示内存中也分配一個同樣大小、指定象素格式的顯存塊。
C、然後,當應用程序獲得窗口的DC時,因為這個窗口還沒有參與到WDM的合成,所以現在,它活動的DC不在是主視頻内存中,而且前面在系統内存中分配的内存塊。
D、經過GDI的操作後,在系統内存形成一個Surface。
E、系統會根據窗口的各種參數、适當的從系統内存複制顯示内容到視頻内存中。
F、這樣,視頻内存的數據就和窗口保持一緻,剩下的工作就由WDM完成:合成各個Surface,形成最終的桌面。
其他信息
另外還有兩點需要特别說明
(1)、雙緩沖窗口。現在,雙緩沖技術顯示的窗口特别多,它能有效的避免閃爍。确實,在使用了雙緩沖的GDI窗口中,它本身就有兩個内存塊,一個在系統,一個在顯卡。所以問題來了:為什麼重定向時不直接使用雙緩沖中的顯示内存塊呢?這樣做主要有兩個問題:一是格式不相同,GDI顯示的格式和DirectX的格式不相同。
GDI不支持以DirectX格式進行提交。二是很多GDI操作(XOR、文本、Alpha混合等等)是一種“讀取-修改-寫回”這樣的三步操作。如果重定向時直接使用顯存塊,GDI顯示的時候必須從顯存讀取原來的顯示内容到CPU(或者系統内存),然後再修改,最後寫回到顯存。這樣的操作效率非常低。所以沒有采用。
(2)、最小化窗口。通常,最小化後的窗口隻顯示在任務欄的一個很小範圍内,我們需要畫窗口的大小估計也隻有130X30。但是,在DWM中沒有采用這種用法。因為,如果窗口最小化後我們把Surface的大小修改為130x30再按需顯示,這樣會在Filp3D或者取縮略圖時有問題,因此窗口已經被修改。所以,DWM在窗口最小化後保存了最後一次更新的Sureface内容。
隻用DirectX顯示的窗口
由于DirectX應用程序通常是通過調用Present()函數進行Surface的提交,所以這類應用程序通常隻需要一個窗口緩沖就可以實現重定向。這種DirectX窗口的重定向是由DirectX系統(實際上是DirectX10)處理的,當DirectX10決定顯示某個Surface時,它會調用DWM的接口,以此實現跨進程的共享。DirectX10的“Furface共享”是一個非常獨特的功能,其建立在WDDM之上。這也是運行DWM必須要WDDM的關鍵原因之一。
當Present()顯示Surface時,DWM會得到通知,表示應該更新其原來的窗口Surface,更新後DWM再重新進行合成。注意WPF應用程序也是DirectX應用程序。它們也是采用這種重定向方式。
混合GDI和DirectX的窗口
現在,有很多的Top-level窗口采用了GDI+DirectX的方式進行内容顯示。根據混合的方式不同結果也不同。如果Top-Level窗口以及它的每個子窗口是用唯一的方式進行顯示,比如主窗口隻用DirectX,子窗口隻用了GDI,DWM對這樣的窗口會形成自己的“合成”樹。沒有子窗口單獨顯示,然後整個Tree的Surface被合成為傳遞給桌面。這樣的混合方式能很好的實現。
對于單獨一個Top-level窗口同時使用GDI+DirectX顯示,比較麻煩。特别是GDI+DirectX對窗口的某個區域進行重複顯示的情況。DWM通常不支持這樣的窗口。



















