リングコマンド!

こんばんわ、Pocolです。

ImGui使っていると、なんかみんな同じ見た目になってしまって面白くないなーと思いました。
そこで,聖剣伝説風のリングメニューを作ってみました。

ソースコードはGitHubにあげています。
https://github.com/ProjectAsura/ImGuiRingMenu

使い方はいたって簡単です。
メニュー項目は第1引数にラベル名,第2引数にImTextureID型のアイコン画像を指定してください。
実装例は次のように追加します。

ImGuiRingMenu menu;
menu.Add({"Menu1", MenuIcon1});
menu.Add({"Menu2", MenuIcon2});
menu.Add({"Menu3", ImTexureID_Invalid});

アイコン画像がない場合は,ラベル名の1文字目をアイコン代わりに描画します。
アニメーション更新のため,毎フレームImGuiRingMenu::Update()と,ImGuiRingMenu::Draw()を呼び出してください.

// アニメーションを更新.
menu.Update(deltaSeconds);

// 描画処理.
if (menu.Draw(selectedItemIndex))
{
    // ここで,選択された項目に応じた処理を行う.
    ...
}

アイコンを削除したい場合は,Remove()を利用します。第1引数にメニュー項目番号を指定してください。
終了処理などで一気にメニュー項目を削除したい場合は,Clear()を呼んでください。
キーを操作を変更したい場合は,ImGuiRingMenu::ConfigのKeyMenuStartやKeyXXXという値を使用したキーのImGuiKey列挙体の値に変更してください。

…というわけで、自作したリングメニューの紹介でした。

あとで読むリスト

こんばんわ、Pocolです。
仕事が忙しすぎて、全然最近論文が読めていないです。
年末・年始の時間を使って、今年の論文を見ておきたいなーと思ったので,メモを随時追加しておくことにします。

SIGGRAPH 2025

・Spherical Lighting with Spherical Harmonics Hessian
  岩崎先生と土橋先生のやつ。
・Bernstein Bounds for Caustics
  コースティクスが気になったので…。
・WishGI: Lightweight Static Global Illumination Baking vis Spherical Harmonics Fitting
  メモリ削減がかなりできるらしい。
・Segment Based Light Transport Simulation
  蜂須賀先生が共同著者にいるやつ。頂点ベースではなくセグメントベースで光輸送を計算する新しいレンダリング手法っぽい。
・Histogram Stratification for Spatio-Temporal Reservoir Sampling
  画像をみる感じだと良さげ。

Eurographics 2025

・Fast Sphere Tracing of Procedural Volumetric Noise for Very Large and Detailed Scenes
  スフィアトレーシングの高速化の話っぽいので,雲とかのレンダリングの高速化に使えるかも。
・Physically Based Real-Time Rendering of Eclipses
  日食の物理ベースレンダリングで、画像がかっこいい。大気の話も含んでいるかもしれないので、あとで確認。
・Dynamic Voxel-Based Global Illumination
  あまり良くはなさそうだが、アイデアがもらえるかもしれないので見る。

I3D 2025

・Aokana:A GPU-Driven Voxel Rendering Framework for Open World games
  メモリ使用量が従来の1/9で,レンダリング速度が最大4.8倍速くなるらしいので、要チェック。

レイトレ合宿11 参加レポート

こんにちわ、Pocolです!
毎年恒例のレイトレ合宿に参加してきました。
ついに第1回合宿から連続で作品提出しているのは,ykozwさんと私だけになってしまったので,どんなにへぼくても何とか来年も作品提出できるように頑張ろうと思いました。

本戦

今年は最多の22作品+1エクスビジョンという結果になりました。

さて、今年の私の提出作品ですが,下記のような作品を作りました。


ソースコードは下記にて公開しています。
https://github.com/ProjectAsura/ponzu/tree/rtcamp_2025

実装概要ですが,下記のような感じです。

今年はブリキのおもちゃ感をテーマにレンダリングしてみました。
まぁ、実装の方は大したことやっていないのですが,RISを導入してみました。
気持ち収束が早くなったかな?という感じがしていますが、ちゃんと比較していないので気のせいかもしれません。

