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 <enga@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Corentin Wallez 2022-10-03 15:03:52 +00:00 committed by Dawn LUCI CQ
parent 6ff74a6d3e
commit 324e446f9c
14 changed files with 237 additions and 46 deletions

View File

@ -40,6 +40,13 @@ struct DAWN_NATIVE_EXPORT AdapterDiscoveryOptions : public AdapterDiscoveryOptio
bool forceSwiftShader = false; 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 { struct DAWN_NATIVE_EXPORT ExternalImageDescriptorVk : ExternalImageDescriptor {
public: public:
// The following members may be ignored if |ExternalImageDescriptor::isInitialized| is false // 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 releasedOldLayout = VK_IMAGE_LAYOUT_GENERAL;
VkImageLayout releasedNewLayout = 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: protected:
using ExternalImageDescriptor::ExternalImageDescriptor; using ExternalImageDescriptor::ExternalImageDescriptor;
}; };

View File

@ -670,6 +670,7 @@ source_set("sources") {
"vulkan/VulkanFunctions.h", "vulkan/VulkanFunctions.h",
"vulkan/VulkanInfo.cpp", "vulkan/VulkanInfo.cpp",
"vulkan/VulkanInfo.h", "vulkan/VulkanInfo.h",
"vulkan/external_memory/MemoryService.cpp",
"vulkan/external_memory/MemoryService.h", "vulkan/external_memory/MemoryService.h",
"vulkan/external_semaphore/SemaphoreService.h", "vulkan/external_semaphore/SemaphoreService.h",
] ]

View File

@ -552,6 +552,7 @@ if (DAWN_ENABLE_VULKAN)
"vulkan/VulkanFunctions.h" "vulkan/VulkanFunctions.h"
"vulkan/VulkanInfo.cpp" "vulkan/VulkanInfo.cpp"
"vulkan/VulkanInfo.h" "vulkan/VulkanInfo.h"
"vulkan/external_memory/MemoryService.cpp"
"vulkan/external_memory/MemoryService.h" "vulkan/external_memory/MemoryService.h"
"vulkan/external_semaphore/SemaphoreService.h" "vulkan/external_semaphore/SemaphoreService.h"
) )

View File

@ -14,7 +14,6 @@
#include "dawn/native/vulkan/DeviceVk.h" #include "dawn/native/vulkan/DeviceVk.h"
#include "dawn/common/Log.h"
#include "dawn/common/NonCopyable.h" #include "dawn/common/NonCopyable.h"
#include "dawn/common/Platform.h" #include "dawn/common/Platform.h"
#include "dawn/native/BackendConnection.h" #include "dawn/native/BackendConnection.h"

View File

@ -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

View File

@ -30,6 +30,7 @@ namespace dawn::native::vulkan::external_memory {
struct MemoryImportParams { struct MemoryImportParams {
VkDeviceSize allocationSize; VkDeviceSize allocationSize;
uint32_t memoryTypeIndex; uint32_t memoryTypeIndex;
bool dedicatedAllocation = false;
}; };
class Service { class Service {
@ -70,6 +71,8 @@ class Service {
const VkImageCreateInfo& baseCreateInfo); const VkImageCreateInfo& baseCreateInfo);
private: private:
bool RequiresDedicatedAllocation(const ExternalImageDescriptorVk* descriptor, VkImage image);
Device* mDevice = nullptr; Device* mDevice = nullptr;
// True if early checks pass that determine if the service is supported // True if early checks pass that determine if the service is supported

View File

@ -118,7 +118,10 @@ ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
mDevice->GetVkDevice(), aHardwareBufferDescriptor->handle, &bufferProperties), mDevice->GetVkDevice(), aHardwareBufferDescriptor->handle, &bufferProperties),
"vkGetAndroidHardwareBufferPropertiesANDROID")); "vkGetAndroidHardwareBufferPropertiesANDROID"));
MemoryImportParams params = {bufferProperties.allocationSize, bufferProperties.memoryTypeBits}; MemoryImportParams params;
params.allocationSize = bufferProperties.allocationSize;
params.memoryTypeIndex = bufferProperties.memoryTypeBits;
params.dedicatedAllocation = RequiresDedicatedAllocation(aHardwareBufferDescriptor, image);
return params; return params;
} }
@ -152,6 +155,14 @@ ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle,
allocateInfoChain.Add(&importMemoryAHBInfo, allocateInfoChain.Add(&importMemoryAHBInfo,
VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID); 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; VkDeviceMemory allocatedMemory = VK_NULL_HANDLE;
DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo, DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo,
nullptr, &*allocatedMemory), nullptr, &*allocatedMemory),

