#include #include "SwapChainStateVk.h" #include "Standalone.h" #include "vulkan/VulkanDispatch.h" namespace gfxstream { namespace vk { namespace { class SwapChainStateVkTest : public ::testing::Test { protected: static void SetUpTestCase() { k_vk = vkDispatch(false); } void SetUp() override { // skip the test when testing without a window if (!shouldUseWindow()) { GTEST_SKIP(); } ASSERT_NE(k_vk, nullptr); createInstance(); createWindowAndSurface(); pickPhysicalDevice(); createLogicalDevice(); } void TearDown() override { if (shouldUseWindow()) { k_vk->vkDestroyDevice(m_vkDevice, nullptr); k_vk->vkDestroySurfaceKHR(m_vkInstance, m_vkSurface, nullptr); k_vk->vkDestroyInstance(m_vkInstance, nullptr); } } static VulkanDispatch* k_vk; static const uint32_t k_width = 0x100; static const uint32_t k_height = 0x100; OSWindow *m_window; VkInstance m_vkInstance = VK_NULL_HANDLE; VkSurfaceKHR m_vkSurface = VK_NULL_HANDLE; VkPhysicalDevice m_vkPhysicalDevice = VK_NULL_HANDLE; uint32_t m_swapChainQueueFamilyIndex = 0; VkDevice m_vkDevice = VK_NULL_HANDLE; private: void createInstance() { VkApplicationInfo appInfo = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pNext = nullptr, .pApplicationName = "emulator SwapChainStateVk unittest", .applicationVersion = VK_MAKE_VERSION(1, 0, 0), .pEngineName = "No Engine", .engineVersion = VK_MAKE_VERSION(1, 0, 0), .apiVersion = VK_API_VERSION_1_1}; auto extensions = SwapChainStateVk::getRequiredInstanceExtensions(); VkInstanceCreateInfo instanceCi = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = &appInfo, .enabledExtensionCount = static_cast(extensions.size()), .ppEnabledExtensionNames = extensions.data()}; ASSERT_EQ(k_vk->vkCreateInstance(&instanceCi, nullptr, &m_vkInstance), VK_SUCCESS); ASSERT_TRUE(m_vkInstance != VK_NULL_HANDLE); } void createWindowAndSurface() { m_window = createOrGetTestWindow(0, 0, k_width, k_height); ASSERT_NE(m_window, nullptr); #ifdef _WIN32 VkWin32SurfaceCreateInfoKHR surfaceCi = { .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, .hinstance = GetModuleHandle(nullptr), .hwnd = m_window->getNativeWindow()}; ASSERT_EQ(k_vk->vkCreateWin32SurfaceKHR(m_vkInstance, &surfaceCi, nullptr, &m_vkSurface), VK_SUCCESS); #elif defined(__linux__) VkXcbSurfaceCreateInfoKHR surfaceCi = { .sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, .pNext = nullptr, .flags = {}, .window = static_cast(m_window->getNativeWindow()), }; ASSERT_EQ(k_vk->vkCreateXcbSurfaceKHR(m_vkInstance, &surfaceCi, nullptr, &m_vkSurface), VK_SUCCESS); #elif defined(__APPLE__) VkMetalSurfaceCreateInfoEXT surfaceCi = { .sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT, .pNext = nullptr, .flags = {}, .pLayer = reinterpret_cast( m_window->getNativeWindow()), }; ASSERT_EQ(k_vk->vkCreateMetalSurfaceEXT(m_vkInstance, &surfaceCi, nullptr, &m_vkSurface), VK_SUCCESS); #endif } void pickPhysicalDevice() { uint32_t physicalDeviceCount = 0; ASSERT_EQ(k_vk->vkEnumeratePhysicalDevices( m_vkInstance, &physicalDeviceCount, nullptr), VK_SUCCESS); ASSERT_GT(physicalDeviceCount, 0); std::vector physicalDevices(physicalDeviceCount); ASSERT_EQ( k_vk->vkEnumeratePhysicalDevices(m_vkInstance, &physicalDeviceCount, physicalDevices.data()), VK_SUCCESS); for (const auto &device : physicalDevices) { uint32_t queueFamilyCount = 0; k_vk->vkGetPhysicalDeviceQueueFamilyProperties( device, &queueFamilyCount, nullptr); ASSERT_GT(queueFamilyCount, 0); uint32_t queueFamilyIndex = 0; for (; queueFamilyIndex < queueFamilyCount; queueFamilyIndex++) { if (!SwapChainStateVk::validateQueueFamilyProperties( *k_vk, device, m_vkSurface, queueFamilyIndex)) { continue; } if (!SwapChainStateVk::createSwapChainCi(*k_vk, m_vkSurface, device, k_width, k_height, {queueFamilyIndex})) { continue; } break; } if (queueFamilyIndex == queueFamilyCount) { continue; } m_swapChainQueueFamilyIndex = queueFamilyIndex; m_vkPhysicalDevice = device; return; } FAIL() << "Can't find a suitable VkPhysicalDevice."; } void createLogicalDevice() { const float queuePriority = 1.0f; VkDeviceQueueCreateInfo queueCi = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .queueFamilyIndex = m_swapChainQueueFamilyIndex, .queueCount = 1, .pQueuePriorities = &queuePriority}; VkPhysicalDeviceFeatures features = {}; const std::vector enabledDeviceExtensions = SwapChainStateVk::getRequiredDeviceExtensions(); VkDeviceCreateInfo deviceCi = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queueCi, .enabledLayerCount = 0, .enabledExtensionCount = static_cast(enabledDeviceExtensions.size()), .ppEnabledExtensionNames = enabledDeviceExtensions.data(), .pEnabledFeatures = &features}; ASSERT_EQ(k_vk->vkCreateDevice(m_vkPhysicalDevice, &deviceCi, nullptr, &m_vkDevice), VK_SUCCESS); ASSERT_TRUE(m_vkDevice != VK_NULL_HANDLE); } }; VulkanDispatch* SwapChainStateVkTest::k_vk = nullptr; TEST_F(SwapChainStateVkTest, init) { auto swapChainCi = SwapChainStateVk::createSwapChainCi( *k_vk, m_vkSurface, m_vkPhysicalDevice, k_width, k_height, {m_swapChainQueueFamilyIndex}); ASSERT_NE(swapChainCi, std::nullopt); std::unique_ptr swapChainState = SwapChainStateVk::createSwapChainVk(*k_vk, m_vkDevice, swapChainCi->mCreateInfo); } } // namespace } // namespace vk } // namespace gfxstream