昨年までは乱数生成にPCGを使っていたのですが,今年はAndanteさんのブログで紹介されているIbuki Hashに変更してみました。サクッと差し替えできるのでお勧めです。

あと、去年まではお手製デノイザーを使っていたのですが、このデノイザー内でクロスバイラテラルフィルタを使用していたのですが,この関係で最終出力結果がボケボケな絵になってしまうということが分かったので,今年は思い切ってクロスバイラテラルフィルタを一切使わないという割り切った実装にしてみました。そのおかげでスペキュラーがいい感じの見た目になるようになりました。

アセット作成にはAsset Forgeを使用しました。


Kenneyさんのサイトで配布しているキットバッシュとAsset Forgeを使って,レベルを作りました。
Asset Forgeを初めて使う状態でしたが,操作が簡単なので2時間ぐらいでレベルを作成しました。何とか間に合ってよかったです。お手軽にシーンが作成できるようになったので、来年も使おうかなとおもっています。おススメです。
 ちなみにAsset Forgeは下記から購入できます。日本円で約3000円ちょっとでそんなにお高くないので,自分で配置シーンツールとか作るのがかったるい人には良いと思います。
https://kenney.nl/tools/asset-forge

セミナー


今年も、非常に盛りだくさんの内容でした。
また、皆さんのセミナー資料がアップされたら、順次取り上げていこうと思います。

今年度は本当に時間がなかったので、比較的に誰にも分かる内容かつ知らない人には役立つ内容ということで,DXR 1.2の機能紹介をちらっとやりました。
以下に資料を上げているので,興味ある人は見てやってください!

…ということで本業で忙しい状態でしたが、今年も何とか参加できて良かったです。
このあと、参加者の方から続々とレポートが上がってくると思われるので,そちらも楽しみです。
みなさん、レイを飛ばしましょう!では。

恒例のBBQ会!

こんにちわ。Pocolです。
今年もCEDEC恒例のグラフィックスプログラマーで集まってやるBBQ会(グリル会)を開催するそうです!
昨年参加された方は今年もご参加ください!

詳細については幹事のnikqさんのツイートをご参照ください。

2025/07/07更新
※チケットは完売しました。

果報は寝て待て!

こんばんわ、Pocolです。

昨年に引き続き,グラフィックスプログラマーやTAさんなどでBBQ会を開催するようです。
昨年参加された方は是非奮ってご参加ください。
詳細は,近日中に主催者よりご案内あるそうなので,お待ちください。

そんなわけで,皆で肉喰いましょう!
今年も楽しみだ…。

それではまた!

Steam Deckでのデバッグ

こんにちわ。Pocolです。

Steam Deckでのデバッグ方法について,ググってもあんまりいい情報が出てこなかったので,ここにメモしておこうと思います。

前提

  • Steamの公式ドキュメントを見ておきましょう。
  • Microsoft Child Process Debugging Power Tool をインストールしておきましょう。設定も忘れずに
  • デバッグDLLはSteam Deck実機上に含まれないので,あらかじめ転送するフォルダにデバッグ用のDLLを含めるようにしましょう
  • 開発PCとSteam Deckは同一LAN上になるように接続しておきましょう。
  • Windowsで開発しているものであれば,Proton – Experimentalにするのを忘れないように。

Visual Studioを使ったデバッグ

リモートデバッグを使用して,デバッグを行います。
まず,SteamOS Devkit OSを立ち上げて,実行ファイルやアセットなどを1つのフォルダ下にまとめておきます。
次にUploadを実行する前に下記の設定を行っています。

  • Steam Playにチェック入れる(This title requires Steam Playの項目)
  • Steam Play debugにチェックを入れる(Start Visual Studio C++ debugger service on launchの項目)
  • Wait for attachにチェックを入れる(Wait for a debug client to attach)

