blob: 79525b77f79ef9daff6646188b710acb17f2fddf [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#include <gtest/gtest.h>
#include "src/graphics/tests/common/vulkan_context.h"
class TestBase : public testing::Test {
public:
TestBase(std::vector<const char*> desired_device_extensions)
: desired_device_extensions_(std::move(desired_device_extensions)) {}
void SetUp() override {
auto app_info =
vk::ApplicationInfo().setPApplicationName("test").setApiVersion(VK_API_VERSION_1_1);
auto instance_info = vk::InstanceCreateInfo().setPApplicationInfo(&app_info);
constexpr uint32_t kPhysicalDeviceIndex = 0;
context_ = std::make_unique<VulkanContext>(kPhysicalDeviceIndex);
context_->set_instance_info(instance_info);
context_->set_validation_layers_enabled(false);
ASSERT_TRUE(context_->InitInstance());
loader_.init(*context_->instance(), vkGetInstanceProcAddr);
ASSERT_TRUE(context_->InitQueueFamily());
{
uint32_t ext_count = 0;
auto [result, extensions] = context_->physical_device().enumerateDeviceExtensionProperties();
EXPECT_EQ(result, vk::Result::eSuccess);
for (auto& extension : extensions) {
for (auto& desired : desired_device_extensions_) {
if (strcmp(extension.extensionName, desired) == 0) {
ext_count++;
}
}
}
if (ext_count != desired_device_extensions_.size()) {
fprintf(stderr, "Missing extension(s)\n");
GTEST_SKIP();
}
}
auto device_create_info = vk::DeviceCreateInfo()
.setQueueCreateInfoCount(1)
.setPQueueCreateInfos(&context_->queue_info())
.setPEnabledExtensionNames(desired_device_extensions_);
context_->set_device_info(std::move(device_create_info));
ASSERT_TRUE(context_->InitDevice());
}
std::vector<const char*> desired_device_extensions_;
std::unique_ptr<VulkanContext> context_;
vk::DispatchLoaderDynamic loader_;
};
// Test the vulkan semaphore external fd extension.
class TestVkExtSemFd : public TestBase {
public:
TestVkExtSemFd()
: TestBase({VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME}) {}
};
TEST_F(TestVkExtSemFd, SemaphoreExportThenImport) {
auto export_create_info = vk::ExportSemaphoreCreateInfo().setHandleTypes(
vk::ExternalSemaphoreHandleTypeFlagBits::eOpaqueFd);
auto create_info = vk::SemaphoreCreateInfo().setPNext(&export_create_info);
auto ret = context_->device()->createSemaphore(create_info);
ASSERT_EQ(vk::Result::eSuccess, ret.result);
vk::Semaphore& sem_export = ret.value;
int fd;
{
auto semaphore_get_info =
vk::SemaphoreGetFdInfoKHR()
.setSemaphore(sem_export)
.setHandleType(vk::ExternalSemaphoreHandleTypeFlagBits::eOpaqueFd);
auto export_ret = context_->device()->getSemaphoreFdKHR(semaphore_get_info, loader_);
ASSERT_EQ(vk::Result::eSuccess, export_ret.result);
fd = export_ret.value;
}
// TODO(https://fxbug.dev/42146493) - check non negative
EXPECT_NE(0, fd);
{
auto ret = context_->device()->createSemaphore(create_info);
ASSERT_EQ(vk::Result::eSuccess, ret.result);
vk::Semaphore& sem_import = ret.value;
auto semaphore_import_info =
vk::ImportSemaphoreFdInfoKHR()
.setSemaphore(sem_import)
.setHandleType(vk::ExternalSemaphoreHandleTypeFlagBits::eOpaqueFd)
.setFd(fd);
auto import_ret = context_->device()->importSemaphoreFdKHR(semaphore_import_info, loader_);
ASSERT_EQ(vk::Result::eSuccess, import_ret);
}
}
TEST_F(TestVkExtSemFd, FenceExportThenImport) {
auto export_create_info =
vk::ExportFenceCreateInfo().setHandleTypes(vk::ExternalFenceHandleTypeFlagBits::eOpaqueFd);
auto create_info = vk::FenceCreateInfo().setPNext(&export_create_info);
auto ret = context_->device()->createFence(create_info);
ASSERT_EQ(vk::Result::eSuccess, ret.result);
vk::Fence& fence_export = ret.value;
int fd;
{
auto fence_get_info = vk::FenceGetFdInfoKHR()
.setFence(fence_export)
.setHandleType(vk::ExternalFenceHandleTypeFlagBits::eOpaqueFd);
auto export_ret = context_->device()->getFenceFdKHR(fence_get_info, loader_);
ASSERT_EQ(vk::Result::eSuccess, export_ret.result);
fd = export_ret.value;
}
// TODO(https://fxbug.dev/42146493) - check non negative
EXPECT_NE(0, fd);
{
auto ret = context_->device()->createFence(create_info);
ASSERT_EQ(vk::Result::eSuccess, ret.result);
vk::Fence& fence_import = ret.value;
auto fence_import_info = vk::ImportFenceFdInfoKHR()
.setFence(fence_import)
.setHandleType(vk::ExternalFenceHandleTypeFlagBits::eOpaqueFd)
.setFd(fd);
auto import_ret = context_->device()->importFenceFdKHR(fence_import_info, loader_);
ASSERT_EQ(vk::Result::eSuccess, import_ret);
}
}
// Test the vulkan memory external fd extension.
class TestVkExtMemFd : public TestBase {
public:
TestVkExtMemFd() : TestBase({VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME}) {}
};
TEST_F(TestVkExtMemFd, ImageExport) {
constexpr uint32_t kDefaultWidth = 64;
constexpr uint32_t kDefaultHeight = 64;
constexpr vk::Format kDefaultVkFormat = vk::Format::eB8G8R8A8Unorm;
vk::UniqueImage image;
vk::UniqueDeviceMemory memory;
{
auto external_create_info = vk::ExternalMemoryImageCreateInfo().setHandleTypes(
vk::ExternalMemoryHandleTypeFlagBitsKHR::eOpaqueFd);
auto create_info = vk::ImageCreateInfo()
.setImageType(vk::ImageType::e2D)
.setFormat(kDefaultVkFormat)
.setExtent(vk::Extent3D(kDefaultWidth, kDefaultHeight, 1))
.setMipLevels(1)
.setArrayLayers(1)
.setSamples(vk::SampleCountFlagBits::e1)
.setTiling(vk::ImageTiling::eOptimal)
.setUsage(vk::ImageUsageFlagBits::eTransferSrc)
.setSharingMode(vk::SharingMode::eExclusive)
.setInitialLayout(vk::ImageLayout::eUndefined)
.setPNext(&external_create_info);
auto result = context_->device()->createImageUnique(create_info);
ASSERT_EQ(vk::Result::eSuccess, result.result);
image = std::move(result.value);
}
{
auto memory_reqs_chain =
context_->device()
->getImageMemoryRequirements2<vk::MemoryRequirements2, vk::MemoryDedicatedRequirements>(
image.get());
EXPECT_TRUE(
memory_reqs_chain.get<vk::MemoryDedicatedRequirements>().requiresDedicatedAllocation);
auto& mem_reqs = memory_reqs_chain.get<vk::MemoryRequirements2>().memoryRequirements;
uint32_t memory_type_index = __builtin_ctz(mem_reqs.memoryTypeBits);
auto dedicated_create_info = vk::MemoryDedicatedAllocateInfo().setImage(image.get());
auto export_create_info =
vk::ExportMemoryAllocateInfo()
.setHandleTypes(vk::ExternalMemoryHandleTypeFlagBitsKHR::eOpaqueFd)
.setPNext(&dedicated_create_info);
auto alloc_info = vk::MemoryAllocateInfo()
.setAllocationSize(mem_reqs.size)
.setMemoryTypeIndex(memory_type_index)
.setPNext(&export_create_info);
auto result = context_->device()->allocateMemoryUnique(alloc_info);
ASSERT_EQ(result.result, vk::Result::eSuccess);
memory = std::move(result.value);
ASSERT_EQ(vk::Result::eSuccess,
context_->device()->bindImageMemory(image.get(), memory.get(), 0u));
}
{
auto get_fd_info = vk::MemoryGetFdInfoKHR()
.setMemory(memory.get())
.setHandleType(vk::ExternalMemoryHandleTypeFlagBitsKHR::eOpaqueFd);
auto result = context_->device()->getMemoryFdKHR(get_fd_info, loader_);
ASSERT_EQ(result.result, vk::Result::eSuccess);
}
}