高/標準のダイナミック レンジ ディスプレイで DirectX と高度な色を使用する

このトピックでは、ハイ ダイナミック レンジ (HDR)、自動システム カラー管理による広色域 (WCG)、高ビット深度などの高度なカラー シナリオで DirectX を使用する方法を説明します。 上記の拡張機能の少なくとも 1 つを備えたプレミアム パーソナル コンピュータ (PC) ディスプレイが普及しつつあり、従来の標準ダイナミック レンジ (SDR) ディスプレイよりも大幅に高いカラー忠実度を実現しています。

このトピックでは、Windows Advanced Color サポートの背後にある主要な技術的概念の概要を説明します。 HDR、WCG、高ビット深度の DirectX コンテンツをこれらのディスプレイのいずれかにレンダリングするための要件と手順について学習します。 カラー管理されたアプリ (ICC プロファイルを使用するアプリなど) をお持ちの場合は、自動カラー管理によってシナリオのカラー精度が向上する仕組みを学習します。

Windows の高度なカラーの概要

高度なカラー は、標準ディスプレイよりも大幅に高い色再現性を持つディスプレイ向けのオペレーティング システム (OS) テクノロジの総称です。 主要な拡張機能については、以下のセクションで説明します。 高度なカラー機能は、Windows 10 バージョン 1709 (Fall Creators Update) の HDR ディスプレイで初めて導入され、Windows 11 バージョン 22H2 (10.0、ビルド 22621) リリースでは、特別にプロビジョニングされた SDR ディスプレイで初めて導入されました。

高ダイナミック レンジ

ダイナミック レンジとは、シーン内の最大輝度と最小輝度の差を指します。これは通常、nits (平方センチメートルあたりのカンデラ) で測定されます。 この夕焼けのような現実世界のシーンでは、輝度のダイナミック レンジが 10 桁に達することがよくあります。人間の目は、順応するとさらに広い範囲を識別できます。

シーン内の最も明るい部分と最も暗い部分がラベル付けされた夕焼けの写真

Direct3D 9 以降、グラフィックス エンジンは、このレベルの物理的に正確な忠実度でシーンを内部的にレンダリングできるようになりました。 しかし、一般的な標準ダイナミック レンジ ディスプレイでは、3 桁強の輝度しか再現できないため、HDR レンダリングされたコンテンツは、ディスプレイの限られた範囲にトーンマップ (圧縮) する必要がありました。 HDR10 (BT.2100) 規格に準拠したものを含む新しい HDR ディスプレイは、この制限を打ち破ります。たとえば、高品質の自発光ディスプレイは、6 桁を超える解像度を実現できます。

広い色域

色域とは、ディスプレイが再現できる色相の範囲と彩度を指します。 人間の目が認識できる最も彩度の高い自然色は、レーザーによって生成されるような純粋な単色光で構成されています。 しかし、主流の消費者向けディスプレイでは、多くの場合、sRGB 色域内の色しか再現できず、これは人間が認識できるすべての色の約 35% にしか相当しません。 下の図は、人間の「スペクトル軌跡」、つまり特定の輝度レベルで知覚できるすべての色を表したもので、小さい三角形が sRGB 色域です。

人間のスペクトル軌跡と sRGB 色域の図

ハイエンドのプロフェッショナル向け PC ディスプレイは、人間が認識できる色の約半分をカバーする Adobe RGB や DCI-P3 など、sRGB よりも大幅に広い色域を長い間サポートしてきました。 そして、こうした広色域ディスプレイはますます一般的になりつつあります。

システムの色の自動管理

カラー管理とは、デバイス間で正確かつ一貫した色再現を保証する技術と実践です。 デジタル コンテンツの作成者にとって、写真、製品画像、ロゴなどのビジュアル コンテンツの色が、視聴者のさまざまなデジタル デバイスに表示される色と同じようにディスプレイに表示されることは非常に重要です。

Windows は、Windows 2000 以降、イメージ カラー管理 (ICM) 以降の Windows カラー システム (WCS) API を使用して、カラー管理サポート API を提供してきました。 ただし、これらの API は、カラー管理を希望または必要とするアプリのためのヘルパーに過ぎず、ほとんどのアプリとデジタル コンテンツは業界標準の sRGB 色空間を前提としており、OS によってカラー管理されることはありませんでした。 それは過去には妥当な仮定でしたが、高品質の広色域ディスプレイはますます一般的になりつつあります。

