Sunday, January 8, 2017

[Vulkan] VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMICが便利

VulkanのUniform Bufferには、VK_DESCRIPTOR_TYPE_UNIFORM_BUFFERとVK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMICの二種類がありますが、"DYNAMIC"はオフセットをコマンドバッファに一緒に積めるので便利です。

DirectX12やVulkanのような低レベルAPIでは、Constant buffer/Uniform buffer用に大きなGPU側バッファをまず確保しておいて、自前のアロケータで割り当てながら使うことになると思います。どのDraw Callがどのメモリ領域をConstant buffer/Uniform bufferとして使うかは毎フレーム変化するしかないので、Draw Call毎にGPUアドレスを渡すことになります。

それは、VK_DESCRIPTOR_TYPE_UNIFORM_BUFFERを使っても可能なのですが、GPUアドレスはdescriptor setに書き込んで渡す必要があるので、uniform bufferを使う回数分vkAllocateDescriptorSetsとvkUpdateDescriptorSetsでdescritor setも作ってあげる必要があります。

VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMICを使うと、descritor setは1個だけ、大きなGPUバッファの先頭アドレスを書き込んだものを用意するだけで済みます。その代わりdraw call毎にvkCmdBindDescriptorSetsでUniform bufferをバインドするときにオフセットを指定します。複数のdescriptor setを管理する手間が省けるので便利です。

NVIDIAのドキュメントによると、NVIDIAのハードウェアで"Uniform Buffer Dynamic Binding"は速いのだそうです。
https://developer.nvidia.com/vulkan-shader-resource-binding

推測に過ぎませんが、NVIDIAのハードウェアではDirectX12の"Root Constant"が"Uniform Buffer Dynamic Binding"に相当するのかもしれません。
DX12 Do's And Don'tsのRoot Signaturesの項で"sit in the root"でバインドしたコンスタント/CBVが特にPixel Shaderで速いとされています。
https://developer.nvidia.com/dx12-dos-and-donts

SetGraphicsRootConstantBufferViewもDescriptor Heapを介さずにコマンドリストに直接GPUアドレスを乗せるという部分も、descriptor set1個を使いまわせるVK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMICに似ています。