Vulkanのリソースバリア
StageFlagsやAccessBits、ImageLayoutなど色々と紛らわしいので整理
vkCmdPipelineBarrier(3)
code:cpp
// Provided by VK_VERSION_1_0
void vkCmdPipelineBarrier(
VkCommandBuffer commandBuffer,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkDependencyFlags dependencyFlags,
uint32_t memoryBarrierCount,
const VkMemoryBarrier* pMemoryBarriers,
uint32_t bufferMemoryBarrierCount,
const VkBufferMemoryBarrier* pBufferMemoryBarriers,
uint32_t imageMemoryBarrierCount,
const VkImageMemoryBarrier* pImageMemoryBarriers);
VkPipelineStageFlags、VkDependencyFlagsの遷移であればイメージメモリ、バッファメモリをまとめて1つのコマンドで遷移することができる
VkPipelineStageFlags: 後述
VkBufferMemoryBarrier,VkImageMemoryBarrier: 遷移内容はバッファメモリ、イメージごとに個別に指定する。
VkMemoryBarrier: わからん!(todo)
VkDependencyFlags: 依存性をBY_REGION,VIEW_LOCAL,GROUPで設定する。イマイチ役割がわかっていないのでわかったら追記する(todo)。とりあえマルチGPU、マルチビューじゃない限りBY_REGIONでいいと思う
vkCmdPipelineBarrierをリソースバリアしたいときに使うという頭の状態でいると後述するVkPipelineStageFlagsの存在が頭に入らないのであくまでも前後のレンダーパスのパイプライン同士の依存関係を設定するみたいな認識でいたほうが理解しやすそう。ついでにメモリバリアも指定できるよくらいのスタンス。
hr.icon
VkPipelineStageFlagsについて
以下のサイトで非常にわかりやすく解説をしてくれている。
Yorung's Hotfix: Vulkan vkCmdPipelineBarrierで指定するVkPipelineStageFlagBitsとは? SDC 2017
srcStageMaskは前のパスのパイプラインステージ(例:vertex shader等)、dstStageMaskは後のパスのパイプラインステージを表します。前のパスのsrcStageMaskで指定のステージが終わるまで、後のパスのdstStageMaskで指定のステージは始めてはいけないという意味になります。
要するに、リソースバリアを行うということは前後のパスに依存関係が生じて待ち時間が発生する(Pipeline Bubble)と呼ぶらしい。前のパスでレンダーターゲットとして使っていたものを次のパスでテクスチャリソースとして使う場合、前のパスのレンダーターゲット書き込みから次のパスのフラグメントシェーダー実行時の間の待ち時間。Vulkanではその待つタイミングすらも開発者が指定しなくてはならない(D3D12はドライバが決める)。先の例でいうとsrcは前パスのレンダーターゲット書き込み時、VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT を指定し、dstはフラグメントステージVK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT を指定することになるという解釈であっているだろうか。
多いのでどんな種類があるかはドキュメントを確認。
VkPipelineStageFlagBits(3)
hr.icon
VkBufferMemoryBarrierについて
Vulkanのリソースはバッファメモリとイメージメモリがありこっちはバッファメモリに対するステートの変更を記述する。
code:cpp
// Provided by VK_VERSION_1_0
typedef struct VkBufferMemoryBarrier {
VkStructureType sType;
const void* pNext;
VkAccessFlags srcAccessMask;
VkAccessFlags dstAccessMask;
uint32_t srcQueueFamilyIndex;
uint32_t dstQueueFamilyIndex;
VkBuffer buffer;
VkDeviceSize offset;
VkDeviceSize size;
} VkBufferMemoryBarrier;
VkAccessFlagsで前後のリソースの状態を遷移させる。ドキュメントに簡易的な説明しかされていないのでもう少し調べたほうがいいと思うけどAccessFlagという名前からメモリにアクセスされる可能性のあるフラグという理解をしている。このフラグによってドライバ内で最適な配置が決まるのだろうか(予想)。QueueFamilyIndexについてはあとから調べる(todo)が、そのリソースに対するコマンドがつまれるキューが別のキューをまたぐ場合は適切に指定するということなんじゃないかな。(これも予想でしかない)
どんな種類があるかはドキュメントを確認。
VkAccessFlagBits(3)
hr.icon
VkBufferImageBarrierについて
Vulkanのリソースはバッファメモリとイメージメモリがありこっちはイメージメモリに対するステートの変更を記述する。
code:cpp
// Provided by VK_VERSION_1_0
typedef struct VkImageMemoryBarrier {
VkStructureType sType;
const void* pNext;
VkAccessFlags srcAccessMask;
VkAccessFlags dstAccessMask;
VkImageLayout oldLayout;
VkImageLayout newLayout;
uint32_t srcQueueFamilyIndex;
uint32_t dstQueueFamilyIndex;
VkImage image;
VkImageSubresourceRange subresourceRange;
} VkImageMemoryBarrier;
バッファメモリと同じ部分は割愛するとして、違う部分としてVkImageLayoutが出てくる。
VkImageにはImageLayoutという概念があり、ドキュメントに"Layout of image"としか書いていないのでレイアウトなんだなぁという理解しかしていないがレンダーターゲットとしてのレイアウト、コピー先としてのレイアウトなどがある。これはD3D12のD3D12_RESOURCE_STATESに近いと自分は思っている。ImageLayoutはディスクリプタセットでも指定するのでバインドされたリソースのImageLayoutとディスクリプタセットのレイアウトが合っていないとValidationErrorとなる。
VkAccesFlagsとVkImageLayout、どちらもGPU側からの見え方を指定しているような感じで大変紛らわしい。
#vulkan