blob: d545890be5c704da52c636e9c5aef2c6e8fd828d [file] [log] [blame]
// 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/ResourceMemoryAllocatorVk.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.GetPhysicalDeviceFormatProperties2(physicalDevice, format, &formatProps);
uint32_t modifierCount = formatModifierPropsList.drmFormatModifierCount;
std::vector<VkDrmFormatModifierPropertiesEXT> formatModifierProps(modifierCount);
formatModifierPropsList.pDrmFormatModifierProperties = formatModifierProps.data();
fn.GetPhysicalDeviceFormatProperties2(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();
mSupported = deviceInfo.HasExt(DeviceExt::ExternalMemoryFD) &&
deviceInfo.HasExt(DeviceExt::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 != ExternalImageType::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 = VkResult::WrapUnsafe(mDevice->fn.GetPhysicalDeviceImageFormatProperties2(
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 != ExternalImageType::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->GetResourceMemoryAllocator()->FindBestTypeIndex(
memoryRequirements, MemoryKind::Opaque);
if (memoryTypeIndex == -1) {
return DAWN_VALIDATION_ERROR("Unable to find appropriate memory type for import");
}
MemoryImportParams params = {memoryRequirements.size,
static_cast<uint32_t>(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 = VkBuffer{};
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 != ExternalImageType::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