Share via


在高/標準動態範圍顯示器上使用 DirectX 與進階色彩

本主題說明如何使用 DirectX 搭配進階色彩案例,包括高動態範圍(HDR)、寬色域 (WCG) 與自動系統色彩管理,以及高位深度。 進階版 個人電腦(PC)顯示器至少具有上述其中一項增強功能,其色彩逼真度明顯高於傳統標準動態範圍(SDR)顯示器。

在本主題中,您將瞭解 Windows 進階色彩支持背後的重要技術概念概念。 您將瞭解將 HDR、WCG 和高位深度 DirectX 內容轉譯至其中一個顯示器的需求和指示。 如果您有色彩管理的應用程式(例如,使用 ICC 設定檔),則您將了解自動色彩管理如何為您的案例提供更好的色彩精確度。

Windows 中的進階色彩簡介

進階色彩 是操作系統(OS)技術的傘式術語,其色彩逼真度明顯高於標準顯示器。 下列各節將說明主要擴充功能。 針對具有 Windows 10 版本 1709(Fall Creators Update)的 HDR 顯示器,首次引進進階色彩功能,並針對 Windows 11 版本 22H2 (10.0) 特別布建的 SDR 顯示器:組建 22621) 版本。

高動態範圍

動態範圍是指場景中最大和最小亮度之間的差異;這通常以尼茨(candelas 每平方釐米)測量。 真實世界場景,如這個日落,往往有10個級級亮度的動態範圍:適應后,人眼可以分辨出更大的範圍。

picture of a sunset with brightness and darkest points in the scene labeled

自 Direct3D 9 以來,圖形引擎就能夠透過這種實際精確的精確度,在內部轉譯場景。 不過,典型的標準動態範圍顯示器只能重現 3 個以上的亮度級,因此任何 HDR 轉譯的內容都必須經過調音(壓縮)到有限的顯示器範圍。 新的 HDR 顯示器,包括符合 HDR10 (BT.2100) 標準的顯示器,突破這項限制:例如,高品質的自我發射顯示器可以達到6個以上的大小。

寬色色域

色域是指顯示器可以重現的色調範圍和飽和度。 人類眼睛所能察覺到的最飽和自然色彩是由純單色光組成,例如激光產生的。 不過,主流消費者顯示器通常只能在 sRGB 遊戲內重現色彩,它只代表所有人類感知色彩的大約 35%。 下圖代表人類「光譜定位」或所有可感知的色彩(在指定的亮度等級),其中較小的三角形是 sRGB 色域。

diagram of the human spectral locus and sRGB gamut

高端、專業的計算機顯示器長期以來一直支援比 sRGB 更寬的色彩範圍,例如 Adobe RGB 和 DCI-P3,其涵蓋大約一半的人類感知色彩。 這些寬廣的色板顯示器正變得越來越常見。

自動系統色彩管理

色彩管理是確保裝置之間正確且一致色彩複製的技術與做法。 如果您是數位內容建立者,其對於視覺內容中的色彩至關重要,例如相片、產品影像或標誌,在顯示器上與觀眾的各種數位裝置上一樣。

自 Windows 2000 以來,Windows 已提供色彩管理支援 API,其中包含影像色彩管理 (ICM) 和更新版本的 Windows 色彩系統 (WCS) API。 不過,這些 API 只是想要/需要進行色彩管理之應用程式的協助程式;雖然大部分的應用程式和數位內容只是假設業界標準的 sRGB 色彩空間,而且永遠不會由 OS 管理色彩。 這是過去一個合理的假設,但高品質的廣域顯示器正在變得更加普遍。

新版本的 Windows 支援自動系統色彩管理;可確保每個 Windows 應用程式中的所有色彩,無論它們是否為色彩感知,都會在每個支援的顯示器上正確且一致地顯示。

注意

自動色彩管理不是顯示硬體的屬性;相反地,它是 Windows 功能,可正確支援比 sRGB 更大的色彩色域的顯示器。

深度精確度/位深度

數值精確度或位深度是指用來唯一識別色彩的資訊量。 較高的位深度表示您可以區分非常相似的色彩,而不需要像帶狀等成品。 主流電腦顯示每色通道支援 8 位,而人眼至少需要 10-12 位的精確度,以避免可察覺的失真。

picture of windmills at a simulated 2 bits per color channel vs. 8 bits per channel

在 [進階色彩] 之前,桌面視窗管理員 (DWM) 限制的視窗化應用程式在每一色彩通道只輸出 8 位的內容,即使顯示器支援較高的位深度也一樣。 啟用進階色彩時,DWM 會使用 IEEE 半精確度浮點 (FP16)執行其組合,並消除任何瓶頸,並允許使用顯示器的完整精確度。

Windows 進階色彩系統架構

本節中的資訊是建置進階色彩應用程式的選擇性資訊;但瞭解技術的運作方式,以優化應用程式的轉譯和行為很有説明。

在本節中,我們將使用簡化圖表來描述 Windows 圖形堆疊的相關元件:

block diagram of Windows graphics stack: app to DWM to display kernel

現有的 Windows:8 位/sRGB 顯示器

