V4L2'den Vulkan'a sıfır kopya: kamera DMA-Buf'larını texture olarak içe aktarma

V4L2 kamerasının CPU belleğine inmesi gerekmez. V4L2_MEMORY_DMABUF ile kamera sürücüsü her capture buffer’ını DMA-Buf olarak export eder — VAAPI’nin export ettiği fd tipinin aynısıdır. Bunu Vulkan’a import ettiğinizde kamera sensörü grid shader’ı doğrudan besler. Decode yazılarında VAAPI kareleri için kurulan sıfır kopya pipeline’ının capture tarafıdır.

V4L2 tarafı — DMA-Buf buffer’ları isteyin

v4l2.cpp
int fd = open("/dev/video0", O_RDWR);

v4l2_format fmt{};
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;  // veya V4L2_PIX_FMT_…
fmt.fmt.pix_mp.width  = 1920;
fmt.fmt.pix_mp.height = 1080;
ioctl(fd, VIDIOC_S_FMT, &fmt);

v4l2_requestbuffers req{};
req.count   = 4;
req.type    = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
req.memory  = V4L2_MEMORY_DMABUF;            // ← DMA-Buf olarak export et
ioctl(fd, VIDIOC_REQBUFS, &req);

// kare başına dequeue → buffer'ın fd'si DMA-Buf'tur:
v4l2_buffer buf{};
buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4L2_MEMORY_DMABUF;
buf.length = nPlanes;
buf.m.planes = planes;
ioctl(fd, VIDIOC_DQBUF, &buf);
// buf.m.planes[i].m.fd — karenin plane'leri için DMA-Buf fd'leri

Vulkan tarafı — decode ile aynı import

import.cpp
// decoder yoluyla aynı — fd → VkDeviceMemory → VkImage:
vk::ImportMemoryFdInfoKHR imp{};
imp.handleType = vk::ExternalMemoryHandleTypeFlagBits::eDmaBufEXT;
imp.fd         = dup(buf.m.planes[0].m.fd);

// kamera bir modifier sunuyorsa image tiling = eDrmFormatModifierEXT,
// sunmuyorsa açık stride'lı eLinear

Mekanizma, decoder yazılarındaki VK_EXT_external_memory_dma_buf + VK_EXT_image_drm_format_modifier ikilisinin birebir aynısıdır — kamera karesi de sadece başka bir DMA-Buf’tur.

Tüm pipeline

pipe.txt
/dev/video0 ──► V4L2 DQBUF → DMA-Buf fd
            ──► vkImportMemoryFdKHR → VkImage
            ──► grid shader'da örnekle
            ──► render → swapchain
CPU piksel yolu yok — VAAPI decode ile aynı, ancak *kaynak*
decoder değil sensör.

VAAPI’ye göre konumu

compare.txt
V4L2 DMA-Buf:     USB/CSI kameralar, capture card'lar — ham veya
                  vendor'a özel sıkıştırılmış sensör verisi,
                  sıkıştırılmamış YUV/RGB
VAAPI DMA-Buf:    IP kameralar, dosyalar — VCN/VCU bloğunda decode edilen
                  sıkıştırılmış bitstream, çıktı YUV plane'leridir
ikisi de:         aynı import API'si, aynı modifier mekanizması, aynı
                  foreign-queue transferi

IP kameraları (VAAPI decode) ve yerel bir USB kamerayı (V4L2) karıştıran bir kamera duvarı, Vulkan tarafının tamamını paylaşır — tek fark fd’nin nereden geldiğidir.

Pratik kurallar

  • REQBUFS‘ta varsayılan MMAP değil V4L2_MEMORY_DMABUF kullanın; kamera sürücüsü export’u desteklemelidir (modern sürücülerin çoğu destekler).
  • Çok düzlemli için V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE — NV12/YUV kameralar plane’leri buf.m.planes[] üzerinden sunar; tek düzlemli formatlar _CAPTURE + buf.m.fd kullanır.
  • Decoder’ın import kodunu yeniden kullanın — FFmpeg’in AVDRMFrameDescriptor‘ı ile v4l2_buffer plane’leri farklı sarmalayıcılardaki aynı veridir; {fd, offset, stride, format, modifier} değerlerine normalize edin.
  • Foreign-queue transferi (VK_EXT_queue_family_foreign) aynen geçerlidir — V4L2 sürücüsü buffer’ı kendi context’inde yazmıştır.
  • Buffer’ları hemen iade edin — VIDIOC_QBUF, DMA-Buf’u bir sonraki kare için geri koyar; fd’leri elde tutmak kamerayı aç bırakır.

Check out similar posts by category: Vulkan Linux Camera