From ae687f5b8303c3fc5069ed8568cc4c6eac60ac82 Mon Sep 17 00:00:00 2001 From: Brian Ho Date: Wed, 20 Nov 2019 23:53:43 +0000 Subject: [PATCH] Add CreateImage support to MemoryService This CL introduces SupportsCreateImage and CreateImage to the external memory service API to provide different implementations for creating VkImages for different types of external image handles. While opaque FD and Zircon seem to share the same vkCreateImage implementation, dma-buf import will require the use of the VkImageDrmFormatModifierExplicitCreateInfoEXT [1] struct (among other differences) with vkCreateImage. [1] https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImageDrmFormatModifierExplicitCreateInfoEXT.html BUG=chromium:996470 Change-Id: I3eb11f8877d4465f5fcdd4089d5fdd8acbc1da10 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/13781 Reviewed-by: Austin Eng Commit-Queue: Brian Ho --- src/dawn_native/vulkan/DeviceVk.cpp | 5 +- src/dawn_native/vulkan/TextureVk.cpp | 85 +++++++++---------- src/dawn_native/vulkan/TextureVk.h | 10 ++- .../vulkan/external_memory/MemoryService.h | 19 +++-- .../external_memory/MemoryServiceNull.cpp | 19 +++-- .../external_memory/MemoryServiceOpaqueFD.cpp | 31 +++++-- .../MemoryServiceZirconHandle.cpp | 31 +++++-- 7 files changed, 131 insertions(+), 69 deletions(-) diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp index ed85121e5a..f317588d1f 100644 --- a/src/dawn_native/vulkan/DeviceVk.cpp +++ b/src/dawn_native/vulkan/DeviceVk.cpp @@ -615,7 +615,7 @@ namespace dawn_native { namespace vulkan { if (!mExternalSemaphoreService->Supported()) { return DAWN_VALIDATION_ERROR("External semaphore usage not supported"); } - if (!mExternalMemoryService->Supported( + if (!mExternalMemoryService->SupportsImportMemory( VulkanImageFormat(textureDescriptor->format), VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VulkanImageUsage(textureDescriptor->usage, @@ -683,7 +683,8 @@ namespace dawn_native { namespace vulkan { // if a failure happems. Texture* result = nullptr; // TODO(crbug.com/1026480): Consolidate this into a single CreateFromExternal call. - if (ConsumedError(Texture::CreateFromExternal(this, descriptor, textureDescriptor), + if (ConsumedError(Texture::CreateFromExternal(this, descriptor, textureDescriptor, + mExternalMemoryService.get()), &result) || ConsumedError(ImportExternalImage(descriptor, memoryHandle, result->GetHandle(), waitHandles, &signalSemaphore, &allocation, diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp index 211719db38..86104bbaf7 100644 --- a/src/dawn_native/vulkan/TextureVk.cpp +++ b/src/dawn_native/vulkan/TextureVk.cpp @@ -200,22 +200,6 @@ namespace dawn_native { namespace vulkan { return {extent.width, extent.height, extent.depth}; } - bool IsSampleCountSupported(const dawn_native::vulkan::Device* device, - const VkImageCreateInfo& imageCreateInfo) { - ASSERT(device); - - VkPhysicalDevice physicalDevice = ToBackend(device->GetAdapter())->GetPhysicalDevice(); - VkImageFormatProperties properties; - if (device->fn.GetPhysicalDeviceImageFormatProperties( - physicalDevice, imageCreateInfo.format, imageCreateInfo.imageType, - imageCreateInfo.tiling, imageCreateInfo.usage, imageCreateInfo.flags, - &properties) != VK_SUCCESS) { - UNREACHABLE(); - } - - return properties.sampleCounts & imageCreateInfo.samples; - } - } // namespace // Converts Dawn texture format to Vulkan formats. @@ -397,6 +381,22 @@ namespace dawn_native { namespace vulkan { return {}; } + bool IsSampleCountSupported(const dawn_native::vulkan::Device* device, + const VkImageCreateInfo& imageCreateInfo) { + ASSERT(device); + + VkPhysicalDevice physicalDevice = ToBackend(device->GetAdapter())->GetPhysicalDevice(); + VkImageFormatProperties properties; + if (device->fn.GetPhysicalDeviceImageFormatProperties( + physicalDevice, imageCreateInfo.format, imageCreateInfo.imageType, + imageCreateInfo.tiling, imageCreateInfo.usage, imageCreateInfo.flags, + &properties) != VK_SUCCESS) { + UNREACHABLE(); + } + + return properties.sampleCounts & imageCreateInfo.samples; + } + // static ResultOrError Texture::Create(Device* device, const TextureDescriptor* descriptor) { std::unique_ptr texture = @@ -409,10 +409,11 @@ namespace dawn_native { namespace vulkan { ResultOrError Texture::CreateFromExternal( Device* device, const ExternalImageDescriptor* descriptor, - const TextureDescriptor* textureDescriptor) { + const TextureDescriptor* textureDescriptor, + external_memory::Service* externalMemoryService) { std::unique_ptr texture = std::make_unique(device, textureDescriptor, TextureState::OwnedInternal); - DAWN_TRY(texture->InitializeFromExternal(descriptor)); + DAWN_TRY(texture->InitializeFromExternal(descriptor, externalMemoryService)); return texture.release(); } @@ -481,38 +482,34 @@ namespace dawn_native { namespace vulkan { } // Internally managed, but imported from external handle - MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptor* descriptor) { + MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptor* descriptor, + external_memory::Service* externalMemoryService) { + VkFormat format = VulkanImageFormat(GetFormat().format); + if (!externalMemoryService->SupportsCreateImage(descriptor, format)) { + return DAWN_VALIDATION_ERROR("Creating an image from external memory is not supported"); + } + mExternalState = ExternalState::PendingAcquire; - Device* device = ToBackend(GetDevice()); - - VkImageCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - createInfo.pNext = nullptr; - createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR; - createInfo.imageType = VulkanImageType(GetDimension()); - createInfo.format = VulkanImageFormat(GetFormat().format); - createInfo.extent = VulkanExtent3D(GetSize()); - createInfo.mipLevels = GetNumMipLevels(); - createInfo.arrayLayers = GetArrayLayers(); - createInfo.samples = VulkanSampleCount(GetSampleCount()); - createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - createInfo.usage = VulkanImageUsage(GetUsage(), GetFormat()); - createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - createInfo.queueFamilyIndexCount = 0; - createInfo.pQueueFamilyIndices = nullptr; - createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - ASSERT(IsSampleCountSupported(device, createInfo)); + VkImageCreateInfo baseCreateInfo = {}; + baseCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + baseCreateInfo.pNext = nullptr; + baseCreateInfo.imageType = VulkanImageType(GetDimension()); + baseCreateInfo.format = format; + baseCreateInfo.extent = VulkanExtent3D(GetSize()); + baseCreateInfo.mipLevels = GetNumMipLevels(); + baseCreateInfo.arrayLayers = GetArrayLayers(); + baseCreateInfo.samples = VulkanSampleCount(GetSampleCount()); + baseCreateInfo.usage = VulkanImageUsage(GetUsage(), GetFormat()); + baseCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + baseCreateInfo.queueFamilyIndexCount = 0; + baseCreateInfo.pQueueFamilyIndices = nullptr; // We always set VK_IMAGE_USAGE_TRANSFER_DST_BIT unconditionally beause the Vulkan images // that are used in vkCmdClearColorImage() must have been created with this flag, which is // also required for the implementation of robust resource initialization. - createInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; - - DAWN_TRY(CheckVkSuccess( - device->fn.CreateImage(device->GetVkDevice(), &createInfo, nullptr, &mHandle), - "CreateImage")); + baseCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + DAWN_TRY_ASSIGN(mHandle, externalMemoryService->CreateImage(descriptor, baseCreateInfo)); return {}; } diff --git a/src/dawn_native/vulkan/TextureVk.h b/src/dawn_native/vulkan/TextureVk.h index 5174292ce2..82366ae0ef 100644 --- a/src/dawn_native/vulkan/TextureVk.h +++ b/src/dawn_native/vulkan/TextureVk.h @@ -20,6 +20,7 @@ #include "common/vulkan_platform.h" #include "dawn_native/ResourceMemoryAllocation.h" #include "dawn_native/vulkan/ExternalHandle.h" +#include "dawn_native/vulkan/external_memory/MemoryService.h" namespace dawn_native { namespace vulkan { @@ -34,6 +35,9 @@ namespace dawn_native { namespace vulkan { MaybeError ValidateVulkanImageCanBeWrapped(const DeviceBase* device, const TextureDescriptor* descriptor); + bool IsSampleCountSupported(const dawn_native::vulkan::Device* device, + const VkImageCreateInfo& imageCreateInfo); + class Texture : public TextureBase { public: // Used to create a regular texture from a descriptor. @@ -45,7 +49,8 @@ namespace dawn_native { namespace vulkan { static ResultOrError CreateFromExternal( Device* device, const ExternalImageDescriptor* descriptor, - const TextureDescriptor* textureDescriptor); + const TextureDescriptor* textureDescriptor, + external_memory::Service* externalMemoryService); Texture(Device* device, const TextureDescriptor* descriptor, VkImage nativeImage); ~Texture(); @@ -76,7 +81,8 @@ namespace dawn_native { namespace vulkan { using TextureBase::TextureBase; MaybeError InitializeAsInternalTexture(); - MaybeError InitializeFromExternal(const ExternalImageDescriptor* descriptor); + MaybeError InitializeFromExternal(const ExternalImageDescriptor* descriptor, + external_memory::Service* externalMemoryService); void DestroyImpl() override; MaybeError ClearTexture(CommandRecordingContext* recordingContext, diff --git a/src/dawn_native/vulkan/external_memory/MemoryService.h b/src/dawn_native/vulkan/external_memory/MemoryService.h index bcd3ea4f4b..1d0d475eca 100644 --- a/src/dawn_native/vulkan/external_memory/MemoryService.h +++ b/src/dawn_native/vulkan/external_memory/MemoryService.h @@ -36,12 +36,15 @@ namespace dawn_native { namespace vulkan { namespace external_memory { explicit Service(Device* device); ~Service(); - // True if the device reports it supports this feature - bool Supported(VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags flags); + // True if the device reports it supports importing external memory. + bool SupportsImportMemory(VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags); + + // True if the device reports it supports creating VkImages from external memory. + bool SupportsCreateImage(const ExternalImageDescriptor* descriptor, VkFormat format); // Returns the parameters required for importing memory ResultOrError GetMemoryImportParams( @@ -53,6 +56,10 @@ namespace dawn_native { namespace vulkan { namespace external_memory { const MemoryImportParams& importParams, VkImage image); + // Create a VkImage for the given handle type + ResultOrError CreateImage(const ExternalImageDescriptor* descriptor, + const VkImageCreateInfo& baseCreateInfo); + private: Device* mDevice = nullptr; diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceNull.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceNull.cpp index c7417d7958..78144d6e0e 100644 --- a/src/dawn_native/vulkan/external_memory/MemoryServiceNull.cpp +++ b/src/dawn_native/vulkan/external_memory/MemoryServiceNull.cpp @@ -24,11 +24,15 @@ namespace dawn_native { namespace vulkan { namespace external_memory { Service::~Service() = default; - bool Service::Supported(VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags flags) { + bool Service::SupportsImportMemory(VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags flags) { + return false; + } + + bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor, VkFormat format) { return false; } @@ -44,4 +48,9 @@ namespace dawn_native { namespace vulkan { namespace external_memory { return DAWN_UNIMPLEMENTED_ERROR("Using null memory service to interop inside Vulkan"); } + ResultOrError Service::CreateImage(const ExternalImageDescriptor* descriptor, + const VkImageCreateInfo& baseCreateInfo) { + return DAWN_UNIMPLEMENTED_ERROR("Using null memory service to interop inside Vulkan"); + } + }}} // namespace dawn_native::vulkan::external_memory diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp index 64cd3a5bba..00cb4464a3 100644 --- a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp +++ b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp @@ -16,6 +16,7 @@ #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" @@ -33,11 +34,11 @@ namespace dawn_native { namespace vulkan { namespace external_memory { Service::~Service() = default; - bool Service::Supported(VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags flags) { + 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; @@ -80,6 +81,10 @@ 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) { + return mSupported; + } + ResultOrError Service::GetMemoryImportParams( const ExternalImageDescriptor* descriptor, VkImage image) { @@ -113,4 +118,20 @@ namespace dawn_native { namespace vulkan { namespace external_memory { return allocatedMemory; } + ResultOrError 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 diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp index d461d44cd4..0a72205375 100644 --- a/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp +++ b/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp @@ -16,6 +16,7 @@ #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" @@ -33,11 +34,11 @@ namespace dawn_native { namespace vulkan { namespace external_memory { Service::~Service() = default; - bool Service::Supported(VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags flags) { + 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; @@ -80,6 +81,10 @@ 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) { + return mSupported; + } + ResultOrError Service::GetMemoryImportParams( const ExternalImageDescriptor* descriptor, VkImage image) { @@ -115,4 +120,20 @@ namespace dawn_native { namespace vulkan { namespace external_memory { return allocatedMemory; } + ResultOrError 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