幾十年來,取用者顯示器和 Windows 圖形堆疊是以每個通道 8 位(每圖元 24 位)sRGB 內容為基礎。 使用圖形 API 的應用程式,例如 DirectX 可以使用高位深度和延伸色彩空間來執行內部轉譯;不過,OS 僅支援具有隱含 sRGB 且沒有系統色彩管理的 8 位整數:

block diagram of SDR display stack: limited to sRGB, 8-bit, with no color management

這表示應用程式所轉譯的任何其他色彩資料會在顯示時遺失;而且應用程式必須自行執行色彩管理,以確保顯示器上的精確重現。

Windows 10 版本 1703:具有進階色彩的 HDR 顯示器

Windows 10 版本 1703 引進了 HDR 顯示器的第一個進階色彩功能版本。 這需要 OS 圖形堆疊中的數個重大進展:

  • HDR 顯示器訊號支援
  • 使用高位深度、標準色彩空間的系統組合
  • 自動系統色彩管理

block diagram of HDR display stack: FP16, scRGB, with auto color management

下列子區段涵蓋每項進步。 淨結果是,OS 現在已正確保留擴充應用程式色彩資料,並在 HDR 顯示器上正確重現。

HDR 顯示器訊號支援

透過顯示器連接器的 HDR 訊號,例如 DisplayPort 和 HDMI 主要使用每個通道精確度 (或更新版本) 10 位,以及 BT.2100 ST.2084 色彩空間。 顯示核心、顯示驅動程式和基礎 GPU 硬體都需要支援偵測、選取及驅動此訊號模式。

使用高位深度、標準色彩空間的系統組合

BT.2100 ST.2084 色彩空間是編碼 HDR 色彩的有效標準,但它不適合許多轉譯和組合(混合)作業。 我們也希望未來證明 OS 支援技術與色彩空間遠遠超出 BT.2100,其涵蓋人類可見色彩的不足 2/3。 最後,在可能的情況下,我們想要將 GPU 資源耗用量降到最低,以改善電源和效能。

在 HDR 模式中時,桌面視窗管理員 (DWM) 會使用標準組合色彩空間 (CCCS) 定義為:

  • scRGB 色彩空間 (BT.709/sRGB 初選與線性伽瑪)
  • IEEE 半精確度 (FP16 位深度)

這提供了上述所有目標之間的良好平衡。 CCCS 允許 [0, 1] 數值範圍以外的色彩值;假設有效 FP16 值的範圍,它可以代表比自然人類視覺範圍更多的色彩順序,包括亮度值超過 500 萬尼茨。 FP16 對於線性伽瑪混合作業具有絕佳的精確度,但成本是傳統單精確度(FP32)的 GPU 記憶體耗用量和頻寬的一半,沒有察覺的品質損失。

自動系統色彩管理

Windows 是多工環境,使用者可以同時執行任意數目的 SDR 和 HDR 應用程式與重迭視窗。 因此,當輸出到顯示器時,所有類型的內容類型看起來都正確且品質最高,這一點非常重要:例如,具有 BT.2100 ST.2084 (HDR) 視訊視窗播放的 sRGB (SDR) 生產力應用程式。

在 HDR 模式中時,Windows 會在兩個階段中執行色彩管理作業:

  1. DWM 會在混合之前,先將每個應用程式從原生色彩空間轉換成 CCCS。
  2. 顯示核心會將 OS 框架緩衝區從 CCCS 轉換成有線格式色彩空間(BT.2100 ST.2084)。

block diagram of auto color management occuring in DWM and display kernelblock diagram of auto color management occuring in DWM and display kernel, part 2

注意

在這兩個階段中,色彩管理作業包含色彩空間轉換(矩陣和 1DLUT)。 超過顯示目標色域的色彩會以數值方式裁剪。

Windows 11 版本 22H2:SDR 顯示進階色彩

雖然 HDR 顯示器的普及率正在迅速增長,但 SDR 顯示器在未來幾年內仍將很重要。 Windows 10 版本 1703 中的 HDR 支援也奠定了增強 SDR 顯示器所需的大部分基礎。 Windows 11 版本 22H2 會將進階色彩和自動色彩管理功能延伸至特定合格的 SDR 顯示器。 進階色彩 SDR 顯示器的圖形區塊圖看起來與 HDR 非常類似:

block diagram of SDR AC display stack: FP16, scRGB, with auto color management

具有高位深度的 SDR 顯示訊號支援

雖然 Windows 11 版本 22H2 版本支援每個通道 10 位,而且根據顯示器的功能,SDR 顯示器的基礎訊號不會變更。

使用高位深度、標準色彩空間的系統組合

DWM 進階色彩功能,包括在 CCCS 中混合幾乎與 HDR 顯示器完全保持不變。 主要差異在於 DWM 會搭配 SDR 顯示器使用顯示器參考的亮度,並使用 HDR 顯示器使用場景參照的亮度。 這會變更作業系統解譯進階色彩轉譯內容的方式:

顯示種類 亮度行為 如何解譯 1.0f
SDR Display-referred 作為顯示器的參考白階
Hdr 場景參考 作為80尼茨(名義參考白色)

自動系統色彩管理

OS 系統色彩管理功能也大多與 HDR 顯示器沒有變更。 主要差異在於顯示核心會轉換成顯示器色彩測量和校正資料所定義的顯示參照色彩空間,而不是 HDR 顯示器的標準 BT.2100 ST.2084 色彩空間。

