From 45ba247b55ab46d7e95bcf0051f908058322d7e9 Mon Sep 17 00:00:00 2001 From: Per Inge Mathisen Date: Tue, 27 Apr 2021 13:52:27 +0200 Subject: [PATCH] Add support for rendering for the headless extension --- CMakeLists.txt | 3 +++ base/VulkanSwapChain.cpp | 10 +++++++- base/VulkanSwapChain.h | 4 +++- base/vulkanexamplebase.cpp | 44 ++++++++++++++++++++++++++++++++-- base/vulkanexamplebase.h | 6 ++++- examples/triangle/triangle.cpp | 6 +++++ 6 files changed, 68 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 029cee4f..dc4b33bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ include_directories(base) OPTION(USE_D2D_WSI "Build the project using Direct to Display swapchain" OFF) OPTION(USE_DIRECTFB_WSI "Build the project using DirectFB swapchain" OFF) OPTION(USE_WAYLAND_WSI "Build the project using Wayland swapchain" OFF) +OPTION(USE_HEADLESS "Build the project using headless extension swapchain" OFF) set(RESOURCE_INSTALL_DIR "" CACHE PATH "Path to install resources to (leave empty for running uninstalled)") @@ -79,6 +80,8 @@ ELSEIF(LINUX) execute_process(COMMAND ${WAYLAND_SCANNER} client-header ${protocol_dir}/stable/xdg-shell/xdg-shell.xml ${CMAKE_BINARY_DIR}/xdg-shell-client-protocol.h COMMAND ${WAYLAND_SCANNER} private-code ${protocol_dir}/stable/xdg-shell/xdg-shell.xml ${CMAKE_BINARY_DIR}/xdg-shell-protocol.c) include_directories(${CMAKE_BINARY_DIR}) + ELSEIF(USE_HEADLESS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_HEADLESS_EXT") ELSE(USE_D2D_WSI) find_package(XCB REQUIRED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_XCB_KHR") diff --git a/base/VulkanSwapChain.cpp b/base/VulkanSwapChain.cpp index 9ff00b5e..432fee10 100644 --- a/base/VulkanSwapChain.cpp +++ b/base/VulkanSwapChain.cpp @@ -23,7 +23,7 @@ void VulkanSwapChain::initSurface(wl_display *display, wl_surface *window) void VulkanSwapChain::initSurface(xcb_connection_t* connection, xcb_window_t window) #elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) void VulkanSwapChain::initSurface(void* view) -#elif defined(_DIRECT2DISPLAY) +#elif (defined(_DIRECT2DISPLAY) || defined(VK_USE_PLATFORM_HEADLESS_EXT)) void VulkanSwapChain::initSurface(uint32_t width, uint32_t height) #endif { @@ -75,6 +75,14 @@ void VulkanSwapChain::initSurface(uint32_t width, uint32_t height) surfaceCreateInfo.connection = connection; surfaceCreateInfo.window = window; err = vkCreateXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface); +#elif defined(VK_USE_PLATFORM_HEADLESS_EXT) + VkHeadlessSurfaceCreateInfoEXT surfaceCreateInfo = {}; + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT; + PFN_vkCreateHeadlessSurfaceEXT fpCreateHeadlessSurfaceEXT = (PFN_vkCreateHeadlessSurfaceEXT)vkGetInstanceProcAddr(instance, "vkCreateHeadlessSurfaceEXT"); + if (!fpCreateHeadlessSurfaceEXT){ + vks::tools::exitFatal("Could not fetch function pointer for the headless extension!", -1); + } + err = fpCreateHeadlessSurfaceEXT(instance, &surfaceCreateInfo, nullptr, &surface); #endif if (err != VK_SUCCESS) { diff --git a/base/VulkanSwapChain.h b/base/VulkanSwapChain.h index 67b72a52..686bf498 100644 --- a/base/VulkanSwapChain.h +++ b/base/VulkanSwapChain.h @@ -66,9 +66,11 @@ public: void initSurface(xcb_connection_t* connection, xcb_window_t window); #elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) void initSurface(void* view); -#elif defined(_DIRECT2DISPLAY) +#elif (defined(_DIRECT2DISPLAY) || defined(VK_USE_PLATFORM_HEADLESS_EXT)) void initSurface(uint32_t width, uint32_t height); +#if defined(_DIRECT2DISPLAY) void createDirect2DisplaySurface(uint32_t width, uint32_t height); +#endif #endif void connect(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device); void create(uint32_t* width, uint32_t* height, bool vsync = false); diff --git a/base/vulkanexamplebase.cpp b/base/vulkanexamplebase.cpp index 622a1667..c96ad438 100644 --- a/base/vulkanexamplebase.cpp +++ b/base/vulkanexamplebase.cpp @@ -51,6 +51,8 @@ VkResult VulkanExampleBase::createInstance(bool enableValidation) instanceExtensions.push_back(VK_MVK_IOS_SURFACE_EXTENSION_NAME); #elif defined(VK_USE_PLATFORM_MACOS_MVK) instanceExtensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_HEADLESS_EXT) + instanceExtensions.push_back(VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME); #endif // Get extensions supported by the instance and store for later use @@ -584,6 +586,40 @@ void VulkanExampleBase::renderLoop() } updateOverlay(); } +#elif defined(VK_USE_PLATFORM_HEADLESS_EXT) + while (!quit) + { + auto tStart = std::chrono::high_resolution_clock::now(); + if (viewUpdated) + { + viewUpdated = false; + viewChanged(); + } + render(); + frameCounter++; + auto tEnd = std::chrono::high_resolution_clock::now(); + auto tDiff = std::chrono::duration(tEnd - tStart).count(); + frameTimer = tDiff / 1000.0f; + camera.update(frameTimer); + if (camera.moving()) + { + viewUpdated = true; + } + // Convert to clamped timer value + timer += timerSpeed * frameTimer; + if (timer > 1.0) + { + timer -= 1.0f; + } + float fpsTimer = std::chrono::duration(tEnd - lastTimestamp).count(); + if (fpsTimer > 1000.0f) + { + lastFPS = (float)frameCounter * (1000.0f / fpsTimer); + frameCounter = 0; + lastTimestamp = tEnd; + } + updateOverlay(); + } #elif (defined(VK_USE_PLATFORM_MACOS_MVK) && defined(VK_EXAMPLE_XCODE_GENERATED)) [NSApp run]; #endif @@ -2425,6 +2461,10 @@ void VulkanExampleBase::handleEvent(const xcb_generic_event_t *event) break; } } +#else +void VulkanExampleBase::setupWindow() +{ +} #endif void VulkanExampleBase::viewChanged() {} @@ -2690,14 +2730,14 @@ void VulkanExampleBase::initSwapchain() swapChain.initSurface(androidApp->window); #elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) swapChain.initSurface(view); -#elif defined(_DIRECT2DISPLAY) - swapChain.initSurface(width, height); #elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) swapChain.initSurface(dfb, surface); #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) swapChain.initSurface(display, surface); #elif defined(VK_USE_PLATFORM_XCB_KHR) swapChain.initSurface(connection, window); +#elif (defined(_DIRECT2DISPLAY) || defined(VK_USE_PLATFORM_HEADLESS_EXT)) + swapChain.initSurface(width, height); #endif } diff --git a/base/vulkanexamplebase.h b/base/vulkanexamplebase.h index 34bc1fd1..12fe99d5 100644 --- a/base/vulkanexamplebase.h +++ b/base/vulkanexamplebase.h @@ -283,6 +283,8 @@ public: xcb_screen_t *screen; xcb_window_t window; xcb_intern_atom_reply_t *atom_wm_delete_window; +#elif defined(VK_USE_PLATFORM_HEADLESS_EXT) + bool quit = false; #endif VulkanExampleBase(bool enableValidation = false); @@ -356,6 +358,8 @@ public: xcb_window_t setupWindow(); void initxcbConnection(); void handleEvent(const xcb_generic_event_t *event); +#else + void setupWindow(); #endif /** @brief (Virtual) Creates the application wide Vulkan instance */ virtual VkResult createInstance(bool enableValidation); @@ -480,7 +484,7 @@ int main(const int argc, const char *argv[]) \ delete(vulkanExample); \ return 0; \ } -#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +#elif (defined(VK_USE_PLATFORM_WAYLAND_KHR) || defined(VK_USE_PLATFORM_HEADLESS_EXT)) #define VULKAN_EXAMPLE_MAIN() \ VulkanExample *vulkanExample; \ int main(const int argc, const char *argv[]) \ diff --git a/examples/triangle/triangle.cpp b/examples/triangle/triangle.cpp index f54487b0..093198e5 100644 --- a/examples/triangle/triangle.cpp +++ b/examples/triangle/triangle.cpp @@ -1188,6 +1188,7 @@ int main(const int argc, const char *argv[]) // Linux entry point VulkanExample *vulkanExample; +#if defined(VK_USE_PLATFORM_XCB_KHR) static void handleEvent(const xcb_generic_event_t *event) { if (vulkanExample != NULL) @@ -1195,6 +1196,11 @@ static void handleEvent(const xcb_generic_event_t *event) vulkanExample->handleEvent(event); } } +#else +static void handleEvent() +{ +} +#endif int main(const int argc, const char *argv[]) { for (size_t i = 0; i < argc; i++) { VulkanExample::args.push_back(argv[i]); };