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>
This commit is contained in:
parent
0d4a7b0ba5
commit
899c17090f
7
BUILD.gn
7
BUILD.gn
|
@ -478,7 +478,12 @@ source_set("libdawn_native_sources") {
|
|||
"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",
|
||||
|
|
|
@ -722,6 +722,10 @@ namespace dawn_native { namespace vulkan {
|
|||
mResourceMemoryAllocator->Deallocate(allocation);
|
||||
}
|
||||
|
||||
int Device::FindBestMemoryTypeIndex(VkMemoryRequirements requirements, bool mappable) {
|
||||
return mResourceMemoryAllocator->FindBestTypeIndex(requirements, mappable);
|
||||
}
|
||||
|
||||
ResourceMemoryAllocator* Device::GetResourceMemoryAllocatorForTesting() const {
|
||||
return mResourceMemoryAllocator.get();
|
||||
}
|
||||
|
|
|
@ -95,6 +95,8 @@ namespace dawn_native { namespace vulkan {
|
|||
bool mappable);
|
||||
void DeallocateMemory(ResourceMemoryAllocation* allocation);
|
||||
|
||||
int FindBestMemoryTypeIndex(VkMemoryRequirements requirements, bool mappable);
|
||||
|
||||
ResourceMemoryAllocator* GetResourceMemoryAllocatorForTesting() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -485,7 +485,8 @@ namespace dawn_native { namespace vulkan {
|
|||
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 @@ namespace dawn_native { namespace vulkan {
|
|||
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;
|
||||
|
|
|
@ -44,7 +44,9 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
|
|||
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(
|
||||
|
|
|
@ -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
|
|
@ -32,7 +32,9 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor, VkFormat format) {
|
||||
bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor,
|
||||
VkFormat format,
|
||||
VkImageUsageFlags usage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,9 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
|
|||
!(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,9 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
|
|||
!(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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue