From 98ba76af00d4e36430b86067e2283e97efff5f09 Mon Sep 17 00:00:00 2001 From: Brian Ho Date: Wed, 20 Nov 2019 23:57:03 +0000 Subject: [PATCH] Define an interface to import dma-bufs This CL adds an API to import a dma-buf into Dawn as a WGPUTexture. We also add a descriptor type enum to the base ExternalImageDescriptor struct. This is because all memory import code (e.g. MemoryService, Texture::CreateFromExternal) takes the a base ExternalImageDescriptor as a parameter. The dma-buf external memory and image services, however, will need to downcast to ExternalImageDescriptorDmaBuf to access import parameters like stride. Explicitly adding a type enum will let us more safely verify the type before downcasting. BUG=chromium:996470 Change-Id: I2d9883a15e9059a91f2c7bdb7a96d74373e18c56 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/13782 Reviewed-by: Austin Eng Commit-Queue: Brian Ho --- src/dawn_native/vulkan/TextureVk.cpp | 5 -- src/dawn_native/vulkan/VulkanBackend.cpp | 34 +++++++++++++ .../external_memory/MemoryServiceOpaqueFD.cpp | 15 +++++- .../MemoryServiceZirconHandle.cpp | 15 +++++- src/include/dawn_native/VulkanBackend.h | 50 +++++++++++++++++-- 5 files changed, 107 insertions(+), 12 deletions(-) diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp index 86104bbaf7..3422ab0e03 100644 --- a/src/dawn_native/vulkan/TextureVk.cpp +++ b/src/dawn_native/vulkan/TextureVk.cpp @@ -518,11 +518,6 @@ namespace dawn_native { namespace vulkan { VkDeviceMemory externalMemoryAllocation, std::vector waitSemaphores) { Device* device = ToBackend(GetDevice()); - VkMemoryRequirements requirements; - device->fn.GetImageMemoryRequirements(device->GetVkDevice(), mHandle, &requirements); - - ASSERT(requirements.size <= descriptor->allocationSize); - DAWN_TRY(CheckVkSuccess( device->fn.BindImageMemory(device->GetVkDevice(), mHandle, externalMemoryAllocation, 0), "BindImageMemory (external)")); diff --git a/src/dawn_native/vulkan/VulkanBackend.cpp b/src/dawn_native/vulkan/VulkanBackend.cpp index e13b965f27..02c3c3832d 100644 --- a/src/dawn_native/vulkan/VulkanBackend.cpp +++ b/src/dawn_native/vulkan/VulkanBackend.cpp @@ -60,6 +60,23 @@ namespace dawn_native { namespace vulkan { } #ifdef DAWN_PLATFORM_LINUX + ExternalImageDescriptor::ExternalImageDescriptor(ExternalImageDescriptorType type) + : type(type) { + } + + ExternalImageDescriptorFD::ExternalImageDescriptorFD(ExternalImageDescriptorType type) + : ExternalImageDescriptor(type) { + } + + ExternalImageDescriptorOpaqueFD::ExternalImageDescriptorOpaqueFD() + : ExternalImageDescriptorFD(ExternalImageDescriptorType::OpaqueFD) { + } + + ExternalImageDescriptorDmaBuf::ExternalImageDescriptorDmaBuf() + : ExternalImageDescriptorFD(ExternalImageDescriptorType::DmaBuf) { + } + + // TODO(hob): Remove this once we switch over to WrapVulkanImage in Chromium. WGPUTexture WrapVulkanImageOpaqueFD(WGPUDevice cDevice, const ExternalImageDescriptorOpaqueFD* descriptor) { Device* device = reinterpret_cast(cDevice); @@ -85,6 +102,23 @@ namespace dawn_native { namespace vulkan { return outHandle; } + + WGPUTexture WrapVulkanImage(WGPUDevice cDevice, const ExternalImageDescriptor* descriptor) { + Device* device = reinterpret_cast(cDevice); + + switch (descriptor->type) { + case ExternalImageDescriptorType::OpaqueFD: + case ExternalImageDescriptorType::DmaBuf: { + const ExternalImageDescriptorFD* fdDescriptor = + static_cast(descriptor); + TextureBase* texture = device->CreateTextureWrappingVulkanImage( + descriptor, fdDescriptor->memoryFD, fdDescriptor->waitFDs); + return reinterpret_cast(texture); + } + default: + return nullptr; + } + } #endif }} // namespace dawn_native::vulkan diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp index 00cb4464a3..5e6bf7cbad 100644 --- a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp +++ b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp @@ -88,7 +88,14 @@ namespace dawn_native { namespace vulkan { namespace external_memory { ResultOrError Service::GetMemoryImportParams( const ExternalImageDescriptor* descriptor, VkImage image) { - MemoryImportParams params = {descriptor->allocationSize, descriptor->memoryTypeIndex}; + if (descriptor->type != ExternalImageDescriptorType::OpaqueFD) { + return DAWN_VALIDATION_ERROR("ExternalImageDescriptor is not an OpaqueFD descriptor"); + } + const ExternalImageDescriptorOpaqueFD* opaqueFDDescriptor = + static_cast(descriptor); + + MemoryImportParams params = {opaqueFDDescriptor->allocationSize, + opaqueFDDescriptor->memoryTypeIndex}; return params; } @@ -99,6 +106,12 @@ namespace dawn_native { namespace vulkan { namespace external_memory { 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; diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp index 0a72205375..bfbd5ccb67 100644 --- a/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp +++ b/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp @@ -88,7 +88,14 @@ namespace dawn_native { namespace vulkan { namespace external_memory { ResultOrError Service::GetMemoryImportParams( const ExternalImageDescriptor* descriptor, VkImage image) { - MemoryImportParams params = {descriptor->allocationSize, descriptor->memoryTypeIndex}; + if (descriptor->type != ExternalImageDescriptorType::OpaqueFD) { + return DAWN_VALIDATION_ERROR("ExternalImageDescriptor is not an OpaqueFD descriptor"); + } + const ExternalImageDescriptorOpaqueFD* opaqueFDDescriptor = + static_cast(descriptor); + + MemoryImportParams params = {opaqueFDDescriptor->allocationSize, + opaqueFDDescriptor->memoryTypeIndex}; return params; } @@ -99,6 +106,12 @@ namespace dawn_native { namespace vulkan { namespace external_memory { 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"); + } + VkImportMemoryZirconHandleInfoFUCHSIA importMemoryHandleInfo; importMemoryHandleInfo.sType = VK_STRUCTURE_TYPE_TEMP_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA; diff --git a/src/include/dawn_native/VulkanBackend.h b/src/include/dawn_native/VulkanBackend.h index 77a4c4f05c..46dbdb9a0c 100644 --- a/src/include/dawn_native/VulkanBackend.h +++ b/src/include/dawn_native/VulkanBackend.h @@ -24,12 +24,23 @@ namespace dawn_native { namespace vulkan { + // The different types of ExternalImageDescriptors + enum ExternalImageDescriptorType { +#ifdef __linux__ + OpaqueFD, + DmaBuf, +#endif // __linux__ + }; + // Common properties of external images struct ExternalImageDescriptor { + public: + const ExternalImageDescriptorType type; // Must match the subclass const WGPUTextureDescriptor* cTextureDescriptor; // Must match image creation params - bool isCleared; // Sets whether the texture will be cleared before use - VkDeviceSize allocationSize; // Must match VkMemoryAllocateInfo from image creation - uint32_t memoryTypeIndex; // Must match VkMemoryAllocateInfo from image creation + bool isCleared; // Sets whether the texture will be cleared before use + + protected: + ExternalImageDescriptor(ExternalImageDescriptorType type); }; DAWN_NATIVE_EXPORT VkInstance GetInstance(WGPUDevice device); @@ -43,10 +54,30 @@ namespace dawn_native { namespace vulkan { // Can't use DAWN_PLATFORM_LINUX since header included in both dawn and chrome #ifdef __linux__ - // Descriptor for opaque file descriptor image import - struct ExternalImageDescriptorOpaqueFD : ExternalImageDescriptor { + // Common properties of external images represented by FDs + struct ExternalImageDescriptorFD : ExternalImageDescriptor { + public: int memoryFD; // A file descriptor from an export of the memory of the image std::vector waitFDs; // File descriptors of semaphores which will be waited on + + protected: + ExternalImageDescriptorFD(ExternalImageDescriptorType type); + }; + + // Descriptor for opaque file descriptor image import + struct ExternalImageDescriptorOpaqueFD : ExternalImageDescriptorFD { + ExternalImageDescriptorOpaqueFD(); + + VkDeviceSize allocationSize; // Must match VkMemoryAllocateInfo from image creation + uint32_t memoryTypeIndex; // Must match VkMemoryAllocateInfo from image creation + }; + + // Descriptor for dma-buf file descriptor image import + struct ExternalImageDescriptorDmaBuf : ExternalImageDescriptorFD { + ExternalImageDescriptorDmaBuf(); + + uint32_t stride; // Stride of the buffer in bytes + uint64_t drmModifier; // DRM modifier of the buffer }; // Imports an external vulkan image from an opaque file descriptor. Internally, this uses @@ -54,6 +85,8 @@ namespace dawn_native { namespace vulkan { // |descriptor->waitFDs| before the texture can be used. Finally, a signal semaphore // can be exported, transferring control back to the caller. // On failure, returns a nullptr + // NOTE: This is deprecated. Use WrapVulkanImage instead. + // TODO(hob): Remove this once Chromium has switched over to WrapVulkanImage. DAWN_NATIVE_EXPORT WGPUTexture WrapVulkanImageOpaqueFD(WGPUDevice cDevice, const ExternalImageDescriptorOpaqueFD* descriptor); @@ -62,6 +95,13 @@ namespace dawn_native { namespace vulkan { // textures before they are destroyed. On failure, returns -1 DAWN_NATIVE_EXPORT int ExportSignalSemaphoreOpaqueFD(WGPUDevice cDevice, WGPUTexture cTexture); + + // Imports external memory into a Vulkan image. Internally, this uses external memory / + // semaphore extensions to import the image and wait on the provided synchronizaton + // primitives before the texture can be used. + // On failure, returns a nullptr. + DAWN_NATIVE_EXPORT WGPUTexture WrapVulkanImage(WGPUDevice cDevice, + const ExternalImageDescriptor* descriptor); #endif // __linux__ }} // namespace dawn_native::vulkan