blob: f1cee0070b80f42a2dbce58870e77ab91163bdf2 [file] [log] [blame]
// Copyright 2018 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 "garnet/lib/vulkan/src/swapchain/image_pipe_surface.h"
#include "gtest/gtest.h"
class MockImagePipeSurface : public image_pipe_swapchain::ImagePipeSurface {
public:
void AddImage(uint32_t image_id, fuchsia::images::ImageInfo image_info,
zx::vmo buffer, uint64_t size_bytes) override {}
void RemoveImage(uint32_t image_id) override {}
void PresentImage(uint32_t image_id,
std::vector<zx::event> acquire_fences,
std::vector<zx::event> release_fences) override {
presented_.push_back(
{image_id, std::move(acquire_fences), std::move(release_fences)});
}
struct Presented {
uint32_t image_id;
std::vector<zx::event> acquire_fences;
std::vector<zx::event> release_fences;
};
std::vector<Presented> presented_;
};
class TestSwapchain {
public:
template <class T>
void LoadProc(T* proc, const char* name) {
auto get_device_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
vkGetInstanceProcAddr(vk_instance_, "vkGetDeviceProcAddr"));
*proc = reinterpret_cast<T>(get_device_proc_addr(vk_device_, name));
}
TestSwapchain() {
std::vector<const char*> instance_layers{
"VK_LAYER_GOOGLE_image_pipe_swapchain"};
std::vector<const char*> instance_ext{VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_MAGMA_SURFACE_EXTENSION_NAME};
std::vector<const char*> device_ext{VK_KHR_SWAPCHAIN_EXTENSION_NAME};
VkInstanceCreateInfo inst_info = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = nullptr,
.pApplicationInfo = nullptr,
.enabledLayerCount = static_cast<uint32_t>(instance_layers.size()),
.ppEnabledLayerNames = instance_layers.data(),
.enabledExtensionCount = static_cast<uint32_t>(instance_ext.size()),
.ppEnabledExtensionNames = instance_ext.data(),
};
if (VK_SUCCESS != vkCreateInstance(&inst_info, nullptr, &vk_instance_))
return;
uint32_t gpu_count = 1;
std::vector<VkPhysicalDevice> physical_devices(gpu_count);
if (VK_SUCCESS != vkEnumeratePhysicalDevices(vk_instance_, &gpu_count,
physical_devices.data()))
return;
float queue_priorities[1] = {0.0};
VkDeviceQueueCreateInfo queue_create_info = {
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.pNext = nullptr,
.queueFamilyIndex = 0,
.queueCount = 1,
.pQueuePriorities = queue_priorities,
.flags = 0};
std::vector<const char*> enabled_layers{
"VK_LAYER_GOOGLE_image_pipe_swapchain"};
VkDeviceCreateInfo device_create_info = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = nullptr,
.queueCreateInfoCount = 1,
.pQueueCreateInfos = &queue_create_info,
.enabledLayerCount = 0,
.ppEnabledLayerNames = nullptr,
.enabledExtensionCount = static_cast<uint32_t>(device_ext.size()),
.ppEnabledExtensionNames = device_ext.data(),
.pEnabledFeatures = nullptr};
if (VK_SUCCESS != vkCreateDevice(physical_devices[0], &device_create_info,
nullptr, &vk_device_))
return;
PFN_vkGetDeviceProcAddr get_device_proc_addr =
reinterpret_cast<PFN_vkGetDeviceProcAddr>(
vkGetInstanceProcAddr(vk_instance_, "vkGetDeviceProcAddr"));
if (!get_device_proc_addr) {
fprintf(stderr, "Failed to find vkGetDeviceProcAddr\n");
return;
}
LoadProc(&create_swapchain_khr_, "vkCreateSwapchainKHR");
LoadProc(&destroy_swapchain_khr_, "vkDestroySwapchainKHR");
LoadProc(&get_swapchain_images_khr_, "vkGetSwapchainImagesKHR");
LoadProc(&acquire_next_image_khr_, "vkAcquireNextImageKHR");
LoadProc(&queue_present_khr_, "vkQueuePresentKHR");
init_ = true;
}
VkResult CreateSwapchainHelper(VkSurfaceKHR surface,
VkSwapchainKHR* swapchain_out) {
VkSwapchainCreateInfoKHR create_info = {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = nullptr,
.flags = 0,
.surface = surface,
.minImageCount = 3,
.imageFormat = VK_FORMAT_B8G8R8A8_UNORM,
.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
.imageArrayLayers = 1,
.imageExtent = {100, 100},
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
.presentMode = VK_PRESENT_MODE_FIFO_KHR,
.clipped = VK_TRUE,
.oldSwapchain = VK_NULL_HANDLE,
};
return create_swapchain_khr_(vk_device_, &create_info, nullptr,
swapchain_out);
}
void Surface() {
zx::channel endpoint0, endpoint1;
EXPECT_EQ(ZX_OK, zx::channel::create(0, &endpoint0, &endpoint1));
VkMagmaSurfaceCreateInfoKHR create_info = {
.sType = VK_STRUCTURE_TYPE_MAGMA_SURFACE_CREATE_INFO_KHR,
.imagePipeHandle = endpoint0.release(),
.pNext = nullptr,
};
VkSurfaceKHR surface;
EXPECT_EQ(VK_SUCCESS, vkCreateMagmaSurfaceKHR(vk_instance_, &create_info,
nullptr, &surface));
vkDestroySurfaceKHR(vk_instance_, surface, nullptr);
}
void CreateSwapchain() {
zx::channel endpoint0, endpoint1;
EXPECT_EQ(ZX_OK, zx::channel::create(0, &endpoint0, &endpoint1));
VkMagmaSurfaceCreateInfoKHR create_info = {
.sType = VK_STRUCTURE_TYPE_MAGMA_SURFACE_CREATE_INFO_KHR,
.imagePipeHandle = endpoint0.release(),
.pNext = nullptr,
};
VkSurfaceKHR surface;
EXPECT_EQ(VK_SUCCESS, vkCreateMagmaSurfaceKHR(vk_instance_, &create_info,
nullptr, &surface));
VkSwapchainKHR swapchain;
EXPECT_EQ(VK_SUCCESS, CreateSwapchainHelper(surface, &swapchain));
destroy_swapchain_khr_(vk_device_, swapchain, nullptr);
vkDestroySurfaceKHR(vk_instance_, surface, nullptr);
}
void AcquireNoSemaphore() {
ASSERT_TRUE(init_);
MockImagePipeSurface surface;
VkSwapchainKHR swapchain;
ASSERT_EQ(VK_SUCCESS,
CreateSwapchainHelper(reinterpret_cast<VkSurfaceKHR>(&surface),
&swapchain));
uint32_t image_index;
EXPECT_EQ(VK_SUCCESS,
acquire_next_image_khr_(vk_device_, swapchain, 0, VK_NULL_HANDLE,
VK_NULL_HANDLE, &image_index));
EXPECT_EQ(0u, image_index);
EXPECT_EQ(VK_SUCCESS,
acquire_next_image_khr_(vk_device_, swapchain, 0, VK_NULL_HANDLE,
VK_NULL_HANDLE, &image_index));
EXPECT_EQ(1u, image_index);
EXPECT_EQ(VK_SUCCESS,
acquire_next_image_khr_(vk_device_, swapchain, 0, VK_NULL_HANDLE,
VK_NULL_HANDLE, &image_index));
EXPECT_EQ(2u, image_index);
EXPECT_EQ(VK_NOT_READY,
acquire_next_image_khr_(vk_device_, swapchain, 0, VK_NULL_HANDLE,
VK_NULL_HANDLE, &image_index));
VkQueue queue;
vkGetDeviceQueue(vk_device_, 0, 0, &queue);
uint32_t present_index = 0;
VkResult present_result;
VkPresentInfoKHR present_info = {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.pNext = nullptr,
.waitSemaphoreCount = 0,
.pWaitSemaphores = nullptr,
.swapchainCount = 1,
.pSwapchains = &swapchain,
.pImageIndices = &present_index,
.pResults = &present_result,
};
EXPECT_EQ(VK_SUCCESS, queue_present_khr_(queue, &present_info));
EXPECT_EQ(1u, surface.presented_.size());
EXPECT_EQ(1u, surface.presented_[0].acquire_fences.size());
ASSERT_EQ(1u, surface.presented_[0].release_fences.size());
surface.presented_[0].release_fences[0].signal(0, ZX_EVENT_SIGNALED);
surface.presented_.erase(surface.presented_.begin());
EXPECT_EQ(VK_SUCCESS,
acquire_next_image_khr_(vk_device_, swapchain, 0, VK_NULL_HANDLE,
VK_NULL_HANDLE, &image_index));
EXPECT_EQ(0u, image_index);
EXPECT_EQ(VK_NOT_READY,
acquire_next_image_khr_(vk_device_, swapchain, 0, VK_NULL_HANDLE,
VK_NULL_HANDLE, &image_index));
}
VkInstance vk_instance_;
VkDevice vk_device_;
PFN_vkCreateSwapchainKHR create_swapchain_khr_;
PFN_vkDestroySwapchainKHR destroy_swapchain_khr_;
PFN_vkGetSwapchainImagesKHR get_swapchain_images_khr_;
PFN_vkAcquireNextImageKHR acquire_next_image_khr_;
PFN_vkQueuePresentKHR queue_present_khr_;
bool init_ = false;
};
TEST(Swapchain, AcquireNoSemaphore) { TestSwapchain().AcquireNoSemaphore(); }
TEST(Swapchain, Surface) { TestSwapchain().Surface(); }
TEST(Swapchain, Create) { TestSwapchain().CreateSwapchain(); }