2026年5月10日日曜日

ステンシル描画仕様変更

ステンシルの仕組みを使ってアウトラインと遮蔽物の影を描画できるようにスプライト追加時にパラメータ指定できるようにした。


今回作ったステンシルの仕組み


ステンシルで実現する際、通常のスプライト描画とは別でステンシル書き込み専用のシェーダを実行していた。スプライトではまとめて描画したり、Z値によりソートして描画したりで、特定のスプライトだけで描画しているわけではないので、アウトラインで同じアウトライン色で各データをまとめて、ステンシル書き込み専用で描画する。
その後、ステンシル値を指定して単色やスプライトで塗りつぶしたりするんだけど、ちょっと回りくどい。

形状指定でステンシル値を書きこんで、単色やスプライトで塗りつぶす機能だけ残して、アウトラインと遮蔽物の影の仕組みは別で作ることにした。


作り直した仕組み


通常の描画時に深度と同時にステンシルも書き込んで、その後ステンシルマスクを利用するということであれば無駄がなかったんだけど、ステンシル値の為だけの専用描画と、そのステンシル値の部分だけ塗りつぶすという2ステップになってしまっていたので、それを止めて直接描画してしまう。

やってることはステンシルの時と同じで、ちょっと拡大した絵を描画して、透明以外の部分にアウトラインで指定した色を出力。今回は直接アウトラインの色を描き込める。
ただ、アルファブレンドありで透過部分を無視してclip/discardなしでシェーダかけるかなと思ったけど、いろいろ試行錯誤して無理という結論に至り、最大3回同じシェーダを実行する。

1回目:拡大したスプライトを指定色で描画。
2回目:深度バッファを有効にしつつ、比較演算子をLESS_EQUALにして中抜き描画。
3回目:深度バッファを有効にしつつ、比較演算子をGREATERにして遮蔽物の影を描画。

float4 c = Tex[ NonUniformResourceIndex( In.tno )].Sample( Sampler, In.UV ) ;
clip( c.a - 0.5 ) ; // 閾値以下は破棄
uint w = uint( In.Col.w ) ;
switch( w ) {
case 0u :	// 中抜き
	Out.Col = float4( 0, 0, 0, 0 ) ;
	break ;
case 2u :	// 遮蔽物の影
	Out.Col = c * 0.25f ;
	break ;
default :
	Out.Col = In.Col ;
	Out.Col.a *= c.a * 0.75f ;
	break ;
}
Out.Col.rgb *= c.a ;

In.Colで制御していて、float4(0,0,0,0)は中抜き用、float4(0,0,0,2)は遮蔽物の影用の特殊カラー。それ以外の色はアウトライン色になる。



オレンジの部分が遮蔽物。
緑と青がアウトラインで、緑の方だけ遮蔽物の影を描画。

描画エンジン作り直し

今まで、3Dの描画から始めて2Dのライブラリまで追加してきたけど、いまいち何かしっくりこない。
初めて作ったのもあるし、まだまともに使ったこともないので過不足もよくわからない。


固定パイプライン?


DirectX 9にあったような固定パイプラインになっていて、データを投入すると画面に描かれるようには作れたけど、自由度が足りない。
その仕組みの延長で2Dも加えたので、自由度が全くなかった。


再構築


DirectX12のデバイス管理クラスと、リソース管理クラス、マルチスレッドで動作するコマンド発行の仕組み以外はすべて捨てて作り直すことにした。

まずは、描画エンジン内のリソースの管理方法。今まで各リソースは文字列で管理をしていた。リソースの名前を知っていれば共通のデータを取り出せるので、いちいち取得用の関数を定義する必要もなくGetResourceのみ用意して、あとはヘッダに共有のリソース名を公開するだけでアクセスできる。また、まだ出来てないリソース名を指定して描画を行った場合勝手にスキップされ、次フレームで用意されたタイミングで描画開始されるなど、本物のポインタではなくゆるくつながっているので柔軟性があり、使いやすかった。

今回はそれをリソースハンドルに切り替えて採番制にした。PIXで名前が表示されるのでリソースにSetNameするように名称も指定はしているが、キーはハンドルで64bit整数。共通リソースのハンドル取得関数が必要にはなったけど、アクセスは高速になり、データ追加についても名称被りを気にする必要はなくなった。名前で管理するのはアプリケーション側に任せてライブラリはハンドルで管理する。


2D描画ライブラリ


