D3D12ではテクスチャスイズルが使える様になっています。D3D12_SHADER_RESOURCE_VIEW_DESC.Shader4ComponentMappingで指定できます。しかし、少し紛らわしいので整理しておきます。

列挙子がShader Component Mapping From Memoryとなっていますがフォーマットがスイズルされたフォーマットの場合に紛らわしさがあります。下記の条件の場合は、

  • LEのGPUとします
  • メモリ上にFF 00 00 00とコンポーネントが並んでいる
  • デスクリプタはDXGI_FORMAT_B8G8R8A8を指定
  • ダイレクトマッピングのD3D12_DEFAULT_SHADER_4_COMPONENT_MAPPINGを指定(下記コードでNO_SWIZZLE時)

シェーダではSample().bがFFになります。Sample().bをD3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2からフェッチするならSample().bは00になると連想※するのが自然です。

#if NO_SWIZZLE   // メモリレイアウト DXGI_FORMAT_B8G8R8A8_UNORM で .xyzw = RGBA
            D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
                D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0,
                D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1,
                D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2,
                D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3
            );
#else   // .xyzw = BGRA
            D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
                D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2,
                D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1,
                D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0,
                D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3
            );
#endif

ただドキュメントをよく読むと”This enum allows the SRV to select how memory gets routed to the four return components in a shader after a memory fetch.“と書かれています。GPU HWはテクセルフェッチする際下記の様に動作します。

  1. メモリからL2に乗せる
    • 圧縮を解く
    • BGRA等のスイズルを解く – APIで指定したフォーマットに従いレジスタ上でrgbaの順に並べる
  2. L2からレジスタに乗せる
    • SRVのスイズルを適用
  3. LD_TEX等のシェーダインストラクション
    • Sample().abgrの様なシェーダ内でのサンプルマスクの適用

“after a memory fetch”は1.の後と考えれば※1 SRVのスイズルはSample().rgbaをデスクリプタでスイズルする機能と考えても違和感がありません。上記コードでNO_SWIZZLEを定義しない時はSample().rgba.bgraの.bgraをデスクリプタ上に記述する様なイメージです。

 

※1 : 考え方は自由だが私はL2に乗ったんだからフェッチは終わっていると考える。