新しいバージョンの Windows では、自動システム カラー管理がサポートされています。これにより、カラー対応かどうかに関係なく、すべての Windows アプリのすべての色が、サポートされているすべてのディスプレイで正確かつ一貫して表示されます。

Note

自動カラー管理はディスプレイ ハードウェアの特性ではなく、sRGB よりも広い色域を持つディスプレイを適切にサポートするための Windows 機能です。

深い精度/ビット深度

数値精度 (ビット深度) は、色を一意に識別するために使用される情報の量を指します。 ビット深度が高いほど、バンディングなどのアーティファクトなしで非常に類似した色を区別できます。 主流の PC ディスプレイはカラー チャネルごとに 8 ビットをサポートしていますが、人間の目には知覚できる歪みを避けるために少なくとも 10 ~ 12 ビットの精度が必要です。

風車の画像 (カラーチャンネルあたり 2 ビットのシミュレーションとチャンネルあたり 8 ビットのシミュレーション)

高度なカラーより前は、ディスプレイがより高いビット深度をサポートしていたとしても、デスクトップ ウィンドウ マネージャー (DWM) によって、ウィンドウ アプリはカラー チャネルあたり 8 ビットでのみコンテンツを出力するように制限されていました。 高度なカラーを有効にすると、DWM は IEEE 半精度浮動小数点 (FP16) を使用して合成を実行し、ボトルネックを解消して、ディスプレイの完全な精度を使用できるようになります。

Windows 高度なカラー システムのアーキテクチャ

このセクションの情報は、 高度なカラー アプリの構築ではオプションですが、アプリのレンダリングと動作を最適化するために、テクノロジの仕組みを理解しておくと役立ちます。

このセクションでは、簡略化された図を使用して、Windows グラフィックス スタックの関連コンポーネントについて説明します。

Windows グラフィックス スタックのブロック図: アプリから DWM、ディスプレイ カーネルまで

既存の Windows: 8 ビット/sRGB ディスプレイ

数十年にわたり、消費者向けディスプレイと Windows グラフィックス スタックは、チャネルあたり 8 ビット (ピクセルあたり 24 ビット) の sRGB コンテンツに基づいていました。 DirectX などのグラフィック API を使用するアプリは、高ビット深度と拡張色空間を使用して内部レンダリングを実行できますが、OS は暗黙的な sRGB を使用した 8 ビット整数のみをサポートし、システム カラー管理はサポートしていませんでした。

SDR 表示スタックのブロック図: sRGB、8 ビットに制限され、カラー管理なし

つまり、アプリによってレンダリングされた追加のカラー データは表示時に失われ、ディスプレイ上で正確に再現されるようにするには、アプリ自体でカラー管理を実行する必要がありました。

Windows 10 バージョン 1703: 高度なカラーの HDR ディスプレイ

Windows 10 バージョン 1703 では、HDR ディスプレイ向けの高度なカラー機能の最初のバージョンが導入されました。 これには、OS グラフィックス スタックにおけるいくつかの重要な進歩が必要でした。

  • HDRディスプレイ シグナリング サポート
  • 高ビット深度の標準色空間を使用したシステム構成
  • システムの色の自動管理

HDR 表示スタックのブロック図: FP16、scRGB、自動カラー管理

それぞれの進歩については、以下のサブセクションで説明します。 最終的な結果として、拡張されたアプリのカラー データが OS によって正しく保存され、HDR ディスプレイで正確に再現されるようになりました。

HDRディスプレイ シグナリング サポート

DisplayPort や HDMI などのディスプレイ コネクタを介した HDR シグナリングでは、主にチャネルあたり 10 ビット (またはそれ以上) の精度と BT.2100 ST.2084 色空間が使用されます。 ディスプレイ カーネル、ディスプレイ ドライバー、および基盤となる GPU ハードウェアはすべて、このシグナリング モードの検出、選択、および駆動をサポートする必要があります。

高ビット深度の標準色空間を使用したシステム構成

