• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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