チェックを入れてから,Uploadボタンを押して実行ファイルとアセットファイルなどを実機に転送します。
DISMISSにならずにちゃんとアップロードできていたら,Steam Deck実機上からゲームを起動します。
ゲームはSteam Deckのホーム画面から「ライブラリでもっと見る」を選択し,「非STEAM」の項目に居る場合があるので,R1ボタンで切り替えて,デバッグしたいアプリを選択してください。

ゲームが起動したらアタッチ待ちに入るので,Steam Deck上で,Steamアイコンが表示された状態でグルグル回っている画面で止まった状態になります。
この状態で,開発用PC側からアタッチをかけます。
Visual Studioを立ち上げて,リモートデバッグを選択します(「デバッグ」>「プロセスにアタッチ」)。

「リモート認証なしーWindows」を選択して,検索ボタンを押します。
ウィンドウが立ち上がるので,その中からsteamdeckを選択します。
選択するとプロセス一覧が表示されるようになるはずなので,steam.exeを選択します。
前述したChild Process Debugging Power Toolがインストールされて入れば,ゲームにアタッチできるようになります。
アタッチ後は通常のVisual Studioのデバッグと同様に進めていけばよいです。

RenderDocを使ったデバッグ

SteamOS Devkit Client を立ち上げ,Devkitsボタンを押して,下から3番目あたりにある 「RenderDoc captures enabled」にチェックを入れておきます。
チェックを入れたSteam Deck上でデバッグしたいゲームを起動します。
ちゃんと設定がされていれば,画面左上にRenderDocのオーバーレイが表示されるようになっているはずなので,これを確認します。

続いて,開発PCからRenderDocを立ち上げ、メニューから File > Attach to Running Instanceを選択します。
Remote Host Managerというウィンドウが立ち上がるので,Steam DeckのIPアドレスを打ち込み,Addします。
Referesh Allを押して,更新をかけます。ゲームが立ち上がっていれば,win64_preloaderというようなプロセスがあるので,これを選択して Connect to App ボタンを押します。
コネクションが確立されたら,RenderDoc上から,Capture Frame(s) Immediately ボタンを押して,フレームキャプチャーを実行します。
キャプチャーが成功すれば,Captures collected にフレーム画面が表示されるようになります。このデータを一度開発PC上に保存しておきます。
保存の仕方はフレーム画像を右クリックしてポップアップメニューからSave を選択すればファイルダイアログが立ち上がるので,好みの場所に保存しておいてください。

次にフレームデバッグの準備をします。Steam Deck上で,RenderDocのremoteserverを起動する必要があります。
SteamOS Devkit Clientに戻り,Devkitsボタンを押して切り替え,Remote Shell ボタンを押し,ターミナルを起動します。
ターミナルが起動したら renderdoccmd remoteserver -d を打ち込み,RenderDocリモートサーバーを起動させます。
成功すれば,
Spawning a replay host listening on *…
Detaching.
というようなメッセージが表示されるはずです。
次に開発PC側のRenderDocの接続設定を変更します。
RenderDocウィンドウの左下にReplay Contextがあるので,これを接続しているSteam Deckに変更してください。
接続できれば,ステータスバーが Remote server ready というように表示が変わるはずです。

ここまで来たら,あとはいつも通りです。
キャプチャーしたフレームを選択すると,ドローコールなどが見えるようになるので,通常通りにグラフィックスデバッグを進めていきます。

おわりに

かなり設定が面倒ですが,これでデバッグが進められるようになるはずです。
デバッグDLLがなかったり,依存DLLが無いとサイレントでゲームが落ちるようなので,まずはちゃんと起動する状態にするのと,RenderDocのフレームキャプチャーしても落ちない状態に持っていくのが,難所だったりするので頑張ってください。

またカスタムビルド

どうしてもエディタとしてVisual Studioを使いたいPocolです。

一番簡単なカスタムビルドのメモです。
.vcxprojをテキストエディタで開いて,一番下のほうに次ような感じでコマンドを挿入します。

  </ImportGroup>
  <Target Name="Build">
      <Exec Command="call build.bat" />
  </Target>
  <Target Name="Clean">
      <Exec Command="call clean.bat" />
  </Target>
