架構與元件

注意

針對Windows 10上的應用程式,我們建議使用 Windows.UI.Composition API,而不是 DirectComposition。 如需詳細資訊,請參閱 使用視覺層將傳統型應用程式現代化

本主題描述組成 Microsoft DirectComposition 的元件。 其中包含下列各節。

軟體元件

DirectComposition 包含下列主要軟體元件。

  • 實作元件物件模型 (COM) 公用 API 的使用者模式應用程式程式庫 (dcomp.dll) 。
  • 使用者模式組合引擎 (dwmcore.dll) 裝載于桌面視窗管理員 (DWM) 進程 (dwm.exe) ,並執行實際的桌面組合。
  • 核心模式物件資料庫 (將命令從應用程式封送處理至組合引擎的一部分win32k.sys) 。

組合引擎的單一實例會處理所有應用程式的 DirectComposition 組合樹狀結構,以及代表整個桌面的 DWM 組合樹狀結構。 核心模式物件資料庫和使用者模式組合引擎都會在每個會話具現化一次,因此具有多個使用者的終端機伺服器電腦同時擁有這兩個元件的多個實例。

下圖顯示主要 DirectComposition 元件,以及它們彼此的關聯性。

directcomposition 最上層架構

應用程式程式庫

DirectComposition 應用程式程式庫是公用 COM 型 API,具有從 dcomp.dll 匯出的單一一般進入點,並傳回裝置物件的介面指標。 裝置物件接著具有建立所有其他物件的方法,每個物件都是由介面指標表示。 所有 DirectComposition 介面都會繼承自 並完全實作 IUnknown 介面。 接受 DirectComposition 介面的所有方法都會檢查介面是在dcomp.dll內實作,還是由另一個元件實作。 由於 DirectComposition 不是可延伸的,因此如果介面未在 dcomp.dll 中實作,則採用介面做為參數的方法會傳回E_INVALIDARG。 API 不需要特殊許可權;它可以由在最低層級存取的處理常式呼叫。 不過,由於 API 不會在會話 0 中運作,因此不適用於服務。 在這些方面,DirectComposition API 與其他 Microsoft DirectX API 類似,尤其是 Direct2D、Microsoft Direct3D 和 Microsoft DirectWrite。

由於組合引擎是專為非同步執行所設計,因此 DirectComposition API 中的物件屬性是唯讀的。 所有屬性都有 setter 方法,但沒有 getter 方法。 讀取屬性不僅需要大量資源,也可能會不正確,因為組合引擎傳回的任何值都可以立即變成無效。 例如,如果獨立動畫系結至正在讀取的屬性,就會發生這種情況。

API 是安全線程的。 應用程式可以隨時從任何執行緒呼叫任何方法。 不過,因為必須在特定序列中呼叫許多 API 方法,而不需要任何同步處理,應用程式就可能會根據執行緒交錯的方式遇到無法預期的行為。 例如,如果兩個執行緒同時將相同物件的相同屬性變更為不同的值,則應用程式無法預測兩個值中的哪一個是屬性的最終值。 同樣地,如果兩個執行緒在相同的裝置上呼叫 Commit ,兩個執行緒都不會真正發生交易行為,因為一個執行緒上對 Commit 的呼叫會提交這兩個執行緒所發出之所有命令的批次,而不只是呼叫 Commit的命令。

系統會維護每個裝置物件的所有內部狀態。 如果應用程式建立兩個以上的 DirectComposition 裝置物件,應用程式可以維護獨立批次和兩者之間的其他狀態。

所有 DirectComposition 物件都有裝置物件親和性;特定裝置物件所建立的物件只能與該裝置物件搭配使用,而且只能與相同裝置物件所建立的其他物件相關聯。 換句話說,每個裝置物件都是個別的脫離功能島。 其中一個例外狀況是視覺類別,允許建置視覺化樹狀結構,其中視覺效果可以屬於與其父系不同的裝置物件。 這可讓應用程式和控制項管理單一組合樹狀結構,而不需要共用單一 DirectComposition 裝置物件的情況。

組合引擎

DirectComposition 組合引擎會在專用進程上執行,與任何應用程式進程分開。 單一組合程式dwm.exe支援會話中的每個應用程式。 每個應用程式都可以為其擁有的每個視窗建立兩個視覺化樹狀結構。 所有樹狀結構實際上都會實作為較大視覺化樹狀結構的子樹,同時包含 DWM 的組成結構。 DWM 會針對會話中的每個桌面建構一個大型視覺化樹狀結構。 以下是此架構的主要優點:

  • 組合引擎可存取所有應用程式點陣圖和視覺化樹狀結構,以啟用跨進程視窗互通性和組合。
  • 組合引擎會在與任何應用程式進程分開的受信任系統進程中執行,讓具有低存取權限的應用程式安全地撰寫受保護的內容。
  • 組合引擎可以偵測特定視窗遭到完全遮蔽的時間,並避免浪費 CPU 和圖形處理單位, (GPU) 為視窗撰寫的資源。
  • 組合引擎可以直接撰寫到螢幕背景緩衝區,避免需要個別進程組合引擎所需的額外複本。
  • 所有應用程式都會共用單一 Direct3D 裝置以進行組合,這可節省大量記憶體

