NVIDIA Nsight Visual Studio Edition 5.2 RC1を見ていく~Direct3D12編

はじめに

先にリリースに関する記事を書きましたが,Nsight Visual Studio Edition 5.2 RC1が公開になりました.今回のアップデートを実際に試したのですが,なかなか新機能などがよくなっていたのでちょっと取り上げて行きたいと思います.
なおこの記事ではまずは,Direct3D12に関して取り上げていきますが,のちほどVulkanに関しての記事も用意します(基本的に機能は同じでVulkanが少ないだけなのでDirect3D12とVulkanに詳しい方であれば応用が利きます).
Nsight Visual Studio Edition 5.2 release candidate is now available for download!
https://developer.nvidia.com/nsight-visual-studio-edition-52-release-candidate-now-available-download
リリースノート:Nsight Visual Studio Edition 5.2 New Features
https://developer.nvidia.com/nsight-visual-studio-edition-5_2-new-features
すべての機能を網羅するのはなかなか大変ですので気になったものを中心に紹介していきます.特にDirect3D12向けの下記のあたりを扱おうかと思ってますが,Dynamic shader editing is now available(シェーダの動的な編集)だけちょっと割愛します.

  • Graphics profiling is now supported
  • Dynamic shader editing is now available
  • Improvements have been made to the scrubber for multi-threaded applications
  • Source code serialization of a frame is now supported

まずはDirect3D12アプリケーションキャプチャの手順を紹介していきますが,MicrosoftのサンプルのMiniEngineがある程度描画のフィーチャーが入ったサンプルなのでこれを中心にやっていきますが,一部の機能確認(複数のCommand Queueを使用していない)には適切ではないので他にn-Body Gravity Sampleなども使用します.
https://github.com/Microsoft/DirectX-Graphics-Samples

NsightでDirect3D12プログラムをキャプチャする

キャプチャしたいプログラムのビルドが終わったら(ビルド済みの実行ファイルに対するキャプチャも可能ですが今回は割愛します),Visual StudioのNsightメニューのStart Graphics Debuggingのからを選択します.
nsight
Start Graphics Debuggingを押すとプログラムが起動しますので,Ctrl + ZをしてNsightのHUDを出します.
nsight001
ウィンドウ右上にHUDが出たので,アイコンの一番下のを選択(?の下)すると下記のようにウィンドウ下部にタイムラインやHUDのアイコンが増えたりします.
nsight002
この画面が出たらVisual Studioの方を見ます.無事にキャプチャできました.
2016-08-18 (4)
このほかにキャプチャの方法としてVisual StudioのNsightメニューのPause and Capture Frameからもできます.

Scrubberを見ていく

Scrubberはなんて日本語に訳すのが適切か不明なのでそのまま行きますが,Visual Studioで上部の方で表示されてるタイムラインになります.
nsight003
Scrubberでは,グラフィックスのコマンドの実行状況が可視化されてわかりやすく並べられています.今回キャプチャしたMiniEngineはMicrosoftのサンプルで丁寧に作られているのでグラフィックスの処理の単位でマーカーが打ち込まれているので,階層的に表示され,処理がタイムラインで表示されます.こうしたマーカーの打ち方については後述の「自分のコードを分析しやすくするために…」で説明します.
Scrubberの上の方のAll Eventから適当なDrawコマンドを選択してみます.選択後にScrubberの下の段のタブをAPI InspectorにしてみるとDrawの中のシェーダステージや固定機能の確認ができます.下図の例ではPSを見てみた例ですね.RenderColorのDrawCallなのでShaderResouceViewにモデルのテクスチャがバインドされてるのがわかりますね.基本的なDrawCallに付随する情報など見れますね.
nsight006
とりあえず,API Inspectorとの組み合わせでデバッグはできそうですね.
Scrubberでは,Queueやスレッドなどの観点から描画コマンドの表示を変えたり,階層型をやめてフラットに表示するなどができます.

Range Profiler – グラフィックスのプロファイル機能周りを見ていく

