HDRレンダリング

内部計算としてのHDR

初代PSからPS2の頃は、レンダリング結果を8bit(0〜255)のフレームバッファに書き込んでいました。この形式は256段階を均等に刻むため、扱えるダイナミックレンジ(最も明るい部分と暗い部分の比)は最大でも256:1しかありません。

一方、現実のシーンでは太陽と室内の電球で輝度が何桁も違います。これを256段階に押し込もうとすると、明るい側に合わせれば暗部の階調が消え、暗部に合わせれば明るい側が飽和して区別がつかなくなる。結果として、太陽も電球も同じ「白」として扱うしかありませんでした。

PS3、Xbox 360時代のGPUになって、1ピクセルを浮動小数点の実数や16ビットや32ビットの整数が取り扱えるようになりました。つまり、より高いダイナミックレンジでレンダリングが行えるようになったのです。

このように現実世界の暗さや明るさをそれなりに正確に表現、再現できるようにレンダリングするしくみは HDRレンダリング(High-Dynamic-Range rendering) と呼ばれ、PS3、Xbox 360の世代から積極的にこの概念が導入されることとなりました。

出力としてのHDR

SDRディスプレイの問題
前節のHDRレンダリングは、あくまで内部の計算の話でした。浮動小数点フォーマットによって現実に近いダイナミックレンジを保持できるようになったものの、それを実際に画面へ出すとなると話は別です。PS3・Xbox 360の世代でHDRレンダリングが普及して以降10年以上、出力先は従来通り8bitのディスプレイでした。

内部で広いレンジを持っていても、最後は表示可能なレンジへ圧縮していました。この処理をトーンマッピングと呼びます。圧縮である以上、明暗の差は必ず失われます。雪原は「明るい白」として描かれるだけで実際に眩しくはなく、表示の段階で潰れています。

HDRディスプレイについて

表示側のHDR対応は、この圧縮先そのものを広げる取り組みです。従来のディスプレイのピーク輝度が100cd/m²前後を基準としていたのに対し、HDR対応機はその数倍から10倍程度を持ちます。出口が広がるぶん、失われる情報が減ります。

表示信号の側では、次の三点が同時に拡張されました。輝度レンジを広げる伝達関数、それを破綻なく刻むためのビット深度、そして色の表現範囲を広げる色域です。

  • 伝達関数:従来の信号は「0〜1の相対値」で、1.0がどれだけ明るく光るかはディスプレイ任せでした。HDRで主に使われるPQ(SMPTE ST 2084)は信号値と輝度の対応を絶対値で規定し、規格上10,000cd/m²まで表現できるよう定義されています
  • ビット深度:レンジが広がると8bitでは階調が足りずバンディングが出るため、10bit以上を使います
  • 色域:sRGB/Rec.709からRec.2020へ広がりました

これらをまとめた規格がHDR10です。派生として、シーンごとに調整情報を持たせるHDR10+、より高いビット深度に対応するDolby Visionがあります。

ジオメトリパイプラインの改善について

パイプラインにおける「ジオメトリシェーダ」「テッセレーションステージ」は、実際のゲームグラフィックス開発においてはあまり活用されていませんでした。そもそも、ジオメトリの処理はCompute Shaderで行う場合が多いです。

AMDのジオメトリパイプライン案

ポジションシェーディング(頂点の座標操作のみ)を行った後、プリミティブカリングによって早期にカリングを行います。アトリビュートシェーディングではそれ以外の操作(法線、UV、接線など)を行います。早期にカリングしておくことで、計算を最小限に抑えられるというわけです。

NVIDIAのジオメトリパイプライン案

NVIDIAも2018年8月に新ジオメトリパイプライン案としてメッシュシェーダ(Mesh shader)を提唱し、これをGeForce RTX/Qaudro RTXシリーズに実装しました。

メッシュをMeshletというメッシュを分割した小さな塊に事前に分割して処理を行います。次にタスクシェーダーでは、そのメッシュをどのLODで扱うのか、またはカリングするのかを決めた上でスケジュールします。最後にメッシュシェーダーでは頂点変換と三角形のカリングを行います。それ以外は通常通りです。

デバイスメモリに関する基礎知識

電子回路のエラーメカニズムと対策

CPUやGPUのエラーは、その大部分が宇宙線によりCMOS(Complementary MOS)回路が誤動作するのが原因と言われています。

エラーを起こす宇宙線について

宇宙から来るのは主に高エネルギーの陽子や重い原子核です。大気の分子と衝突して砕けてそこから生まれた粒子がまた衝突して、と連鎖して粒子シャワーになっていきます。

大体の流れはこんな感じです。

  1. 宇宙から高エネルギーの粒子が降ってくる
  2. 大気にぶつかって砕け、そのカケラの中性子が地上まで届く。これは壁も屋根も貫通する
  3. 中性子がチップのシリコン原子核に直撃すると、核反応で荷電粒子の破片が飛び散る
  4. その破片がシリコンの中を走りながら電荷をばら撒く
  5. メモリセルは「電荷があるかないか」で0と1を覚えてるので、ばら撒かれた電荷が紛れ込むと値が変わる

ハードが故障している訳では無く、記憶している値が書き換わるだけなので上書きすれば正常に戻ります。

エラー検出だけだと、誤った結果を使ってしまう事故は防げるものの、エラーが出た時点で計算が中断してしまいます。そこで大型サーバーやスパコンでは、訂正までやって計算を続けられるECC(Error Correction Code) が使われます。