📺

Windows HDR (とキャプチャ問題について) の解説

2021/01/03に公開

はじめに

先日 PC Watch で下記の記事が掲載されました。

この記事では Windows HDR 環境下でのキャプチャに関する挙動の問題を指摘されてました。

私自身は記事にあるような事は全く遭遇した事がなかったので、あれこれ試してどうなっているのか調べてみました。その上で私の見解としては

  • Windows 10 の HDR 出力は基本的には正しく動作していると思います
  • 但し、一部誤解を招きやすい機能が標準で有効化されていて結果的におかしな動作になることがあります

となりました。

Windows HDR の誤解がされているのもちょっと悲しいのでキャプチャ問題を含めて Windows HDR の動作について記事としてまとめてみました。

問題についての対策 (結論)

  • Windows で HDR 出力を使う場合は Windows HD Color 設定の "HDR/SDR 明るさのバランス" は 0 (左端) にするべきです
    • 明るさバランス 0 に設定した上でディスプレイ側の輝度/コンストラストを調整してください
      • HDR 時の輝度は高め~最大にする
      • SDR 時は逆に低めにする (エクスプローラーの白が HDR 時と同じ程度になるようにするのが望ましいと思います)
    • 明るさバランス を 0 にして画面が暗いと感じるなら HDR は常用せず、基本的には SDR で必要に応じて HDR にした方がよいと思います
  • "HDR/SDR 明るさのバランス" は計算上正しくない状態にする (計算上の正しさより利便性を優先する) ものなので 0 以外にする時は挙動をよく理解して利用する必要があります
    • 設定すると HDR アプリの輝度はそのまま SDR アプリの輝度を上げます
      • よって同一輝度でも HDR アプリと SDR アプリとで色の明るさが異なりバランスが崩れます
    • これに関連する Chrome のキャプチャに関する問題は 2020/12/25 時点で確認した際に極力発生しないように対処されており、明るさバランスを上げても通常利用ではキャプチャしても問題ないようにも思います
      • 個人的にはそれでも 0 にすべきとは考えます

Windows HDR の動作

PC やその他映像出力機器がディスプレイに映像を送る場合、一般的にピクセル毎に RGB の 3 色の輝度レベルをそれぞれ 0~1 の範囲で設定して送出しますが (RGB ではない場合もありますがここでは扱いません) 、その数値が実際にどの色になるのかは別問題です。つまり例えば RGB=#FF0000 だった場合 "赤" ということになりますが、それがどのような赤かは未定義、ということになります。これを規定するのが "色空間" になります。色空間の規定も様々ありますが、ここで出てくるものは次のものです。

  • sRGB - PC 上で使用される最も一般的な SDR 色空間。いわゆる "Gamma 空間" と呼ばれる場合は大体これのこと。
  • scRGB - いわゆる "Linear 空間" のこと (対応する Gamma 空間が sRGB の場合)
  • BT.2100 - 現在標準的な HDR 空間のこと。 "HDR10" の色空間。伝達特性 (ガンマカーブ) が PQ と HLG の 2 種類ありますが通常は PQ 。

映像のフォーマット、色空間は出力するディスプレイ毎に設定するものです。ということは 画面に表示される映像はそのディスプレイに指定した色空間に揃える必要がある わけです。 HDR 映像を表示する場合、画面内のあらゆる映像を HDR フォーマットにしなくてはならなくなります。

なので Windows で HDR 出力をサポートする、と聞いた時は私はゲーム向けのフルスクリーンモード限定かと思っていました (実際、以前から Direct3D では 10bit カラー出力がフルスクリーンで可能であったため) 。ところが Windows に実装された HDR は

  • デスクトップでも HDR が有効になる
  • ウィンドウ単位で HDR/SDR の切り替えができる
  • SDR ウィンドウは Windows 側のカラーマネジメントで HDR に変換されて合成、表示される

といった従来アプリとの互換性を完全に維持したまま HDR 化するといったものでした。これは素晴らしい対応で、もしフルスクリーンのみしか HDR に対応できなかったのであればアプリの HDR 対応はほとんど進まなかったと思います (まあ現在でも HDR 対応アプリはそんなに多くはありませんが・・・) 。

映像のレンダリングからディスプレイに出力されるまでの流れ

Windows 10 では WDDM/DWM 動作により、各ウィンドウのレンダリング結果はオフスクリーンバッファにレンダリングされ、それらを一枚のバッファに合成してディスプレイに出力されます。