今回は3Dからではなく、2Dのライブラリから作ってみる。


スプライト描画


まず用意したのがスプライト描画。
前回はスプライト用のテクスチャが変わるたびに描画を行っていたが、テクスチャの無限配列のやり方がわかったので複数枚のテクスチャでも1回の描画で出来るようになった。

・不透過と透明を含むスプライト
これらの描画は1回で描画することは出来ず、分ける必要がある。
不透過のオブジェクトは深度バッファの書き込みを有効にして、すべてを1回で描画できる。
半透明はまずZ順にソートして、重なる下の方から順番に描いていく。ただこれだとZの階層分描画が必要になってしまうため、AABBTreeを使って重ならないように違う階層のZも同時に描画して全体の描画回数を減らすようにした。

文字描画


次に用意したのは文字描画。
前回は結構複雑な仕組みで作ってしまい、表示データを全部管理していた。
1つの文字列を描画オブジェクトとして管理し、変更、削除などが出来る。
フレームを跨いで保持しているため、使う側から同じデータで更新されると管理データのすべての項目と比較し変更がなければ更新フラグを立てないようにしてある。
描画用のバイナリデータを作るときまったく更新がなければ前回のバッファをそのまま利用し更新による負荷を軽減しようとしていた。

ゲームでは毎フレーム更新(ゲームのスコアとか)が基本だろうけど、常に同じ文字が表示されるラベルのようなものもあるだろうと、この2つの用途を合わせて作ってみたはいいものの、いろいろとコードが複雑だし実際の使う場面でこの比較処理がどこまで有用なのかもわからない。

そこで今回は一切管理するのを止めてみた。

まずラベルについては、フォントの違いによる描画回数を1回にするべく中間レンダーターゲットを用意して、そこに書き込む。追記だけ出来るようにして更新したい場合は基本的には全削除のみ。これで用意した中間レンダーターゲットを文字列単位でスプライトとして登録することにより、フォントが変わっても1回の描画で出来るようになる。

次に毎フレーム更新の文字列。これはそんなに数が多くないはずなので、フォント毎に1回ずつ描画を行うようにした。

形状描画


ここで久しぶりに頂点バッファ、インデックスバッファが登場。スプライト、文字については頂点バッファ指定なしで描画できる仕組みで描画してた。前回同様、線、連結線、矩形、円、塗りつぶし矩形、塗りつぶし円が描けるように頂点バッファを用意した。


2D描画


上記の描画を取りまとめて中間レンダーターゲットに行い、出来上がった絵をレンダーターゲットに描画、もしくは自分自身をテクスチャとしてまた別の描画で使える。
前はエンジン内部で2D描画もパイプラインに組み込まれていたためどうにもできなかったが、今回2D描画を別クラスで扱えるようにしたことにより、インスタンスを複数持ったりも可能だし、描画順も自由に設定できる。


ステンシル描画


今まで作ってきた描画内部では深度バッファを使ってZ指定したものが前後関係をもって描画できるようにしていた。深度バッファをステンシル付きのものに切り替えステンシルに書き込めるように変更した。

ステンシルの利用は2段階に分かれる。
1段階目はステンシルバッファへの書き込み。
スプライト、矩形、円でステンシルへ指定の値で書き込めるようにした。
2段階目はステンシルテスト。
書き込んだ値を指定してその部分、もしくはその部分以外に単色で色を塗る、指定スプライトで描画する機能を用意した。

これらを使って、アウトライン描画、遮蔽物の影、マスク描画が出来る。

左が元画像、真ん中が少し拡大してステンシルに書き込んだマスク、右が合成した絵。
正確なアウトラインではないけどお手軽。

・半透明データのステンシル書き込み問題
上記のスプライトをステンシルに書き込む際、そのまま描画すると矩形でステンシルに書き込まれ、真ん中の画像のようにはならない。

    clip( saturate( c.a ) - 0.5 ) ; // 閾値以下は破棄 -> ステンシル更新対象外
PSでclipをすることで、ステンシルへの書き込みを抑制している。ただ、これをやるとGPU側の最適化を妨げる要因になるらしく引っかかってる。


パーティクル描画