BT.2100 ST.2084 色空間は HDR カラーをエンコードするための効率的な標準ですが、多くのレンダリングおよび合成 (ブレンディング) 操作には適していません。 また、人間が見える色の 2/3 未満をカバーする BT.2100 をはるかに超えるテクノロジと色空間をサポートするために、OS を将来的にも保証したいと考えています。 最後に、可能な限り、電力とパフォーマンスを向上させるために、GPU リソースの消費を最小限に抑えたいと考えています。

HDR モードの場合、デスクトップ ウィンドウ マネージャー (DWM) は次のように定義される標準構成色空間 (CCCS) を使用します。

  • scRGB 色空間 (線形ガンマの BT.709/sRGB 原色)
  • IEEE の半精度 (FP16 ビット深度)

これにより、上記のすべての目標の間で適切なバランスが保たれます。 CCCS は [0, 1] の数値範囲外のカラー値を許可します。有効な FP16 値の範囲が与えられれば、500 万 nits を超える輝度値を含む、人間の自然な視覚範囲よりも桁違いに多くの色を表現できます。 FP16 は線形ガンマ ブレンド演算の精度に優れていますが、GPU メモリ消費量と帯域幅は従来の単精度 (FP32) の半分で済み、品質の低下も目立ちません。

システムの色の自動管理

Windows はマルチタスク環境であり、ユーザーはウィンドウを重ねて任意の数の SDR アプリと HDR アプリを同時に実行できます。 したがって、ディスプレイに出力するときに、すべての種類のコンテンツが正しく表示され、最高の品質であることが重要です。たとえば、BT.2100 ST.2084 (HDR) ビデオ ウィンドウが再生されている sRGB (SDR) 生産性アプリなどです。

HDR モードでは、Windows は次の 2 段階でカラー管理操作を実行します。

  1. DWM は、ブレンドする前に各アプリをネイティブ色空間から CCCS に変換します。
  2. ディスプレイ カーネルは、OS フレームバッファーを CCCS からワイヤ形式の色空間 (BT.2100 ST.2084) に変換します。

DWM とディスプレイ カーネルで実行される自動カラー管理のブロック図DWM とディスプレイ カーネルで実行される自動カラー管理のブロック図、パート 2

Note

どちらのステージでも、カラー管理操作は色空間変換 (マトリックスと 1DLUT) で構成されます。 ディスプレイのターゲット 色域を超える色は、数値的にクリップされます。

Windows 11、バージョン 22H2: 高度なカラーを搭載した SDR ディスプレイ

HDR ディスプレイの普及は急速に進んでいますが、SDR ディスプレイは今後も重要な位置を占め続けるでしょう。 Windows 10 バージョン 1703 の HDR サポートにより、SDR ディスプレイを強化するために必要な基礎の大部分が整いました。 Windows 11 バージョン 22H2 では、特定の対象 SDR ディスプレイに高度なカラーおよび自動カラー管理機能が拡張されています。 高度なカラー SDR ディスプレイのグラフィックス ブロック図は、HDR と非常によく似ています。

SDR AC 表示スタックのブロック図: FP16、scRGB、自動カラー管理

高ビット深度での SDR ディスプレイ シグナリングのサポート

SDR ディスプレイの基本的なシグナリングは変更されていませんが、Windows 11 バージョン 22H2 リリースでは、ディスプレイの機能に応じて、チャネルあたり 10 ビット以上がサポートされます。

高ビット深度の標準色空間を使用したシステム構成

CCCS でのブレンドを含む DWM の高度なカラー機能は、HDR ディスプレイとほとんど変わりません。 主な違いは、DWM が SDR ディスプレイではディスプレイ参照輝度を使用し、HDR ディスプレイではシーン参照輝度を使用することです。 これにより、高度なカラーでレンダリングされたコンテンツが OS によって解釈される方法が変わります。

表示の種類 輝度の動作 1.0f はどのように解釈されるか
SDR 表示参照 ディスプレイの参照ホワイト レベルとして
HDR シーン参照 80 nits (標準参照ホワイト)

システムの色の自動管理

OS システムのカラー管理機能も HDR ディスプレイとほとんど変わりません。 主な違いは、ディスプレイ カーネルが、HDR ディスプレイの標準 BT.2100 ST.2084 色空間ではなく、ディスプレイの測色および調整データによって定義されたディスプレイ参照色空間に変換することです。

ディスプレイのプロビジョニングが必要