</Project>

ちなみにExecタスクのドキュメントは下記ですので,細かい設定を追加した場合は下記を参考にしてください.
MSBuildリファレンス > タスクリファレンス > Execタスク
https://learn.microsoft.com/ja-jp/visualstudio/msbuild/exec-task?view=vs-2022

Visual Studio上からリビルドを実行した場合は,Clean —> Build の順番で呼び出しされます。
もしリビルド自体をカスタマイズしたいなら

  <Target Name="Rebuild">
    <Exec Command="call rebuild.bat" />
  </Target>

とやってあれば,自前にリビルドコマンドに変更できます。

実行時のコマンドのカスタマイズは,通常のVCと同じようにプロパティから変更すれば良いと思うので,それでやればよいかと思います。
…というわけでカスタムビルドのメモ書きでした。

どっかで

クリックしてtede-msbuild-2.0.pdfにアクセス

とか

あたりを参考にもうちょいちゃんとしたものを今後改造してみたいと思います。

DREDとAftermathのサンプルプログラムを作りました。

こんばんわんわん、Pocolです。

X(旧Tiwtter)でも書いたのですが,DRED(Device Removed Extended Data)のサンプルプログラムを書きました。
サンプルは以下に置いておきました。
https://github.com/ProjectAsura/D3D12Samples/tree/master/D3D12_DRED

DREDなんですが,意外とまともなドキュメントが無いです。ドキュメントあるんですけども,わかりづらい,「この変数の意味は?」みたいな痒いところに手が届くものが無い感じがしますね。(単純に、ドキュメントみて理解できない私がアホなだけなんですが…)
…というわけで,コードを書いてみました。
仕事で使っているのはちゃんと,Push/Popの入れ子とかも考慮しているやつですけども,まぁええでしょ。こまけぇこたぁいいんっすよ。
結局,DREDのサンプルで困るのは「これちゃんとGPUクラッシュ時に出るの?」という所で,故意にGPUクラッシュさせるようなプログラムがなかなかネットで見つからない。
それだと,動作確認に困るので,GPUクラッシュさせるプログラム書きました。
ここ最近,ずっとGPUクラッシュの調査していたので,どうやれば簡単にGPUクラッシュを引き起こせるかなどのノウハウが溜まったので,その知見を活かして書きました。
一番よくある例,実行中にテクスチャを解放しちゃうやつ。これが一番良くあるので,Tボタン押したら,テクスチャをRelease()するようにしました。これで簡単にPageFaultのGPUクラッシュが発生します。TDRはレジストリいじっている場合は,発生までに時間かかるし,意外とGPU側でちゃんと対処してくれちゃったりする場合もあるので,無理やりやろうとしても意外と発生しなかったりします。サクッといかない。
DirectX-Samplesにはhttps://github.com/microsoft/DirectX-Graphics-Samples/tree/master/Tools/DXGIAdapterRemovalSupportTestというやつもあるみたいですが,こっちは触ったことないんで良く分からんっす(詳しい人教えてください)。

…で馬鹿の一つ覚えみたいな感じなんですが,PageFaultを発生できるようになったので,NVIDIA Aftermathのサンプルも書きました。
一応クラッシュ発生時に,ShaderBinaryとShaderPDBを吐き出して,クラッシュログを調査できる感じにしてみました。私のサンプルの場合は,クラッシュが発生している該当シェーダだけを出力するので,そんなにクラッシュダンプ出力に時間はかからないと思います(仕事でつかっているやつは,別の人が既に実装されたやつなんで,全部のシェーダのバイナリとPDBを出力しやがるんで,時間とディスク容量を食いまくって,困るんですよね。直すのは面倒ですし、時間の余裕もないので直す気はサラサラないです)。
サンプルプログラムは下記にあります。
https://github.com/ProjectAsura/D3D12Samples/tree/master/D3D12_NvAftermath
時間があれば,解説書いてもいいんですが,残念ながら,その時間がないのと,若干仕事のせいで鬱気味なのでやる気が起きないっす。(どうせみんなUEやらUnityつかうでしょ?こういう直叩きするひとがもう日本じゃ少数だから,親切に書いてあげても意味が無いんですよ。見る人いないから…)