View File

@ -252,7 +252,10 @@ ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
memoryRequirements, MemoryKind::Opaque); memoryRequirements, MemoryKind::Opaque);
DAWN_INVALID_IF(memoryTypeIndex == -1, "Unable to find an appropriate memory type for import."); DAWN_INVALID_IF(memoryTypeIndex == -1, "Unable to find an appropriate memory type for import.");
MemoryImportParams params = {memoryRequirements.size, static_cast<uint32_t>(memoryTypeIndex)}; MemoryImportParams params;
params.allocationSize = memoryRequirements.size;
params.memoryTypeIndex = static_cast<uint32_t>(memoryTypeIndex);
params.dedicatedAllocation = RequiresDedicatedAllocation(dmaBufDescriptor, image);
return params; return params;
} }
@ -277,10 +280,12 @@ ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle,
memoryAllocateInfoChain.Add(&importMemoryFdInfo, VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR); memoryAllocateInfoChain.Add(&importMemoryFdInfo, VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR);
VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo; VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo;
if (importParams.dedicatedAllocation) {
memoryDedicatedAllocateInfo.image = image; memoryDedicatedAllocateInfo.image = image;
memoryDedicatedAllocateInfo.buffer = VkBuffer{}; memoryDedicatedAllocateInfo.buffer = VkBuffer{};
memoryAllocateInfoChain.Add(&memoryDedicatedAllocateInfo, memoryAllocateInfoChain.Add(&memoryDedicatedAllocateInfo,
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO); VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO);
}
VkDeviceMemory allocatedMemory = VK_NULL_HANDLE; VkDeviceMemory allocatedMemory = VK_NULL_HANDLE;
DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &memoryAllocateInfo, DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &memoryAllocateInfo,

View File

@ -73,7 +73,6 @@ bool Service::SupportsImportMemory(VkFormat format,
return false; return false;
} }
// TODO(http://crbug.com/dawn/206): Investigate dedicated only images
VkFlags memoryFlags = externalFormatProperties.externalMemoryProperties.externalMemoryFeatures; VkFlags memoryFlags = externalFormatProperties.externalMemoryProperties.externalMemoryFeatures;
return (memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR) != 0; return (memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR) != 0;
} }
@ -95,8 +94,10 @@ ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
const ExternalImageDescriptorOpaqueFD* opaqueFDDescriptor = const ExternalImageDescriptorOpaqueFD* opaqueFDDescriptor =
static_cast<const ExternalImageDescriptorOpaqueFD*>(descriptor); static_cast<const ExternalImageDescriptorOpaqueFD*>(descriptor);
MemoryImportParams params = {opaqueFDDescriptor->allocationSize, MemoryImportParams params;
opaqueFDDescriptor->memoryTypeIndex}; params.allocationSize = opaqueFDDescriptor->allocationSize;
params.memoryTypeIndex = opaqueFDDescriptor->memoryTypeIndex;
params.dedicatedAllocation = RequiresDedicatedAllocation(opaqueFDDescriptor, image);
return params; return params;
} }
@ -115,17 +116,25 @@ ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle,
"Requested allocation size (%u) is smaller than the image requires (%u).", "Requested allocation size (%u) is smaller than the image requires (%u).",
importParams.allocationSize, requirements.size); 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; VkMemoryAllocateInfo allocateInfo;
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocateInfo.pNext = &importMemoryFdInfo; allocateInfo.pNext = nullptr;
allocateInfo.allocationSize = importParams.allocationSize; allocateInfo.allocationSize = importParams.allocationSize;
allocateInfo.memoryTypeIndex = importParams.memoryTypeIndex; 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; VkDeviceMemory allocatedMemory = VK_NULL_HANDLE;
DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo, DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo,

