【Super Point】K3 PowerVR BXM-4-64:VK_EXT_external_memory_dma_buf 扩展报告支持但 vkGetMemoryFdEXT 函数未实现

系统版本 / 镜像

项目 信息
系统 Bianbu 4.0.1 (Resolute Raccoon)
内核 6.18.3-generic #1.0.2.4 SMP PREEMPT_DYNAMIC
架构 RISC-V 64 (rv64gc)
SoC SpacemiT Key Stone K3
GPU PowerVR B-Series BXM-4-64 MC1
Vulkan 驱动 PowerVR ICD (libVK_IMG.so)
开发板 SpacemiT K3 Pico ITX

使用场景或测试目标

目标是构建端到端的零拷贝渲染管线:

text

Vulkan 离屏渲染 (BGRA) ↓ 通过 DMA-BUF 零拷贝导出 V2D 硬件格式转换 (BGRA → NV12) ↓ 通过 DMA-BUF 零拷贝传递 VPU 硬件编码 (H.264)

DMA-BUF 是实现零拷贝的关键机制——它允许 Vulkan 渲染纹理通过文件描述符(fd)直接共享给 V2D 和 VPU 硬件,无需 CPU 参与数据拷贝。

操作步骤

1. 启用 Vulkan 扩展

vulkan_context.cppcreateInstance() 中添加 DMA-BUF 导出所需的扩展:

cpp

m_extensions.instanceExtensions.push_back(“VK_KHR_external_memory_capabilities”); m_extensions.deviceExtensions.push_back(“VK_KHR_external_memory”); m_extensions.deviceExtensions.push_back(“VK_KHR_external_memory_fd”); m_extensions.deviceExtensions.push_back(“VK_EXT_external_memory_dma_buf”); m_extensions.deviceExtensions.push_back(“VK_KHR_get_memory_requirements2”); m_extensions.deviceExtensions.push_back(“VK_KHR_dedicated_allocation”);

2. 验证扩展是否启用

createLogicalDevice() 中添加调试日志,打印所有启用的设备扩展:

cpp

std::cout << “[Vulkan] Enabling device extensions:” << std::endl; for (uint32_t i = 0; i < m_extensions.deviceExtensions.size(); i++) { std::cout << " - " << m_extensions.deviceExtensions[i] << std::endl; }

3. 实现 DMA-BUF 导出功能

实现 createExportableTextureexportMemoryToDmaBuf 函数:

cpp

// 创建可导出的纹理(绕过 VMA 直接分配) ExportableTextureResult createExportableTexture( uint32_t width, uint32_t height, VkFormat format, VkImageUsageFlags usage); // 从 VkDeviceMemory 导出 DMA-BUF fd DmaBufExportResult exportMemoryToDmaBuf( VkDeviceMemory memory, VkDeviceSize size);

4. 检测 vkGetMemoryFdEXT 函数可用性

updateCapabilities() 中检测函数指针:

cpp

PFN_vkGetMemoryFdEXT vkGetMemoryFdEXT = reinterpret_cast<PFN_vkGetMemoryFdEXT>( vkGetDeviceProcAddr(m_device, “vkGetMemoryFdEXT”)); std::cout << "[Vulkan] vkGetDeviceProcAddr for vkGetMemoryFdEXT: " << (void*)vkGetMemoryFdEXT << std::endl; m_capabilities.supportsDmaBufExport = (vkGetMemoryFdEXT != nullptr);

5. 检查驱动库符号

bash

strings /usr/lib/libVK_IMG.so | grep -i “GetMemoryFd”

结果数据 / 截图 / 日志

1. vulkaninfo 显示扩展支持

bash

$ vulkaninfo | grep -i “external_memory|dma_buf” WARNING: [Loader Message] Code 0 : Layer VK_LAYER_MESA_device_select uses API version 1.3 which is older than the application specified API version of 1.4. May cause issues. VK_KHR_external_memory_capabilities : extension revision 1 VK_EXT_external_memory_acquire_unmodified : extension revision 1 VK_EXT_external_memory_dma_buf : extension revision 1 VK_KHR_external_memory : extension revision 1 VK_KHR_external_memory_fd : extension revision 1

2. 引擎成功启用所有扩展

text

[Vulkan] Enabling device extensions: - VK_KHR_swapchain - VK_KHR_external_memory - VK_KHR_external_memory_fd - VK_EXT_external_memory_dma_buf - VK_KHR_get_memory_requirements2 - VK_KHR_dedicated_allocation

3. vkGetMemoryFdEXT 函数指针为 NULL

text

[Vulkan] vkGetDeviceProcAddr for vkGetMemoryFdEXT: 0 [Vulkan] vkGetInstanceProcAddr for vkGetMemoryFdEXT: 0 [Vulkan] DMA-BUF export: NO

4. 驱动库中无 GetMemoryFd 符号

bash

$ strings /usr/lib/libVK_IMG.so | grep -i “GetMemoryFd” # (无输出)

5. GPU 信息

text

deviceName = PowerVR B-Series BXM-4-64 MC1

遇到的问题

核心问题VK_EXT_external_memory_dma_buf 扩展在 vulkaninfo 中报告支持,但实际的导出函数 vkGetMemoryFdEXT 在驱动中未实现。

检查项 预期结果 实际结果
vulkaninfo 显示扩展支持 :white_check_mark: 显示 :white_check_mark: 显示
引擎启用扩展 :white_check_mark: 成功 :white_check_mark: 成功
vkGetDeviceProcAddr 返回函数指针 :white_check_mark: 非 NULL :x: 0 (NULL)
驱动库包含符号 :white_check_mark: 存在 :x: 不存在

影响范围

  • DMA-BUF 零拷贝方案无法实现
  • 渲染管线被迫使用 CPU 拷贝(persistent map staging buffer,32.9 FPS)
  • 无法达到预期的端到端硬件零拷贝性能

你的判断 / 改进建议

判断

  1. 驱动实现不完整 :PowerVR BXM-4-64 MC1 的 Vulkan 驱动虽然声明支持 VK_EXT_external_memory_dma_buf 扩展,但 vkGetMemoryFdEXT 函数并未实际实现。这可能是以下原因之一:
  • 驱动版本较旧,扩展处于"声明"状态但功能未完成
  • 需要特定的内核配置或编译选项才能启用
  • 该功能在 BXM-4-64 硬件上不可用(尽管报告支持)
  1. 与其他平台对比 :在桌面 GPU 驱动中,vkGetMemoryFdEXT 通常是完整实现的。嵌入式 GPU 驱动有时会报告扩展但推迟实现。

标准 Vulkan spec 不存在 vkGetMemoryFdEXT 这个函数,你应该使用的是 vkGetMemoryFdKHR

谢谢,问题成功解决了

V2D 转换器初始化成功,DMA-BUF 导出也成功(fd=128),但 V2D 转换在提交任务时失败了:

text

Failed to submit V2D task! :x: V2D DMA-BUF conversion FAILED: V2D_EndJob failed: -1

Vulkan 导出的 DMA-BUF 是 tiled 格式,请问V2D 接受这个格式吗

可以用 vkCmdCopyImage/vkCmdCopyImageToBuffer 在 GPU 内部做一次 OPTIMAL→LINEAR 的操作

你需要用 VK_EXT_image_drm_format_modifier 来固定图像格式(

1 个赞