前回作ったパーティクルの仕組みは既に用意してあった3Dメッシュの管理情報を拡張して追加したため仕組み上複雑になっていたんだけど、その代わりカリングの仕組みも入っていた。
今回は3D用の機能はまだ無く、カメラだけ用意した。
そのうちカリングを出来るようにすると思うけど、とりあえず2D利用なので画面から消えることもないだろう。
まずは矩形データを作り出して、指定ロジックで消せる仕組みだけ用意した。
前回と同じように炎のパーティクルは作れるようになった。
今後円や円柱など用途に合わせたメッシュを追加していく。


Emissive描画


3D描画の時はGBufferの出力で出力レンダーターゲットの1つに含まれていたけど、2Dの場合特に考えてなかった。
今回用意したスプライト描画と、形状描画をマルチレンダーターゲット変えて、Emissive出力に対応させた。オブジェクト追加時に0~1のEmissive値を指定できるようにした。


Blur描画


Emissiveの効果を出すためにまずBlur描画を用意。ブラーテクスチャをCSで描画するシェーダを用意した。前はサンプリングするポイントを8個にしていたが、今回は5個にした。
サンプリングする場所に真ん中を含んでいなかったからたくさん必要だったようで、真ん中を含めたら5個でほぼ同じような結果が得られた。
左が前のサンプリングポイントで、右が今回採用したポイント。


Bloom描画


Blurテクスチャを使ってEmissveの効果を描画するシェーダを用意した。
指定するパラメータで結果がかなり変わってくるし、画面サイズによっても値の調整が必要で難しいエフェクトだけど、以前と同じような結果は得られるようになった。


2026年4月5日日曜日

PIXBeginEvent / PIXEndEvent

PIXを使い始めて少し経った頃、PIXBeginEventを見つけてライブラリのいろいろなところに組み込んだ。今でもその処理が残っているが、いつからかPIX側に反映されなくなった。


表示されなくなった原因


確か、マルチスレッド対応をやったころからだと思う。
突然表示されなくなり、いろいろ試したがダメでその当時は諦めた。
PIX自体もバージョンアップが頻繁にあり出来なくなったのかなと思ってた。

今描画エンジンを作り直してるんだけど、改めて調べなおしてみた。
原因はPIXのバージョンアップでも、機能がなくなったわけでもなく、当然自分のプログラムが原因だった。


マルチスレッド対応


わかってしまえば当然で簡単なことだったけど、なかなか気づけなかった。
マルチスレッド対応を行った際、コマンドリストを発行する処理をすべて別スレッド側に持っていき、パラメータを蓄積する仕組みを用意した。
PIXの関数を呼ぶタイミングは、このコマンドを蓄積するときに呼んでも早すぎで実際にコマンドリストに入れるタイミングで呼び出さないといけない。

それに気づいてコマンド蓄積にPIXのイベントも追加した。
このコマンドを実行するときにPIXBeginEvent / PIXEndEventを呼び出すようにしたところ、以前のようにPIX上でイベントの区切りが作れるようになった。

PIXBeginEvent( L"描画" ) ;	// この場で呼び出しても意味がない
{
	tDXCommand oC ;
    oC->Draw() ;
    AddCommand( oC ) ;
}
PIXEndEvent() ;
PIXのイベント関数を、コマンド蓄積してるときに呼び出しても意味がない

{
	tDXCommand oC ;
    oC->PIXBeginEvent( L"描画" ) ;	// 他のコマンドと同様に蓄積出来るようにして、リスト追加時に呼び出すようにする
    oC->Draw() ;
    oC->PIXEndEvent() ;
    AddCommand( oC ) ;
}
PIXのイベント関数自体も、コマンド蓄積出来るようにして、実際にコマンドリストに追加する場面でPIXのイベント関数を呼び出すように修正



漢字も使えて、範囲に含まれたコマンドを折りたたんで表示ができる。
上図はすべて展開した状態。



グラフの方もイベント範囲がわかりやすく表示される。


2025年6月9日月曜日

テクスチャの無制限配列

これまで、シェーダーによる描画では、テクスチャを1枚ずつ個別に指定していた。

文字列描画の際、スプライト描画の要領で使うテクスチャは1つで、描画は数百文字同時に一括指定などで効率的に描画していた。
ただし、テクスチャ自体が複数枚で、それを一括で描画する仕組みを用意していなかったためテクスチャ毎に描画命令を呼び出していた。

これを改善しようと思う。


テクスチャの無制限配列指定


HLSL変数宣言


Texture2D Tex[] : register(t0) ;
こんな感じでテクスチャを指定して、Tex[n]のように使いたい。
定義自体は可能で、Shader Model 5.1以降で使える模様。