顯示必要布建

需要來自 MHC ICC 設定檔的精確資料,才能定義顯示核心的輸出色彩管理作業。 因此,只有製造商特別布建的 SDR 顯示器,或具有有效配置檔的顯示器校正提供者才有資格進行自動色彩管理。 如需詳細資訊,請參閱 使用進階色彩 的 ICC 配置文件行為。

系統需求和作業系統支援

Windows 10 版本 1709 首次隨附 HDR 顯示器的進階色彩支援。 Windows 11 版本 22H2 版本新增 SDR 顯示具有正確布建數據的進階色彩支援。

本主題假設您的應用程式是以 Windows 10 版本 2004(或更新版本)作為 HDR 顯示器的目標,而適用於 SDR 顯示器的 Windows 11 版本 22H2 版本(或更新版本)。

顯示

高動態範圍顯示器必須實作 HDR10 或 BT.2100 ST.2084 標準。 HDR 顯示器品質可能會有很大的差異,我們強烈建議經過認證的顯示器,例如 VESA DisplayHDR。 從 Windows 11 版本 22H2 開始,Windows 會在 設定 應用程式中顯示已知顯示器的認證狀態。

標準動態範圍顯示器必須有精確的色彩布建數據,才能支援進階色彩。 在 Windows 11 版本 22H2 版本中,唯一支援覆寫此數據的方法是透過 MHC ICC 配置檔;此外,使用者或顯示器製造商必須已啟用自動色彩管理。 如需詳細資訊,請參閱 使用進階色彩的 ICC 配置文件行為。

圖像處理器 (GPU)

如需 SDR 和 HDR 顯示器的完整進階色彩功能,需要最近的 GPU:

  • AMD Radeon RX 400 系列 (Polaris), 或更新
  • NVIDIA GeForce 10 系列 (Pascal), 或更新版本
  • 選取的 Intel Core 第 10 代 (Ice Lake), 或更新的版本*

注意

Intel 程式代碼名稱 Comet Lake (5 位數模型代碼) 晶片組不提供完整的功能。

視案例而定,可能會套用其他硬體需求,包括硬體編解碼器加速(10 位 HEVC、10 位 VP9 等)和 PlayReady 支援(SL3000)。 請連絡 GPU 廠商以取得更具體的資訊。

圖像驅動程式 (WDDM)

強烈建議從 Windows Update 或 GPU 廠商或電腦製造商的網站使用最新的可用圖形驅動程式。 本主題依賴 WDDM 2.7 (Windows 10 版本 2004) 的驅動程式功能來顯示 HDR 顯示器,以及適用於 SDR 顯示器的 WDDM 3.0(Windows 11 版本 21H2)。

支援的轉譯 API

Windows 10 支援各種不同的轉譯 API 和架構。 進階色彩支援基本上依賴您的應用程式能夠使用 DXGI 或視覺層 API 來執行新式簡報。

因此,任何可輸出至其中一種簡報方法的轉譯 API 都可以支援進階色彩。 這包括(但不限於)下列內容。

  • Direct3D 11
  • Direct3D 12
  • Direct2D
  • Win2D
    • 需要使用較低層級 的 CanvasSwapChain CanvasSwapChainPanel API。
  • Windows.UI.Input.Inking
    • 支援使用 DirectX 的自訂幹墨轉譯。
  • XAML
    • 支援使用 MediaPlayerElement 播放 HDR 視訊
    • 支援使用 Image 元素解碼 JPEG XR 影像。
    • 支援使用 SwapChainPanel DirectX Interop。

處理動態顯示功能

Windows 10 支援各種支援進階色彩的顯示器,從高效能的整合面板到高端遊戲監視器和電視。 Windows 使用者預期您的應用程式會順暢地處理所有這些變化,包括無處不在的現有 SDR 顯示器。

Windows 10 可讓使用者控制 HDR 和進階色彩功能。 您的應用程式必須偵測目前顯示器的組態,並動態回應功能中的任何變更。 例如,由於使用者啟用或停用功能,或在不同顯示器之間移動應用程式,或系統電源狀態已變更,因此可能會發生這種情況。

選項 1:AdvancedColorInfo

注意

AdvancedColorInfo Windows 執行階段 API 可獨立于轉譯 API 使用、支援 SDR 顯示器的進階色彩,並使用事件在功能變更時發出訊號。 不過,它僅適用于通用 Windows 平臺 (UWP) 應用程式;傳統型應用程式(沒有 CoreWindow )無法使用。 如需詳細資訊,請參閱 傳統型應用程式中 不支援Windows 執行階段 API。

首先,從 DisplayInformation::GetAdvancedColorInfo 取得 AdvancedColorInfo 實例。

若要檢查目前作用中的進階色彩種類,請使用 AdvancedColorInfo::CurrentAdvancedColorKind 屬性。 這是要檢查的最重要屬性,您應該設定轉譯和呈現管線以回應作用中的類型:

進階色彩種類 顯示功能
SDR 沒有進階色彩功能的 SDR 顯示器
Wcg 具有高位深度和自動色彩管理的 SDR 顯示器
Hdr 具有所有進階色彩功能的 HDR 顯示器

