Specifying Root Signatures in HLSL
MSDNのサンプルは機能紹介のためか「全部入り」の複雑なものになっていますが、ここではもっとシンプルなHLSLにRoot Signatureを書いてみました。キューブマップを空とみなして画面全体にレンダリングしています。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cbuffer perObject : register(b0) | |
{ | |
row_major matrix invVP; | |
} | |
TextureCube texCube : register(t0); | |
SamplerState samplerState : register(s0); | |
struct VsToPs | |
{ | |
float4 pos : SV_POSITION; | |
float3 dir : DIR; | |
}; | |
#define RSDEF "CBV(b0), DescriptorTable(SRV(t0)), StaticSampler(s0)" | |
[RootSignature(RSDEF)] | |
VsToPs VSMain(uint id : SV_VertexID) | |
{ | |
VsToPs ret; | |
ret.pos = float4(id & 2 ? 1 : -1, id & 1 ? -1 : 1, 1, 1); | |
ret.dir = normalize(mul(ret.pos, invVP)).xyz; | |
return ret; | |
} | |
[RootSignature(RSDEF)] | |
float4 PSMain(VsToPs inp) : SV_Target | |
{ | |
return texCube.Sample(samplerState, inp.dir); | |
} |
文字列の全体が、D3D12_ROOT_SIGNATURE_DESCに該当します。
StaticSamplerが、D3D12_STATIC_SAMPLER_DESCに該当する記述になります。フィルタリングの方法なども書けますが、レジスタ以外は省略可能です。嬉しいのはHLSL内でサンプラーの定義から使用まで完結することです。C++側から何もする必要がありません。
RootFlagsとStaticSamplerを除いたそれ以外が、D3D12_ROOT_PARAMETERの配列と同等になります。この並びがC++側から参照するインデックス、つまりSetGraphicsRootConstantBufferViewやSetGraphicsRootDescriptorTableの引数RootParameterIndexに該当します。
こうしてHLSLのattributeに書いたRoot Signatureはシェーダのバイナリに含まれます。MSDNではfxcを使っていますが、D3DCompileFromFile等でID3DBlobを生成している場合にもD3DGetBlobPartでRoot Signatureを取り出せます。Vertex ShaderとPixel Shaderのどちらから取り出しても構いません。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
ComPtr<ID3DBlob> vertexShader = afCompileHLSL(shaderName, "VSMain", "vs_5_0"); | |
ComPtr<ID3DBlob> pixelShader = afCompileHLSL(shaderName, "PSMain", "ps_5_0"); | |
ComPtr<ID3DBlob> rootSignatureBlob; | |
ComPtr<ID3D12RootSignature> rootSignature; | |
if (S_OK == D3DGetBlobPart(vertexShader->GetBufferPointer(), vertexShader->GetBufferSize(), D3D_BLOB_ROOT_SIGNATURE, 0, &rootSignatureBlob)) | |
{ | |
device->CreateRootSignature(0, rootSignatureBlob->GetBufferPointer(), rootSignatureBlob->GetBufferSize(), IID_PPV_ARGS(&rootSignature)); | |
} | |
... | |
ComPtr<ID3DBlob> afCompileHLSL(const char* name, const char* entryPoint, const char* target) | |
{ | |
char path[MAX_PATH]; | |
sprintf_s(path, sizeof(path), "hlsl/%s.hlsl", name); | |
#ifdef _DEBUG | |
UINT flags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; | |
#else | |
UINT flags = D3DCOMPILE_ENABLE_STRICTNESS; | |
#endif | |
ComPtr<ID3DBlob> blob, err; | |
WCHAR wname[MAX_PATH]; | |
MultiByteToWideChar(CP_ACP, 0, path, -1, wname, dimof(wname)); | |
HRESULT hr = D3DCompileFromFile(wname, nullptr, nullptr, entryPoint, target, flags, 0, &blob, &err); | |
if (err) { | |
MessageBoxA(nullptr, (const char*)err->GetBufferPointer(), name, MB_OK | MB_ICONERROR); | |
} | |
return blob; | |
} |
ところで、MSDNによるとDX11でもRoot Signature入りのシェーダを問題なく使えるようで、Root Signatureを単に無視すると書いてあります。別の視点から見ると、DX12でのみ必要だったコードをC++から追い出して、プラットフォームの差を吸収するのにも役立ってくれそうです。
No comments:
Post a Comment