視覺化樹狀結構是保留的結構。 DirectComposition API 會公開方法,以以不可部分完成方式處理的變更批次編輯結構。 DirectComposition API 中的根物件是裝置物件,可作為所有其他 DirectComposition 物件的處理站,並包含稱為 Commit的方法。 組合引擎不會反映應用程式對視覺化樹狀結構所做的任何變更,直到應用程式呼叫 Commit為止,自上次 認可 以來的所有變更都會當做單一交易處理。

呼叫 Commit 的需求類似于「框架」的概念,不同之處在于,因為組合引擎會以非同步方式執行,所以它可以在呼叫 Commit之間呈現數個不同的畫面格。 在 DirectComposition 中, 框架 是組合引擎的單一反復專案,而應用程式在兩次對 Commit 呼叫之間花費的間隔稱為 批次

DirectComposition 會批次處理 DirectComposition API 的所有應用程式呼叫。 在 win32k.sys會話驅動程式中實作的核心物件資料庫,會儲存與 API 呼叫相關聯的所有狀態資訊。

組合引擎會針對顯示中的每個垂直空白產生一個框架。 框架是從垂直空白開始,並以後續的垂直空白為目標。 當框架啟動時,組合引擎會挑選所有擱置的批次,並在該框架中包含其命令。 當應用程式呼叫 Commit時,批次會放在擱置佇列中,而擱置佇列會在畫面開頭以不可部分完成的方式排清。 因此,有一個時間點會標記框架的開頭。 此時間點之前提交的任何批次都會包含在框架中,而之後提交的任何批次都必須等到下一個框架處理為止。 完整組合迴圈如下所示:

  1. 估計下一個垂直空白的時間。
  2. 擷取所有擱置的批次。
  3. 處理擷取的批次。
  4. 使用步驟 1 中估計的時間更新所有動畫。
  5. 決定需要重新撰寫之畫面的區域。
  6. 重新撰寫已變更的區域。
  7. 透過翻轉每個畫面的後端和前端緩衝區來呈現畫面。
  8. 如果步驟 6 和 7 中未撰寫並呈現任何內容,請等候批次認可。
  9. 等候下一個垂直空白。

如果有多個監視器連結至單一視訊配接器,組合引擎會使用主要監視器的垂直空白來驅動組合迴圈,並設定動畫取樣時間。 每個監視器都是由個別的全螢幕翻轉鏈結來表示;組合引擎會使用單一 Direct3D 裝置,以迴圈配置資源的方式,針對每個監視器重複步驟 6 和 7。 如果有多個視訊介面卡,組合引擎會針對步驟 6 和 7 中的每個視訊介面卡使用不同的 Direct3D 裝置。

下拉式列示方塊架會排程為一律以垂直空白開始,如下圖所示。

下拉式列示方塊架排程

如果組合引擎沒有因組合樹狀結構未變更而無法執行的工作,組合執行緒會在等候新的批次時睡眠。 提交新批次時,組合執行緒會喚醒,但會立即回到睡眠狀態,直到下一個垂直空白為止。 此行為可確保應用程式和組合引擎的可預測畫面開始和結束時間。

組合引擎會發佈畫面簡報時間和目前的畫面播放速率。 發佈此資訊可讓應用程式預估其本身批次的呈現時間,進而讓動畫同步處理。 特別是,應用程式可以使用組合引擎中的畫面統計資料組合,以及其 UI 執行緒產生批次所需時間的歷程記錄模型,以判斷其本身動畫的取樣時間。

例如,在上圖所示的應用程式批次開頭,應用程式可以查詢組合引擎,以判斷下一個畫面格的確切呈現時間。 應用程式接著可以使用目前時間,以及先前產生批次的相關資訊,以判斷應用程式是否可以在下一個垂直空白之前完成目前的批次。 因此,應用程式會使用框架呈現時間做為其本身動畫的取樣時間。 如果應用程式判斷它不太可能在目前的垂直空白中完成其工作,應用程式可以使用後續的框架時間做為取樣時間,而是使用組合引擎傳回的畫面播放速率資訊來計算該時間。

DirectComposition 概念