ウィンドウのレンダリングバッファは Direct3D 10 以降の API を使用する場合は DXGI という API で作成をします。ここで DXGI 1.4 で追加された API を使用する と HDR 対応のレンダリングバッファ (バックバッファ) を作成することができます。より正確には レンダリングバッファのフォーマットと色空間 を設定します。従来の API を使用する (あるいはそもそも DXGI / Direct3D を使用しない) と SDR(sRGB) として処理されます。

API 的には様々な組み合わせが使用できるようですが、通常使用する (使用可能な) 組み合わせは次の通りです。

色空間 SDR / HDR DXGI_FORMAT DXGI_COLOR_SPACE_TYPE
sRGB SDR DXGI_FORMAT_R8G8B8A8_UNORM DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
BT.2100(PQ) HDR DXGI_FORMAT_R10G10B10A2_UNORM DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
scRGB HDR DXGI_FORMAT_R16G16B16A16_FLOAT DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709

オフスクリーンバッファにレンダリングされた各映像は最終的にディスプレイ出力用のバッファ上で合成され、ディスプレイに出力されます。その際、 単一の HDR 色空間に変換した上で合成処理 が行われます。色空間変換を Windows 側が自動で適切に行うので SDR アプリは従来との互換性を維持したまま HDR 出力になっているディスプレイに表示ができるようになっているわけです。

ドキュメントによると一旦 scRGB に変換してから合成した上でディスプレイ向け色空間 (BT.2100(PQ)) に変換をしているようです。ウィンドウ間でのアルファブレンド等が必要になるのでこれは致し方ない対応でしょう。
(ウィンドウモードアプリであるならアプリ上で BT.2100(PQ) を使用する意味はないような気もしますね)

"HDR/SDR 明るさのバランス" について

Windows 10 (1709) で HDR が実装された際、 HDR に切り替えると "画面が暗く表示される" という意見がありました。その次のアップデート (1803) で実装されたものが "HDR/SDR 明るさのバランス" です。

Windows の HDR 出力は前項に記述した通り、 SDR ソースは HDR 空間に "正しい計算通り" 変換されて表示されるように実装されています。しかし、計算的にいくら正しくても従来の SDR (sRGB) モードで見た場合と比較して暗く見えてしまう事があるわけです。

よって SDR → HDR 変換をする際に輝度を上げて SDR 部分を明るくするように調整できるようにした機能が "HDR/SDR 明るさのバランス" になります。

以下、動作例を参考映像で示します。 HDR 表示ではないので正確ではないです。あくまで "このようなイメージで動作している" ことを理解してください。

左側は HDR ビデオを再生している状態 (HDR アプリ) と仮定します。

画像
a)
b)
c)

a) は "HDR を使用する" を OFF にした状態です。

b) は "HDR を使用する" を ON にした状態です。デスクトップ背景を含めて全体的に暗く見えるようになってしまいました。

c) は "HDR/SDR 明るさのバランス" で SDR 部の明るさを上げた状態です。エクスプローラーやデスクトップは明るくなりましたが ビデオプレイヤーの HDR ビデオの明るさはそのままです (重要) 。 この機能は SDR 部分の明るさを調整する機能なので HDR 部は変わりません。また、このビデオプレイヤー ("映画 & テレビ" アプリ) は UI 部分は SDR (別ウィンドウハンドル) なので UI 部分の明るさもバランス値で変化しています。

この機能のメリットは暗くなって見づらくなった SDR の表示を見やすくできるように調整できることです。

反面、大きな問題として 同じ色なのに同一ディスプレイ上で違う色に見えるようになってしまう ようになってしまいました。

  • HDR ON / 明るさバランスなし
  • HDR ON / 明るさバランスあり

※繰り返しになりますが SDR 環境下では正しく表現できないためで、 "左の灰色は白、右はより明るい白" と見てください。

先ほどの b), c) と同じ状態ですが、この画像では Chrome が HDR アプリです。元々同じ "白 (sRGB で #FFFFFF)" だったはずなのに、 "明るさバランス" の調整をした結果 SDR 側が明るくなり違う白色になってしまいました。同一ディスプレイ内の同一色 (少なくともアプリのコード上ではそのようになるように実装されている) のはずなのに、ウィンドウが SDR か HDR かの違いだけで色が変わってしまっています。

"HDR/SDR 明るさのバランス" に伴う Chrome/Edge の挙動と問題点

