i.MX8M Plus平台DMA-buf导入Vulkan后映射无原数据问题求助
问题分析与解决方案
在i.MX8M Plus平台上,将/cma-uncached区域的DMA-buf导入Vulkan后,vkMapMemory无法读取原始数据(验证层无报错),核心问题集中在内存类型匹配错误、外部内存导入参数误用两个方面,以下是具体分析和修复方案:
关键问题点
1. 错误的内存类型选择
导入外部DMA-buf时,不能直接指定VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT来筛选内存类型。DMA-buf的内存属性由其创建时的内存区域(/cma-uncached)决定,必须选择驱动认可的、支持VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT导入的内存类型,而非自定义组合属性。
2. 不必要的VkMemoryDedicatedAllocateInfo
导入已存在的外部内存时,无需指定VkMemoryDedicatedAllocateInfo——该结构用于驱动分配全新的专用内存,而DMA-buf是预先分配好的内存,强行添加会干扰驱动对外部内存的关联逻辑。
3. 驱动扩展验证缺失
需确保已启用VK_KHR_external_memory_fd和VK_EXT_external_memory_dma_buf扩展,这是DMA-buf导入Vulkan的必要前提。
修复后的代码示例
// 确保已启用VK_KHR_external_memory_fd和VK_EXT_external_memory_dma_buf扩展 VkExternalMemoryBufferCreateInfo extMemBufInfo{}; extMemBufInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO; extMemBufInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; extMemBufInfo.pNext = nullptr; int FD_width = widthVIV; int FD_height = heightVIV; int size = FD_width * FD_height * 2; VkBufferCreateInfo bufferInfo{}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; bufferInfo.pNext = &extMemBufInfo; if (vkCreateBuffer(device, &bufferInfo, nullptr, &fdBuffer) != VK_SUCCESS) { qDebug("failed to create buffer!"); } VkMemoryRequirements memRequirements; vkGetBufferMemoryRequirements(device, fdBuffer, &memRequirements); // 移除VkMemoryDedicatedAllocateInfo VkImportMemoryFdInfoKHR importInfo{}; importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; importInfo.fd = dmafd; importInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; importInfo.pNext = nullptr; // 修改内存类型查找逻辑:筛选支持DMA-buf导入的内存类型 uint32_t findExternalMemoryType(VkPhysicalDevice physicalDevice, uint32_t memoryTypeBits, VkExternalMemoryHandleTypeFlagBitsEXT handleType) { VkPhysicalDeviceMemoryProperties memProps; vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps); for (uint32_t i = 0; i < memProps.memoryTypeCount; i++) { if (!(memoryTypeBits & (1 << i))) continue; VkExternalMemoryPropertiesKHR extMemProps{}; extMemProps.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_PROPERTIES_KHR; VkPhysicalDeviceExternalMemoryInfoKHR extMemInfo{}; extMemInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_INFO_KHR; extMemInfo.handleType = handleType; vkGetPhysicalDeviceExternalMemoryPropertiesKHR(physicalDevice, &extMemInfo, &extMemProps); if (extMemProps.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR) { return i; } } return UINT32_MAX; } uint32_t memTypeIndex = findExternalMemoryType(physicalDevice, memRequirements.memoryTypeBits, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT); if (memTypeIndex == UINT32_MAX) { qDebug("failed to find compatible external memory type!"); } VkMemoryAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = memTypeIndex; allocInfo.pNext = &importInfo; if (vkAllocateMemory(device, &allocInfo, nullptr, &fdBufferMemory) != VK_SUCCESS) { qDebug("failed to allocate image memory!"); } if(vkBindBufferMemory(device, fdBuffer, fdBufferMemory, 0) != VK_SUCCESS) { qDebug() << "vkBindBufferMemory failed: " << strerror(errno); }
额外验证步骤
- 确认
dmafd未被提前关闭,且与mmap使用的是同一个文件描述符; - 映射内存后,检查指针偏移:由于DMA-buf可能存在硬件对齐要求,需确认
vkMapMemory返回的指针与DMA-buf实际起始地址的偏移是否为0; - 若仍存在问题,可通过
vkGetDeviceMemoryOpaqueCaptureAddressKHR获取内存地址,与DMA-buf的物理地址对比,验证是否正确关联。
内容的提问来源于stack exchange,提问作者AB2
相关产品推荐
相关产品推荐

