VK_EXT_host_image_copy 解説:ステージングバッファなしのイメージアップロード

古典的な Vulkan イメージアップロードは3ステップの儀式: ステージングバッファ → vkCmdCopyBufferToImage → レイアウト 遷移——すべてキュー上のコマンドバッファ内。 VK_EXT_host_image_copy(Vulkan 1.4 でコア化)はホスト側の ドアを加える:vkCopyMemoryToImageEXT が CPU メモリから ピクセルをイメージに直接書き込む——ステージングなし、 コマンドバッファなし、キュー投入なし。

古典経路 vs ホスト経路

paths.txt
classic:  cpu buf → staging VkBuffer → cmd copy → image (キュー投入!)
host:     cpu buf ──────────────────► image     (即座)
upload.cpp
// 1. イメージは作成時に HOST_TRANSFER フラグが必要:
vk::ImageCreateInfo ici{};
ici.format = vk::Format::eR8G8B8A8Unorm;
ici.extent = {w, h, 1};
ici.usage  = vk::ImageUsageFlagBits::eSampled
           | vk::ImageUsageFlagBits::eHostTransferEXT;
ici.initialLayout = vk::ImageLayout::eUndefined;
// … vkCreateImage、メモリをバインド、それから:

// 2. ホスト経由で一度遷移——vkTransitionImageLayoutEXT:
vk::HostImageLayoutTransitionInfoEXT tr{};
tr.image      = img;
tr.oldLayout  = vk::ImageLayout::eUndefined;
tr.newLayout  = vk::ImageLayout::eShaderReadOnlyOptimal;
tr.subresourceRange = {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
dev.transitionImageLayoutEXT(1, &tr);

// 3. ピクセルをコピー——同期、ホスト可視側:
vk::MemoryToImageCopyEXT cpy{};
cpy.pHostPointer           = pixels.data();
cpy.memoryRowLength        = w * 4;   // 行あたりバイト数、0 = 密
cpy.imageSubresource       = {vk::ImageAspectFlagBits::eColor, 0, 0, 1};
cpy.imageExtent            = {w, h, 1};
dev.copyMemoryToImageEXT(vk::CopyMemoryToImageInfoEXT{
    vk::CopyMemoryToImageFlagBitsEXT::eNoInternalFormatConversion,
    img, vk::ImageLayout::eShaderReadOnlyOptimal, 1, &cpy});

vkCopyImageToMemoryEXT は鏡像——リードバックバッファ + フェンスの踊りなしでイメージを CPU に読み戻す。

なぜ使うか

  • 小さくまれなアップロード(フォント、LUT、アイコン): コマンドプールなし、フェンスなし、ステージング簿記なし ——1回の呼び出しで完了。
  • タイル/最適レイアウト書き込み:ドライバが内部でスウィズル、 あなたは線形行を渡すだけ。
  • 初期化時リソース:キューが存在する前にアップロード; エンジン起動を劇的に単純化。

合わない場面

  • フレームごとのストリーミング——コピーは同期寄りの ホスト作業で、しばしば非同期 DMA ステージングコピーより遅い; 毎フレームデータ(ビデオフレーム、動的アトラス)では古典 ステージング経路か HOST_COHERENT デバイスローカルバッファが 速いまま。
  • すべてのフォーマット/レイアウトが対象ではない—— vkGetPhysicalDeviceFormatProperties2 → VkFormatProperties3::hostImageCopy と vkGetPhysicalDeviceImageFormatProperties2 の hostImageCopySupport を確認。
probe.cpp
vk::FormatProperties3 fp3{};
dev.getPhysicalDeviceFormatProperties2(
        vk::PhysicalDeviceFormatInfo2{vk::Format::eR8G8B8A8Unorm})
   .get<vk::FormatProperties2, vk::FormatProperties3>();
// fp3.optimalTilingFeatures & eHostImageCopy?

実践的なルール

  • 常に eHostTransfer usage を設定 + 書き込み間でイメージを ホスト転送互換レイアウトに保つ(eGeneral はどこでも動く)。
  • 正しいレイアウト追跡の必要性を取り除かない——遷移を ホスト呼び出しに移すだけ。
  • 利便性 + 配管削減と考え、perf 向上ではない。

同じカテゴリの類似記事をチェック: Vulkan C++