…というわけで,リリースして精神的に落ち着いたら,のんびりゆったり解説を書こうかなと思います。
まぁ,そんなの期待する人はほぼいないと居ないと思いますが。

GPUクラッシュが激減した…

こんばんわ、Pocolです。

このところ,仕事でずっとGPUクラッシュを追っていたのですが,なんとなくノウハウが溜まってきました。
ほぼ、毎日のようにGPUクラッシュが何十件もあり,色々な人に手伝ってもらいながら,調査していたんですが,ようやくそれがパッタリ収まりました。

いくつか対策を入れていたのですが,結局どれが効いたのかは正直分からないのですが…
groupsharedで,UINT32_MAXでアクセスして,GPU上でメモリ破壊を発生させるコードがあったので,修正した所,謎に発生していたGPUクラッシュが治まりました。
多分,数年レベルで放置されていたバグなんじゃないかと思います。

NVIDIA AftermathとかでGPUクラッシュダンプを調べても,PageFault,さらにシェーダ情報もでない,挙句の果てにはResourceBarrierを実行するとGPUクラッシュする,定数バッファが壊れて無限ループして,TDRで落ちるなど,過去のクラッシュログを見ても,まったく共通性もなく,しかも結構頻発する。でも全然再現性が無い,手元で全く発生しない…という困ったちゃんで,困りまくった挙句何かないのか?と調べてみたら,NVIDIA Aftermathに,GFSDK_Aftermath_FeatureFlags_EnableShaderErrorReportingというフラグがあるのですが,これを有効にしたところ即クラッシュするようになりました。
何で無効だったのか聞いたんですが,こちらはヘッダファイルにも書かれているようにパフォーマンスペナルティがあるということで,ゲームプレイに支障があるとのことで無効化していたとのことでした。
結局,このフラグを有効にしたところ,先ほど述べたgroupsharedのバグを発見できたのと,他にもクラッシュする原因が見つかって,大いに役立ちました。

今後は,確定で発生しないものはGPU上のメモリ破壊を疑った方が良いという知見が得られました。
基本的にはUAVとかSRVとかのLoad()とかoperator []あたりミスっているんじゃないかって思いがちなんですが,これらはAPIドキュメントを見ると、安全に良しなにしてくれそうなことがあるので,メモリ破壊が発生するのは,CPU上での書き換えか,groupsharedのアクセスミスによる2パターンしかないように思えます(他のパターンがあったら教えてください)。CPU上でのメモリ破壊の可能性がほとんど低いことが分かったなら,groupsharedでの破壊が無いかどうかを調べましょう。
今回のバグは,

groupshared g_Variable[XXX][XXX];
みたいなのが定義されていて,
float temp0 = saturate(XXX);
uint temp1 = temp0 * MAX_VALUE – 1;
uint index = min(temp, MAX_VALUE);
g_Variable[index][XXX] = ….;
っぽいような,謎の計算がされていて(uintをマイナス1する時点でぞわぞわしちゃんですが…)
temp0がゼロになったときに,アボンするみたいケースでした。
よくよく見ると「馬鹿か!」って怒鳴りたくなったっちゃうような,不具合なんですが,変数がごちゃごちゃ定義されていたりとか,ジュニアレベルのエンジニアだとこういうチェックがおざなりになりがちなんで,気を付けた方が良いよ!…という良い事例になりました。

…というわけで,社内でも共有したんですが,この場でも共有してみました。
謎バグに困っている方は,groupsharedで変なことしていないかどうか確認してみると良いかもです。
(※ちなみ1個あったら,他にも絶対あるだろうと思って全シェーダをチェックしてみたのですが,確認した所発生しているのは該当シェーダの1個だけでした。)