ディスプレイ カーネルの出力カラー管理操作を定義するには、MHC ICC プロファイルからの正確なデータが必要です。 したがって、有効なプロファイルを使用して製造元またはディスプレイ調整プロバイダーによって特別にプロビジョニングされた SDR ディスプレイのみが自動カラー管理の対象となります。 詳細については、「ICC プロファイルの動作と高度なカラー」を参照してください。

システム要件とオペレーティング システムのサポート

Windows 10 バージョン 1709 では、HDR ディスプレイ向けの高度なカラー サポートが初めて提供されました。 Windows 11 バージョン 22H2 リリースでは、正確なプロビジョニング データを持つ SDR ディスプレイの高度なカラーのサポートが追加されました。

このトピックでは、HDR ディスプレイの場合はアプリが Windows 10 バージョン 2004 (またはそれ以降)、SDR ディスプレイの場合はアプリが Windows 11 バージョン 22H2 リリース (またはそれ以降) を対象としていることを前提としています。

ディスプレイ

高ダイナミック レンジ ディスプレイでは、HDR10 または BT.2100 ST.2084 標準を実装する必要があります。 HDR の表示品質は大きく異なる場合があり、認定を受けたディスプレイ (VESA DisplayHDR など) を強くお勧めします。 Windows 11 バージョン 22H2 リリース以降、Windows では、Settings アプリに既知の表示の認定状態が表示されるようになりました。

標準のダイナミック レンジ ディスプレイでは、高度なカラーをサポートするために正確なカラー プロビジョニング データが必要です。 Windows 11 バージョン 22H2 リリースでは、このデータをオーバーライドする方法としてサポートされているのは、MHC ICC プロファイルを使用する方法のみです。また、ユーザーまたはディスプレイの製造元が自動カラー管理を有効にしている必要があります。 詳細については、「ICC プロファイルの動作と高度なカラー」を参照してください。

グラフィックス プロセッサ (GPU)

SDR ディスプレイと HDR ディスプレイの両方で完全な高度なカラー機能を使用するには、最新の GPU が必要です。

  • AMD Radeon RX 400 シリーズ (Polaris) 以降
  • NVIDIA GeForce 10 シリーズ (Pascal) 以降
  • 選択された Intel Core 10th Gen (Ice Lake) 以降*

Note

Intel コード名 Comet Lake (5 桁のモデル コード) チップセットでは、完全な機能は提供されません。

シナリオに応じて、ハードウェア コーデック アクセラレーション (10 ビット HEVC、10 ビット VP9 など) や PlayReady サポート (SL3000) などの追加のハードウェア要件が適用される場合があります。 詳細については、GPU ベンダーにお問い合わせください。

グラフィックス ドライバー (WDDM)

Windows Update、GPU ベンダー、または PC 製造元の Web サイトから入手できる最新のグラフィック ドライバーを入手することを強くお勧めします。 このトピックは、HDR ディスプレイの場合は WDDM 2.7 (Windows 10、バージョン 2004)、SDR ディスプレイの場合は WDDM 3.0 (Windows 11、バージョン 21H2) のドライバー機能に依存しています。

サポートされているレンダリング API

Windows 10 は、さまざまなレンダリング API とフレームワークをサポートしています。 高度なカラーのサポートは、基本的に、アプリが DXGI または Visual Layer API のいずれかを使用して最新のプレゼンテーションを実行できることに依存します。

そのため、これらのプレゼンテーション メソッドのいずれかに出力できるレンダリング API では、高度なカラーをサポートできます。 これには次のものが含まれますが、これらに限定されません。

  • Direct3D 11
  • Direct3D 12
  • Direct2D
  • Win2D
    • CanvasSwapChain または CanvasSwapChainPanel API の下位レベルを使用する必要があります。
  • Windows.UI.Input.Inking
    • DirectX を使用したカスタム ドライ インク レンダリングをサポートします。
  • XAML
    • MediaPlayerElement を使用した HDR ビデオの再生をサポートします。
    • Image 要素を使用した JPEG XR イメージのデコードをサポートします。
    • SwapChainPanel を使用した DirectX 相互運用をサポートします。

動的表示機能の処理