Chrome は HDR 対応した当初は素直な HDR アプリとして実装されていたので、 "明るさバランス" を有効にすると前項の画像のように Chrome が暗く見えてしまう、という問題がありました。
理屈の上では正しいのですが、 SDR アプリが中心となる中で Chrome のような常時使用する (と思われる) アプリが暗く表示されバランスが欠けているのは HDR 環境下での利用の大きな妨げになっていると思いました。

ところがどのタイミングだったのかは不明ですが、 Chrome が "HDR/SDR 明るさのバランス" を参照し、そのパラメーターに応じて SDR 部分の輝度を調整する機能を実装していました。

https://twitter.com/TANY_FMPMD/status/1338263523500027904

これによりデスクトップ内の色の不整合が解消され問題がなくなった・・・と思ったのですが別の問題が生じるようになりました。それが "Chrome をキャプチャするとキャプチャした映像が白飛びしている" という問題です。

何故白飛びが起きるのか

一言で言えば Chrome が HDR アプリとして HDR 空間で輝度調整をしたため です。

上のフローは SDR アプリ、下のフローは HDR アプリ (ここでは Chrome) です。 SDR アプリは色空間変換、輝度調整が Windows で行われます。一方 HDR アプリは HDR 映像をレンダリングするので SDR ソースはアプリ側で処理する必要があります。

"HDR/SDR 明るさのバランス" による輝度調整はデフォルトより明るくするものなので SDR (sRGB) 空間をはみ出ます 。 "Print Screen" キーによるキャプチャは HDR に対応していないので補正前の方が望ましいです。 Windows で明るさ調整をする場合は Windows 側が元の色空間を把握しているので元に戻す (あるいは調整前にキャプチャする) のは容易でしょう。よって元の白飛びがしていない映像がキャプチャすることができます。

一方、アプリ側の HDR 空間で明るさ補正をした場合、その結果は Windows 側から見た場合 SDR ではなく HDR ソースになっているので Windows 側は認識できません。 結果として明るいまま白飛びした映像がキャプチャされることなってしまいます。

Windows 側が調整した場合は左側でキャプチャ可能ですが、アプリで調整した場合は右側を SDR 変換したものでキャプチャするしかなくなります。

Chrome の改善

2020/12/25 時点で確認したところ上記の現象はほとんどのケースで問題がなくなっています。

https://twitter.com/TANY_FMPMD/status/1342288248790339585

ほぼ SDR モードで動作するようになり、 HDR になるのは本当に必要なケースのみになっていました。具体的には下記の両方の条件を満たす場合のみです。

  • HDR が必要なコンテンツ (Youtube HDR のページ) をレンダリングする
  • 上記のタブがアクティブ (前面) になっている

従来は常に HDR モードか、一旦 HDR になったら SDR に戻る事はありませんでした (よって影響が非常に大きかった) 。

上記の対応により現状では Youtube HDR 以外のページでは PrtScr によるキャプチャをしても問題はなさそうです。 Youtube HDR は HDR モードにするしかないので回避できないでしょう。

Youtube HDR は上図のように赤いビデオ部分のみ HDR でそれ以外の青い部分は (ソース的に) SDR です。 この状態の Chrome は全体を HDR でレンダリングしているので、 Chrome は青い部分に対して SDR → HDR の色空間変換と明るさバランス設定による輝度補正をかけるわけです。

ビデオ部分とそれ以外の部分でウィンドウハンドルの分離は技術的には可能でそこまでやれば完全と思いますが、ブラウザのレンダリングエンジンのかなり根深いところに Windows 依存のコードが入ってしまうのとそこまでやるメリットはないと思うので、現状の対策が限界ではないかと思います。

Visual Studio Code での動作

VSCode (1.52.1) は Electron (= Chronium) ベースの HDR アプリになっています。つまり本質的には VSCode も Chrome と同様の問題を内包しているのですが、確認した限りだと基本的に Chrome と同様で

  • HDR を要求するタブをアクティブにした時のみ HDR モードになる
  • 確認した限りでは Release Notes が HDR モードになりましたが Welcome ページや通常のテキスト編集は SDR モードだった
    • Release Notes ページは "明るさのバランス" で輝度を上げているとキャプチャ結果がおかしくなります

ので VSCode も基本的には問題なさそうです。

0 100

