From 324e446f9ce566e8b0ea1c34bb590c619d16cf52 Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Mon, 3 Oct 2022 15:03:52 +0000 Subject: [PATCH] Vulkan: Add support for using dedicated allocation when importing images. This is required to make importing images work on some systems. The ideal version would be detecting whether dedicated allocations are needed as Vulkan provides reflection for that. However this reflection doesn't work on Nvidia, so instead Dawn requires a NeedsDedicatedAllocation enum on import that's Yes/No/Detect so the application can force use of a specific code path. Support for this enum and toggling dedicated allocations on/off is added for all external memory service implementations. Vulkan image wrapping tests are modified to add test parameters so that the Yes/No/Detect code paths are covered by tests. This is technically post-V1 work, but gl_tests in Chromium fail on Nvidia workstations without this fix, which makes it hard to debug other issues. Bug: dawn:1552, dawn:206, dawn:1260 Change-Id: Iee4f7bb9dbec520432ec623551221ef9e4d3d984 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/103560 Reviewed-by: Austin Eng Kokoro: Kokoro Commit-Queue: Corentin Wallez --- include/dawn/native/VulkanBackend.h | 12 ++++ src/dawn/native/BUILD.gn | 1 + src/dawn/native/CMakeLists.txt | 1 + src/dawn/native/vulkan/DeviceVk.cpp | 1 - .../vulkan/external_memory/MemoryService.cpp | 57 +++++++++++++++++++ .../vulkan/external_memory/MemoryService.h | 3 + .../MemoryServiceAHardwareBuffer.cpp | 13 ++++- .../external_memory/MemoryServiceDmaBuf.cpp | 15 +++-- .../external_memory/MemoryServiceOpaqueFD.cpp | 29 ++++++---- .../MemoryServiceZirconHandle.cpp | 29 +++++++--- .../white_box/VulkanImageWrappingTests.cpp | 44 ++++++++++++-- .../white_box/VulkanImageWrappingTests.h | 14 +++++ .../VulkanImageWrappingTests_DmaBuf.cpp | 15 ++++- .../VulkanImageWrappingTests_OpaqueFD.cpp | 49 +++++++++++----- 14 files changed, 237 insertions(+), 46 deletions(-) create mode 100644 src/dawn/native/vulkan/external_memory/MemoryService.cpp diff --git a/include/dawn/native/VulkanBackend.h b/include/dawn/native/VulkanBackend.h index 22adb0eac9..8fb8a7173a 100644 --- a/include/dawn/native/VulkanBackend.h +++ b/include/dawn/native/VulkanBackend.h @@ -40,6 +40,13 @@ struct DAWN_NATIVE_EXPORT AdapterDiscoveryOptions : public AdapterDiscoveryOptio bool forceSwiftShader = false; }; +enum class NeedsDedicatedAllocation { + Yes, + No, + // Use Vulkan reflection to detect whether a dedicated allocation is needed. + Detect, +}; + struct DAWN_NATIVE_EXPORT ExternalImageDescriptorVk : ExternalImageDescriptor { public: // The following members may be ignored if |ExternalImageDescriptor::isInitialized| is false @@ -54,6 +61,11 @@ struct DAWN_NATIVE_EXPORT ExternalImageDescriptorVk : ExternalImageDescriptor { VkImageLayout releasedOldLayout = VK_IMAGE_LAYOUT_GENERAL; VkImageLayout releasedNewLayout = VK_IMAGE_LAYOUT_GENERAL; + // Try to detect the need to use a dedicated allocation for imported images by default but let + // the application override this as drivers have bugs and forget to require a dedicated + // allocation. + NeedsDedicatedAllocation dedicatedAllocation = NeedsDedicatedAllocation::Detect; + protected: using ExternalImageDescriptor::ExternalImageDescriptor; }; diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn index ac57e07437..85025fbc68 100644 --- a/src/dawn/native/BUILD.gn +++ b/src/dawn/native/BUILD.gn @@ -670,6 +670,7 @@ source_set("sources") { "vulkan/VulkanFunctions.h", "vulkan/VulkanInfo.cpp", "vulkan/VulkanInfo.h", + "vulkan/external_memory/MemoryService.cpp", "vulkan/external_memory/MemoryService.h", "vulkan/external_semaphore/SemaphoreService.h", ] diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt index 6eececf9fb..ec2e9906c3 100644 --- a/src/dawn/native/CMakeLists.txt +++ b/src/dawn/native/CMakeLists.txt @@ -552,6 +552,7 @@ if (DAWN_ENABLE_VULKAN) "vulkan/VulkanFunctions.h" "vulkan/VulkanInfo.cpp" "vulkan/VulkanInfo.h" + "vulkan/external_memory/MemoryService.cpp" "vulkan/external_memory/MemoryService.h" "vulkan/external_semaphore/SemaphoreService.h" ) diff --git a/src/dawn/native/vulkan/DeviceVk.cpp b/src/dawn/native/vulkan/DeviceVk.cpp index fec7cb51ad..826de69d24 100644 --- a/src/dawn/native/vulkan/DeviceVk.cpp +++ b/src/dawn/native/vulkan/DeviceVk.cpp @@ -14,7 +14,6 @@ #include "dawn/native/vulkan/DeviceVk.h" -#include "dawn/common/Log.h" #include "dawn/common/NonCopyable.h" #include "dawn/common/Platform.h" #include "dawn/native/BackendConnection.h" diff --git a/src/dawn/native/vulkan/external_memory/MemoryService.cpp b/src/dawn/native/vulkan/external_memory/MemoryService.cpp new file mode 100644 index 0000000000..0db58f4a86 --- /dev/null +++ b/src/dawn/native/vulkan/external_memory/MemoryService.cpp @@ -0,0 +1,57 @@ +// Copyright 2022 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 "dawn/native/vulkan/external_memory/MemoryService.h" + +#include "dawn/native/vulkan/DeviceVk.h" + +namespace dawn::native::vulkan::external_memory { + +bool Service::RequiresDedicatedAllocation(const ExternalImageDescriptorVk* descriptor, + VkImage image) { + switch (descriptor->dedicatedAllocation) { + case NeedsDedicatedAllocation::Yes: + return true; + + case NeedsDedicatedAllocation::No: + return false; + + case NeedsDedicatedAllocation::Detect: + if (!mDevice->GetDeviceInfo().HasExt(DeviceExt::DedicatedAllocation)) { + return false; + } + + VkMemoryDedicatedRequirements dedicatedRequirements; + dedicatedRequirements.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS; + dedicatedRequirements.pNext = nullptr; + + VkMemoryRequirements2 baseRequirements; + baseRequirements.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; + baseRequirements.pNext = &dedicatedRequirements; + + VkImageMemoryRequirementsInfo2 imageInfo; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2; + imageInfo.pNext = nullptr; + imageInfo.image = image; + + mDevice->fn.GetImageMemoryRequirements2(mDevice->GetVkDevice(), &imageInfo, + &baseRequirements); + + // The Vulkan spec requires that prefersDA is set if requiresDA is, so we can just check + // for prefersDA. + return dedicatedRequirements.prefersDedicatedAllocation; + } +} + +} // namespace dawn::native::vulkan::external_memory diff --git a/src/dawn/native/vulkan/external_memory/MemoryService.h b/src/dawn/native/vulkan/external_memory/MemoryService.h index eee4e992d5..0800bf21c1 100644 --- a/src/dawn/native/vulkan/external_memory/MemoryService.h +++ b/src/dawn/native/vulkan/external_memory/MemoryService.h @@ -30,6 +30,7 @@ namespace dawn::native::vulkan::external_memory { struct MemoryImportParams { VkDeviceSize allocationSize; uint32_t memoryTypeIndex; + bool dedicatedAllocation = false; }; class Service { @@ -70,6 +71,8 @@ class Service { const VkImageCreateInfo& baseCreateInfo); private: + bool RequiresDedicatedAllocation(const ExternalImageDescriptorVk* descriptor, VkImage image); + Device* mDevice = nullptr; // True if early checks pass that determine if the service is supported diff --git a/src/dawn/native/vulkan/external_memory/MemoryServiceAHardwareBuffer.cpp b/src/dawn/native/vulkan/external_memory/MemoryServiceAHardwareBuffer.cpp index cf379292b7..203136540f 100644 --- a/src/dawn/native/vulkan/external_memory/MemoryServiceAHardwareBuffer.cpp +++ b/src/dawn/native/vulkan/external_memory/MemoryServiceAHardwareBuffer.cpp @@ -118,7 +118,10 @@ ResultOrError Service::GetMemoryImportParams( mDevice->GetVkDevice(), aHardwareBufferDescriptor->handle, &bufferProperties), "vkGetAndroidHardwareBufferPropertiesANDROID")); - MemoryImportParams params = {bufferProperties.allocationSize, bufferProperties.memoryTypeBits}; + MemoryImportParams params; + params.allocationSize = bufferProperties.allocationSize; + params.memoryTypeIndex = bufferProperties.memoryTypeBits; + params.dedicatedAllocation = RequiresDedicatedAllocation(aHardwareBufferDescriptor, image); return params; } @@ -152,6 +155,14 @@ ResultOrError Service::ImportMemory(ExternalMemoryHandle handle, allocateInfoChain.Add(&importMemoryAHBInfo, VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID); + VkMemoryDedicatedAllocateInfo dedicatedAllocateInfo; + if (importParams.dedicatedAllocation) { + dedicatedAllocateInfo.image = image; + dedicatedAllocateInfo.buffer = VkBuffer{}; + allocateInfoChain.Add(&dedicatedAllocateInfo, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO); + } + VkDeviceMemory allocatedMemory = VK_NULL_HANDLE; DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo, nullptr, &*allocatedMemory), diff --git a/src/dawn/native/vulkan/external_memory/MemoryServiceDmaBuf.cpp b/src/dawn/native/vulkan/external_memory/MemoryServiceDmaBuf.cpp index c712d7ea90..fc6a1e3ea3 100644 --- a/src/dawn/native/vulkan/external_memory/MemoryServiceDmaBuf.cpp +++ b/src/dawn/native/vulkan/external_memory/MemoryServiceDmaBuf.cpp @@ -252,7 +252,10 @@ ResultOrError Service::GetMemoryImportParams( memoryRequirements, MemoryKind::Opaque); DAWN_INVALID_IF(memoryTypeIndex == -1, "Unable to find an appropriate memory type for import."); - MemoryImportParams params = {memoryRequirements.size, static_cast(memoryTypeIndex)}; + MemoryImportParams params; + params.allocationSize = memoryRequirements.size; + params.memoryTypeIndex = static_cast(memoryTypeIndex); + params.dedicatedAllocation = RequiresDedicatedAllocation(dmaBufDescriptor, image); return params; } @@ -277,10 +280,12 @@ ResultOrError Service::ImportMemory(ExternalMemoryHandle handle, memoryAllocateInfoChain.Add(&importMemoryFdInfo, VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR); VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo; - memoryDedicatedAllocateInfo.image = image; - memoryDedicatedAllocateInfo.buffer = VkBuffer{}; - memoryAllocateInfoChain.Add(&memoryDedicatedAllocateInfo, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO); + if (importParams.dedicatedAllocation) { + memoryDedicatedAllocateInfo.image = image; + memoryDedicatedAllocateInfo.buffer = VkBuffer{}; + memoryAllocateInfoChain.Add(&memoryDedicatedAllocateInfo, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO); + } VkDeviceMemory allocatedMemory = VK_NULL_HANDLE; DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &memoryAllocateInfo, diff --git a/src/dawn/native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp b/src/dawn/native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp index 00a74e4908..1ad48f1c34 100644 --- a/src/dawn/native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp +++ b/src/dawn/native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp @@ -73,7 +73,6 @@ bool Service::SupportsImportMemory(VkFormat format, 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) != 0; } @@ -95,8 +94,10 @@ ResultOrError Service::GetMemoryImportParams( const ExternalImageDescriptorOpaqueFD* opaqueFDDescriptor = static_cast(descriptor); - MemoryImportParams params = {opaqueFDDescriptor->allocationSize, - opaqueFDDescriptor->memoryTypeIndex}; + MemoryImportParams params; + params.allocationSize = opaqueFDDescriptor->allocationSize; + params.memoryTypeIndex = opaqueFDDescriptor->memoryTypeIndex; + params.dedicatedAllocation = RequiresDedicatedAllocation(opaqueFDDescriptor, image); return params; } @@ -115,17 +116,25 @@ ResultOrError Service::ImportMemory(ExternalMemoryHandle handle, "Requested allocation size (%u) is smaller than the image requires (%u).", importParams.allocationSize, requirements.size); - 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; - importMemoryFdInfo.fd = handle; - VkMemoryAllocateInfo allocateInfo; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocateInfo.pNext = &importMemoryFdInfo; + allocateInfo.pNext = nullptr; allocateInfo.allocationSize = importParams.allocationSize; allocateInfo.memoryTypeIndex = importParams.memoryTypeIndex; + PNextChainBuilder allocateInfoChain(&allocateInfo); + + VkImportMemoryFdInfoKHR importMemoryFdInfo; + importMemoryFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + importMemoryFdInfo.fd = handle; + allocateInfoChain.Add(&importMemoryFdInfo, VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR); + + VkMemoryDedicatedAllocateInfo dedicatedAllocateInfo; + if (importParams.dedicatedAllocation) { + dedicatedAllocateInfo.image = image; + dedicatedAllocateInfo.buffer = VkBuffer{}; + allocateInfoChain.Add(&dedicatedAllocateInfo, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO); + } VkDeviceMemory allocatedMemory = VK_NULL_HANDLE; DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo, diff --git a/src/dawn/native/vulkan/external_memory/MemoryServiceZirconHandle.cpp b/src/dawn/native/vulkan/external_memory/MemoryServiceZirconHandle.cpp index 5836b87962..2f0dd3b56b 100644 --- a/src/dawn/native/vulkan/external_memory/MemoryServiceZirconHandle.cpp +++ b/src/dawn/native/vulkan/external_memory/MemoryServiceZirconHandle.cpp @@ -95,8 +95,10 @@ ResultOrError Service::GetMemoryImportParams( const ExternalImageDescriptorOpaqueFD* opaqueFDDescriptor = static_cast(descriptor); - MemoryImportParams params = {opaqueFDDescriptor->allocationSize, - opaqueFDDescriptor->memoryTypeIndex}; + MemoryImportParams params; + params.allocationSize = opaqueFDDescriptor->allocationSize; + params.memoryTypeIndex = opaqueFDDescriptor->memoryTypeIndex; + params.dedicatedAllocation = RequiresDedicatedAllocation(opaqueFDDescriptor, image); return params; } @@ -115,17 +117,26 @@ ResultOrError Service::ImportMemory(ExternalMemoryHandle handle, "Requested allocation size (%u) is smaller than the required image size (%u).", importParams.allocationSize, requirements.size); - VkImportMemoryZirconHandleInfoFUCHSIA importMemoryHandleInfo; - importMemoryHandleInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA; - importMemoryHandleInfo.pNext = nullptr; - importMemoryHandleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA; - importMemoryHandleInfo.handle = handle; - VkMemoryAllocateInfo allocateInfo; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocateInfo.pNext = &importMemoryHandleInfo; + allocateInfo.pNext = nullptr; allocateInfo.allocationSize = importParams.allocationSize; allocateInfo.memoryTypeIndex = importParams.memoryTypeIndex; + PNextChainBuilder allocateInfoChain(&allocateInfo); + + VkImportMemoryZirconHandleInfoFUCHSIA importMemoryHandleInfo; + importMemoryHandleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA; + importMemoryHandleInfo.handle = handle; + allocateInfoChain.Add(&importMemoryHandleInfo, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA); + + VkMemoryDedicatedAllocateInfo dedicatedAllocateInfo; + if (importParams.dedicatedAllocation) { + dedicatedAllocateInfo.image = image; + dedicatedAllocateInfo.buffer = VkBuffer{}; + allocateInfoChain.Add(&dedicatedAllocateInfo, + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO); + } VkDeviceMemory allocatedMemory = VK_NULL_HANDLE; DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo, diff --git a/src/dawn/tests/white_box/VulkanImageWrappingTests.cpp b/src/dawn/tests/white_box/VulkanImageWrappingTests.cpp index 6747a0465a..f98c6cbc04 100644 --- a/src/dawn/tests/white_box/VulkanImageWrappingTests.cpp +++ b/src/dawn/tests/white_box/VulkanImageWrappingTests.cpp @@ -27,9 +27,22 @@ namespace dawn::native::vulkan { using ExternalTexture = VulkanImageWrappingTestBackend::ExternalTexture; using ExternalSemaphore = VulkanImageWrappingTestBackend::ExternalSemaphore; +void VulkanImageWrappingTestBackend::SetParam( + const VulkanImageWrappingTestBackend::TestParams& params) { + mParams = params; +} + +const VulkanImageWrappingTestBackend::TestParams& VulkanImageWrappingTestBackend::GetParam() const { + return mParams; +} + namespace { -class VulkanImageWrappingTestBase : public DawnTest { +using UseDedicatedAllocation = bool; +using DetectDedicatedAllocation = bool; +DAWN_TEST_PARAM_STRUCT(ImageWrappingParams, UseDedicatedAllocation, DetectDedicatedAllocation); + +class VulkanImageWrappingTestBase : public DawnTestWithParams { protected: std::vector GetRequiredFeatures() override { return {wgpu::FeatureName::DawnInternalUsages}; @@ -37,11 +50,22 @@ class VulkanImageWrappingTestBase : public DawnTest { public: void SetUp() override { - DawnTest::SetUp(); + DawnTestWithParams::SetUp(); DAWN_TEST_UNSUPPORTED_IF(UsesWire()); + // TODO(dawn:1552): Nvidia doesn't seem to correctly reflect whether an import requires a + // dedicated allocation. + DAWN_SUPPRESS_TEST_IF(IsLinux() && IsNvidia() && GetParam().mUseDedicatedAllocation && + GetParam().mDetectDedicatedAllocation); + mBackend = VulkanImageWrappingTestBackend::Create(device); + VulkanImageWrappingTestBackend::TestParams params; + params.useDedicatedAllocation = GetParam().mUseDedicatedAllocation; + params.detectDedicatedAllocation = GetParam().mDetectDedicatedAllocation; + DAWN_TEST_UNSUPPORTED_IF(!mBackend->SupportsTestParams(params)); + mBackend->SetParam(params); + defaultDescriptor.dimension = wgpu::TextureDimension::e2D; defaultDescriptor.format = wgpu::TextureFormat::RGBA8Unorm; defaultDescriptor.size = {1, 1, 1}; @@ -56,13 +80,13 @@ class VulkanImageWrappingTestBase : public DawnTest { void TearDown() override { if (UsesWire()) { - DawnTest::TearDown(); + DawnTestWithParams::TearDown(); return; } defaultTexture = nullptr; mBackend = nullptr; - DawnTest::TearDown(); + DawnTestWithParams::TearDown(); } wgpu::Texture WrapVulkanImage(wgpu::Device dawnDevice, @@ -868,7 +892,15 @@ TEST_P(VulkanImageWrappingUsageTests, SRGBReinterpretation) { IgnoreSignalSemaphore(texture); } -DAWN_INSTANTIATE_TEST(VulkanImageWrappingValidationTests, VulkanBackend()); -DAWN_INSTANTIATE_TEST(VulkanImageWrappingUsageTests, VulkanBackend()); +DAWN_INSTANTIATE_TEST_P(VulkanImageWrappingValidationTests, + {VulkanBackend()}, + {true, false}, // UseDedicatedAllocation + {true, false} // DetectDedicatedAllocation +); +DAWN_INSTANTIATE_TEST_P(VulkanImageWrappingUsageTests, + {VulkanBackend()}, + {true, false}, // UseDedicatedAllocation + {true, false} // DetectDedicatedAllocation +); } // namespace dawn::native::vulkan diff --git a/src/dawn/tests/white_box/VulkanImageWrappingTests.h b/src/dawn/tests/white_box/VulkanImageWrappingTests.h index dd7152b3dd..a430783113 100644 --- a/src/dawn/tests/white_box/VulkanImageWrappingTests.h +++ b/src/dawn/tests/white_box/VulkanImageWrappingTests.h @@ -45,6 +45,17 @@ class VulkanImageWrappingTestBackend { virtual ~ExternalSemaphore() = default; }; + // Test parameters passed from the wrapping tests so that they can be used by the test + // backends. The DAWN_TEST_PARAM_STRUCT is not declared here because it is unnecessary but also + // because it declares a bunch of functions that would cause ODR violations. + struct TestParams { + bool useDedicatedAllocation = false; + bool detectDedicatedAllocation = false; + }; + void SetParam(const TestParams& params); + const TestParams& GetParam() const; + virtual bool SupportsTestParams(const TestParams& params) const = 0; + virtual std::unique_ptr CreateTexture(uint32_t width, uint32_t height, wgpu::TextureFormat format, @@ -57,6 +68,9 @@ class VulkanImageWrappingTestBackend { virtual bool ExportImage(const wgpu::Texture& texture, VkImageLayout layout, ExternalImageExportInfoVkForTesting* exportInfo) = 0; + + private: + TestParams mParams; }; struct ExternalImageDescriptorVkForTesting : public ExternalImageDescriptorVk { diff --git a/src/dawn/tests/white_box/VulkanImageWrappingTests_DmaBuf.cpp b/src/dawn/tests/white_box/VulkanImageWrappingTests_DmaBuf.cpp index adb03e764a..d2be7ba7fe 100644 --- a/src/dawn/tests/white_box/VulkanImageWrappingTests_DmaBuf.cpp +++ b/src/dawn/tests/white_box/VulkanImageWrappingTests_DmaBuf.cpp @@ -22,6 +22,7 @@ #include #include +#include "dawn/native/vulkan/DeviceVk.h" #include "dawn/tests/white_box/VulkanImageWrappingTests.h" namespace dawn::native::vulkan { @@ -80,7 +81,9 @@ class ExternalTextureDmaBuf : public VulkanImageWrappingTestBackend::ExternalTex class VulkanImageWrappingTestBackendDmaBuf : public VulkanImageWrappingTestBackend { public: - explicit VulkanImageWrappingTestBackendDmaBuf(const wgpu::Device& device) {} + explicit VulkanImageWrappingTestBackendDmaBuf(const wgpu::Device& device) { + mDeviceVk = dawn::native::vulkan::ToBackend(dawn::native::FromAPI(device.Get())); + } ~VulkanImageWrappingTestBackendDmaBuf() { if (mGbmDevice != nullptr) { @@ -89,6 +92,14 @@ class VulkanImageWrappingTestBackendDmaBuf : public VulkanImageWrappingTestBacke } } + bool SupportsTestParams(const TestParams& params) const override { + // Even though this backend doesn't decide on creation whether the image should use + // dedicated allocation, it still supports all options of NeedsDedicatedAllocation so we + // test them. + return !params.useDedicatedAllocation || + mDeviceVk->GetDeviceInfo().HasExt(DeviceExt::DedicatedAllocation); + } + std::unique_ptr CreateTexture(uint32_t width, uint32_t height, wgpu::TextureFormat format, @@ -186,6 +197,7 @@ class VulkanImageWrappingTestBackendDmaBuf : public VulkanImageWrappingTestBacke } gbm_device* mGbmDevice = nullptr; + dawn::native::vulkan::Device* mDeviceVk; }; // static @@ -195,4 +207,5 @@ std::unique_ptr VulkanImageWrappingTestBackend:: backend->CreateGbmDevice(); return backend; } + } // namespace dawn::native::vulkan diff --git a/src/dawn/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp b/src/dawn/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp index e8e8a59333..8944deead5 100644 --- a/src/dawn/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp +++ b/src/dawn/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp @@ -21,6 +21,7 @@ #include "dawn/native/vulkan/DeviceVk.h" #include "dawn/native/vulkan/FencedDeleter.h" #include "dawn/native/vulkan/ResourceMemoryAllocatorVk.h" +#include "dawn/native/vulkan/UtilsVulkan.h" #include "dawn/tests/white_box/VulkanImageWrappingTests.h" #include "gtest/gtest.h" @@ -95,6 +96,11 @@ class VulkanImageWrappingTestBackendOpaqueFD : public VulkanImageWrappingTestBac mDeviceVk = dawn::native::vulkan::ToBackend(dawn::native::FromAPI(device.Get())); } + bool SupportsTestParams(const TestParams& params) const override { + return !params.useDedicatedAllocation || + mDeviceVk->GetDeviceInfo().HasExt(DeviceExt::DedicatedAllocation); + } + std::unique_ptr CreateTexture(uint32_t width, uint32_t height, wgpu::TextureFormat format, @@ -141,6 +147,14 @@ class VulkanImageWrappingTestBackendOpaqueFD : public VulkanImageWrappingTestBac descriptorOpaqueFD.memoryTypeIndex = textureOpaqueFD->memoryTypeIndex; descriptorOpaqueFD.waitFDs = std::move(waitFDs); + if (GetParam().detectDedicatedAllocation) { + descriptorOpaqueFD.dedicatedAllocation = NeedsDedicatedAllocation::Detect; + } else if (GetParam().useDedicatedAllocation) { + descriptorOpaqueFD.dedicatedAllocation = NeedsDedicatedAllocation::Yes; + } else { + descriptorOpaqueFD.dedicatedAllocation = NeedsDedicatedAllocation::No; + } + return wgpu::Texture::Acquire( dawn::native::vulkan::WrapVulkanImage(device.Get(), &descriptorOpaqueFD)); } @@ -167,17 +181,12 @@ class VulkanImageWrappingTestBackendOpaqueFD : public VulkanImageWrappingTestBac uint32_t height, VkFormat format, VkImage* image) { - VkExternalMemoryImageCreateInfoKHR externalInfo; - externalInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR; - externalInfo.pNext = nullptr; - externalInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; - auto usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; VkImageCreateInfo createInfo; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - createInfo.pNext = &externalInfo; + createInfo.pNext = nullptr; createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR; createInfo.imageType = VK_IMAGE_TYPE_2D; createInfo.format = format; @@ -191,6 +200,11 @@ class VulkanImageWrappingTestBackendOpaqueFD : public VulkanImageWrappingTestBac createInfo.queueFamilyIndexCount = 0; createInfo.pQueueFamilyIndices = nullptr; createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + PNextChainBuilder createChain(&createInfo); + + VkExternalMemoryImageCreateInfoKHR externalInfo; + externalInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + createChain.Add(&externalInfo, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR); return deviceVk->fn.CreateImage(deviceVk->GetVkDevice(), &createInfo, nullptr, &**image); } @@ -205,19 +219,28 @@ class VulkanImageWrappingTestBackendOpaqueFD : public VulkanImageWrappingTestBac VkMemoryRequirements requirements; deviceVk->fn.GetImageMemoryRequirements(deviceVk->GetVkDevice(), handle, &requirements); - // Import memory from file descriptor - VkExportMemoryAllocateInfoKHR externalInfo; - externalInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; - externalInfo.pNext = nullptr; - externalInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; - int bestType = deviceVk->GetResourceMemoryAllocator()->FindBestTypeIndex( requirements, MemoryKind::Opaque); + VkMemoryAllocateInfo allocateInfo; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocateInfo.pNext = &externalInfo; + allocateInfo.pNext = nullptr; allocateInfo.allocationSize = requirements.size; allocateInfo.memoryTypeIndex = static_cast(bestType); + PNextChainBuilder allocateChain(&allocateInfo); + + // Import memory from file descriptor + VkExportMemoryAllocateInfoKHR externalInfo; + externalInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + allocateChain.Add(&externalInfo, VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR); + + // Use a dedicated memory allocation if testing that path. + VkMemoryDedicatedAllocateInfo dedicatedInfo; + if (GetParam().useDedicatedAllocation) { + dedicatedInfo.image = handle; + dedicatedInfo.buffer = VkBuffer{}; + allocateChain.Add(&dedicatedInfo, VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO); + } *allocationSize = allocateInfo.allocationSize; *memoryTypeIndex = allocateInfo.memoryTypeIndex;