Windows 10 は、電力効率の高い統合パネルからハイエンドのゲーム用モニターやテレビまで、幅広い高度なカラー対応ディスプレイをサポートしています。 Windows ユーザーは、既存の SDR ディスプレイを含め、これらすべてのバリエーションをアプリがシームレスに処理することを期待しています。

Windows 10 では、HDR および高度なカラーの機能をユーザーが制御できます。 アプリは現在のディスプレイの構成を検出し、機能の変更に動的に応答する必要があります。 これは、ユーザーが機能を有効または無効にしたり、アプリを異なるディスプレイ間で移動したり、システムの電源状態が変化したりしたなど、さまざまな理由で発生する可能性があります。

オプション 1: AdvancedColorInfo

Note

AdvancedColorInfo Windows ランタイム API は、レンダリング API とは無関係に使用でき、SDR ディスプレイ用の高度なカラーをサポートし、イベントを使用して機能が変更されたときに通知します。 ただし、使用できるのはユニバーサル Windows プラットフォーム (UWP) アプリのみです。デスクトップ アプリ (CoreWindow を持たない) では使用できません。 詳細については、「デスクトップ アプリで使用できる Windows ランタイム API」を参照してください。

まず、DisplayInformation::GetAdvancedColorInfo から AdvancedColorInfo のインスタンスを取得します。

現在アクティブになっている高度なカラーの種類を確認するには、AdvancedColorInfo::CurrentAdvancedColorKind プロパティを使用します。 これは確認すべき最も重要なプロパティであり、アクティブな種類に応じてレンダリングとプレゼンテーションのパイプラインを構成する必要があります。

高度なカラーの種類 ディスプレイの機能
SDR 高度なカラー機能のない SDR ディスプレイ
WCG 高いビット深度と自動カラー管理を備えた SDR ディスプレイ
HDR すべての高度なカラー機能を備えた HDR ディスプレイ

サポートされているが必ずしもアクティブではない高度なカラーの種類を確認するには、AdvancedColorInfo::IsAdvancedColorKindAvailable を呼び出します。 たとえば、その情報を使用して、ユーザーに Windows Settings アプリに移動して HDR または自動カラー管理を有効にするように促すことができます。

AdvancedColorInfo の他のメンバーは、SMPTE ST.2086 静的 HDR メタデータに対応する、パネルの物理的なカラーボリューム (輝度と色度) に関する定量的な情報を提供します。 ST.2086 はもともと HDR ディスプレイ用に設計されましたが、その情報は有用であり、HDR ディスプレイと SDR ディスプレイの両方で利用できます。 その情報を使用して、アプリのトーン マッピングと色域マッピングを構成する必要があります。

高度なカラー機能の変更を処理するには、 DisplayInformation::AdvancedColorInfoChanged イベントを登録します。 このイベントは、何らかの理由でディスプレイの高度なカラー機能のパラメーターが変更された場合に発生します。

そのイベントを処理するには、 AdvancedColorInfo の新しいインスタンスを取得し、変更された値を確認します。

IDXGIOutput6

Note

DirectX グラフィックス インフラストラクチャ IDXGIOutput6 インターフェイスは、デスクトップでもユニバーサル Windows プラットフォーム (UWP) でも、DirectX を使用するすべてのアプリで使用できます。 ただし、 IDXGIOutput6 では、自動色管理などの高度なカラー機能を備えた SDR ディスプレイがサポートされません。HDR ディスプレイのみを識別できます。

Win32 デスクトップ アプリを作成し、DirectX を使用してレンダリングする場合は、DXGI_OUTPUT_DESC1 を使用して表示機能を取得します。 IDXGIOutput6::GetDesc1 を使用して、その構造体のインスタンスを取得します。

現在アクティブになっている高度なカラーの種類を確認するには、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 ディスプレイ

Note

高度なカラー機能を備えた SDR ディスプレイも DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 として報告されます。DXGI では、2 つの型を区別できません。

Note

DXGI では、現在サポートされているがアクティブではない高度なカラーの種類を確認することはできません。

DXGI_OUTPUT_DESC1 の他のメンバーのほとんどは、SMPTE ST.2086 静的 HDR メタデータに対応するパネルの物理的なカラー ボリューム (輝度と色度) に関する定量的な情報を提供します。 ST.2086 はもともと HDR ディスプレイ用に設計されましたが、その情報は有用であり、HDR ディスプレイと SDR ディスプレイの両方で利用できます。 その情報を使用して、アプリのトーン マッピングと色域マッピングを構成する必要があります。

