blob: a27c8e089af555bce5b24de4de8a85eee6e3d9af [file] [log] [blame]
// Copyright 2018 The Chromium 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 <sys/eventfd.h>
#include "base/android/android_hardware_buffer_compat.h"
#include "base/android/scoped_hardware_buffer_handle.h"
#include "base/files/scoped_file.h"
#include "components/viz/common/gpu/vulkan_in_process_context_provider.h"
#include "gpu/vulkan/android/vulkan_implementation_android.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gpu {
class VulkanImplementationAndroidTest : public testing::Test {
public:
void SetUp() override {
// Create a vulkan implementation.
vk_implementation_ = std::make_unique<VulkanImplementationAndroid>();
ASSERT_TRUE(vk_implementation_);
// This call checks for all instance extensions. Let the test pass if this
// call fails since many bots would not have this extension present.
if (!vk_implementation_->InitializeVulkanInstance())
return;
// Create vulkan context provider. This call checks for all device
// extensions. Let the test pass if this call fails since many bots would
// not have this extension present.
vk_context_provider_ =
viz::VulkanInProcessContextProvider::Create(vk_implementation_.get());
if (!vk_context_provider_)
return;
// Get the VkDevice.
vk_device_ = vk_context_provider_->GetDeviceQueue()->GetVulkanDevice();
ASSERT_TRUE(vk_device_);
// Get the physical device.
vk_phy_device_ =
vk_context_provider_->GetDeviceQueue()->GetVulkanPhysicalDevice();
ASSERT_TRUE(vk_phy_device_);
}
void TearDown() override {
if (vk_context_provider_)
vk_context_provider_->Destroy();
vk_device_ = VK_NULL_HANDLE;
}
protected:
std::unique_ptr<VulkanImplementationAndroid> vk_implementation_;
scoped_refptr<viz::VulkanInProcessContextProvider> vk_context_provider_;
VkDevice vk_device_;
VkPhysicalDevice vk_phy_device_;
};
TEST_F(VulkanImplementationAndroidTest, ExportImportSyncFd) {
if (!vk_implementation_ || !vk_context_provider_)
return;
// Create a vk semaphore which can be exported.
// To create a semaphore whose payload can be exported to external handles,
// add the VkExportSemaphoreCreateInfo structure to the pNext chain of the
// VkSemaphoreCreateInfo structure.
VkExportSemaphoreCreateInfo export_info;
export_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
export_info.pNext = nullptr;
export_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
VkSemaphore semaphore1;
VkSemaphoreCreateInfo sem_info;
sem_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
sem_info.pNext = &export_info;
sem_info.flags = 0;
bool result = vkCreateSemaphore(vk_device_, &sem_info, nullptr, &semaphore1);
EXPECT_EQ(result, VK_SUCCESS);
// SYNC_FD semaphores must be signalled or have an associated semaphore
// signal operation pending execution before the export.
// Semaphores can be signaled by including them in a batch as part of a queue
// submission command, defining a queue operation to signal that semaphore.
unsigned int submit_count = 1;
VkFence fence = VK_NULL_HANDLE;
VkSubmitInfo submit_info = {VK_STRUCTURE_TYPE_SUBMIT_INFO};
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &semaphore1;
result =
vkQueueSubmit(vk_context_provider_->GetDeviceQueue()->GetVulkanQueue(),
submit_count, &submit_info, fence);
EXPECT_EQ(result, VK_SUCCESS);
// Export a sync fd from the semaphore.
base::ScopedFD sync_fd;
EXPECT_TRUE(
vk_implementation_->GetSemaphoreFdKHR(vk_device_, semaphore1, &sync_fd));
EXPECT_GT(sync_fd.get(), -1);
// Import the above sync fd into a new semaphore.
VkSemaphore semaphore2;
EXPECT_TRUE(vk_implementation_->ImportSemaphoreFdKHR(
vk_device_, std::move(sync_fd), &semaphore2));
// Wait for the device to be idle.
result = vkDeviceWaitIdle(vk_device_);
EXPECT_EQ(result, VK_SUCCESS);
// Destroy the semaphores.
vkDestroySemaphore(vk_device_, semaphore1, nullptr);
vkDestroySemaphore(vk_device_, semaphore2, nullptr);
}
TEST_F(VulkanImplementationAndroidTest, CreateVkImageFromAHB) {
if (!vk_implementation_ || !vk_context_provider_)
return;
// Setup and Create an AHardwareBuffer.
AHardwareBuffer* buffer = nullptr;
AHardwareBuffer_Desc hwb_desc;
hwb_desc.width = 128;
hwb_desc.height = 128;
hwb_desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
hwb_desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
hwb_desc.layers = 1;
hwb_desc.stride = 0;
hwb_desc.rfu0 = 0;
hwb_desc.rfu1 = 0;
// Allocate an AHardwareBuffer.
base::AndroidHardwareBufferCompat::GetInstance().Allocate(&hwb_desc, &buffer);
EXPECT_TRUE(buffer);
// Create a vkimage and import the AHB into it.
const gfx::Size size(hwb_desc.width, hwb_desc.height);
VkImage vk_image;
VkImageCreateInfo vk_image_info;
VkDeviceMemory vk_device_memory;
VkDeviceSize mem_allocation_size;
EXPECT_TRUE(vk_implementation_->CreateVkImageAndImportAHB(
vk_device_, vk_phy_device_, size,
base::android::ScopedHardwareBufferHandle::Adopt(buffer), &vk_image,
&vk_image_info, &vk_device_memory, &mem_allocation_size));
// Free up resources.
vkDestroyImage(vk_device_, vk_image, nullptr);
vkFreeMemory(vk_device_, vk_device_memory, nullptr);
}
} // namespace gpu