Implement a dma-buf MemoryService
This CL implements the MemoryService for importing memory and
creating VkImages from a dma-buf handle. Under the hood, it uses the
VK_EXT_external_memory_dma_buf and
VK_EXT_image_drm_format_modifier extensions to find a memory type
that supports dma-buf import. In addition, the extensions are also
used to properly specify the stride and tiling of the dma-buf to
vkAllocateMemory and vkCreateImage.
BUG=chromium:996470
Change-Id: Ie72d73117a4cbafcb40468aab0952b783351d499
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/13785
Commit-Queue: Brian Ho <hob@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 6079642..0fd9cf4 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -478,7 +478,12 @@
"src/dawn_native/vulkan/external_semaphore/SemaphoreService.h",
]
- if (is_linux) {
+ if (is_chromeos) {
+ sources += [
+ "src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp",
+ "src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp",
+ ]
+ } else if (is_linux) {
sources += [
"src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp",
"src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp",
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index f317588..b9f326a 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -722,6 +722,10 @@
mResourceMemoryAllocator->Deallocate(allocation);
}
+ int Device::FindBestMemoryTypeIndex(VkMemoryRequirements requirements, bool mappable) {
+ return mResourceMemoryAllocator->FindBestTypeIndex(requirements, mappable);
+ }
+
ResourceMemoryAllocator* Device::GetResourceMemoryAllocatorForTesting() const {
return mResourceMemoryAllocator.get();
}
diff --git a/src/dawn_native/vulkan/DeviceVk.h b/src/dawn_native/vulkan/DeviceVk.h
index 74ae79d..e5210d6 100644
--- a/src/dawn_native/vulkan/DeviceVk.h
+++ b/src/dawn_native/vulkan/DeviceVk.h
@@ -95,6 +95,8 @@
bool mappable);
void DeallocateMemory(ResourceMemoryAllocation* allocation);
+ int FindBestMemoryTypeIndex(VkMemoryRequirements requirements, bool mappable);
+
ResourceMemoryAllocator* GetResourceMemoryAllocatorForTesting() const;
private:
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index 3422ab0..5d11976 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -485,7 +485,8 @@
MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptor* descriptor,
external_memory::Service* externalMemoryService) {
VkFormat format = VulkanImageFormat(GetFormat().format);
- if (!externalMemoryService->SupportsCreateImage(descriptor, format)) {
+ VkImageUsageFlags usage = VulkanImageUsage(GetUsage(), GetFormat());
+ if (!externalMemoryService->SupportsCreateImage(descriptor, format, usage)) {
return DAWN_VALIDATION_ERROR("Creating an image from external memory is not supported");
}
@@ -499,7 +500,7 @@
baseCreateInfo.mipLevels = GetNumMipLevels();
baseCreateInfo.arrayLayers = GetArrayLayers();
baseCreateInfo.samples = VulkanSampleCount(GetSampleCount());
- baseCreateInfo.usage = VulkanImageUsage(GetUsage(), GetFormat());
+ baseCreateInfo.usage = usage;
baseCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
baseCreateInfo.queueFamilyIndexCount = 0;
baseCreateInfo.pQueueFamilyIndices = nullptr;
diff --git a/src/dawn_native/vulkan/external_memory/MemoryService.h b/src/dawn_native/vulkan/external_memory/MemoryService.h
index 1d0d475..0c4b64d 100644
--- a/src/dawn_native/vulkan/external_memory/MemoryService.h
+++ b/src/dawn_native/vulkan/external_memory/MemoryService.h
@@ -44,7 +44,9 @@
VkImageCreateFlags flags);
// True if the device reports it supports creating VkImages from external memory.
- bool SupportsCreateImage(const ExternalImageDescriptor* descriptor, VkFormat format);
+ bool SupportsCreateImage(const ExternalImageDescriptor* descriptor,
+ VkFormat format,
+ VkImageUsageFlags usage);
// Returns the parameters required for importing memory
ResultOrError<MemoryImportParams> GetMemoryImportParams(
diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp
new file mode 100644
index 0000000..e9944f8
--- /dev/null
+++ b/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp
@@ -0,0 +1,271 @@
+// Copyright 2019 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "common/Assert.h"
+#include "dawn_native/vulkan/AdapterVk.h"
+#include "dawn_native/vulkan/BackendVk.h"
+#include "dawn_native/vulkan/DeviceVk.h"
+#include "dawn_native/vulkan/VulkanError.h"
+#include "dawn_native/vulkan/external_memory/MemoryService.h"
+
+namespace dawn_native { namespace vulkan { namespace external_memory {
+
+ namespace {
+
+ // Some modifiers use multiple planes (for example, see the comment for
+ // I915_FORMAT_MOD_Y_TILED_CCS in drm/drm_fourcc.h), but dma-buf import in Dawn only
+ // supports single-plane formats.
+ ResultOrError<uint32_t> GetModifierPlaneCount(const VulkanFunctions& fn,
+ VkPhysicalDevice physicalDevice,
+ VkFormat format,
+ uint64_t modifier) {
+ VkDrmFormatModifierPropertiesListEXT formatModifierPropsList;
+ formatModifierPropsList.sType =
+ VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
+ formatModifierPropsList.pNext = nullptr;
+ formatModifierPropsList.drmFormatModifierCount = 0;
+ formatModifierPropsList.pDrmFormatModifierProperties = nullptr;
+
+ VkFormatProperties2 formatProps;
+ formatProps.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
+ formatProps.pNext = &formatModifierPropsList;
+
+ fn.GetPhysicalDeviceFormatProperties2KHR(physicalDevice, format, &formatProps);
+
+ uint32_t modifierCount = formatModifierPropsList.drmFormatModifierCount;
+ std::vector<VkDrmFormatModifierPropertiesEXT> formatModifierProps(modifierCount);
+ formatModifierPropsList.pDrmFormatModifierProperties = formatModifierProps.data();
+
+ fn.GetPhysicalDeviceFormatProperties2KHR(physicalDevice, format, &formatProps);
+ for (const auto& props : formatModifierProps) {
+ if (props.drmFormatModifier == modifier) {
+ uint32_t count = props.drmFormatModifierPlaneCount;
+ return count;
+ }
+ }
+ return DAWN_VALIDATION_ERROR("DRM format modifier not supported");
+ }
+
+ } // anonymous namespace
+
+ Service::Service(Device* device) : mDevice(device) {
+ const VulkanDeviceInfo& deviceInfo = mDevice->GetDeviceInfo();
+ const VulkanGlobalInfo& globalInfo =
+ ToBackend(mDevice->GetAdapter())->GetBackend()->GetGlobalInfo();
+
+ mSupported = globalInfo.getPhysicalDeviceProperties2 &&
+ globalInfo.externalMemoryCapabilities && deviceInfo.externalMemory &&
+ deviceInfo.externalMemoryFD && deviceInfo.externalMemoryDmaBuf &&
+ deviceInfo.imageDrmFormatModifier;
+ }
+
+ Service::~Service() = default;
+
+ bool Service::SupportsImportMemory(VkFormat format,
+ VkImageType type,
+ VkImageTiling tiling,
+ VkImageUsageFlags usage,
+ VkImageCreateFlags flags) {
+ return mSupported;
+ }
+
+ bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor,
+ VkFormat format,
+ VkImageUsageFlags usage) {
+ // Early out before we try using extension functions
+ if (!mSupported) {
+ return false;
+ }
+ if (descriptor->type != ExternalImageDescriptorType::DmaBuf) {
+ return false;
+ }
+ const ExternalImageDescriptorDmaBuf* dmaBufDescriptor =
+ static_cast<const ExternalImageDescriptorDmaBuf*>(descriptor);
+
+ // Verify plane count for the modifier.
+ VkPhysicalDevice physicalDevice = ToBackend(mDevice->GetAdapter())->GetPhysicalDevice();
+ uint32_t planeCount = 0;
+ if (mDevice->ConsumedError(GetModifierPlaneCount(mDevice->fn, physicalDevice, format,
+ dmaBufDescriptor->drmModifier),
+ &planeCount)) {
+ return false;
+ }
+ if (planeCount == 0) {
+ return false;
+ }
+ // TODO(hob): Support multi-plane formats like I915_FORMAT_MOD_Y_TILED_CCS.
+ if (planeCount > 1) {
+ return false;
+ }
+
+ // Verify that the format modifier of the external memory and the requested Vulkan format
+ // are actually supported together in a dma-buf import.
+ VkPhysicalDeviceImageDrmFormatModifierInfoEXT drmModifierInfo;
+ drmModifierInfo.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT;
+ drmModifierInfo.pNext = nullptr;
+ drmModifierInfo.drmFormatModifier = dmaBufDescriptor->drmModifier;
+ drmModifierInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+ VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
+ externalImageFormatInfo.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
+ externalImageFormatInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
+ externalImageFormatInfo.pNext = &drmModifierInfo;
+
+ VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
+ imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
+ imageFormatInfo.format = format;
+ imageFormatInfo.type = VK_IMAGE_TYPE_2D;
+ imageFormatInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
+ imageFormatInfo.usage = usage;
+ imageFormatInfo.flags = 0;
+ imageFormatInfo.pNext = &externalImageFormatInfo;
+
+ VkExternalImageFormatProperties externalImageFormatProps;
+ externalImageFormatProps.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
+ externalImageFormatProps.pNext = nullptr;
+
+ VkImageFormatProperties2 imageFormatProps;
+ imageFormatProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
+ imageFormatProps.pNext = &externalImageFormatProps;
+
+ VkResult result = mDevice->fn.GetPhysicalDeviceImageFormatProperties2KHR(
+ physicalDevice, &imageFormatInfo, &imageFormatProps);
+ if (result != VK_SUCCESS) {
+ return false;
+ }
+ VkExternalMemoryFeatureFlags featureFlags =
+ externalImageFormatProps.externalMemoryProperties.externalMemoryFeatures;
+ return featureFlags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
+ }
+
+ ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
+ const ExternalImageDescriptor* descriptor,
+ VkImage image) {
+ if (descriptor->type != ExternalImageDescriptorType::DmaBuf) {
+ return DAWN_VALIDATION_ERROR("ExternalImageDescriptor is not a dma-buf descriptor");
+ }
+ const ExternalImageDescriptorDmaBuf* dmaBufDescriptor =
+ static_cast<const ExternalImageDescriptorDmaBuf*>(descriptor);
+ VkDevice device = mDevice->GetVkDevice();
+
+ // Get the valid memory types for the VkImage.
+ VkMemoryRequirements memoryRequirements;
+ mDevice->fn.GetImageMemoryRequirements(device, image, &memoryRequirements);
+
+ VkMemoryFdPropertiesKHR fdProperties;
+ fdProperties.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR;
+ fdProperties.pNext = nullptr;
+
+ // Get the valid memory types that the external memory can be imported as.
+ mDevice->fn.GetMemoryFdPropertiesKHR(device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
+ dmaBufDescriptor->memoryFD, &fdProperties);
+ // Choose the best memory type that satisfies both the image's constraint and the import's
+ // constraint.
+ memoryRequirements.memoryTypeBits &= fdProperties.memoryTypeBits;
+ int memoryTypeIndex =
+ mDevice->FindBestMemoryTypeIndex(memoryRequirements, false /** mappable */);
+ if (memoryTypeIndex == -1) {
+ return DAWN_VALIDATION_ERROR("Unable to find appropriate memory type for import");
+ }
+ MemoryImportParams params = {memoryRequirements.size, memoryTypeIndex};
+ return params;
+ }
+
+ ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle,
+ const MemoryImportParams& importParams,
+ VkImage image) {
+ if (handle < 0) {
+ return DAWN_VALIDATION_ERROR("Trying to import memory with invalid handle");
+ }
+
+ VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo;
+ memoryDedicatedAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
+ memoryDedicatedAllocateInfo.pNext = nullptr;
+ memoryDedicatedAllocateInfo.image = image;
+ memoryDedicatedAllocateInfo.buffer = VK_NULL_HANDLE;
+
+ VkImportMemoryFdInfoKHR importMemoryFdInfo;
+ importMemoryFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
+ importMemoryFdInfo.pNext = &memoryDedicatedAllocateInfo;
+ importMemoryFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
+ importMemoryFdInfo.fd = handle;
+
+ VkMemoryAllocateInfo memoryAllocateInfo;
+ memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ memoryAllocateInfo.pNext = &importMemoryFdInfo;
+ memoryAllocateInfo.allocationSize = importParams.allocationSize;
+ memoryAllocateInfo.memoryTypeIndex = importParams.memoryTypeIndex;
+
+ VkDeviceMemory allocatedMemory = VK_NULL_HANDLE;
+ DAWN_TRY(
+ CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &memoryAllocateInfo,
+ nullptr, &allocatedMemory),
+ "vkAllocateMemory"));
+ return allocatedMemory;
+ }
+
+ ResultOrError<VkImage> Service::CreateImage(const ExternalImageDescriptor* descriptor,
+ const VkImageCreateInfo& baseCreateInfo) {
+ if (descriptor->type != ExternalImageDescriptorType::DmaBuf) {
+ return DAWN_VALIDATION_ERROR("ExternalImageDescriptor is not a dma-buf descriptor");
+ }
+ const ExternalImageDescriptorDmaBuf* dmaBufDescriptor =
+ static_cast<const ExternalImageDescriptorDmaBuf*>(descriptor);
+ VkPhysicalDevice physicalDevice = ToBackend(mDevice->GetAdapter())->GetPhysicalDevice();
+ VkDevice device = mDevice->GetVkDevice();
+
+ // Dawn currently doesn't support multi-plane formats, so we only need to create a single
+ // VkSubresourceLayout here.
+ VkSubresourceLayout planeLayout;
+ planeLayout.offset = 0;
+ planeLayout.size = 0; // VK_EXT_image_drm_format_modifier mandates size = 0.
+ planeLayout.rowPitch = dmaBufDescriptor->stride;
+ planeLayout.arrayPitch = 0; // Not an array texture
+ planeLayout.depthPitch = 0; // Not a depth texture
+
+ uint32_t planeCount;
+ DAWN_TRY_ASSIGN(planeCount,
+ GetModifierPlaneCount(mDevice->fn, physicalDevice, baseCreateInfo.format,
+ dmaBufDescriptor->drmModifier));
+ ASSERT(planeCount == 1);
+
+ VkImageDrmFormatModifierExplicitCreateInfoEXT explicitCreateInfo;
+ explicitCreateInfo.sType =
+ VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
+ explicitCreateInfo.pNext = NULL;
+ explicitCreateInfo.drmFormatModifier = dmaBufDescriptor->drmModifier;
+ explicitCreateInfo.drmFormatModifierPlaneCount = planeCount;
+ explicitCreateInfo.pPlaneLayouts = &planeLayout;
+
+ VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo;
+ externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
+ externalMemoryImageCreateInfo.pNext = &explicitCreateInfo;
+ externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
+
+ VkImageCreateInfo createInfo = baseCreateInfo;
+ createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ createInfo.pNext = &externalMemoryImageCreateInfo;
+ createInfo.flags = 0;
+ createInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
+
+ // Create a new VkImage with tiling equal to the DRM format modifier.
+ VkImage image;
+ DAWN_TRY(CheckVkSuccess(mDevice->fn.CreateImage(device, &createInfo, nullptr, &image),
+ "CreateImage"));
+ return image;
+ }
+
+}}} // namespace dawn_native::vulkan::external_memory
diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceNull.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceNull.cpp
index 78144d6..14d882a 100644
--- a/src/dawn_native/vulkan/external_memory/MemoryServiceNull.cpp
+++ b/src/dawn_native/vulkan/external_memory/MemoryServiceNull.cpp
@@ -32,7 +32,9 @@
return false;
}
- bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor, VkFormat format) {
+ bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor,
+ VkFormat format,
+ VkImageUsageFlags usage) {
return false;
}
diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp
index 5e6bf7c..2a31b31 100644
--- a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp
+++ b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp
@@ -81,7 +81,9 @@
!(memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR);
}
- bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor, VkFormat format) {
+ bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor,
+ VkFormat format,
+ VkImageUsageFlags usage) {
return mSupported;
}
diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp
index bfbd5cc..8c70c67 100644
--- a/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp
+++ b/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp
@@ -81,7 +81,9 @@
!(memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR);
}
- bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor, VkFormat format) {
+ bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor,
+ VkFormat format,
+ VkImageUsageFlags usage) {
return mSupported;
}