| // 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/TextureVk.h" | |
| #include "dawn_native/vulkan/VulkanError.h" | |
| #include "dawn_native/vulkan/external_memory/MemoryService.h" | |
| namespace dawn_native { namespace vulkan { namespace external_memory { | |
| Service::Service(Device* device) : mDevice(device) { | |
| mSupported = device->GetDeviceInfo().HasExt(DeviceExt::ExternalMemoryFD); | |
| } | |
| Service::~Service() = default; | |
| bool Service::SupportsImportMemory(VkFormat format, | |
| VkImageType type, | |
| VkImageTiling tiling, | |
| VkImageUsageFlags usage, | |
| VkImageCreateFlags flags) { | |
| // Early out before we try using extension functions | |
| if (!mSupported) { | |
| return false; | |
| } | |
| VkPhysicalDeviceExternalImageFormatInfo externalFormatInfo; | |
| externalFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR; | |
| externalFormatInfo.pNext = nullptr; | |
| externalFormatInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; | |
| VkPhysicalDeviceImageFormatInfo2 formatInfo; | |
| formatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR; | |
| formatInfo.pNext = &externalFormatInfo; | |
| formatInfo.format = format; | |
| formatInfo.type = type; | |
| formatInfo.tiling = tiling; | |
| formatInfo.usage = usage; | |
| formatInfo.flags = flags; | |
| VkExternalImageFormatProperties externalFormatProperties; | |
| externalFormatProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR; | |
| externalFormatProperties.pNext = nullptr; | |
| VkImageFormatProperties2 formatProperties; | |
| formatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR; | |
| formatProperties.pNext = &externalFormatProperties; | |
| VkResult result = VkResult::WrapUnsafe(mDevice->fn.GetPhysicalDeviceImageFormatProperties2( | |
| ToBackend(mDevice->GetAdapter())->GetPhysicalDevice(), &formatInfo, &formatProperties)); | |
| // If handle not supported, result == VK_ERROR_FORMAT_NOT_SUPPORTED | |
| if (result != VK_SUCCESS) { | |
| return false; | |
| } | |
| // TODO(http://crbug.com/dawn/206): Investigate dedicated only images | |
| VkFlags memoryFlags = | |
| externalFormatProperties.externalMemoryProperties.externalMemoryFeatures; | |
| return (memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR) && | |
| !(memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR); | |
| } | |
| bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor, | |
| VkFormat format, | |
| VkImageUsageFlags usage) { | |
| return mSupported; | |
| } | |
| ResultOrError<MemoryImportParams> Service::GetMemoryImportParams( | |
| const ExternalImageDescriptor* descriptor, | |
| VkImage image) { | |
| if (descriptor->type != ExternalImageDescriptorType::OpaqueFD) { | |
| return DAWN_VALIDATION_ERROR("ExternalImageDescriptor is not an OpaqueFD descriptor"); | |
| } | |
| const ExternalImageDescriptorOpaqueFD* opaqueFDDescriptor = | |
| static_cast<const ExternalImageDescriptorOpaqueFD*>(descriptor); | |
| MemoryImportParams params = {opaqueFDDescriptor->allocationSize, | |
| opaqueFDDescriptor->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"); | |
| } | |
| VkMemoryRequirements requirements; | |
| mDevice->fn.GetImageMemoryRequirements(mDevice->GetVkDevice(), image, &requirements); | |
| if (requirements.size > importParams.allocationSize) { | |
| return DAWN_VALIDATION_ERROR("Requested allocation size is too small for image"); | |
| } | |
| VkImportMemoryFdInfoKHR importMemoryFdInfo; | |
| importMemoryFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; | |
| importMemoryFdInfo.pNext = nullptr; | |
| importMemoryFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; | |
| importMemoryFdInfo.fd = handle; | |
| VkMemoryAllocateInfo allocateInfo; | |
| allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | |
| allocateInfo.pNext = &importMemoryFdInfo; | |
| allocateInfo.allocationSize = importParams.allocationSize; | |
| allocateInfo.memoryTypeIndex = importParams.memoryTypeIndex; | |
| VkDeviceMemory allocatedMemory = VK_NULL_HANDLE; | |
| DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo, | |
| nullptr, &*allocatedMemory), | |
| "vkAllocateMemory")); | |
| return allocatedMemory; | |
| } | |
| ResultOrError<VkImage> Service::CreateImage(const ExternalImageDescriptor* descriptor, | |
| const VkImageCreateInfo& baseCreateInfo) { | |
| VkImageCreateInfo createInfo = baseCreateInfo; | |
| createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR; | |
| createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; | |
| createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | |
| ASSERT(IsSampleCountSupported(mDevice, createInfo)); | |
| VkImage image; | |
| DAWN_TRY(CheckVkSuccess( | |
| mDevice->fn.CreateImage(mDevice->GetVkDevice(), &createInfo, nullptr, &*image), | |
| "CreateImage")); | |
| return image; | |
| } | |
| }}} // namespace dawn_native::vulkan::external_memory |