びわの家ブログ

【技術書】DirectX12 Programming Vol.1を読んだ

すらりんラボさんの
「DirectX12 Programming Vol.1」を読んだ。
技術書典に行けなかったのでBOOTHからpdfを購入。
購入はこちら(https://booth.pm/ja/items/1286096)

読後の感想

本の感想じゃないのも含まれているが、12章まで読んだので思っていること

  • 一言でいうならばわかりやすくておすすめ
  • 読者ステータスとしては以下のような感じでhello worldから来ましたな人にわかりやすいかは不明
    • OpenGLは入門程度やったことがあるがほとんどおまじないのようにコードを書いてた
    • シェーダープログラミング(GLSL/HLSL)はUnityやThree.js(webGLライブラリ)での経験あり
    • C++は初心者
  • 本の中に対象読者書いてあったけど大体自分のような人が対象読者かもしれない
  • 初学者向けに書いてあるが、補足で”今回は紹介しないが〇〇というものもある”みたいな感じで気になった人はそれを頼りに調べられるように書いてあってよかった
  • 自分は出来上がったコードは全く同じだができるだけ写経するようにこころがけた
  • それでも(D3D12の性質上)1週読んだだけではちゃんと理解できない気がする
    • (個人の地頭の良さでかわるだろうが、、)
  • Vol.2もでたら買おうと思う 発売されたので技術書典で購入したのだけどまだ読めてない
  • DirectX12は命令の名前に統一感があってわかりやすさを感じた
  • ちなみに次は同著者のVlukanの本を読む予定
  • 読んでから2ヶ月たったらほとんど覚えていないので本気でD3D12と向き合おうと思ったら何回か読む必要がある
  • 自分はこれから仕事で使うので電車の中で通勤中に読んで復習しようと思う

以下は読みながら書いたメモ
特に推敲とかなく順番も適当、書いてることもバラバラ

1~3章

序盤は普通に読み物として読み進めて問題なく対象読者だとかD3D12とは何かとか開発環境のセットアップなど。
D3D11を踏まえてのD3D12がどういった位置付けなのかをある程度解説してありわかりやすかった。
他で読んだことと合わせて自分なりにD3D12を解釈すると、

  • 今まで(D3D11やOpenGLなど)はAPIで隠ぺいされていたGPUに直接アクセスするようなより低レイヤーなAPI
    • 現状生き残っているGPUはある程度仕様が揃ってきたため?
    • コンシューマー機のAPIは昔からこんなんだったみたい(固定GPUなため)
  • それによる実装の複雑化
  • マルチスレッド云々
  • GPUの低レイヤーAPIとしてMantleAPIが先駆けでD3D12が影響を受けたみたいなの4gamerかなんかで読んだ気がするけどurl忘れた

みたいな感じだと思う。
つまりよりGPUに近いAPIになってアプリケーション側で考えることが増えた代わりにいままでGPUにまかせてふわっとしていた部分まで設定ができるようになったということ。

個人的には今からグラフィックスAPIをちゃんと学び始めるなら、このような丁寧に解説がある本もあるし12からでいいのではないかと思った。
OpenGL書いてるコードがどうGPUに影響しているのかいまいち分かりづらい印象があったし。(もちろん自分がそこまで理解できなかったのかもしれないが。)

あと2.4のCPUとGPUという部分の図は重要。
CPUとGPUは非同期に動いていて、命令をコマンドバッファに記録しコマンドキューに積む。GPUはコマンドキューに積まれた命令を実行していく。メモリはCPUGPU間で共有できるメモリとGPU専用のメモリ(VRAM)がある。VRAMのほうが早い。

4章

ここからはコードベースな解説が続くと思うので印象に残った部分の断片的なメモ
本ではコードが抜粋されているので本をもみながらGithubのコードを写し書きしていく。

コマンドキュー
本では1つのみの使用だが複数使用するケースはどんなケースか

ディスクリプタヒープは重要そう

  • コードを書いていくとより理解深まるかも?
  • RTV: レンダーターゲットビュー
  • DSV: デプスステンシルビュー

メモリ管理について
メモリ管理についてリソースの確保に以下のメソッドが用意されているが

  • CreateCommittedResource
  • CreatePlacedResource
  • CreateReservedResource

この本ではCreateCommittedResource以外取り扱わないので余裕があれば調べる

コマンドアロケーター
コマンドアロケーターの生成もD3D12_COMMAND_LIST_TYPE_DIRECTのみを使用しますとかいてあるので他も余裕があればみておく

5章

ここまでくるとひとまず画面がクリアできる。
fenceを使って待機させるところは自分で深く考えて理解する必要があった。

  • 目的としてはコマンドキューに積んだCommandAllocatorが実行される前にリセットされたりしないようにするため
  • 次のフレームのフェンスは1足された数になるはず(実行時にそうなるように設定したため)
  • GetCompletedValue()関数で次フレームのフェンスを取得して、まだその値になってなかったら前のコマンドを実行中もしくは実行前
  • 実行中もしくは実行前の場合はCPUは待機する

たぶんこれで合ってると思う。

6章

6~8章は9章以降に出てくる用語などの解説が多いので一旦読んでおいて、9章以降で詰まったら参照するみたいな流れになりそう。

レンダリングパイプラインとルートシグネチャについての解説。
具体的な実装には触れてないので実装するときにまた見ることになる章かな。

7章

HLSLの基本構文はわかってるつもりなので流し見

アップロードヒープ?デフォルトヒープ?となったので要復習

  • アップロードのヒープではMapメソッドが使用できるらしい

8章

テクスチャやvertex buffer, 定数バッファなどのリソース関連の章
このへんGPUとのやりとりに関わるのできちんと理解したい。

Mapを使用してのバッファへの書き込みの部分、buffer.Map()関数を使用すると第三引数に書き込むポインタがセットされて、そのあとのmemcpyでデータをそこのポインタにセットするという理解で正しいのかな。
そしてそのbufferは元々CreateCommitedResource()で確保したリソースなのでどうやら正しそう。

まとめると、

  1. CreateCommittedResource()でHEAP_TYPEやbufferのサイズなどを指定してリソースを確保する
  2. Map()でリソースのポインタを得る
  3. memcpyでポインタに対してデータをコピーする
  4. bufferを作成後、シェーダーで使用するためにBufferViewが必要になる

と理解した。

vertex/index bufferにはそれぞれ生成が必要で使うためにはbuffer viewというものが必要
constant bufferにも同様。

9章

6~8章に説明がされていたことを使って三角形を書いてみる章。
実際に書いてみることで理解が深まったが、ルートシグネチャに関しては今回はシェーダーに渡すものがないので理解を次章以降にまわした。

終了処理に関して、めんどくさいながらもfenceを使ったGPUの処理待ちの部分を自分なりに噛み砕いて理解していたおかげですっと理解できた気がするので、ちゃんと読むって大事だなと感じた。

10,11章

次のテクスチャがはられたキューブの描画に向けてテクスチャ関連の説明をしている章。
個人的に、OpenGLだとサンプラーがテクスチャと一緒に設定されて(多分)、両者が別れている概念だということがいまいち理解できなかったのでD3D12のほうがわかりやすくていい気がする。

12章を読みながらもう一度戻って読む章。

12章

ディスクリプタヒープって何だったかすっかり忘れていた。
4章に詳しく書いてある。抜粋すると

DirectX 12でのディスクリプタとは、各GPU固有のデータで、メモリ上に置かれ たリソースをどのように解釈するかを記録しているものとなっています。そして、こ のディスクリプタはレンダーターゲットビュー、デプスステンシルビュー、サンプ ラー、シェーダーリソースビューといった分類で分けられています。

こういうことらしい。

ちなみに
CBV: Constant Buffer view
SRV: Shader Resource view
UAV: Unordered Access View
と予想。(UAVだけ調べた。まだ使ったことない)

一通り実装したけど要素多すぎて全然覚えられなかった。
ここまでの内容は脳内再生できるくらいにしておかないといけないように感じるのでまた別の実装でやってみたいと思う。

13章

ルートシグネチャについて詳細。
読んで理解はできたけど、教科書を読んだけどテストでは解けない程度の理解にとどまっているので、後日読んだらまた理解が深まりそうな部分。

14,15章

13章までの内容で満足してしまったので読んでなくて、いつか読む。