"HDR/SDR 明るさのバランス" を 0 と 100 に設定し、Release Notes をそれぞれ PrtScr でキャプチャしたものの比較です。

"HDR にすると暗くなる" は正しいのか?

"HDR にすると暗くなる" は私としては基本的にはディスプレイ自体の問題、というか使い方の問題と考えます。

そもそも SDR ディスプレイの輝度が高すぎるように思います。

※PQ の 10000nits は規格上の最大値で参考値です

sRGB ソースを HDR 空間に変換する際、 sRGB の最大輝度は 80nits なので 80nits をターゲットに変換するように計算しますが、今時の SDR の液晶ディスプレイはカタログスペックで 250nits くらいが普通なので、 SDR 環境でディスプレイの明るさを (最大で使われている事はないとしても) 80nits を越える高めの設定で使用していた場合、 HDR に移行したら暗く感じるのはある意味当然と思います。

現状、多くの方が使われている HDR ディスプレイは 400nits くらいのものと思いますが、比較的高価格帯の HDR ディスプレイであれば 600~1000nits くらいのものもあります。ただ、どちらにしろ sRGB = 80nits というのは変わらないので、高輝度のディスプレイにしても (ディスプレイ側で独自の仕組みを実装されていない限りは) 結局状況は変わらないようにも思います。

Windows 側に問題はないのか?

Windows 側に問題や改善の余地が他にないのか、というとそういうわけでもなく "HDR Metadata の活用" があります。 Windows の API には輝度レンジを含んだ Metadata を指定するものがあります。

これらの情報を活用すれば Windows 側でも適切な輝度制御ができそうにも思いますが、

  • アプリが必ずしも正しい値を設定する保証がない (Metadata の設定自体をしない場合も)
  • ディスプレイ側も Metadata を認識して適切な処理をするかどうかが不明瞭

もあって確実性に乏しいかなあという気もします。システム全体での改善が必要そうです。

HDR キャプチャー機能の不具合

別件ですが、 "HDR/SDR 明るさのバランス" と異なり、これはおそらく不具合と思います。

Xbox Game Bar (Win + G で表示される) に静止画キャプチャ機能があり、これでキャプチャすると任意のウィンドウの映像をクリップボードではなく PNG ファイルとして直接ファイルに出力します。また、 HDR 出力になっているディスプレイ上のウィンドウは PNG に加えて JPEG XR (.jxr) ファイルにも出力されます。 JPEG XR は名前こそ JPEG とついていますが全くの別物で HDR 対応フォーマットとなっており、 HDR の映像を手軽に保存できる機能で重宝しています。この機能自体は Game Bar の UI を通さず、 "Win + Alt + PrtScr" のショートカットで直接実行可能です。

この機能、 (2020/12/25 現在の Windows 10 20H2) 一部動作に不具合があり、使用には注意が必要です。本命である "HDR ウィンドウの JPEG XR キャプチャ" は問題がないのですが、それ以外だと問題があるようです。

  • HDR ディスプレイ下の映像をキャプチャした PNG ファイルが Linear ガンマで記録されているようで、キャプチャしたファイルを開くと暗く表示されます
  • SDR モードのウィンドウをキャプチャした JPEG XR ファイルは輝度が 2 倍になっていました

"HDR/SDR 明るさのバランス" により HDR モード (Youtube HDR) 時の Chrome の JPEG-XR が明るくキャプチャされてしまう場合があるのは、まあ正しいと思います (SDR 部分を Chrome が輝度上げているので) 。

おわりに

HDR は規格と現在のディスプレイ、テレビ側の性能の乖離が大きく、 SDR と HDR を両方扱うと期待したような映像が見られないケースがどうしてもでてきます。

上記記事も技術的に見ればまあ仕方ないかなあという気もするのですが、ユーザーから見るとなかなか理解を得るのはなかなか難しいように思います。

Windows では現状で少しでも体験をよくしようといろいろ対策しようとしているのではないと思います。が、個人的には "明るさのバランス" は悪手だったのではないかと思います ("HDR は暗い" と呼ばれるのを回避するには仕方ないのかもしれませんが) 。

Windows HDR は基本的には問題ないと思っていたのですが、今回いろいろ調べてみてまだ課題があるなあとも思いました。うまく改善がされていけばいいなと思います。とはいってもディスプレイ側の性能改善が一番とは思いますが。
"HDR ウィンドウがある時は明るさのバランスを自動で無効にする" ってなればいいのかなあ・・・

Discussion