VK_EXT_external_memory_dma_buf は GPU↔GPU 共有をカバーする。
しかしデータがすでにホストメモリにある場合はどうか——
mmap されたファイル、V4L2 USERPTR キャプチャバッファ、
自分で埋める共有メモリリング?VK_EXT_external_memory_host は
既存の CPU ポインタを VkDeviceMemory としてインポートする。
ゼロコピーアップロード、ステージングバッファなし。
アイデア
path.txt
従来: host ptr → memcpy → ステージング VkBuffer → cmd copy → VkImage
インポート:host ptr ──────────────────► VkDeviceMemory ──► VkImage
(GPU がホスト割り当てを直接サンプル)要件とプローブ
probe.cpp
// デバイス拡張:VK_EXT_external_memory_host
// (+ VK_KHR_external_memory は通常すでに有効)
// どのホストポインタがインポートできるか?mmap 前に聞く:
vk::PhysicalDeviceExternalMemoryHostPropertiesEXT hostProps{};
// (vkGetPhysicalDeviceProperties2 にチェーン)
hostProps.minImportedHostPointerAlignment; // 多くの場合 4096 = ページサイズ
// このポインタはインポート可能か?
vk::MemoryHostPointerPropertiesEXT mpp{};
dev.getMemoryHostPointerPropertiesEXT(
vk::ExternalMemoryHandleTypeFlagBits::eHostAllocationEXT,
ptr, &mpp);
// mpp.memoryTypeBits — どの vkAllocateMemory タイプが受け付けるか
ポインタは minImportedHostPointerAlignment に整列しなければ
ならない。通常 getpagesize()。malloc したメモリではだめで、
posix_memalign か mmap なら使える。
インポート
import.cpp
vk::ImportMemoryHostPointerInfoEXT imp{};
imp.handleType = vk::ExternalMemoryHandleTypeFlagBits::eHostAllocationEXT;
imp.pHostPointer = ptr; // メモリが破棄されるまで有効でなければならない
vk::MemoryAllocateInfo ai{};
ai.pNext = &imp;
ai.allocationSize = size;
ai.memoryTypeIndex = pickFrom(mpp.memoryTypeBits);
auto mem = dev.allocateMemoryUnique(ai);
// リニア VkImage か VkBuffer にバインド——GPU があなたのバイトを読む。
インポートされたホストメモリでの vkMapMemory は概念的に
no-op だ。「マップ」はすでに持っているポインタ。コヒーレントな
ホスト可視メモリと同様、書き込み前に vkInvalidateMappedMemoryRanges、
後に vkFlushMappedMemoryRanges を呼ぶだけだ。
特に有効な場面
- V4L2 USERPTR キャプチャ:
m.userptrがインポートした範囲を 指すVIDIOC_QBUF→ カメラが GPU アドレス可能メモリに 直接 DMA する。 - mmap されたフレームファイル:ディスクからマップされた プリレンダーテクスチャリング。read+staging+free サイクルなし。
- 共有メモリ IPC:プロデューサーが
shmにピクセルを書き、 Vulkan コンシューマーが直接サンプルする。unix ソケット バッファコピーなし。 - FFmpeg SW フレーム:
posix_memalignしたバッファにデコードし、 インポートし、1回のvkCmdCopyBufferToImageでアップロード。 ステージング割り当てをスキップする。
vs.txt
vs ステージングバッファ: -1 割り当て、フレームあたり -1 memcpy、cmd 1つ減
vs DMA-Buf インポート: fd 不要 — ホストメモリ、デバイス BO ではない
vs HOST_VISIBLE イメージ: メモリ寿命をあなたが制御、ドライバーではない実践的なルール
- ポインタは
VkDeviceMemoryより長生きしなければならない。 早くfreeするのは GPU 上の use-after-free であり、キャッチ できる segfault ではない。 minImportedHostPointerAlignmentが契約だ。posix_memalign(&p, 4096, size)かmmap(NULL, …, MAP_PRIVATE…)で整列する。- すべてのメモリタイプがホストインポートを受け付けるわけではない。
任意の割り当てと同様に
memoryTypeBitsをフィルタする。一部の ドライバーでは HOST_VISIBLE タイプのみが適格。 - タイル化/optimal イメージはリニアホストメモリでバックできない。
VkBufferにインポートして1回のvkCmdCopyBufferToImageを するか、VK_EXT_host_image_copyでリニアレイアウトを書き込む。 - キャッシュコヒーレンシーはあなたの仕事:CPU 書き込み後、
サブミット前に
vkFlushMappedMemoryRanges。GPU はあなたの キャッシュをスヌープしない。
この記事が役に立った場合は、TechOverflow での新しい記事の調査と公開を支援するため、「Buy Me a Coffee」でのご支援、または PayPal 経由でのご寄付をご検討ください