共用方式為


架構和元件

注意

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

本主題描述構成 directComposition Microsoft元件。 它包含下列各節。

軟體元件

DirectComposition 是由下列主要軟體元件所組成。

  • 實作元件物件模型(COM)型公用 API 的使用者模式應用程式連結庫(dcomp.dll)。
  • 裝載於桌面視窗管理員 (DWM) 行程 (dwm.exe) 中的使用者模式組合引擎 (dwmcore.dll),並執行實際的桌面組合。
  • 核心模式物件資料庫(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的命令批次。

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

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

組合引擎

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

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

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

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

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

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

  1. 估計下一個垂直空白的時間。
  2. 擷取所有暫止批次。
  3. 處理擷取的批次。
  4. 使用步驟 1 中估計的時間更新所有動畫。
  5. 判斷需要重新撰寫之畫面的區域。
  6. 重新撰寫髒區域。
  7. 藉由翻轉每個畫面的背面和前端緩衝區來呈現畫面。
  8. 如果步驟 6 和 7 中未撰寫並呈現任何專案,請等候批次認可。
  9. 等候下一個垂直空白。

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

組合框架會排程為一律從垂直空白開始,如下圖所示。

組合畫面排程

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

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

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

DirectComposition 概念