系统版本 / 镜像
| 项目 | 信息 |
|---|---|
| 系统 | 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.cpp 的 createInstance() 中添加 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 导出功能
实现 createExportableTexture 和 exportMemoryToDmaBuf 函数:
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 显示扩展支持 |
||
| 引擎启用扩展 | ||
vkGetDeviceProcAddr 返回函数指针 |
||
| 驱动库包含符号 |
影响范围
- DMA-BUF 零拷贝方案无法实现
- 渲染管线被迫使用 CPU 拷贝(persistent map staging buffer,32.9 FPS)
- 无法达到预期的端到端硬件零拷贝性能
你的判断 / 改进建议
判断
- 驱动实现不完整 :PowerVR BXM-4-64 MC1 的 Vulkan 驱动虽然声明支持
VK_EXT_external_memory_dma_buf扩展,但vkGetMemoryFdEXT函数并未实际实现。这可能是以下原因之一:
- 驱动版本较旧,扩展处于"声明"状态但功能未完成
- 需要特定的内核配置或编译选项才能启用
- 该功能在 BXM-4-64 硬件上不可用(尽管报告支持)
- 与其他平台对比 :在桌面 GPU 驱动中,
vkGetMemoryFdEXT通常是完整实现的。嵌入式 GPU 驱动有时会报告扩展但推迟实现。