若要檢查支援哪些進階色彩類型,但不一定使用中,請呼叫 AdvancedColorInfo::IsAdvancedColorKindAvailable 。 例如,您可以使用該資訊來提示使用者流覽至 Windows 設定 應用程式,讓他們能夠啟用 HDR 或自動色彩管理。

AdvancedColorInfo 其他成員提供面板實體色彩量(亮度和色度)的量化資訊,其對應至 SMPTE ST.2086 靜態 HDR 中繼資料。 即使 ST.2086 原本是針對 HDR 顯示器所設計,但該資訊很有用,而且適用于 HDR 和 SDR 顯示器。 您應該使用該資訊來設定應用程式的音調對應和遊戲對應。

若要處理進階色彩功能的變更,請註冊 DisplayInformation::AdvancedColorInfoChanged 事件。 如果顯示器進階色彩功能的任何參數因任何原因而變更,就會引發該事件。

取得 AdvancedColorInfo 的新實例 並檢查哪些值已變更,以處理該事件。

IDXGIOutput6

注意

DirectX Graphics Infrastructure IDXGIOutput6 介面適用于任何使用 DirectX 的應用程式,無論是桌面還是通用 Windows 平臺 (UWP)。 不過, IDXGIOutput6 不支援 具有進階色彩功能的 SDR 顯示器,例如自動色彩管理;它只能識別 HDR 顯示器。

如果您要撰寫 Win32 傳統型應用程式,並使用 DirectX 轉譯,請使用 DXGI_OUTPUT_DESC1 來取得顯示功能。 透過 IDXGIOutput6::GetDesc1 取得該結構的實例。

若要檢查目前作用中的進階 Color 種類,請使用 ColorSpace 屬性,其類型 為 DXGI_COLOR_SPACE_TYPE ,並包含下列其中一個值:

DXGI_COLOR_SPACE_TYPE 顯示功能
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 沒有進階色彩功能的 SDR 顯示器
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 具有所有進階色彩功能的 HDR 顯示器

注意

具有進階色彩功能的 SDR 顯示器也會回報為 DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 ;DXGI 不允許您區分這兩種類型。

注意

DXGI 不會讓您檢查目前支援哪些進階色彩類型。但目前不支援。

DXGI_OUTPUT_DESC1 大多數其他成員都提供面板實體色彩量(亮度和色度)的量化資訊,其對應至 SMPTE ST.2086 靜態 HDR 中繼資料。 即使 ST.2086 原本是針對 HDR 顯示器所設計,但該資訊很有用,而且適用于 HDR 和 SDR 顯示器。 您應該使用該資訊來設定應用程式的音調對應和遊戲對應。

Win32 傳統型應用程式沒有原生機制來回應進階色彩功能變更。 相反地,如果您的應用程式使用轉譯迴圈,則您應該使用每個畫面查詢 IDXGIFactory1::IsCurrent 。 如果報告 FALSE ,則您應該取得新的 DXGI_OUTPUT_DESC1 ,並檢查哪些值已變更。

此外,您的 Win32 訊息幫浦應該處理 WM_SIZE 訊息,這表示您的應用程式可能在不同的顯示器之間移動。

注意

若要取得新的 DXGI_OUTPUT_DESC1 ,您必須取得目前的顯示。 不過,您不應該呼叫 IDXGISwapChain::GetContainingOutput 。 這是因為交換鏈結會在 DXGIFactory::IsCurrent 為 false 時 傳回過時的 DXGI 輸出,並重新建立交換鏈結以取得暫時黑色畫面的結果。 相反地,我們建議您列舉所有 DXGI 輸出的界限,並判斷哪一個與應用程式視窗界限有最大的交集。

下列範例程式碼來自 GitHub 上的 Direct3D 12 HDR 範例應用程式

// Retrieve the current default adapter.
ComPtr<IDXGIAdapter1> dxgiAdapter;
ThrowIfFailed(m_dxgiFactory->EnumAdapters1(0, &dxgiAdapter));

// Iterate through the DXGI outputs associated with the DXGI adapter,
// and find the output whose bounds have the greatest overlap with the
// app window (i.e. the output for which the intersection area is the
// greatest).

UINT i = 0;
ComPtr<IDXGIOutput> currentOutput;
ComPtr<IDXGIOutput> bestOutput;
float bestIntersectArea = -1;

while (dxgiAdapter->EnumOutputs(i, &currentOutput) != DXGI_ERROR_NOT_FOUND)
{
    // Get the retangle bounds of the app window
    int ax1 = m_windowBounds.left;
    int ay1 = m_windowBounds.top;
    int ax2 = m_windowBounds.right;
    int ay2 = m_windowBounds.bottom;

    // Get the rectangle bounds of current output
    DXGI_OUTPUT_DESC desc;
    ThrowIfFailed(currentOutput->GetDesc(&desc));
    RECT r = desc.DesktopCoordinates;
    int bx1 = r.left;
    int by1 = r.top;
    int bx2 = r.right;
    int by2 = r.bottom;

    // Compute the intersection
    int intersectArea = ComputeIntersectionArea(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2);
    if (intersectArea > bestIntersectArea)
    {
        bestOutput = currentOutput;
        bestIntersectArea = static_cast<float>(intersectArea);
    }

    i++;
}