グラフィックスのプロファイル機能で,個人的に良いと思ったのがRange Profilerですね.これはDirect3D12向けの新機能ではなくほかのグラフィックスAPI(Direct3D11やOpenGL, Vulkan)などにも対応した機能です.
デフォルトでは表示されていないのでNsightメニューのWindowsから呼び出します.
nsight007
Range Profilerの画面を下記にピックアップしてみました.
nsight008
Range ProfilerはScrubberと似た画面ですが,CommandListsの実行の部分で処理時間が表示されるようになっています.適切にマーカーを打っておけば処理ごとの処理時間が表示されるので自分たちが想定しているバジェットに収まってるかということを判断しやすいと思います.
それからRange Profilerはハードウェア的な部分も見ていけるようでDrawCallの処理におけるシェーダステージや固定機能の処理割合の算出やL2などの使用具合などを出してくれるようでボトルネック検出がVisual Studio 2015のグラフィックス診断よりも踏み込んだものになっています(その代わりNVIDIA GPU向けのベンダー依存な部分ありますが).
この機能は,下記の図のように適当なDrawを選択して(赤丸)で中段のPipeline OverviewをSummaryからRange Detailsに変えるとみることができます.緑丸でMemoryのところをRange Details見るとメモリ面のネックを探すのによさそうですね.テクスチャのキャッシュヒットなどもわかるようです.
nsight009
Range Profilerをきっかけにパフォーマンス分析と問題点を見つけるあたりのとっかかりにはなりそうですね.

複数Command Queueを使用したプログラムのキャプチャをしてみる

NVIDIA GeForce 10シリーズからAsync ComputeがサポートされたGPUがあるので複数のCommand Queueを使ったプログラムの開発を行う機会が増えていると思いますが,そういった場合のキャプチャもしてみます.MiniEngineは低スペック環境などをサポートしている関係であまりマルチスレッドやマルチCommand Queueを使用していないのでここではn-Body Gravity Sampleをキャプチャします.
2016-08-18
Scrubberを切り抜いてみたのが下記です.
scrubber002
複数のCommand Queue使ったプログラムではCommand Queueの処理待ちでリソースのやり取りや依存関係がある場合にSignalやWaitを使用しますが,Nsightではその様子が可視化されているのがわかります.

その他のDirect3D12向け機能

Descriptor Heap確認機能

これは以前のバージョンからあったかもしれないですが,Descriptor Heapの確認機能もちゃんとついているのでリソースの積み具合は確認できます.
この機能はVisual StudioのNsightメニューのWindowsからDescriptor Heapsを選択で開きます.
nsight010
見たところDescriptor Heapとその中でバインドされてるリソースがわかります.キャプチャしたプログラム側でリソースに対して名前が付けてあれば名前付きで見れるため確認が楽になります.名前の付け方については後述の「自分のコードを分析しやすくするために…」で説明します.

Root Parameter確認機能

Root Parametersの確認機能も付いています.この機能はVisual StudioのNsightメニューのWindowsからRoot Parametersを選択で開きます.
この機能は現在選択しているDrawCallなどにバインドされたRoot Parameters(Cbufferや定数,リソース)やDescriptor Tablesなどの内容や各リソースがDescriptor HeapsのEntity(Heapの中のどこにあるか)がわかります.
nsight011

自分のコードを分析しやすくするために…

これはNSightの機能ではないのですが,ここまでの話でMicrosoftのサンプルコードはキャプチャした際にScrubberやRange ProfilerでのデバッグがしやすいようにCommand Listsの一定の処理の単位にマーカーを打ったり, Descriptor Heap確認機能ではリソースにちゃんと名前がついたりしています.
Command Listsの一定の処理の単位にマーカーを打つのは下記の「アプリのユーザー定義イベントのマーク付け」のあたりに記載があります.
https://msdn.microsoft.com/ja-jp/library/hh873200.aspx
一部記事が切れていて,わからない部分があるのですがpix.h(Windows 10 SDKに入っています)を#includeして
#include <pix.h>
PIXBeginEvent()とPIXEndEvent()などでマーカーを付ける区間をくくることでイベントに名前を付けられます.
一方リソースに名前を付けたりするにはID3D12Object::SetNameで名前を付けることができます.ID3D12ResouceなどはID3D12Objectを継承しているのでSetNameで名前を付けることができます(製品のデータをぶっこぬかれる際のヒントを与えるのを防止のためReleaseでは使わない方がいいかもしれません).
ID3D12Object::SetName
https://msdn.microsoft.com/ja-jp/library/windows/desktop/dn788701.aspx

