VK_EXT_queue_family_foreign açıklaması: import edilen buffer'ların sahipliğini alma

Bir DMA-Buf import ettiniz (external_memory_dma_buf yazısı) — ancak decoder onu kendi queue’sunda, yabancı bir sürücüde yazdı. Vulkan’ın bellek modeli şöyle der: yazmalar, sahipliği transfer etmediğiniz sürece yalnızca yazan queue family’ye görünürdür. VK_EXT_queue_family_foreign, sentinel family indeksi VK_QUEUE_FAMILY_FOREIGN_EXT‘i — “en son kim dokunduysa” queue’su — ve buffer’ı kendi queue family’nize taşımak için semaphore/barrier mekaniğini verir.

Sorun

problem.txt
decoder queue'su DMA-Buf'a yazar → grafik queue'nuz örnekler
                                 ↑  Vulkan'ın bellek modelinde farklı
                                    bir "queue family" —
                                    yazmaların görünür olması garanti değil

Transfer olmadan örnekleme UB’dir — çoğu zaman şans eseri çalışır, bazen bayat veri döndürür.

Transfer

transfer.cpp
// decoder tarafı (kavramsal — exporter bir semaphore sinyaller
// veya bittiğini bilirsiniz):
//   DMA-Buf, VK_QUEUE_FAMILY_FOREIGN_EXT'e "ait"tir

// sizin queue'nuz — bir release/acquire çifti veya iki alanlı barrier:
vk::ImageMemoryBarrier imb{};
imb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT;  // önce: foreign
imb.dstQueueFamilyIndex = myGraphicsFamily;             // şimdi: benim
imb.image    = importedImg;
imb.oldLayout = vk::ImageLayout::eGeneral;
imb.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
// srcAccess = foreign tarafın yaptığı — genelde senkronu taşıyan
//   bir semaphore wait üzerinden eMemoryWrite
cmd.pipelineBarrier(eTopOfPipe, eFragmentShader, {}, {}, {}, {imb});

srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT işin püf noktasıdır: “hangi family’nin yazdığını bilmiyorum — al gitsin” der. Exporter’ın tamamlanmasını taşıyan bir semaphore wait ile eşleştiğinde yazma artık görünürdür.

Semaphore yolu

sem.cpp
// decoder sinyaller; siz wait + acquire edersiniz:
vk::SubmitInfo si{};
si.waitSemaphoreCount   = 1;
si.pWaitSemaphores      = &decoderSem;    // VA-API/V4L2 fence'inden
si.pWaitDstStageMask    = &fragmentStage;
// … yukarıdaki barrier aynı cmd buffer'a girer …
queue.submit(si);

Pratikte VAAPI/V4L2, VkSemaphore‘a dönüşen bir sync fd üzerinden tamamlanma sinyaller — vkGetSemaphoreFdKHR/vkImportSemaphoreFdKHR ile içeri alınır.

Uçtan uca akış

flow.txt
FFmpeg decode bitti → AVDRMFrameDescriptor plane'lerin fd'lerini taşır
→ DMA-Buf yoluyla VkImage olarak import et
→ barrier: FOREIGN_EXT → grafik queue'su, eGeneral → eShaderReadOnly
→ grid shader'da örnekle
→ kare emekliliğinde: geri ver (dst=FOREIGN_EXT) veya VkImage'i
  doğrudan düşür — DMA-Buf decoder'ın havuzuna döner

Pratik kurallar

  • VK_QUEUE_FAMILY_FOREIGN_EXT bir sözde family‘dir — queueFamilyProperties‘te asla görünmez; yalnızca srcQueueFamilyIndex/dstQueueFamilyIndex alanlarına girer.
  • Barrier tek başına sıralama taşımaz — semaphore wait ile eşleştirin ki okumanız başlamadan önce foreign yazma tamamlanmış olsun.
  • Bitince release edin: dst=FOREIGN_EXT barrier’ı buffer’ı geri verir — yalnızca DMA-Buf yeniden kullanılmayıp yok ediliyorsa atlayın.
  • Sürücü ve donanımın gerçekten aynı queue family’yi paylaştığı aynı cihaz import’larında barrier no-op’tur — ancak spec yine de bildirimi gerektirir.
  • Atlarsanız belirti aralıklı bayat karelerdir — klasik “ilk kare yeşil, sonraki kareler iyi” video-import bug’ı.

Check out similar posts by category: Vulkan C++