// Having determined the output (display) upon which the app is primarily being 
// rendered, retrieve the HDR capabilities of that display by checking the color space.
ComPtr<IDXGIOutput6> output6;
ThrowIfFailed(bestOutput.As(&output6));

DXGI_OUTPUT_DESC1 desc1;
ThrowIfFailed(output6->GetDesc1(&desc1));

設定 DirectX 交換鏈結

一旦您判斷顯示器目前支援進階色彩功能,請設定交換鏈結,如下所示。

使用翻轉簡報模型效果

使用其中一個 CreateSwapChainFor[Hwnd| 建立交換鏈結時組合|CoreWindow] 方法,您必須選取 DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL 或 DXGI_SWAP_EFFECT_FLIP_DISCARD 選項來使用 DXGI 翻轉模型,這可讓您的交換鏈結有資格從 DWM 和 各種全螢幕優化進行進階色彩處理。 如需詳細資訊,請參閱 如需最佳效能,請使用 DXGI 翻轉模型

選項 1。 使用 FP16 像素格式和 scRGB 色彩空間

Windows 10 支援兩個主要的像素格式和進階色彩空間組合。 根據應用程式的特定需求選取一個。

我們建議一般用途的應用程式使用選項 1。 這是適用于所有類型的進階色彩顯示、內容和轉譯 API 的唯一選項。 建立交換鏈結時,請在DXGI_SWAP_CHAIN_DESC1中 指定 DXGI_FORMAT_R16G16B16A16_FLOAT 。 根據預設,使用浮點像素格式建立的交換鏈結會被視為使用 DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 色彩空間。 這是 DWM 所使用的相同像素格式和色彩空間。

該組合提供數值範圍和精確度,以指定任何實際可能色彩,並執行任意處理,包括混合。

不過,該選項會耗用每圖元 64 位,相較于傳統的 UINT8 像素格式,這會將 GPU 頻寬和記憶體耗用量加倍。 此外,scRGB 會使用超出正規化 [0, 1] 範圍的數值來表示在 sRGB gamut 和/或大於 80 nits 的亮度之外色彩。 例如,scRGB (1.0, 1.0, 1.0) 會將標準 D65 白色編碼為 80 nits;但 scRGB (12.5, 12.5, 12.5) 編碼相同的 D65 白色在更亮的 1000 nits。 某些圖形作業需要正規化數值範圍,您必須修改作業,或重新正規化色彩值。

使用該選項來解譯亮度值的方式在 SDR 和 HDR 顯示器之間有所不同;請參閱下方。

選項 2:使用 UINT10/RGB10 像素格式和 HDR10/BT.2100 色彩空間

選項 2 是效能優化,只有在您的應用程式符合下列所有條件時,才能使用:

  • 以 HDR 顯示器為目標
  • 使用 Direct3D 12 或 Direct3D 11
  • 交換鏈結不需要與 Alpha/透明度混合

如果您的應用程式不符合所有這些條件,則必須使用選項 1。

但是,如果您的 app 符合選項 2 的資格,則如果您的 app 正在取用 HDR10 編碼的內容,例如視訊播放程式,或主要用於全螢幕案例,例如遊戲,則這可能會提供更好的效能。 建立交換鏈結時,您應該考慮在DXGI_SWAP_CHAIN_DESC1 指定 DXGI_FORMAT_R10G10B10A2_UNORM。 根據預設,會被視為使用 sRGB 色彩空間;因此,您必須明確呼叫 IDXGISwapChain3::SetColorSpace1 ,並將 設定為色彩空間 DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 ,也稱為 HDR10/BT.2100。

此選項會使用與傳統 UINT8 SDR 像素格式相同的每圖元 32 位。 此外,在某些 GPU 上,這可消除將內容轉換成 HDR10 有線格式所需的一些處理。

當顯示器處於 SDR 模式時,使用進階色彩交換鏈結

即使顯示器不支援所有進階色彩功能,您也可以使用進階色彩交換鏈結。 在這些情況下,桌面視窗管理員 (DWM) 會藉由執行數值裁剪來縮小內容,以符合顯示的功能。 例如,如果您轉譯為 FP16 scRGB 交換鏈結,並以標準顯示為目標,則會裁剪 [0, 1] 數值範圍以外的所有專案。

如果您的應用程式視窗跨越兩個以上的顯示器,且具有不同進階色彩功能,也會發生這種向下轉換行為。 AdvancedColorInfo IDXGIOutput6 會抽象化為只 報告主要 顯示器的特性( 主要 定義為包含視窗中央的顯示器)。

比對應用程式的參考白色與 OS SDR 參考白階

注意

參考白色僅適用于 HDR 顯示器;對於 SDR 進階色彩顯示器,(1.0、1.0、1.0)一律表示顯示器可以重現的最大白色亮度。