Win32 デスクトップ アプリには、高度なカラー機能の変更に対応するためのネイティブ メカニズムがありません。 代わりにアプリでレンダー ループを使用する場合は、各フレームで IDXGIFactory1::IsCurrent に対してクエリを実行する必要があります。 FALSE が報告される場合は、新しい DXGI_OUTPUT_DESC1 を取得して、変更された値を確認する必要があります。

さらに、Win32 メッセージ ポンプは、アプリが異なるディスプレイ間で移動した可能性があることを示す WM_SIZE メッセージを処理する必要があります。

Note

新しい 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|Composition|CoreWindow] メソッドでは、DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL または DXGI_SWAP_EFFECT_FLIP_DISCARD オプションを選択して DXGI フリップ モデルを使用する必要があります。これにより、スワップ チェーンは DWM からの高度なカラー処理とさまざまな全画面表示の最適化を実行できます。 詳細については、「パフォーマンスを最大限に高めるために DXGI フリップ モデルを使用する」を参照してください。

オプション 1. FP16 ピクセル形式と scRGB 色空間を使用する

Windows 10 では、高度なカラーのピクセル形式と色空間の 2 つの主な組み合わせがサポートされています。 アプリの特定の要件に基づいて 1 つを選択します。

汎用アプリでは、オプション 1 を使用することをお勧めします。 これは、すべての種類の高度な色の表示、コンテンツ、レンダリング API に対して機能する唯一のオプションです。 スワップ チェーンを作成するときは、DXGI_SWAP_CHAIN_DESC1DXGI_FORMAT_R16G16B16A16_FLOAT を指定します。 既定では、浮動小数点ピクセル形式で作成されたスワップ チェーンは、DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 色空間を使用しているかのように扱われます。 これは、DWM で使用されるのと同じピクセル形式と色空間です。

この組み合わせにより、物理的に可能なあらゆる色を指定し、ブレンドなどの任意の処理を実行するための数値範囲と精度が得られます。

ただし、このオプションでは 1 ピクセルあたり 64 ビットが消費され、従来の UINT8 ピクセル形式と比較して、GPU 帯域幅とメモリ消費量が 2 倍になります。 さらに、scRGB では、正規化された [0, 1] の範囲外の数値を使用して、sRGB 色域の外側にある色や、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 を使用する
  • スワップ チェーンにアルファ/透明度を使用したブレンドは不要

お使いのアプリがこれらの条件をすべて満たしていない場合は、オプション 1 を使用する必要があります。

ただし、アプリがオプション 2 の要件を満たしている場合、ビデオ プレーヤーなどの HDR10 でエンコードされたコンテンツをアプリが使用する場合や、ゲームなどの全画面表示シナリオで主に使用される場合は、パフォーマンスが向上する可能性があります。 スワップ チェーンを作成するときは、DXGI_SWAP_CHAIN_DESC1DXGI_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] の数値範囲外のすべてがクリップされます。

このダウンコンバージョン動作は、アプリ ウィンドウが、異なる高度なカラー機能を持つ 2 つ以上のディスプレイにまたがっている場合にも発生します。 AdvancedColorInfo および IDXGIOutput6 は、 (ウィンドウの中央を含むディスプレイとして定義されている main ディスプレイの特性 main) のみを報告するように抽象化されます。

アプリの参照ホワイトを OS の SDR 参照ホワイト レベルに合わせる

Note

参照ホワイトは HDR ディスプレイにのみ適用されます。SDR 高度なカラー ディスプレイの場合、(1.0、1.0、1.0) は常にディスプレイが再現できる最大のホワイト輝度を意味します。

多くのシナリオでは、アプリは SDR と HDR の両方のコンテンツをレンダリングする必要があります。たとえば、HDR ビデオに字幕やトランスポート コントロールをレンダリングしたり、ゲーム シーンに UI をレンダリングしたりします。 SDR コンテンツが HDR ディスプレイ上で正しく表示されるようにするには、SDR 参照ホワイト レベルの概念を理解することが重要です。 参照ホワイトは、拡散した白い物体 (紙や 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) でレンダリングする輝度です。 デスクトップ HDR モニターでは、SDR 参照ホワイト レベルは通常、約 200 nits に設定されます。

