🌋

Vulkan 1.3のDynamic Renderingを使ってみた

2022/08/29に公開

Dynamic Renderingについて

Vulkanには拡張機能として新しい機能がいろいろと追加されていきますが、一部の機能はコア仕様に昇格することがあります。
拡張機能は有効化するために色々と手順が必要となりますが、コア仕様に昇格されたものはPhysical DeviceのFeaturesを有効化するだけで簡単に使えるのでお手軽です。

Vulkan 1.3でも拡張機能で提供されていた様々な機能がコアに昇格しました。以下のページにリストがあります。

https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_VERSION_1_3.html

その中でも注目機能のひとつがDynamic Renderingです。

https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_dynamic_rendering.html

いままではGraphicsPipelineを作るときにRenderPassやSubpass、Framebufferを用意する必要がありました。
これはマルチパスレンダリングなどでは活用されるみたいですが、簡単なシングルパスレンダリングのアプリを作る際には冗長です。
Dynamic Renderingではこの冗長性を解消してくれるので、コードを簡単に書けるようになるはずです。

おおまかな使い方

従来はレンダリングに必要なアタッチメント(具体的にはレンダリング対象の画像)はRenderPassの作成時に登録する形でした。

void createRenderPass()
{
  vk::AttachmentDescription colorAttachment = ...;
  vk::AttachmentReference colorAttachmentRef = ...;
  vk::SubpassDescription subpass = ...;
  vk::SubpassDependency dependency = ...;
  vk::RenderPassCreateInfo createInfo({}, colorAttachment, subpass, dependency);
  renderPass = device.createRenderPassUnique(createInfo);
}

// メインループ内
void render()
{
  vk::RenderPassBeginInfo beginInfo = ...;
  commandBuffer.beginRenderPass(beginInfo, ...);
  // draw ...
  commandBuffer.endRenderPass();
}

Dynamic Renderingを有効化すると、名前の通りアタッチメントを動的に指定する形式になります。以前のbeginRenderPass()からbeginRendering()という関数に移行しています。

// RenderPassは作成しなくていい
// void createRenderPass(){}

// メインループ内
void render()
{
  vk::RenderingAttachmentInfo colorAttachment = ...;
  vk::RenderingInfo renderingInfo = ...;
  commandBuffer.beginRendering(renderingInfo);
  // draw ...
  commandBuffer.endRendering();
}

おおまかな使い方なこのような形で、全体的にコード量が減少しました。

デメリット

ただ、ひとつデメリットがあります。従来はアタッチメントのImageLayoutはRenderPassが終わったときに暗黙のうちに遷移してくれていたのですが、Dynamic Renderingではそれが使えません。
このため、commandBuffer.endRendering()のあとに自前でImageLayoutの遷移を書く必要があります

// メインループ内
void render()
{
  vk::RenderingAttachmentInfo colorAttachment = ...;
  vk::RenderingInfo renderingInfo = ...;
  commandBuffer.beginRendering(renderingInfo);
  // draw ...
  commandBuffer.endRendering();
  
  vk::ImageMemoryBarrier imageMemoryBarrier = ...;
  commandBuffer.pipelineBarrier(..., imageMemoryBarrier);
}

若干手間が増えるのが少し残念ですね。

実際にDynamic Rendering使ってみた

実際にミニマルな自前プロジェクトでDynamic Renderingを使ってみました。
差分をひとつのコミットにまとめてあるので、これを見ると具体的に何が消えて、どう使うのかが分かりやすいと思います。よければ参考にしてください。

https://github.com/yknishidate/vulkan-minimal-hybrid-rendering/commit/787cb42c23d0b6cf2698b7b1f66bcae4c2fc5dbf

ちなみに、このコミットを見ると58 additions and 84 deletionsとなってるので、26行減ったようです。これは、どうなんでしょうね。

Discussion