在許多情況下,您的應用程式會想要同時轉譯 SDR 和 HDR 內容;例如,透過 HDR 視訊或 UI 轉譯字幕或傳輸控制項,或將 UI 轉譯成遊戲場景。 請務必瞭解 SDR 參考白階 的概念 ,以確保您的 SDR 內容在 HDR 顯示器上看起來正確。 參考白色表示擴散白色物件(例如紙張工作表或有時 UI)出現在 HDR 場景中的亮度。 由於 HDR 色彩值具有 場景參照亮度 ,因此特定色彩值應該會顯示在絕對亮度層級,而不是相對於最大可能面板值。 例如,scRGB (1.0, 1.0, 1.0) 和 HDR10 (497, 497, 497) 都以 80 nits 亮度編碼完全 D65 白色。 Windows 可讓使用者將 SDR 參考白階 調整 為其喜好設定;這就是 Windows 將呈現 sRGB (1.0, 1.0, 1.0, 1.0) 的亮度。 在桌面 HDR 監視器上,SDR 參考白色層級通常會設定為大約 200 個 nits。

您的 HDR 應用程式必須允許使用者設定其所需的參考白階,或讀取系統所設定的值。 您必須將場景中的擴散白色值對應至 SDR 參考白色層級。 這需要線上性伽瑪空間中相乘您的應用程式框架緩衝區。

注意

在支援亮度控制項的顯示器上,例如在膝上型電腦上,Windows 也會調整 HDR(場景參照)內容的亮度,以符合使用者所需的亮度等級,但應用程式看不到。 除非您嘗試保證 HDR 訊號的位精確複製,否則通常可以忽略這一點。

如果您的 app 一律將 SDR 和 HDR 轉譯為不同的表面,並依賴 OS 組合,則 Windows 會自動執行正確的調整,將 SDR 內容提升到所需的白色層級。 例如,如果您的應用程式使用 XAML,並將 HDR 內容轉譯為自己的 SwapChainPanel

不過,如果您的 app 將自己的 SDR 和 HDR 內容組合成單一介面,則您必須自行執行 SDR 參考白階調整。 否則,在一般桌面檢視條件下,SDR 內容可能會顯得太暗。 首先,您必須取得目前的 SDR 參考白階,然後您必須調整您要轉譯之任何 SDR 內容的色彩值。

步驟 1。 取得目前的 SDR 參考白階

您可以透過下列其中一種方式取得目前的 SDR 參考白階:

步驟 2。 調整 SDR 內容的色彩值

Windows 會定義 80 nits 的名義或預設值參考白色層級。 因此,如果您要將標準 sRGB (1.0, 1.0, 1.0) 白色轉譯為 FP16 交換鏈結,則會以 80 nits 的亮度重現。 若要符合實際的使用者定義參考白階,您必須將 SDR 內容從 80 個 nit 調整為透過 AdvancedColorInfo.SdrWhiteLevelInNits 指定的層級。

如果您要使用 FP16 和 scRGB 轉譯,或是使用線性 (1.0) gamma 的任何色彩空間,則只要將 SDR 色彩值乘以 AdvancedColorInfo.SdrWhiteLevelInNits / 80 即可。 如果您使用 Direct2D,則會有預先定義的常數 D2D1_SCENE_REFERRED_SDR_WHITE_LEVEL ,其值為 80。

D2D1_VECTOR_4F inputColor; // Input SDR color value.
D2D1_VECTOR_4F outputColor; // Output color adjusted for SDR white level.
auto acInfo = ...; // Obtain an AdvancedColorInfo.

float sdrAdjust = acInfo->SdrWhiteLevelInNits / D2D1_SCENE_REFERRED_SDR_WHITE_LEVEL;

// Normally in DirectX, color values are manipulated in shaders on GPU textures.
// This example performs scaling on a CPU color value.
outputColor.r = inputColor.r * sdrAdjust; // Assumes linear gamma color values.
outputColor.g = inputColor.g * sdrAdjust;
outputColor.b = inputColor.b * sdrAdjust;
outputColor.a = inputColor.a;

如果您要使用非線性伽瑪色彩空間來轉譯,例如 HDR10,則執行 SDR 白階調整會比較複雜。 如果您要撰寫自己的圖元著色器,請考慮轉換成線性伽瑪以套用調整。

使用音調對應將 HDR 內容調整為顯示器的功能

HDR 和進階色彩顯示器在功能方面有很大的差異。 例如,在最小和最大亮度和色彩範圍中,它們能夠重現。 在許多情況下,您的 HDR 內容會包含超過顯示器功能的色彩。 為了獲得最佳影像品質,請務必執行 HDR 音調對應,基本上壓縮色彩範圍以配合顯示器,同時最好保留內容的視覺意圖。

要適應的最重要單一參數是最大亮度,也稱為 MaxCLL (內容光線等級):更複雜的音調對應程式也會適應最小亮度(MinCLL)和/或色彩初選。

步驟 1。 取得顯示器的色彩磁片區功能

通用 Windows 平台 (UWP) 應用程式

使用 AdvancedColorInfo 取得顯示器的色彩磁片區。

Win32 (桌面) DirectX 應用程式

使用 DXGI_OUTPUT_DESC1 來取得顯示器的色彩音量。

步驟 2。 取得內容的色彩量資訊

視 HDR 內容的來源而定,有許多可能的方式可以判斷其亮度和色域資訊。 某些 HDR 視訊和影像檔案包含 SMPTE ST.2086 中繼資料。 如果您的內容是以動態方式轉譯,則您可能可以從內部轉譯階段擷取場景資訊,例如場景中最亮的光源。

較一般但計算成本較高的解決方案是在轉譯的畫面格上執行長條圖或其他分析傳遞。 GitHub 上的 Direct2D 進階色彩影像轉譯範例應用程式 示範如何使用 Direct2D 來執行此動作;最相關的程式碼片段如下:

// Perform histogram pipeline setup; this should occur as part of image resource creation.
// Histogram results in no visual output but is used to calculate HDR metadata for the image.
void D2DAdvancedColorImagesRenderer::CreateHistogramResources()
{
    auto context = m_deviceResources->GetD2DDeviceContext();

    // We need to preprocess the image data before running the histogram.
    // 1. Spatial downscale to reduce the amount of processing needed.
    DX::ThrowIfFailed(
        context->CreateEffect(CLSID_D2D1Scale, &m_histogramPrescale)
        );

    DX::ThrowIfFailed(
        m_histogramPrescale->SetValue(D2D1_SCALE_PROP_SCALE, D2D1::Vector2F(0.5f, 0.5f))
        );

    // The right place to compute HDR metadata is after color management to the
    // image's native colorspace but before any tonemapping or adjustments for the display.
    m_histogramPrescale->SetInputEffect(0, m_colorManagementEffect.Get());

    // 2. Convert scRGB data into luminance (nits).
    // 3. Normalize color values. Histogram operates on [0-1] numeric range,
    //    while FP16 can go up to 65504 (5+ million nits).
    // Both steps are performed in the same color matrix.
    ComPtr<ID2D1Effect> histogramMatrix;
    DX::ThrowIfFailed(
        context->CreateEffect(CLSID_D2D1ColorMatrix, &histogramMatrix)
        );

    histogramMatrix->SetInputEffect(0, m_histogramPrescale.Get());

    float scale = sc_histMaxNits / sc_nominalRefWhite;

    D2D1_MATRIX_5X4_F rgbtoYnorm = D2D1::Matrix5x4F(
        0.2126f / scale, 0, 0, 0,
        0.7152f / scale, 0, 0, 0,
        0.0722f / scale, 0, 0, 0,
        0              , 0, 0, 1,
        0              , 0, 0, 0);
    // 1st column: [R] output, contains normalized Y (CIEXYZ).
    // 2nd column: [G] output, unused.
    // 3rd column: [B] output, unused.
    // 4th column: [A] output, alpha passthrough.
    // We explicitly calculate Y; this deviates from the CEA 861.3 definition of MaxCLL
    // which approximates luminance with max(R, G, B).

    DX::ThrowIfFailed(histogramMatrix->SetValue(D2D1_COLORMATRIX_PROP_COLOR_MATRIX, rgbtoYnorm));

    // 4. Apply a gamma to allocate more histogram bins to lower luminance levels.
    ComPtr<ID2D1Effect> histogramGamma;
    DX::ThrowIfFailed(
        context->CreateEffect(CLSID_D2D1GammaTransfer, &histogramGamma)
        );

    histogramGamma->SetInputEffect(0, histogramMatrix.Get());

    // Gamma function offers an acceptable tradeoff between simplicity and efficient bin allocation.
    // A more sophisticated pipeline would use a more perceptually linear function than gamma.
    DX::ThrowIfFailed(histogramGamma->SetValue(D2D1_GAMMATRANSFER_PROP_RED_EXPONENT, sc_histGamma));
    // All other channels are passthrough.
    DX::ThrowIfFailed(histogramGamma->SetValue(D2D1_GAMMATRANSFER_PROP_GREEN_DISABLE, TRUE));
    DX::ThrowIfFailed(histogramGamma->SetValue(D2D1_GAMMATRANSFER_PROP_BLUE_DISABLE, TRUE));
    DX::ThrowIfFailed(histogramGamma->SetValue(D2D1_GAMMATRANSFER_PROP_ALPHA_DISABLE, TRUE));

    // 5. Finally, the histogram itself.
    HRESULT hr = context->CreateEffect(CLSID_D2D1Histogram, &m_histogramEffect);
    
    if (hr == D2DERR_INSUFFICIENT_DEVICE_CAPABILITIES)
    {
        // The GPU doesn't support compute shaders and we can't run histogram on it.
        m_isComputeSupported = false;
    }
    else
    {
        DX::ThrowIfFailed(hr);
        m_isComputeSupported = true;

        DX::ThrowIfFailed(m_histogramEffect->SetValue(D2D1_HISTOGRAM_PROP_NUM_BINS, sc_histNumBins));

        m_histogramEffect->SetInputEffect(0, histogramGamma.Get());
    }
}