HDR アプリでは、ユーザーが目的の参照ホワイト レベルを設定するか、システムによって構成された値を読み取ることを許可する必要があります。 シーン内の拡散ホワイトの色の値を SDR 参照ホワイト レベルにマップする必要があります。 これは、線形ガンマ空間でアプリのフレームバッファーを乗算する必要があります。

Note

ノート PC などの明るさコントロールをサポートするディスプレイでは、Windows は HDR (シーン参照) コンテンツの輝度をユーザーの希望する明るさレベルに合わせて調整しますが、これはアプリには表示されません。 HDR 信号のビット精度の再現を保証する場合を除き、通常は無視できます。

アプリが常に SDR と HDR をレンダリングしてサーフェスを分離し、OS の構成に依存している場合、Windows は自動的に適切な調整を実行して、SDR コンテンツを目的のホワイト レベルに昇格させます。 たとえば、アプリで XAML を使用し、HDR コンテンツを独自の SwapChainPanel にレンダリングする場合です。

ただし、アプリで SDR と HDR コンテンツの独自の構成を 1 つのサーフェスに実行する場合は、SDR 参照ホワイト レベルの調整を自分で実行する必要があります。 そうしないと、一般的なデスクトップ表示条件下で SDR コンテンツが暗くなりすぎる可能性があります。 まず、現在の SDR 参照ホワイト レベルを取得し、レンダリングする SDR コンテンツの色値を調整する必要があります。

ステップ 1. 現在の SDR 参照ホワイト レベルを取得する

現在の SDR 参照ホワイト レベルは、次のいずれかの方法で取得できます。

ステップ 2. SDR コンテンツの色の値を調整する

Windows では、標準 (既定) の参照ホワイト レベルが 80 nits で定義されています。 したがって、標準の sRGB (1.0、1.0、1.0) を FP16 スワップ チェーンにホワイトでレンダリングする場合は、80 nits 輝度で再現されます。 実際のユーザー定義参照ホワイト レベルと一致させるには、SDR コンテンツを 80 nits から AdvancedColorInfo.SdrWhiteLevelInNits で指定されたレベルに調整する必要があります。

FP16 と scRGB、または線形 (1.0) ガンマを使用する色空間を使用してレンダリングする場合は、単に 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 と Media Foundation HDR ビデオ再生パイプラインの一部として、組み込みのHDR トーンマッパー効果が用意されています。 他によく使用されるアルゴリズムとしては、ACES Filmic、Reinhard、ITU-R BT.2390-3 EETF (電気-電気伝達関数) などがあります。

この次のコード例では、簡略化された Reinhard トーンマッパー演算子を示します。

// 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 画面コンテンツのキャプチャ

Windows.Graphics.Capture 名前空間内のピクセル形式の指定や、IDXGIOutput5::D uplicateOutput1 メソッドなどのピクセル形式の指定をサポートする API には、ピクセル情報を失うことなく HDR および WCG コンテンツをキャプチャする機能があります。 コンテンツ フレームを取得した後、追加の処理が必要であることに注意してください。 たとえば、HDR から SDR へのトーン マッピング (インターネット共有用の SDR スクリーンショットのコピーなど) や、適切な形式 (JPEG XR など) でのコンテンツの保存などです。

従来のカラー管理と ICC プロファイルの動作の変更

高度なカラーと自動カラー管理により、レガシ アプリと最新アプリの両方で一貫性のある正確な色彩表示が保証されます。 ただし、一部のアプリでは、International Color Consortium (ICC) カラー プロファイルを使用して独自の明示的なカラー管理を実行できます。

SDR ディスプレイまたは HDR ディスプレイで高度なカラーが有効な場合、ディスプレイの ICC プロファイルの動作は、下位互換性のない方法で変化します。 アプリが表示 ICC プロファイルで動作する場合、Windows には互換性ヘルパーが用意され、アプリが引き続き正しい動作を得られるようにします。

ICC プロファイルの動作の変更と、高度なカラーとの互換性を最大限に高めるためにアプリを調整する方法の詳細については、「高度なカラーを使用した ICC プロファイルの動作」を参照してください。

その他のリソース