/* * panvk-bifrost-video — Phase 3 regression probe. * * Enumerates Vulkan device extensions + queue families on every physical * device. Emits structured PASS/FAIL lines for the four conditions Phase 1 * of the campaign must flip from FAIL to PASS: * * 1. extension VK_KHR_video_queue present * 2. extension VK_KHR_video_decode_queue present * 3. extension VK_KHR_video_decode_h264 present * 4. queue family with VK_QUEUE_VIDEO_DECODE_BIT_KHR (advertising * videoCodecOperations & VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR) * * Build: gcc -O2 -Wall probe_vkvideo.c -lvulkan -o probe_vkvideo * Run: VK_ICD_FILENAMES=/usr/lib/panvk-bifrost/icd.json \ * PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1 \ * ./probe_vkvideo * * Phase 3 baseline (panvk-bifrost r4): all 4 → FAIL. * Phase 4 commit 1 target: all 4 → PASS (no functionality, just enumeration). */ #include #include #include #include #include #include #define FAIL(fmt, ...) do { fprintf(stderr, "[fail] " fmt "\n", ##__VA_ARGS__); return 1; } while (0) #define INFO(fmt, ...) printf("[info] " fmt "\n", ##__VA_ARGS__) static void report(bool ok, const char *name) { printf("[%s] %s\n", ok ? "PASS" : "FAIL", name); } static bool has_ext(const VkExtensionProperties *exts, uint32_t n, const char *name) { for (uint32_t i = 0; i < n; i++) if (strcmp(exts[i].extensionName, name) == 0) return true; return false; } int main(void) { VkResult r; VkInstance inst; const VkApplicationInfo app = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pApplicationName = "panvk-bifrost-video-probe", .apiVersion = VK_API_VERSION_1_3, }; const VkInstanceCreateInfo ici = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = &app, }; r = vkCreateInstance(&ici, NULL, &inst); if (r != VK_SUCCESS) FAIL("vkCreateInstance => %d", r); uint32_t n_phys = 0; r = vkEnumeratePhysicalDevices(inst, &n_phys, NULL); if (r != VK_SUCCESS) FAIL("vkEnumeratePhysicalDevices count => %d", r); if (n_phys == 0) FAIL("no physical devices"); VkPhysicalDevice *phys = calloc(n_phys, sizeof(*phys)); r = vkEnumeratePhysicalDevices(inst, &n_phys, phys); if (r != VK_SUCCESS) FAIL("vkEnumeratePhysicalDevices fill => %d", r); int overall_pass = 0; for (uint32_t pi = 0; pi < n_phys; pi++) { VkPhysicalDeviceProperties p; vkGetPhysicalDeviceProperties(phys[pi], &p); INFO("device[%u]: %s (vendor=%04x device=%08x)", pi, p.deviceName, p.vendorID, p.deviceID); uint32_t n_ext = 0; vkEnumerateDeviceExtensionProperties(phys[pi], NULL, &n_ext, NULL); VkExtensionProperties *exts = calloc(n_ext, sizeof(*exts)); vkEnumerateDeviceExtensionProperties(phys[pi], NULL, &n_ext, exts); bool e_queue = has_ext(exts, n_ext, "VK_KHR_video_queue"); bool e_decode = has_ext(exts, n_ext, "VK_KHR_video_decode_queue"); bool e_h264 = has_ext(exts, n_ext, "VK_KHR_video_decode_h264"); report(e_queue, "VK_KHR_video_queue"); report(e_decode, "VK_KHR_video_decode_queue"); report(e_h264, "VK_KHR_video_decode_h264"); /* Queue family enumeration with video-properties pNext walk. * If VK_KHR_video_queue isn't advertised, this still works but * VkQueueFamilyVideoPropertiesKHR fields stay zero. */ uint32_t n_qf = 0; vkGetPhysicalDeviceQueueFamilyProperties2(phys[pi], &n_qf, NULL); VkQueueFamilyProperties2 *qfp = calloc(n_qf, sizeof(*qfp)); VkQueueFamilyVideoPropertiesKHR *vp = calloc(n_qf, sizeof(*vp)); for (uint32_t i = 0; i < n_qf; i++) { qfp[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2; qfp[i].pNext = e_queue ? &vp[i] : NULL; vp[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR; } vkGetPhysicalDeviceQueueFamilyProperties2(phys[pi], &n_qf, qfp); bool qf_has_video = false; bool qf_has_h264 = false; for (uint32_t i = 0; i < n_qf; i++) { INFO(" qf[%u]: flags=0x%08x count=%u", i, qfp[i].queueFamilyProperties.queueFlags, qfp[i].queueFamilyProperties.queueCount); if (qfp[i].queueFamilyProperties.queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) { qf_has_video = true; if (vp[i].videoCodecOperations & VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR) qf_has_h264 = true; } } report(qf_has_video, "queue family with VK_QUEUE_VIDEO_DECODE_BIT_KHR"); report(qf_has_h264, "queue family advertising DECODE_H264 codec op"); if (e_queue && e_decode && e_h264 && qf_has_video && qf_has_h264) overall_pass = 1; free(qfp); free(vp); free(exts); } free(phys); vkDestroyInstance(inst, NULL); printf("\n=== OVERALL: %s ===\n", overall_pass ? "PASS" : "FAIL (Phase 3 baseline expected)"); return overall_pass ? 0 : 2; /* exit 2 distinguishes "ran cleanly, baseline-fail" from build/run errors */ }