RootSignature宣言


RootSignatureのテクスチャ指定部分は下記のようにする

DescriptorTable( SRV(t0, flags=DESCRIPTORS_VOLATILE, numDescriptors=unbounded)...

flagsにはDATA_STATICか、DATA_STATIC_WHILE_SET_AT_EXECUTEを指定していたけど、無制限の場合はDESCRIPTORS_VOLATILEになるらしい。
numDescriptorsにはunboundedを指定する。

問題はデスクリプタヒープをどう指定するか。
現状初期化時に、CBV、SRV、UAV用と、サンプラ用の大きなヒープで作成しており、描画毎に同じヒープをCommandList->SetDescriptorHeapsに指定している。

テクスチャ部分はTex[0]~描画指定数分利用することになるが、SetDescriptorHeapsに配列順になっているデスクリプタヒープを渡す必要がある。
今までのデスクリプタヒープを静的なものとすると、今度は動的なデスクリプタヒープを用意することになる。


Dynamic Descriptor Heap


静的デスクリプタヒープと同様にな動的デスクリプタヒープを初期化時に用意する。
今まで渡していた静的デスクリプタヒープに加えて、動的デスクリプタヒープをSetDescriptorHeapsに渡そうとしたがエラーになる。同じタイプ(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)のものを渡せないらしく、動的デスクリプタヒープを渡したい場合は静的デスクリプタヒープは渡せなくなる。
サンプラ以外はすべて動的デスクリプタヒープで渡すことになる。
そのため、静的デスクリプタヒープの初期化でFlagsに指定していたD3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLED3D12_DESCRIPTOR_HEAP_FLAG_NONEに変更して、動的デスクリプタヒープのFlagsにD3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLEを指定する。

実際描画する際、静的デスクリプタヒープと動的デスクリプタヒープのD3D12_CPU_DESCRIPTOR_HANDLEを用意して、Device->CopyDescriptorsSimple関数でコピーする。静的デスクリプタヒープでは空いている部分をアサインして、利用が終わったら返却しているため、使うリソースの順番はばらばらだったけど、動的デスクリプタヒープを使って、順番を指定できるようになったため、配列で使用できることになる。



定数バッファ(CB)や、構造化バッファ(SB)はサイズを増やせば複数描画分をまとめて渡すことが元々出来た。テクスチャも動的デスクリプタヒープを利用することで、使用するテクスチャを順番に並べることができるようになる。

これで複数枚のテクスチャ全部描画する際、複数回描画命令を実行していたのが1回の描画命令でまとめて描画が可能になった。
ある状況下で比べてみるとCPU使用率が約半分になって、GPU使用率はほぼ変わらずだった。


Barrier

以前拡張バリアの対応を行った。

それまで結構バリア処理で悩んでいて複雑になったになってきたので、修正を機に全部リセットして作り直した。
その際、通常のバリア処理はなくして拡張バリアのみにし、その結果Agility SDKに対応している環境でしか動かなくなった。

というのが今までの状況。

そのうち一般公開されるだろうと思いながら待っていたけど一向にされない。
NvidiaのGPU環境では問題なく動く。
AMDのGPU環境では、Agility SDK対応ドライバを選択して入れてあれば動く。
IntelのGPU環境では、ドライバは対応されているようなことが書いてあるが、少なくとも自分の環境ではそのドライバをインストールに失敗し、拡張バリアはサポートされない状態。

個人的には問題ないんだけど、諸事情でいろいろな環境で動かす必要が出てきたのでAgility SDKなしでも動くようにする。


通常のバリア処理



拡張バリアサポートチェック



起動時に拡張バリアのサポートチェックをして、対応してなかった場合はそこで処理をストップしていた。通常バリアから拡張バリアに完全に切り替えたのでこれで問題なかったが、
これを拡張バリアに対応していない場合でも処理を継続し、両方の環境で動くようにする。

ID3D12Device10::CheckFeatureSupport関数でD3D12_FEATURE_D3D12_OPTIONS12をチェック。
D3D12_FEATURE_DATA_D3D12_OPTIONS12.EnhancedBarriersSupportedの値を保持して、処理を切り替えるようにする。


リソース作成



ID3D12Device10::CreatePlacedResource2でリソースを作っていたけど、通常バリアのモードの場合はID3D12Device::CreatePlacedResourceに切り替える。
D3D12_RESOURCE_DESC1とD3D12_BARRIER_LAYOUTが、D3D12_RESOURCE_DESCとD3D12_RESOURCE_STATESになる。

今のライブラリはCBV、バッファ利用、SRV、テクスチャ利用に分かれているが、CBV、バッファの方は、特に問題なく用意できそう。
昔利用していた時は、リソース種類別に初期のステータスや実行コマンド毎にステータス遷移の制御を行っていたが、バッファに関しては一切の制御を止めて、D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESSに任せることで単純になった。通常のバリアでもそれは同様で、初期ステータスはD3D12_RESOURCE_STATE_COMMONのまま、状態遷移は何もしないようにした。

問題はレンダーターゲットと深度バッファで、このリソースにはD3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESSが指定できないため、自分で制御する必要がある。


コピー時



レンダリングして、結果をテクスチャにコピーするような場合、COPY_SOURCEに遷移してコピー後に、RENDER_TARGETやDEPTH_WRITEに戻しているが、通常バリアでも同様に遷移させる。コピー先に関してはCOPY_DESTで作成するようにしているため遷移不要で、コピー後も拡張バリアではALLOW_SIMULTANEOUS_ACCESSのおかげで何もしなくて済んでいた。
通常バリアではALLOW_SIMULTANEOUS_ACCESSを指定していても多少制御が必要で、コピー後に、ALL_SHADER_RESOURCEに遷移させないとデバッグレイヤにエラーが出力され続ける。


ミップマップ作成時



1.UAV付のテクスチャを用意して、画像をコピー。
2.各ミップマップをCSで縮小コピー。
3.UAV無しのスタティックテクスチャにコピー。
という手順でミップマップを作成している。
ミップマップ作成過程で拡張バリアを使っている箇所で、通常バリアを指定して実行してみるとデバッグレイヤにエラーが表示される。
試行錯誤の結果、通常バリアの場合1から2、2から3の間に、状態遷移を挟む必要があった。
1から2の間には、D3D12_RESOURCE_STATE_COPY_DESTから、D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCEの状態遷移を設定。
2から3の間には、D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCEから、D3D12_RESOURCE_STATE_COPY_SOURCEの状態遷移を設定。
拡張バリアの場合はD3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESSの指定で、かなり自動になったけど、通常バリアの場合は若干制御が増える。






2024年8月12日月曜日

2D描画

D3D11On12をやめて、自前で文字描画を作った。
次に必要になるのが線、矩形、円の描画。矩形と円については線バージョンと塗りつぶしバージョンを用意する。


塗りつぶし用シェーダ


どう描画するのがいいか?
思いつく方法は2つで、オーソドックスに頂点バッファとインデックスバッファを用意して、別途構造化バッファで形状や色を指定する方法。
もう1つは、構造化バッファのみで描画する方法。

文字描画は後者の方法で描画していて、前から2D描画の仕組みもこれで行こうと考えていた。
いざこの方法で描画しようとした場合、形別にシェーダ関数を用意してシェーダ内で振り分けるか、呼び出し側で振り分けてシェーダ自体を切り替える必要があると至った。
どちらもシェーダにとって重くなりそうな処理なので前者の方式で描画することにした。

形状を頂点バッファ、インデックスバッファで表現することにより、シェーダを同一にできる。通常の3Dモデル描画と同じだけど、こうすることによりこの後作る円や、もっと複雑な形状もモデルの準備で済む。
複数インスタンスを同時に描画する部分は構造化バッファに位置、スケール、色情報を含めて対応することにした。
通常3Dモデルの場合はWorldMatrixを複数用意して描画するけど、サイズが大きいのとそこまで複雑な指定をしないので、制限を掛けることでサイズを減らしてパフォーマンスを向上させる。
シェーダ側でWorldMatrixを作って、m[0][0]に幅の倍率、m[1][1]に高さの倍率、m[0][3]にX座標(移動量)、m[1][3]にY座標(移動量)を指定してからmul関数で変換する。

あと、深度バッファを有効にして、z座標を調整することで自動的にZオーダが処理されるようにした。手前ほど先に描画するようにして奥をスキップできるようにソートして構造化バッファに書き込むようにする。


矩形(塗りつぶしバージョン)


矩形のモデルを下記の4点で用意
-0.5,0.5(左上)
0.5,0.5(右上)
-0.5,-0.5(左下)
0.5,-0.5(右下)


円(塗りつぶしバージョン)


3Dモデルの場合はグローシェーディングでモデルがローポリでも球に見えるけど、2Dの場合輪郭だけなのでごまかせない。
分割数16、32、64の輪郭+中心の頂点バッファのデータを用意して、描画サイズにより違和感のないクオリティを選択して描画できるようにした。


線用シェーダ


線の描画自体あまりやったことがなかったけど、唯一やってたのが視錐台の描画でD3D12_PRIMITIVE_TOPOLOGY_TYPE_LINEを使っていた。

線の描画ではD3D_PRIMITIVE_TOPOLOGY_LINELISTとD3D_PRIMITIVE_TOPOLOGY_LINESTRIPの両方を対応できるシェーダを用意したいと考えた。
通常の線描画であれば頂点バッファを用意する必要もないので、構造化バッファのみで描画を行う方式を採用した。
D3D_PRIMITIVE_TOPOLOGY_LINELISTで描画する場合は、構造化バッファに始点、終点のセットで書き込みを行う。
D3D_PRIMITIVE_TOPOLOGY_LINESTRIPで描画する場合は、単純に構造化バッファに点情報を書き込む。ただし、他のデータをまた描きたい場合その前に描いた線と繋がってしまう。そこで、線と線の間に、アルファ0、Zオーダ0の2点(最後の線の終点と次の線の先頭と同じ座標)を追加することにした。こうすることで、D3D_PRIMITIVE_TOPOLOGY_LINESTRIPのデータもまとめて1コマンドで描画できるようになる。


線の場合、D3D_PRIMITIVE_TOPOLOGY_LINELISTで2点追加することで描画できる。


矩形


矩形の場合は、線のD3D_PRIMITIVE_TOPOLOGY_LINESTRIPに対して5点(左上、右上、右下、左下、左上)を指定する。



円の場合は、線のD3D_PRIMITIVE_TOPOLOGY_LINESTRIPに対してN点を指定する。
Nは3点以上で、cos、sinで座標を計算する。8点以上で円ぽくなる。


スプライト用シェーダ


矩形のテクスチャ貼り付けバージョンのシェーダを用意する。
データソースにリソースに登録されたテクスチャの他に、文字列描画で出力したテクスチャ、さらに今作ってる2D描画で出力したテクスチャも指定できるようにした。


スプライト描画


張り付ける位置の矩形、テクスチャを参照する矩形を指定する。



半透明の描画



不透明の描画の場合、Zオーダが手前を先に描画することで高速化を図る。
逆に透明の描画の場合は、Zオーダが奥のものから描画することで結果を正しく表現する。
またシェーダも切り替えて深度バッファ参照のみに変更して書き込みを止める。

同じシェーダ同士の描画順は制御しているが、塗りつぶし、線、スプライトの描画順は固定。
スプライト(不透明)、塗りつぶし(不透明)、線(不透明)、スプライト(透明)、塗りつぶし(透明)、線(透明)の順で描画する。



2024年8月11日日曜日

PIX GPUキャプチャ失敗

今までDirectXの描画でうまくいかない部分をPIXで確認して何度もヒントを貰って直せた。

ところが突然PIXのキャプチャに失敗するようになった。
直前に直したであろうソースを戻しても記憶が曖昧でうまくいかない。
それから2,3日キャプチャができない日が続いた。

ネットで調べると、サスペンド状態で実行してキャプチャすると成功するというのを見つけ、試してみるとたしかに成功した。
ただこれは狙ったタイミングではキャプチャできず、一番最初のみうまくいく。

その状態のまま開発を続けたが、どうしてもキャプチャしたい状態が出てきてちゃんと調査することにした。


ほとんどの動作をコメントにして、キャプチャできるかを試したら久しぶりに成功した。
この状態から徐々に処理を開放していき駄目になる部分を特定した。


最終的に原因の特定に成功。


キャプチャ失敗の原因



最終的に失敗していた箇所が中間レンダーターゲットをテクスチャにコピーする処理だった。
このコピー前後にバリアを張っていたが、外してもデバッグレイヤで怒られないので不要なことはしないようにコメントアウトしていた。
実はこれが原因でPIXのキャプチャ失敗するようになったようだ。

バリアを戻すと、PIXでキャプチャが成功する。
実際の動作には何の問題もないがPIXのために必要なのか、それともデバッグレイアのチェックが抜けていて実は必要な処理なのか?

PIXでキャプチャできないのは困るので、バリアのコメントを外して復活させることで解決した。