// Uses a histogram to compute a modified version of MaxCLL (ST.2086 max content light level).
// Performs Begin/EndDraw on the D2D context.
void D2DAdvancedColorImagesRenderer::ComputeHdrMetadata()
{
    // Initialize with a sentinel value.
    m_maxCLL = -1.0f;

    // MaxCLL is not meaningful for SDR or WCG images.
    if ((!m_isComputeSupported) ||
        (m_imageInfo.imageKind != AdvancedColorKind::HighDynamicRange))
    {
        return;
    }

    // MaxCLL is nominally calculated for the single brightest pixel in a frame.
    // But we take a slightly more conservative definition that takes the 99.99th percentile
    // to account for extreme outliers in the image.
    float maxCLLPercent = 0.9999f;

    auto ctx = m_deviceResources->GetD2DDeviceContext();

    ctx->BeginDraw();

    ctx->DrawImage(m_histogramEffect.Get());

    // We ignore D2DERR_RECREATE_TARGET here. This error indicates that the device
    // is lost. It will be handled during the next call to Present.
    HRESULT hr = ctx->EndDraw();
    if (hr != D2DERR_RECREATE_TARGET)
    {
        DX::ThrowIfFailed(hr);
    }

    float *histogramData = new float[sc_histNumBins];
    DX::ThrowIfFailed(
        m_histogramEffect->GetValue(D2D1_HISTOGRAM_PROP_HISTOGRAM_OUTPUT,
            reinterpret_cast<BYTE*>(histogramData),
            sc_histNumBins * sizeof(float)
            )
        );

    unsigned int maxCLLbin = 0;
    float runningSum = 0.0f; // Cumulative sum of values in histogram is 1.0.
    for (int i = sc_histNumBins - 1; i >= 0; i--)
    {
        runningSum += histogramData[i];
        maxCLLbin = i;

        if (runningSum >= 1.0f - maxCLLPercent)
        {
            break;
        }
    }

    float binNorm = static_cast<float>(maxCLLbin) / static_cast<float>(sc_histNumBins);
    m_maxCLL = powf(binNorm, 1 / sc_histGamma) * sc_histMaxNits;

    // Some drivers have a bug where histogram will always return 0. Treat this as unknown.
    m_maxCLL = (m_maxCLL == 0.0f) ? -1.0f : m_maxCLL;
}

步驟 3。 執行 HDR 音調對應作業

音調對應原本就是遺失的程式,而且可以針對一些感知或目標計量進行優化,因此沒有單一標準演算法。 Windows 會在 Direct2D 以及媒體基礎 HDR 視訊播放管線中提供內建 HDR 音調圖效果 。 其他常用的演算法包括 ACES Filmic、Reinhard 和ITU-R BT.2390-3 EETF(電電傳輸功能)。

下一個程式碼範例會顯示簡化的 Reinhard tonemapper 運算子。

// This example uses C++. A typical DirectX implementation would port this to HLSL.
D2D1_VECTOR_4F simpleReinhardTonemapper(
    float inputMax, // Content's maximum luminance in scRGB values, e.g. 1.0 = 80 nits.
    float outputMax, // Display's maximum luminance in scRGB values, e.g. 1.0 = 80 nits.
    D2D1_VECTOR_4F input // scRGB color.
)
{
    D2D1_VECTOR_4F output = input;

    // Vanilla Reinhard normalizes color values to [0, 1].
    // This modification scales to the luminance range of the display.
    output.r /= inputMax;
    output.g /= inputMax;
    output.b /= inputMax;

    output.r = output.r / (1 + output.r);
    output.g = output.g / (1 + output.g);
    output.b = output.b / (1 + output.b);

    output.r *= outputMax;
    output.g *= outputMax;
    output.b *= outputMax;

    return output;
}

擷取 HDR 和 WCG 畫面內容

支援指定像素格式的 API,例如 Windows.Graphics.Capture 命名空間中的 像素格式,以及 IDXGIOutput5::D uplicateOutput1 方法,提供擷取 HDR 和 WCG 內容而不遺失圖元資訊的功能。 請注意,取得內容框架之後,需要額外的處理。 例如,HDR 到 SDR 音調對應(例如,用於網際網路共用的 SDR 螢幕擷取畫面複本)和以適當格式儲存的內容(例如 JPEG XR)。

舊版色彩管理和 ICC 設定檔行為的變更

進階色彩和自動色彩管理可確保所有應用程式、舊版和新式的顯示色彩一致且能正確顯示色彩。 不過,某些應用程式可能會使用國際色彩聯盟 (ICC) 色彩設定檔來執行自己的明確色彩管理。

當 SDR 或 HDR 顯示器上使用進階色彩時,顯示 ICC 設定檔的行為會以非回溯相容的方式變更。 如果您的 app 可與顯示 ICC 設定檔搭配運作,Windows 會提供相容性協助程式,以確保您的應用程式繼續取得正確的行為。

如需 ICC 設定檔行為變更,以及如何調整應用程式以最大化與進階色彩的相容性的詳細資訊,請參閱 使用進階色彩 的 ICC 設定檔行為。

其他資源

  • 在 GitHub 上, 搭配 DirectX 11 / DirectX 12 的 DirectX 工具組 使用 HDR 轉譯。 如何使用 DirectX 工具組 (DirectXTK) 將 HDR 支援新增至 DirectX 應用程式的逐步解說。
  • Direct2D 進階色彩影像轉譯範例應用程式 。 使用 Direct2D 實作進階色彩感知 HDR 和 WCG 影像檢視器的 UWP SDK 範例應用程式。 示範 UWP app 的完整最佳做法,包括回應顯示功能變更,以及調整 SDR 白色層級。
  • Direct3D 12 HDR 桌面範例應用程式 。 實作基本 Direct3D 12 HDR 場景的桌面 SDK 範例。
  • Direct3D 12 HDR UWP 範例應用程式 。 上述範例的 UWP 對等專案。
  • SimpleHDR_PC。 實作基本 Direct3D 11 HDR 場景的 Xbox ATG SimpleHDR 計算機範例應用程式(傳統型範例應用程式)。