View File

@ -95,8 +95,10 @@ ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
const ExternalImageDescriptorOpaqueFD* opaqueFDDescriptor = const ExternalImageDescriptorOpaqueFD* opaqueFDDescriptor =
static_cast<const ExternalImageDescriptorOpaqueFD*>(descriptor); static_cast<const ExternalImageDescriptorOpaqueFD*>(descriptor);
MemoryImportParams params = {opaqueFDDescriptor->allocationSize, MemoryImportParams params;
opaqueFDDescriptor->memoryTypeIndex}; params.allocationSize = opaqueFDDescriptor->allocationSize;
params.memoryTypeIndex = opaqueFDDescriptor->memoryTypeIndex;
params.dedicatedAllocation = RequiresDedicatedAllocation(opaqueFDDescriptor, image);
return params; return params;
} }
@ -115,17 +117,26 @@ ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle,
"Requested allocation size (%u) is smaller than the required image size (%u).", "Requested allocation size (%u) is smaller than the required image size (%u).",
importParams.allocationSize, requirements.size); 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; VkMemoryAllocateInfo allocateInfo;
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocateInfo.pNext = &importMemoryHandleInfo; allocateInfo.pNext = nullptr;
allocateInfo.allocationSize = importParams.allocationSize; allocateInfo.allocationSize = importParams.allocationSize;
allocateInfo.memoryTypeIndex = importParams.memoryTypeIndex; 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; VkDeviceMemory allocatedMemory = VK_NULL_HANDLE;
DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo, DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo,

View File