フレームのソースコードシリアライゼーション

新機能の”Source code serialization of a frame is now supported”に関してはシリアライゼーション?と思ったのですが,ドキュメントを読んでいくと1フレームのキャプチャを再現するためのソースコードを出力するようですね.Direct3D12になってCommandLists方式に変わったのでこういうことがしやすくなったと思われます.
http://docs.nvidia.com/nsight-visual-studio-edition/5.2/Nsight_Visual_Studio_Edition_User_Guide.htm#Save_Captures.htm?Highlight=serialization
これを使うとDirect3D12でグラフィックスデバッグしたい1フレームのCommand Listやバインドされたリソースやシェーダなどをそのままパックして後ほど検証用に再現できるようですね.
ゲーム開発をしていると大規模なアセットの読みこみやゲーム内の様々な処理を経てるわけですが,これを使うとピンポイントで問題のフレームのグラフィックス処理だけ切り出せるのでデバッグして検証するのが楽になるかもしれません.
手順としては,NsightのHUD上で保存をすれば自動的にVisual Studio向けのプロジェクトを出力してくれるようです.保存ボタンは,キャプチャ後に増えたアイコンにあります.下図の赤丸で囲った場所ですね.
nsight004
これを押すとデフォルトの設定だと下記にキャプチャ結果が出力されます.
C:\Users\ユーザー名\Documents\NVIDIA Nsight\Captures
nsight005
 
これを再度開くと該当フレームのグラフィックスの状態を再現したものをデータから再現するプロジェクトができるのでビルドして実行して,Nsightで再キャプチャするだけですね.
試しに,キャプチャ元のプログラムとシリアライゼーションから再現したものをキャプチャしたものを並べておきます.キャプチャ再現の方では一部の準備処理で全く同じというわけではないのですが,再現できているようです.再現版でも各DrawCallのパイプラインのリソースやシェーダのバインド状況などみることもできました.簡単に使用できるので,Nsight + Direct3D12が使える環境がある方は試してみるとよいと思います.
nsight003
元のキャプチャ
nsight012
シリアライズして再現キャプチャ
ちなみに,Range Profilerを比較して見たのですが,各処理の実行時間はさすがに一致しないようです(若干,シリアライズ再現の方が軽量のようです).ただ,処理の内訳や傾向はあまり変わらないようなので,シリアライズして再現したものでも重い処理は元の処理でも重いといえるとは思います.

おわりに

簡単ですが,NVIDIA Nsight Visual Studio Edition 5.2 RC1のDirect3D12向けの便利そうな機能を紹介していきました.5.2になってキャプチャが簡単になり,画面も見やすくなったのでかなり日常的に使っていきたいと思うようなプロファイラになっていますね.
今回はVisual Studio 2015からの呼び出しですが,ソースコードシリアライゼーションなどはVisual Studioを経ない環境から保存ができる体制ができると描画上のエラーなどがあった際のデバッグがはかどるんではないかと思います.パフォーマンス分析に関しても一定のフレームレート落ちの際に保存,みたいな体制が取れるとキャプチャしたあとにRange Profilerでネックを追うということもできると思います.
それから今回は自作プログラムが前提ですが,UnityやUnreal Engine 4などのDirect3D12ビルドした実行ファイルを追う方法なども確立すると便利という場面は多いかもしれませんね.
今回はDirect3D12ですが,Vulkanのデバッグや分析環境はまだまだ貧弱なので,Nsightの機能はまだ少ないですが,便利ということは多いと思います.Vulkanに関しては近いうちに新しく記事を書いておきたいと思います.
あと,前の記事で書き忘れていましたがOculus向けアプリケーション向けのデバッグ機能も充実させたようですが,残念ながらCV1持っていないのでちょっと紹介はできなさそうですね.