1 #include <gtest/gtest.h>
2 
3 #include "SwapChainStateVk.h"
4 
5 #include "Standalone.h"
6 #include "vulkan/VulkanDispatch.h"
7 
8 namespace gfxstream {
9 namespace vk {
10 namespace {
11 
12 class SwapChainStateVkTest : public ::testing::Test {
13    protected:
SetUpTestCase()14     static void SetUpTestCase() { k_vk = vkDispatch(false); }
15 
SetUp()16     void SetUp() override {
17         // skip the test when testing without a window
18         if (!shouldUseWindow()) {
19             GTEST_SKIP();
20         }
21         ASSERT_NE(k_vk, nullptr);
22 
23         createInstance();
24         createWindowAndSurface();
25         pickPhysicalDevice();
26         createLogicalDevice();
27     }
28 
TearDown()29     void TearDown() override {
30         if (shouldUseWindow()) {
31             k_vk->vkDestroyDevice(m_vkDevice, nullptr);
32             k_vk->vkDestroySurfaceKHR(m_vkInstance, m_vkSurface, nullptr);
33             k_vk->vkDestroyInstance(m_vkInstance, nullptr);
34         }
35     }
36 
37     static VulkanDispatch* k_vk;
38     static const uint32_t k_width = 0x100;
39     static const uint32_t k_height = 0x100;
40 
41     OSWindow *m_window;
42     VkInstance m_vkInstance = VK_NULL_HANDLE;
43     VkSurfaceKHR m_vkSurface = VK_NULL_HANDLE;
44     VkPhysicalDevice m_vkPhysicalDevice = VK_NULL_HANDLE;
45     uint32_t m_swapChainQueueFamilyIndex = 0;
46     VkDevice m_vkDevice = VK_NULL_HANDLE;
47 
48    private:
createInstance()49     void createInstance() {
50         VkApplicationInfo appInfo = {
51             .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
52             .pNext = nullptr,
53             .pApplicationName = "emulator SwapChainStateVk unittest",
54             .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
55             .pEngineName = "No Engine",
56             .engineVersion = VK_MAKE_VERSION(1, 0, 0),
57             .apiVersion = VK_API_VERSION_1_1};
58         auto extensions = SwapChainStateVk::getRequiredInstanceExtensions();
59         VkInstanceCreateInfo instanceCi = {
60             .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
61             .pApplicationInfo = &appInfo,
62             .enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
63             .ppEnabledExtensionNames = extensions.data()};
64         ASSERT_EQ(k_vk->vkCreateInstance(&instanceCi, nullptr, &m_vkInstance),
65                   VK_SUCCESS);
66         ASSERT_TRUE(m_vkInstance != VK_NULL_HANDLE);
67     }
68 
createWindowAndSurface()69     void createWindowAndSurface() {
70         m_window = createOrGetTestWindow(0, 0, k_width, k_height);
71         ASSERT_NE(m_window, nullptr);
72 #ifdef _WIN32
73         VkWin32SurfaceCreateInfoKHR surfaceCi = {
74             .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
75             .hinstance = GetModuleHandle(nullptr),
76             .hwnd = m_window->getNativeWindow()};
77         ASSERT_EQ(k_vk->vkCreateWin32SurfaceKHR(m_vkInstance, &surfaceCi,
78                                                 nullptr, &m_vkSurface),
79                   VK_SUCCESS);
80 #elif defined(__linux__)
81         VkXcbSurfaceCreateInfoKHR surfaceCi = {
82             .sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
83             .pNext = nullptr,
84             .flags = {},
85             .window = static_cast<xcb_window_t>(m_window->getNativeWindow()),
86         };
87         ASSERT_EQ(k_vk->vkCreateXcbSurfaceKHR(m_vkInstance, &surfaceCi,
88                                               nullptr, &m_vkSurface),
89                   VK_SUCCESS);
90 #elif defined(__APPLE__)
91         VkMetalSurfaceCreateInfoEXT surfaceCi = {
92                 .sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT,
93                 .pNext = nullptr,
94                 .flags = {},
95                 .pLayer = reinterpret_cast<const CAMetalLayer*>(
96                         m_window->getNativeWindow()),
97         };
98         ASSERT_EQ(k_vk->vkCreateMetalSurfaceEXT(m_vkInstance, &surfaceCi,
99                                                 nullptr, &m_vkSurface),
100                   VK_SUCCESS);
101 #endif
102     }
103 
pickPhysicalDevice()104     void pickPhysicalDevice() {
105         uint32_t physicalDeviceCount = 0;
106         ASSERT_EQ(k_vk->vkEnumeratePhysicalDevices(
107                       m_vkInstance, &physicalDeviceCount, nullptr),
108                   VK_SUCCESS);
109         ASSERT_GT(physicalDeviceCount, 0);
110         std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
111         ASSERT_EQ(
112             k_vk->vkEnumeratePhysicalDevices(m_vkInstance, &physicalDeviceCount,
113                                              physicalDevices.data()),
114             VK_SUCCESS);
115         for (const auto &device : physicalDevices) {
116             uint32_t queueFamilyCount = 0;
117             k_vk->vkGetPhysicalDeviceQueueFamilyProperties(
118                 device, &queueFamilyCount, nullptr);
119             ASSERT_GT(queueFamilyCount, 0);
120             uint32_t queueFamilyIndex = 0;
121             for (; queueFamilyIndex < queueFamilyCount; queueFamilyIndex++) {
122                 if (!SwapChainStateVk::validateQueueFamilyProperties(
123                         *k_vk, device, m_vkSurface, queueFamilyIndex)) {
124                     continue;
125                 }
126                 if (!SwapChainStateVk::createSwapChainCi(*k_vk, m_vkSurface, device, k_width,
127                                                          k_height, {queueFamilyIndex})) {
128                     continue;
129                 }
130                 break;
131             }
132             if (queueFamilyIndex == queueFamilyCount) {
133                 continue;
134             }
135 
136             m_swapChainQueueFamilyIndex = queueFamilyIndex;
137             m_vkPhysicalDevice = device;
138             return;
139         }
140         FAIL() << "Can't find a suitable VkPhysicalDevice.";
141     }
142 
createLogicalDevice()143     void createLogicalDevice() {
144         const float queuePriority = 1.0f;
145         VkDeviceQueueCreateInfo queueCi = {
146             .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
147             .queueFamilyIndex = m_swapChainQueueFamilyIndex,
148             .queueCount = 1,
149             .pQueuePriorities = &queuePriority};
150         VkPhysicalDeviceFeatures features = {};
151         const std::vector<const char *> enabledDeviceExtensions =
152             SwapChainStateVk::getRequiredDeviceExtensions();
153         VkDeviceCreateInfo deviceCi = {
154             .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
155             .queueCreateInfoCount = 1,
156             .pQueueCreateInfos = &queueCi,
157             .enabledLayerCount = 0,
158             .enabledExtensionCount =
159                 static_cast<uint32_t>(enabledDeviceExtensions.size()),
160             .ppEnabledExtensionNames = enabledDeviceExtensions.data(),
161             .pEnabledFeatures = &features};
162         ASSERT_EQ(k_vk->vkCreateDevice(m_vkPhysicalDevice, &deviceCi, nullptr,
163                                        &m_vkDevice),
164                   VK_SUCCESS);
165         ASSERT_TRUE(m_vkDevice != VK_NULL_HANDLE);
166     }
167 };
168 
169 VulkanDispatch* SwapChainStateVkTest::k_vk = nullptr;
170 
TEST_F(SwapChainStateVkTest,init)171 TEST_F(SwapChainStateVkTest, init) {
172     auto swapChainCi = SwapChainStateVk::createSwapChainCi(
173         *k_vk, m_vkSurface, m_vkPhysicalDevice, k_width, k_height,
174         {m_swapChainQueueFamilyIndex});
175     ASSERT_NE(swapChainCi, std::nullopt);
176     std::unique_ptr<SwapChainStateVk> swapChainState =
177         SwapChainStateVk::createSwapChainVk(*k_vk, m_vkDevice, swapChainCi->mCreateInfo);
178 }
179 
180 }  // namespace
181 }  // namespace vk
182 }  // namespace gfxstream
183