@ -27,9 +27,22 @@ namespace dawn::native::vulkan {
using ExternalTexture = VulkanImageWrappingTestBackend::ExternalTexture; using ExternalTexture = VulkanImageWrappingTestBackend::ExternalTexture;
using ExternalSemaphore = VulkanImageWrappingTestBackend::ExternalSemaphore; using ExternalSemaphore = VulkanImageWrappingTestBackend::ExternalSemaphore;
void VulkanImageWrappingTestBackend::SetParam(
const VulkanImageWrappingTestBackend::TestParams& params) {
mParams = params;
}
const VulkanImageWrappingTestBackend::TestParams& VulkanImageWrappingTestBackend::GetParam() const {
return mParams;
}
namespace { namespace {
class VulkanImageWrappingTestBase : public DawnTest { using UseDedicatedAllocation = bool;
using DetectDedicatedAllocation = bool;
DAWN_TEST_PARAM_STRUCT(ImageWrappingParams, UseDedicatedAllocation, DetectDedicatedAllocation);
class VulkanImageWrappingTestBase : public DawnTestWithParams<ImageWrappingParams> {
protected: protected:
std::vector<wgpu::FeatureName> GetRequiredFeatures() override { std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
return {wgpu::FeatureName::DawnInternalUsages}; return {wgpu::FeatureName::DawnInternalUsages};
@ -37,11 +50,22 @@ class VulkanImageWrappingTestBase : public DawnTest {
public: public:
void SetUp() override { void SetUp() override {
DawnTest::SetUp(); DawnTestWithParams::SetUp();
DAWN_TEST_UNSUPPORTED_IF(UsesWire()); 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); 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.dimension = wgpu::TextureDimension::e2D;
defaultDescriptor.format = wgpu::TextureFormat::RGBA8Unorm; defaultDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
defaultDescriptor.size = {1, 1, 1}; defaultDescriptor.size = {1, 1, 1};
@ -56,13 +80,13 @@ class VulkanImageWrappingTestBase : public DawnTest {
void TearDown() override { void TearDown() override {
if (UsesWire()) { if (UsesWire()) {
DawnTest::TearDown(); DawnTestWithParams::TearDown();
return; return;
} }
defaultTexture = nullptr; defaultTexture = nullptr;
mBackend = nullptr; mBackend = nullptr;
DawnTest::TearDown(); DawnTestWithParams::TearDown();
} }
wgpu::Texture WrapVulkanImage(wgpu::Device dawnDevice, wgpu::Texture WrapVulkanImage(wgpu::Device dawnDevice,
@ -868,7 +892,15 @@ TEST_P(VulkanImageWrappingUsageTests, SRGBReinterpretation) {
IgnoreSignalSemaphore(texture); IgnoreSignalSemaphore(texture);
} }
DAWN_INSTANTIATE_TEST(VulkanImageWrappingValidationTests, VulkanBackend()); DAWN_INSTANTIATE_TEST_P(VulkanImageWrappingValidationTests,
DAWN_INSTANTIATE_TEST(VulkanImageWrappingUsageTests, VulkanBackend()); {VulkanBackend()},
{true, false}, // UseDedicatedAllocation
{true, false} // DetectDedicatedAllocation
);
DAWN_INSTANTIATE_TEST_P(VulkanImageWrappingUsageTests,
{VulkanBackend()},
{true, false}, // UseDedicatedAllocation
{true, false} // DetectDedicatedAllocation
);
} // namespace dawn::native::vulkan } // namespace dawn::native::vulkan

View File

@ -45,6 +45,17 @@ class VulkanImageWrappingTestBackend {
virtual ~ExternalSemaphore() = default; 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<ExternalTexture> CreateTexture(uint32_t width, virtual std::unique_ptr<ExternalTexture> CreateTexture(uint32_t width,
uint32_t height, uint32_t height,
wgpu::TextureFormat format, wgpu::TextureFormat format,
@ -57,6 +68,9 @@ class VulkanImageWrappingTestBackend {
virtual bool ExportImage(const wgpu::Texture& texture, virtual bool ExportImage(const wgpu::Texture& texture,
VkImageLayout layout, VkImageLayout layout,
ExternalImageExportInfoVkForTesting* exportInfo) = 0; ExternalImageExportInfoVkForTesting* exportInfo) = 0;
private:
TestParams mParams;
}; };
struct ExternalImageDescriptorVkForTesting : public ExternalImageDescriptorVk { struct ExternalImageDescriptorVkForTesting : public ExternalImageDescriptorVk {

View File

@ -22,6 +22,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "dawn/native/vulkan/DeviceVk.h"
#include "dawn/tests/white_box/VulkanImageWrappingTests.h" #include "dawn/tests/white_box/VulkanImageWrappingTests.h"
namespace dawn::native::vulkan { namespace dawn::native::vulkan {
@ -80,7 +81,9 @@ class ExternalTextureDmaBuf : public VulkanImageWrappingTestBackend::ExternalTex
class VulkanImageWrappingTestBackendDmaBuf : public VulkanImageWrappingTestBackend { class VulkanImageWrappingTestBackendDmaBuf : public VulkanImageWrappingTestBackend {
public: public:
explicit VulkanImageWrappingTestBackendDmaBuf(const wgpu::Device& device) {} explicit VulkanImageWrappingTestBackendDmaBuf(const wgpu::Device& device) {
mDeviceVk = dawn::native::vulkan::ToBackend(dawn::native::FromAPI(device.Get()));
}
~VulkanImageWrappingTestBackendDmaBuf() { ~VulkanImageWrappingTestBackendDmaBuf() {
if (mGbmDevice != nullptr) { 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<ExternalTexture> CreateTexture(uint32_t width, std::unique_ptr<ExternalTexture> CreateTexture(uint32_t width,
uint32_t height, uint32_t height,
wgpu::TextureFormat format, wgpu::TextureFormat format,
@ -186,6 +197,7 @@ class VulkanImageWrappingTestBackendDmaBuf : public VulkanImageWrappingTestBacke
} }
gbm_device* mGbmDevice = nullptr; gbm_device* mGbmDevice = nullptr;
dawn::native::vulkan::Device* mDeviceVk;
}; };
// static // static
@ -195,4 +207,5 @@ std::unique_ptr<VulkanImageWrappingTestBackend> VulkanImageWrappingTestBackend::
backend->CreateGbmDevice(); backend->CreateGbmDevice();
return backend; return backend;
} }
} // namespace dawn::native::vulkan } // namespace dawn::native::vulkan

View File

@ -21,6 +21,7 @@
#include "dawn/native/vulkan/DeviceVk.h" #include "dawn/native/vulkan/DeviceVk.h"
#include "dawn/native/vulkan/FencedDeleter.h" #include "dawn/native/vulkan/FencedDeleter.h"
#include "dawn/native/vulkan/ResourceMemoryAllocatorVk.h" #include "dawn/native/vulkan/ResourceMemoryAllocatorVk.h"
#include "dawn/native/vulkan/UtilsVulkan.h"
#include "dawn/tests/white_box/VulkanImageWrappingTests.h" #include "dawn/tests/white_box/VulkanImageWrappingTests.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
@ -95,6 +96,11 @@ class VulkanImageWrappingTestBackendOpaqueFD : public VulkanImageWrappingTestBac
mDeviceVk = dawn::native::vulkan::ToBackend(dawn::native::FromAPI(device.Get())); 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<ExternalTexture> CreateTexture(uint32_t width, std::unique_ptr<ExternalTexture> CreateTexture(uint32_t width,
uint32_t height, uint32_t height,
wgpu::TextureFormat format, wgpu::TextureFormat format,
@ -141,6 +147,14 @@ class VulkanImageWrappingTestBackendOpaqueFD : public VulkanImageWrappingTestBac
descriptorOpaqueFD.memoryTypeIndex = textureOpaqueFD->memoryTypeIndex; descriptorOpaqueFD.memoryTypeIndex = textureOpaqueFD->memoryTypeIndex;
descriptorOpaqueFD.waitFDs = std::move(waitFDs); 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( return wgpu::Texture::Acquire(
dawn::native::vulkan::WrapVulkanImage(device.Get(), &descriptorOpaqueFD)); dawn::native::vulkan::WrapVulkanImage(device.Get(), &descriptorOpaqueFD));
} }
@ -167,17 +181,12 @@ class VulkanImageWrappingTestBackendOpaqueFD : public VulkanImageWrappingTestBac
uint32_t height, uint32_t height,
VkFormat format, VkFormat format,
VkImage* image) { 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 | auto usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT; VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkImageCreateInfo createInfo; VkImageCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
createInfo.pNext = &externalInfo; createInfo.pNext = nullptr;
createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR; createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR;
createInfo.imageType = VK_IMAGE_TYPE_2D; createInfo.imageType = VK_IMAGE_TYPE_2D;
createInfo.format = format; createInfo.format = format;
@ -191,6 +200,11 @@ class VulkanImageWrappingTestBackendOpaqueFD : public VulkanImageWrappingTestBac
createInfo.queueFamilyIndexCount = 0; createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr; createInfo.pQueueFamilyIndices = nullptr;
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 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); return deviceVk->fn.CreateImage(deviceVk->GetVkDevice(), &createInfo, nullptr, &**image);
} }
@ -205,19 +219,28 @@ class VulkanImageWrappingTestBackendOpaqueFD : public VulkanImageWrappingTestBac
VkMemoryRequirements requirements; VkMemoryRequirements requirements;
deviceVk->fn.GetImageMemoryRequirements(deviceVk->GetVkDevice(), handle, &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( int bestType = deviceVk->GetResourceMemoryAllocator()->FindBestTypeIndex(
requirements, MemoryKind::Opaque); requirements, MemoryKind::Opaque);
VkMemoryAllocateInfo allocateInfo; VkMemoryAllocateInfo allocateInfo;
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocateInfo.pNext = &externalInfo; allocateInfo.pNext = nullptr;
allocateInfo.allocationSize = requirements.size; allocateInfo.allocationSize = requirements.size;
allocateInfo.memoryTypeIndex = static_cast<uint32_t>(bestType); allocateInfo.memoryTypeIndex = static_cast<uint32_t>(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; *allocationSize = allocateInfo.allocationSize;
*memoryTypeIndex = allocateInfo.memoryTypeIndex; *memoryTypeIndex = allocateInfo.memoryTypeIndex;