Arsitektur Concurrency pada Vulkan Video

Ekosistem Vulkan Video API (ekstensi VK_KHR_video_queue, VK_KHR_video_decode_queue) memungkinkan decoding hardware langsung via compute context lintas platform. Namun, implementasi pada lingkungan worker terdistribusi menghadapi batasan fisik: jumlah hardware decode queue (VkQueueFamilyProperties dengan flag VK_QUEUE_VIDEO_DECODE_BIT_KHR) pada satu physical device sangat terbatas, umumnya hanya 1 hingga 2 engine independen per GPU.

Ketika beberapa proses worker berebut instansiasi VkDevice dan alokasi video session (VkVideoSessionKHR) secara paralel melampaui kapasitas driver, driver akan melempar VK_ERROR_OUT_OF_DEVICE_MEMORY atau memicu segmentation fault di user-space driver. Solusinya memerlukan koordinasi eksternal untuk mengelola akses resource GPU secara deterministik.

Manajemen Akses Hardware dengan Distributed Semaphore

Untuk mencegah resource exhaustion tanpa membatasi skalabilitas node secara statis, alokasi context dikontrol via distributed counting semaphore pada Redis. Semaphore ini merefleksikan jumlah engine decoding hardware aktual pada node GPU target.

-- Lua Script: acquire_vulkan_slot.lua
-- KEYS[1]: resource_key (contoh: "gpu:0:decode_slots")
-- ARGV[1]: worker_id
-- ARGV[2]: max_slots
-- ARGV[3]: ttl_seconds

local current = redis.call("SCARD", KEYS[1])
if current < tonumber(ARGV[2]) then
    redis.call("SADD", KEYS[1], ARGV[1])
    redis.call("EXPIRE", KEYS[1], tonumber(ARGV[3]))
    return 1
end
return 0

Script Lua memastikan operasi penambahan slot berjalan atomik di Redis runtime:

-- Lua Script: release_vulkan_slot.lua
-- KEYS[1]: resource_key
-- ARGV[1]: worker_id

redis.call("SREM", KEYS[1], ARGV[1])
return 1

Worker wajib memperbarui TTL key melalui thread heartbeat terpisah selama pipeline vkQueueSubmit berjalan. Jika worker mati mendadak, lease slot akan kedaluwarsa otomatis dan membebaskan antrean.

Desain Shared Queue Berbasis Ring Buffer

Pemrosesan frame terkompresi membutuhkan zero-copy memory alignment untuk efisiensi transfer PCIe ke staging buffer Vulkan. Job queue diimplementasikan menggunakan circular ring buffer pada shared memory (shm) antarmuka IPC, dipadu Redis stream sebagai dispatcher kontrol metadata.

#pragma pack(push, 1)
struct FrameSlot {
    uint32_t frame_index;
    uint32_t payload_size;
    uint8_t  nal_unit_type;
    uint8_t  is_keyframe;
    uint64_t pts;
    uint8_t  data[1024 * 512]; // 512 KB inline buffer per packet
};

struct RingBufferQueue {
    uint32_t capacity;
    _Atomic uint32_t head;
    _Atomic uint32_t tail;
    struct FrameSlot slots[64];
};
#pragma pack(pop)

Struktur memory-mapped di atas diakses secara lock-free menggunakan atomic operations (memory_order_acquire dan memory_order_release). Ingestion process bertindak sebagai single producer pada indeks tail, sedangkan worker Vulkan mengonsumsi packet pada indeks head sebelum dipetakan ke VkBuffer melalui vkMapMemory.

Pipeline Vulkan Video Decoding

Alur eksekusi decode di worker mengikuti sequence berikut:

  1. Acquire Lock: Eksekusi acquire_vulkan_slot.lua hingga mendapatkan slot decode.
  2. Queue Initialization: Query queue family via vkGetPhysicalDeviceQueueFamilyProperties2, ambil handle VkQueue yang mendukung decoding.
  3. Session Allocation: Alokasi VkVideoSessionKHR dengan profil codec yang cocok (H.264/HEVC/AV1) beserta memory backing bind via vkBindVideoSessionMemoryKHR.
  4. Ring Buffer Ingestion: Salin payload terkompresi dari shared memory ke bound memory VkBuffer.
  5. Command Execution: Panggil vkCmdBeginVideoCodingKHR, vkCmdDecodeVideoKHR, dan vkCmdEndVideoCodingKHR.
  6. Submission: Kirim batch ke GPU via vkQueueSubmit dengan CPU fence (VkFence) untuk sinkronisasi.
  7. Release Lock: Eksekusi release_vulkan_slot.lua dan reset struct state.

Penanganan Crash dan State Recovery

Worker crash saat memegang status decode dapat meninggalkan state hardware zombie atau frame terputus. Recovery dirancang bertingkat:

  • Heartbeat Dead-man Switch: Jika heartbeat Redis gagal diperbarui selama 5 detik, watchdog process menganggap worker failed dan mengembalikan slot via script cleanup.
  • Vulkan Device Loss Mitigation: Jika terjadi error VK_ERROR_DEVICE_LOST akibat bitstream corrupt, worker tidak boleh mencoba recovery inline pada VkDevice yang sama. Worker harus memanggil vkDestroyDevice, menghancurkan pool VkCommandPool, dan menginstansiasi ulang logical device secara bersih.
  • Dangling Shm Cleanup: Ring buffer mencatat PID worker yang aktif. Jika PID mati di tengah konsumsi, tail/head pointer dikembalikan ke sequence keyframe IDR terakhir untuk mencegah error decoding antar-frame (P/B-frame referencing error).