1 // Copyright 2019 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "common/Assert.h" 16 #include "dawn_native/vulkan/AdapterVk.h" 17 #include "dawn_native/vulkan/BackendVk.h" 18 #include "dawn_native/vulkan/DeviceVk.h" 19 #include "dawn_native/vulkan/ResourceMemoryAllocatorVk.h" 20 #include "dawn_native/vulkan/VulkanError.h" 21 #include "dawn_native/vulkan/external_memory/MemoryService.h" 22 23 namespace dawn_native { namespace vulkan { namespace external_memory { 24 25 namespace { 26 27 // Some modifiers use multiple planes (for example, see the comment for 28 // I915_FORMAT_MOD_Y_TILED_CCS in drm/drm_fourcc.h), but dma-buf import in Dawn only 29 // supports single-plane formats. GetModifierPlaneCount(const VulkanFunctions & fn,VkPhysicalDevice physicalDevice,VkFormat format,uint64_t modifier)30 ResultOrError<uint32_t> GetModifierPlaneCount(const VulkanFunctions& fn, 31 VkPhysicalDevice physicalDevice, 32 VkFormat format, 33 uint64_t modifier) { 34 VkDrmFormatModifierPropertiesListEXT formatModifierPropsList; 35 formatModifierPropsList.sType = 36 VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT; 37 formatModifierPropsList.pNext = nullptr; 38 formatModifierPropsList.drmFormatModifierCount = 0; 39 formatModifierPropsList.pDrmFormatModifierProperties = nullptr; 40 41 VkFormatProperties2 formatProps; 42 formatProps.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; 43 formatProps.pNext = &formatModifierPropsList; 44 45 fn.GetPhysicalDeviceFormatProperties2(physicalDevice, format, &formatProps); 46 47 uint32_t modifierCount = formatModifierPropsList.drmFormatModifierCount; 48 std::vector<VkDrmFormatModifierPropertiesEXT> formatModifierProps(modifierCount); 49 formatModifierPropsList.pDrmFormatModifierProperties = formatModifierProps.data(); 50 51 fn.GetPhysicalDeviceFormatProperties2(physicalDevice, format, &formatProps); 52 for (const auto& props : formatModifierProps) { 53 if (props.drmFormatModifier == modifier) { 54 uint32_t count = props.drmFormatModifierPlaneCount; 55 return count; 56 } 57 } 58 return DAWN_FORMAT_VALIDATION_ERROR("DRM format modifier not supported."); 59 } 60 61 } // anonymous namespace 62 Service(Device * device)63 Service::Service(Device* device) 64 : mDevice(device), mSupported(CheckSupport(device->GetDeviceInfo())) { 65 } 66 67 Service::~Service() = default; 68 69 // static CheckSupport(const VulkanDeviceInfo & deviceInfo)70 bool Service::CheckSupport(const VulkanDeviceInfo& deviceInfo) { 71 return deviceInfo.HasExt(DeviceExt::ExternalMemoryFD) && 72 deviceInfo.HasExt(DeviceExt::ImageDrmFormatModifier); 73 } 74 SupportsImportMemory(VkFormat format,VkImageType type,VkImageTiling tiling,VkImageUsageFlags usage,VkImageCreateFlags flags)75 bool Service::SupportsImportMemory(VkFormat format, 76 VkImageType type, 77 VkImageTiling tiling, 78 VkImageUsageFlags usage, 79 VkImageCreateFlags flags) { 80 return mSupported; 81 } 82 SupportsCreateImage(const ExternalImageDescriptor * descriptor,VkFormat format,VkImageUsageFlags usage)83 bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor, 84 VkFormat format, 85 VkImageUsageFlags usage) { 86 // Early out before we try using extension functions 87 if (!mSupported) { 88 return false; 89 } 90 if (descriptor->type != ExternalImageType::DmaBuf) { 91 return false; 92 } 93 const ExternalImageDescriptorDmaBuf* dmaBufDescriptor = 94 static_cast<const ExternalImageDescriptorDmaBuf*>(descriptor); 95 96 // Verify plane count for the modifier. 97 VkPhysicalDevice physicalDevice = ToBackend(mDevice->GetAdapter())->GetPhysicalDevice(); 98 uint32_t planeCount = 0; 99 if (mDevice->ConsumedError(GetModifierPlaneCount(mDevice->fn, physicalDevice, format, 100 dmaBufDescriptor->drmModifier), 101 &planeCount)) { 102 return false; 103 } 104 if (planeCount == 0) { 105 return false; 106 } 107 // TODO(hob): Support multi-plane formats like I915_FORMAT_MOD_Y_TILED_CCS. 108 if (planeCount > 1) { 109 return false; 110 } 111 112 // Verify that the format modifier of the external memory and the requested Vulkan format 113 // are actually supported together in a dma-buf import. 114 VkPhysicalDeviceImageDrmFormatModifierInfoEXT drmModifierInfo; 115 drmModifierInfo.sType = 116 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT; 117 drmModifierInfo.pNext = nullptr; 118 drmModifierInfo.drmFormatModifier = dmaBufDescriptor->drmModifier; 119 drmModifierInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 120 121 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo; 122 externalImageFormatInfo.sType = 123 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; 124 externalImageFormatInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; 125 externalImageFormatInfo.pNext = &drmModifierInfo; 126 127 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo; 128 imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; 129 imageFormatInfo.format = format; 130 imageFormatInfo.type = VK_IMAGE_TYPE_2D; 131 imageFormatInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; 132 imageFormatInfo.usage = usage; 133 imageFormatInfo.flags = 0; 134 imageFormatInfo.pNext = &externalImageFormatInfo; 135 136 VkExternalImageFormatProperties externalImageFormatProps; 137 externalImageFormatProps.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES; 138 externalImageFormatProps.pNext = nullptr; 139 140 VkImageFormatProperties2 imageFormatProps; 141 imageFormatProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; 142 imageFormatProps.pNext = &externalImageFormatProps; 143 144 VkResult result = VkResult::WrapUnsafe(mDevice->fn.GetPhysicalDeviceImageFormatProperties2( 145 physicalDevice, &imageFormatInfo, &imageFormatProps)); 146 if (result != VK_SUCCESS) { 147 return false; 148 } 149 VkExternalMemoryFeatureFlags featureFlags = 150 externalImageFormatProps.externalMemoryProperties.externalMemoryFeatures; 151 return featureFlags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; 152 } 153 GetMemoryImportParams(const ExternalImageDescriptor * descriptor,VkImage image)154 ResultOrError<MemoryImportParams> Service::GetMemoryImportParams( 155 const ExternalImageDescriptor* descriptor, 156 VkImage image) { 157 DAWN_INVALID_IF(descriptor->type != ExternalImageType::DmaBuf, 158 "ExternalImageDescriptor is not a ExternalImageDescriptorDmaBuf."); 159 160 const ExternalImageDescriptorDmaBuf* dmaBufDescriptor = 161 static_cast<const ExternalImageDescriptorDmaBuf*>(descriptor); 162 VkDevice device = mDevice->GetVkDevice(); 163 164 // Get the valid memory types for the VkImage. 165 VkMemoryRequirements memoryRequirements; 166 mDevice->fn.GetImageMemoryRequirements(device, image, &memoryRequirements); 167 168 VkMemoryFdPropertiesKHR fdProperties; 169 fdProperties.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR; 170 fdProperties.pNext = nullptr; 171 172 // Get the valid memory types that the external memory can be imported as. 173 mDevice->fn.GetMemoryFdPropertiesKHR(device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, 174 dmaBufDescriptor->memoryFD, &fdProperties); 175 // Choose the best memory type that satisfies both the image's constraint and the import's 176 // constraint. 177 memoryRequirements.memoryTypeBits &= fdProperties.memoryTypeBits; 178 int memoryTypeIndex = mDevice->GetResourceMemoryAllocator()->FindBestTypeIndex( 179 memoryRequirements, MemoryKind::Opaque); 180 DAWN_INVALID_IF(memoryTypeIndex == -1, 181 "Unable to find an appropriate memory type for import."); 182 183 MemoryImportParams params = {memoryRequirements.size, 184 static_cast<uint32_t>(memoryTypeIndex)}; 185 return params; 186 } 187 ImportMemory(ExternalMemoryHandle handle,const MemoryImportParams & importParams,VkImage image)188 ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle, 189 const MemoryImportParams& importParams, 190 VkImage image) { 191 DAWN_INVALID_IF(handle < 0, "Importing memory with an invalid handle."); 192 193 VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo; 194 memoryDedicatedAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO; 195 memoryDedicatedAllocateInfo.pNext = nullptr; 196 memoryDedicatedAllocateInfo.image = image; 197 memoryDedicatedAllocateInfo.buffer = VkBuffer{}; 198 199 VkImportMemoryFdInfoKHR importMemoryFdInfo; 200 importMemoryFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; 201 importMemoryFdInfo.pNext = &memoryDedicatedAllocateInfo; 202 importMemoryFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, 203 importMemoryFdInfo.fd = handle; 204 205 VkMemoryAllocateInfo memoryAllocateInfo; 206 memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 207 memoryAllocateInfo.pNext = &importMemoryFdInfo; 208 memoryAllocateInfo.allocationSize = importParams.allocationSize; 209 memoryAllocateInfo.memoryTypeIndex = importParams.memoryTypeIndex; 210 211 VkDeviceMemory allocatedMemory = VK_NULL_HANDLE; 212 DAWN_TRY( 213 CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &memoryAllocateInfo, 214 nullptr, &*allocatedMemory), 215 "vkAllocateMemory")); 216 return allocatedMemory; 217 } 218 CreateImage(const ExternalImageDescriptor * descriptor,const VkImageCreateInfo & baseCreateInfo)219 ResultOrError<VkImage> Service::CreateImage(const ExternalImageDescriptor* descriptor, 220 const VkImageCreateInfo& baseCreateInfo) { 221 DAWN_INVALID_IF(descriptor->type != ExternalImageType::DmaBuf, 222 "ExternalImageDescriptor is not a dma-buf descriptor."); 223 224 const ExternalImageDescriptorDmaBuf* dmaBufDescriptor = 225 static_cast<const ExternalImageDescriptorDmaBuf*>(descriptor); 226 VkPhysicalDevice physicalDevice = ToBackend(mDevice->GetAdapter())->GetPhysicalDevice(); 227 VkDevice device = mDevice->GetVkDevice(); 228 229 // Dawn currently doesn't support multi-plane formats, so we only need to create a single 230 // VkSubresourceLayout here. 231 VkSubresourceLayout planeLayout; 232 planeLayout.offset = 0; 233 planeLayout.size = 0; // VK_EXT_image_drm_format_modifier mandates size = 0. 234 planeLayout.rowPitch = dmaBufDescriptor->stride; 235 planeLayout.arrayPitch = 0; // Not an array texture 236 planeLayout.depthPitch = 0; // Not a depth texture 237 238 uint32_t planeCount; 239 DAWN_TRY_ASSIGN(planeCount, 240 GetModifierPlaneCount(mDevice->fn, physicalDevice, baseCreateInfo.format, 241 dmaBufDescriptor->drmModifier)); 242 ASSERT(planeCount == 1); 243 244 VkImageDrmFormatModifierExplicitCreateInfoEXT explicitCreateInfo; 245 explicitCreateInfo.sType = 246 VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT; 247 explicitCreateInfo.pNext = NULL; 248 explicitCreateInfo.drmFormatModifier = dmaBufDescriptor->drmModifier; 249 explicitCreateInfo.drmFormatModifierPlaneCount = planeCount; 250 explicitCreateInfo.pPlaneLayouts = &planeLayout; 251 252 VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo; 253 externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; 254 externalMemoryImageCreateInfo.pNext = &explicitCreateInfo; 255 externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; 256 257 VkImageCreateInfo createInfo = baseCreateInfo; 258 createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 259 createInfo.pNext = &externalMemoryImageCreateInfo; 260 createInfo.flags = 0; 261 createInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; 262 263 // Create a new VkImage with tiling equal to the DRM format modifier. 264 VkImage image; 265 DAWN_TRY(CheckVkSuccess(mDevice->fn.CreateImage(device, &createInfo, nullptr, &*image), 266 "CreateImage")); 267 return image; 268 } 269 270 }}} // namespace dawn_native::vulkan::external_memory 271