diff --git a/.gitignore b/.gitignore index 260b4ef..5e1f38c 100644 --- a/.gitignore +++ b/.gitignore @@ -30,10 +30,3 @@ /Vulkan-Tools-sdk-1.3.283.0.tar.gz /Vulkan-Tools-sdk-1.3.290.0.tar.gz /Vulkan-Tools-sdk-1.3.296.0.tar.gz -/Vulkan-Tools-sdk-1.4.304.0.tar.gz -/Vulkan-Tools-sdk-1.4.309.0.tar.gz -/Vulkan-Tools-sdk-1.4.313.0.tar.gz -/Vulkan-Tools-sdk-1.4.321.0.tar.gz -/Vulkan-Tools-sdk-1.4.328.1.tar.gz -/Vulkan-Tools-sdk-1.4.341.0.tar.gz -/Vulkan-Tools-sdk-1.4.350.0.tar.gz diff --git a/.packit.yaml b/.packit.yaml deleted file mode 100644 index 06febbe..0000000 --- a/.packit.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# packit config for vulkan-tools -# Build Stage 4 - depends on glslang, vulkan-volk - -jobs: - - job: koji_build - trigger: commit | koji_build - allowed_committers: [all_admins] - dist_git_branches: - - fedora-all - sidetag_group: vulkan-sdk-releases - dependencies: - - glslang - - vulkan-volk diff --git a/0001-cube-Support-runtime-selection-of-WSI-platform.patch b/0001-cube-Support-runtime-selection-of-WSI-platform.patch new file mode 100644 index 0000000..0256e42 --- /dev/null +++ b/0001-cube-Support-runtime-selection-of-WSI-platform.patch @@ -0,0 +1,4020 @@ +From f12bc32cddc33f4a37735929632c1a7bb8051755 Mon Sep 17 00:00:00 2001 +From: Charles Giessen +Date: Thu, 5 Sep 2024 12:43:39 -0500 +Subject: [PATCH] cube: Support runtime selection of WSI platform + +By changing the selection of a WSI platform from a build time choice to a +runtime choice, this allows the removal of vkcube-wayland as a separate +binary. + +Use `--wsi ` to choose the WSI platform that vkcube will render +with. The chosen platform must be one that vkcube was compiled with +support for, so directfb will be unavailable without changing the build +parameters to enable it. + +These changes have been made to both vkcube and vkcubepp. + +This includes enabling VK_KHR_display where applicable, which is supported +on linux and windows at the current time. +--- + cube/CMakeLists.txt | 211 ++-- + cube/android/CMakeLists.txt | 2 +- + cube/cube.c | 1626 ++++++++++++++++++++---------- + cube/cube.cpp | 915 ++++++++++++----- + cube/macOS/cube/CMakeLists.txt | 2 +- + cube/macOS/cubepp/CMakeLists.txt | 2 +- + cube/wayland_loader.h | 124 +++ + cube/xcb_loader.h | 129 +++ + cube/xlib_loader.h | 109 ++ + 10 files changed, 2250 insertions(+), 890 deletions(-) + create mode 100644 cube/wayland_loader.h + create mode 100644 cube/xcb_loader.h + create mode 100644 cube/xlib_loader.h + +diff --git a/cube/CMakeLists.txt b/cube/CMakeLists.txt +index 880cf741..4ecd3e36 100644 +--- a/cube/CMakeLists.txt ++++ b/cube/CMakeLists.txt +@@ -61,32 +61,58 @@ if(APPLE) + endif() + endif() + ++if(ANDROID OR APPLE) ++ set(WSI_DISPLAY_DEFAULT_SETTING "OFF") ++else() ++ set(WSI_DISPLAY_DEFAULT_SETTING "ON") ++endif() ++ ++option(BUILD_WSI_DISPLAY_SUPPORT "Build DISPLAY WSI support" ${WSI_DISPLAY_DEFAULT_SETTING}) ++ + if (CMAKE_SYSTEM_NAME MATCHES "Linux|BSD|GNU") + option(BUILD_WSI_XCB_SUPPORT "Build XCB WSI support" ON) + option(BUILD_WSI_XLIB_SUPPORT "Build Xlib WSI support" ON) + option(BUILD_WSI_WAYLAND_SUPPORT "Build Wayland WSI support" ON) + option(BUILD_WSI_DIRECTFB_SUPPORT "Build DirectFB WSI support" OFF) +- set(CUBE_WSI_SELECTION "XCB" CACHE STRING "Select WSI target for vkcube (XCB, XLIB, WAYLAND, DIRECTFB, DISPLAY)") + + find_package(PkgConfig REQUIRED QUIET) # Use PkgConfig to find Linux system libraries + + if(BUILD_WSI_XCB_SUPPORT) + pkg_check_modules(XCB REQUIRED QUIET IMPORTED_TARGET xcb) ++ pkg_get_variable(XCB_INCLUDE_DIRS xcb includedir) ++ message(DEBUG "XCB_INCLUDE_DIRS = ${XCB_INCLUDE_DIRS}") + endif() + + if(BUILD_WSI_XLIB_SUPPORT) + pkg_check_modules(X11 REQUIRED QUIET IMPORTED_TARGET x11) ++ pkg_get_variable(XLIB_INCLUDE_DIRS x11 includedir) ++ message(DEBUG "XLIB_INCLUDE_DIRS = ${XLIB_INCLUDE_DIRS}") + endif() + + if(BUILD_WSI_WAYLAND_SUPPORT) + pkg_check_modules(WAYLAND_CLIENT REQUIRED IMPORTED_TARGET wayland-client) ++ pkg_get_variable(WAYLAND_INCLUDE_DIRS wayland-client includedir) + + pkg_get_variable(WAYLAND_SCANNER_EXECUTABLE wayland-scanner wayland_scanner) +- message(STATUS "WAYLAND_SCANNER_EXECUTABLE = ${WAYLAND_SCANNER_EXECUTABLE}") ++ message(DEBUG "WAYLAND_SCANNER_EXECUTABLE = ${WAYLAND_SCANNER_EXECUTABLE}") ++ ++ pkg_get_variable(WAYLAND_CLIENT_PATH wayland-client pkgdatadir) ++ message(DEBUG "WAYLAND_CLIENT_PATH = ${WAYLAND_CLIENT_PATH}") ++ set(WAYLAND_CODE_PROTOCOL ${WAYLAND_CLIENT_PATH}/wayland.xml) + + pkg_get_variable(WAYLAND_PROTOCOLS_PATH wayland-protocols pkgdatadir) +- message(STATUS "WAYLAND_PROTOCOLS_PATH = ${WAYLAND_PROTOCOLS_PATH}") ++ message(DEBUG "WAYLAND_PROTOCOLS_PATH = ${WAYLAND_PROTOCOLS_PATH}") + set(XDG_SHELL_PROTOCOL ${WAYLAND_PROTOCOLS_PATH}/stable/xdg-shell/xdg-shell.xml) ++ ++ add_custom_command(COMMENT "Generating wayland client protocol dispatch data" ++ OUTPUT wayland-client.c ++ COMMAND ${WAYLAND_SCANNER_EXECUTABLE} ++ private-code ++ ${WAYLAND_CODE_PROTOCOL} ++ ${CMAKE_CURRENT_BINARY_DIR}/wayland-client.c ++ MAIN_DEPENDENCY ${WAYLAND_CODE_PROTOCOL} ++ DEPENDS ${WAYLAND_CODE_PROTOCOL} ${WAYLAND_SCANNER_EXECUTABLE}) ++ + add_custom_command(COMMENT "Generating xdg-shell protocol dispatch data" + OUTPUT xdg-shell-code.c + COMMAND ${WAYLAND_SCANNER_EXECUTABLE} +@@ -121,6 +147,12 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux|BSD|GNU") + ${CMAKE_CURRENT_BINARY_DIR}/xdg-decoration-client-header.h + MAIN_DEPENDENCY ${XDG_DECORATION_PROTOCOL} + DEPENDS ${XDG_DECORATION_PROTOCOL} ${WAYLAND_SCANNER_EXECUTABLE}) ++ ++ set(WAYLAND_ADDITIONAL_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/wayland-client.c ++ ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-code.c ++ ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-header.h ++ ${CMAKE_CURRENT_BINARY_DIR}/xdg-decoration-code.c ++ ${CMAKE_CURRENT_BINARY_DIR}/xdg-decoration-client-header.h) + endif() + + if(BUILD_WSI_DIRECTFB_SUPPORT) +@@ -128,59 +160,39 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux|BSD|GNU") + endif() + endif() + ++if(BUILD_WSI_DISPLAY_SUPPORT) ++ list(APPEND ENABLED_CUBE_PLATFORMS VK_USE_PLATFORM_DISPLAY_KHR) ++endif() ++ + if(WIN32) +- add_definitions(-DVK_USE_PLATFORM_WIN32_KHR -DWIN32_LEAN_AND_MEAN -DNOMINMAX) ++ add_definitions(-DWIN32_LEAN_AND_MEAN -DNOMINMAX) ++ list(APPEND ENABLED_CUBE_PLATFORMS VK_USE_PLATFORM_WIN32_KHR) + elseif(ANDROID) +- add_definitions(-DVK_USE_PLATFORM_ANDROID_KHR) ++ list(APPEND ENABLED_CUBE_PLATFORMS VK_USE_PLATFORM_ANDROID_KHR) + elseif(APPLE) +- add_definitions(-DVK_USE_PLATFORM_METAL_EXT) ++ list(APPEND ENABLED_CUBE_PLATFORMS VK_USE_PLATFORM_METAL_EXT) + elseif(CMAKE_SYSTEM_NAME MATCHES "Linux|BSD|GNU") +- if(NOT CUBE_WSI_SELECTION) +- set(CUBE_WSI_SELECTION "XCB") ++ if(BUILD_WSI_XCB_SUPPORT) ++ list(APPEND ENABLED_CUBE_PLATFORMS VK_USE_PLATFORM_XCB_KHR) + endif() +- +- if(CUBE_WSI_SELECTION STREQUAL "XCB") +- if(NOT BUILD_WSI_XCB_SUPPORT) +- message(FATAL_ERROR "Selected XCB for vkcube build but not building Xcb support") +- endif() +- link_libraries(PkgConfig::XCB) +- set(CUBE_PLATFORM VK_USE_PLATFORM_XCB_KHR) +- elseif(CUBE_WSI_SELECTION STREQUAL "XLIB") +- if(NOT BUILD_WSI_XLIB_SUPPORT) +- message(FATAL_ERROR "Selected XLIB for vkcube build but not building Xlib support") +- endif() +- link_libraries(PkgConfig::X11) +- set(CUBE_PLATFORM VK_USE_PLATFORM_XLIB_KHR) +- elseif(CUBE_WSI_SELECTION STREQUAL "WAYLAND") +- if(NOT BUILD_WSI_WAYLAND_SUPPORT) +- message(FATAL_ERROR "Selected Wayland for vkcube build but not building Wayland support") +- endif() +- link_libraries(PkgConfig::WAYLAND_CLIENT) +- set(CUBE_PLATFORM VK_USE_PLATFORM_WAYLAND_KHR) +- set(XDG_SHELL_PROTOCOL ${WAYLAND_PROTOCOLS_PATH}/stable/xdg-shell/xdg-shell.xml) +- set(OPTIONAL_WAYLAND_DATA_FILES +- ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-code.c +- ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-header.h +- ${CMAKE_CURRENT_BINARY_DIR}/xdg-decoration-code.c +- ${CMAKE_CURRENT_BINARY_DIR}/xdg-decoration-client-header.h) +- include_directories(${CMAKE_CURRENT_BINARY_DIR}) +- elseif(CUBE_WSI_SELECTION STREQUAL "DIRECTFB") +- if(NOT BUILD_WSI_DIRECTFB_SUPPORT) +- message(FATAL_ERROR "Selected DIRECTFB for vkcube build but not building DirectFB support") +- endif() +- link_libraries(PkgConfig::DirectFB) +- set(CUBE_PLATFORM VK_USE_PLATFORM_DIRECTFB_EXT) +- elseif(CUBE_WSI_SELECTION STREQUAL "DISPLAY") +- set(CUBE_PLATFORM VK_USE_PLATFORM_DISPLAY_KHR) +- else() +- message(FATAL_ERROR "Unrecognized value for CUBE_WSI_SELECTION: ${CUBE_WSI_SELECTION}") ++ if(BUILD_WSI_XLIB_SUPPORT) ++ list(APPEND ENABLED_CUBE_PLATFORMS VK_USE_PLATFORM_XLIB_KHR) ++ endif() ++ if(BUILD_WSI_WAYLAND_SUPPORT) ++ list(APPEND ENABLED_CUBE_PLATFORMS VK_USE_PLATFORM_WAYLAND_KHR) ++ endif() ++ if(BUILD_WSI_DIRECTFB_SUPPORT) ++ list(APPEND ENABLED_CUBE_PLATFORMS VK_USE_PLATFORM_DIRECTFB_EXT) + endif() +- + link_libraries(${API_LOWERCASE} m) + else() + message(FATAL_ERROR "Unsupported Platform!") + endif() + ++if(NOT DEFINED ENABLED_CUBE_PLATFORMS) ++ message(FATAL_ERROR "There are no supported WSI platforms on this system, vkcube requires a WSI platform be available to be able to render its output") ++endif() ++ + if (COMPILE_CUBE_SHADERS) + # Try to find glslang in system paths or in an SDK if the VULKAN_SDK env-var is set + find_program(GLSLANG_VALIDATOR names glslang glslangValidator HINTS $ENV{GLSLANG_INSTALL_DIR} $ENV{VULKAN_SDK}/bin $ENV{VULKAN_SDK}/Bin) +@@ -226,7 +238,6 @@ elseif (ANDROID) + + add_subdirectory(android) + +- target_link_libraries(vkcube PRIVATE Vulkan::Headers volk::volk_headers) + elseif(CMAKE_SYSTEM_NAME MATCHES "Linux|BSD|GNU") + add_executable(vkcube) + target_sources(vkcube PRIVATE +@@ -235,15 +246,28 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Linux|BSD|GNU") + ${PROJECT_SOURCE_DIR}/cube/cube.frag + cube.vert.inc + cube.frag.inc +- ${OPTIONAL_WAYLAND_DATA_FILES} + ) +- target_compile_definitions(vkcube PUBLIC ${CUBE_PLATFORM}) ++ target_link_libraries(vkcube Threads::Threads) ++ if(BUILD_WSI_XCB_SUPPORT) ++ target_sources(vkcube PRIVATE xcb_loader.h) ++ target_include_directories(vkcube PRIVATE ${xcb_INCLUDE_DIRS}) ++ endif() ++ if(BUILD_WSI_XLIB_SUPPORT) ++ target_sources(vkcube PRIVATE xlib_loader.h) ++ target_include_directories(vkcube PRIVATE ${XLIB_INCLUDE_DIRS}) ++ endif() ++ if(BUILD_WSI_WAYLAND_SUPPORT) ++ target_include_directories(vkcube PRIVATE ${WAYLAND_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) ++ target_sources(vkcube PRIVATE PRIVATE ${WAYLAND_ADDITIONAL_SOURCES}) ++ endif() ++ if(BUILD_WSI_DIRECTFB_SUPPORT) ++ target_link_libraries(vkcube PkgConfig::DirectFB) ++ endif() + include(CheckLibraryExists) + CHECK_LIBRARY_EXISTS("rt" clock_gettime "" NEED_RT) + if (NEED_RT) +- target_link_libraries(vkcube PRIVATE rt) ++ target_link_libraries(vkcube rt) + endif() +- target_link_libraries(vkcube PRIVATE Vulkan::Headers volk::volk_headers Threads::Threads) + elseif(WIN32) + add_executable(vkcube WIN32) + target_sources(vkcube PRIVATE +@@ -253,12 +277,13 @@ elseif(WIN32) + cube.vert.inc + cube.frag.inc + ) +- target_link_libraries(vkcube PRIVATE Vulkan::Headers volk::volk_headers) + else() + message(FATAL_ERROR "Unsupported Platform!") + endif() + ++target_compile_definitions(vkcube PRIVATE ${ENABLED_CUBE_PLATFORMS}) + target_include_directories(vkcube PRIVATE .) ++target_link_libraries(vkcube Vulkan::Headers volk::volk_headers) + + if (ANDROID) + install(TARGETS vkcube DESTINATION ${CMAKE_INSTALL_LIBDIR}) +@@ -280,6 +305,16 @@ if (ANDROID) + return() + endif() + ++if (XCB_LINK_LIBRARIES) ++ target_compile_definitions(vkcube PRIVATE "XCB_LIBRARY=\"${XCB_LINK_LIBRARIES}\"") ++endif() ++if (X11_LINK_LIBRARIES) ++ target_compile_definitions(vkcube PRIVATE "XLIB_LIBRARY=\"${X11_LINK_LIBRARIES}\"") ++endif() ++if (WAYLAND_CLIENT_LINK_LIBRARIES) ++ target_compile_definitions(vkcube PRIVATE "WAYLAND_LIBRARY=\"${WAYLAND_CLIENT_LINK_LIBRARIES}\"") ++endif() ++ + # ---------------------------------------------------------------------------- + # vkcubepp + +@@ -291,10 +326,24 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Linux|BSD|GNU") + ${PROJECT_SOURCE_DIR}/cube/cube.vert + ${PROJECT_SOURCE_DIR}/cube/cube.frag + cube.vert.inc +- cube.frag.inc +- ${OPTIONAL_WAYLAND_DATA_FILES}) +- target_link_libraries(vkcubepp Vulkan::Headers volk::volk_headers Threads::Threads) +- target_compile_definitions(vkcubepp PUBLIC ${CUBE_PLATFORM}) ++ cube.frag.inc) ++ target_link_libraries(vkcubepp Threads::Threads) ++ ++ if(BUILD_WSI_XCB_SUPPORT) ++ target_sources(vkcubepp PRIVATE xcb_loader.h) ++ target_include_directories(vkcubepp PRIVATE ${xcb_INCLUDE_DIRS}) ++ endif() ++ if(BUILD_WSI_XLIB_SUPPORT) ++ target_sources(vkcubepp PRIVATE xlib_loader.h) ++ target_include_directories(vkcubepp PRIVATE ${XLIB_INCLUDE_DIRS}) ++ endif() ++ if(BUILD_WSI_WAYLAND_SUPPORT) ++ target_include_directories(vkcubepp PRIVATE ${WAYLAND_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) ++ target_sources(vkcubepp PRIVATE ${WAYLAND_ADDITIONAL_SOURCES}) ++ endif() ++ if(BUILD_WSI_DIRECTFB_SUPPORT) ++ target_link_libraries(vkcubepp PkgConfig::DirectFB) ++ endif() + else() + add_executable(vkcubepp + WIN32 +@@ -303,9 +352,21 @@ else() + ${PROJECT_SOURCE_DIR}/cube/cube.frag + cube.vert.inc + cube.frag.inc) +- target_link_libraries(vkcubepp Vulkan::Headers volk::volk_headers) + endif() ++ + target_include_directories(vkcubepp PRIVATE .) ++target_compile_definitions(vkcubepp PRIVATE ${ENABLED_CUBE_PLATFORMS}) ++target_link_libraries(vkcubepp Vulkan::Headers volk::volk_headers) ++ ++if (XCB_LINK_LIBRARIES ) ++ target_compile_definitions(vkcubepp PUBLIC "XCB_LIBRARY=\"${XCB_LINK_LIBRARIES}\"") ++endif() ++if (X11_LINK_LIBRARIES) ++ target_compile_definitions(vkcubepp PUBLIC "XLIB_LIBRARY=\"${X11_LINK_LIBRARIES}\"") ++endif() ++if (WAYLAND_CLIENT_LINK_LIBRARIES) ++ target_compile_definitions(vkcubepp PUBLIC "WAYLAND_LIBRARY=\"${WAYLAND_CLIENT_LINK_LIBRARIES}\"") ++endif() + + if(APPLE) + install( +@@ -320,41 +381,3 @@ if(APPLE) + else() + install(TARGETS vkcubepp) + endif() +- +-# ---------------------------------------------------------------------------- +-# vkcube-wayland +- +-if (CMAKE_SYSTEM_NAME MATCHES "Linux|BSD") +- if(BUILD_WSI_WAYLAND_SUPPORT AND EXISTS ${WAYLAND_PROTOCOLS_PATH}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml) +- add_executable(vkcube-wayland) +- +- target_sources(vkcube-wayland PRIVATE +- cube.c +- ${PROJECT_SOURCE_DIR}/cube/cube.vert +- ${PROJECT_SOURCE_DIR}/cube/cube.frag +- cube.vert.inc +- cube.frag.inc +- ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-code.c +- ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-header.h +- ${CMAKE_CURRENT_BINARY_DIR}/xdg-decoration-code.c +- ${CMAKE_CURRENT_BINARY_DIR}/xdg-decoration-client-header.h +- ) +- target_include_directories(vkcube-wayland PRIVATE +- ${CMAKE_CURRENT_BINARY_DIR} +- . +- ) +- target_link_libraries(vkcube-wayland PRIVATE +- Vulkan::Headers +- volk::volk_headers +- Threads::Threads +- PkgConfig::WAYLAND_CLIENT +- ) +- target_compile_definitions(vkcube-wayland PRIVATE VK_USE_PLATFORM_WAYLAND_KHR) +- include(CheckLibraryExists) +- CHECK_LIBRARY_EXISTS("rt" clock_gettime "" NEED_RT) +- if (NEED_RT) +- target_link_libraries(vkcube-wayland PRIVATE rt) +- endif() +- install(TARGETS vkcube-wayland) +- endif() +-endif() +diff --git a/cube/android/CMakeLists.txt b/cube/android/CMakeLists.txt +index 66f75b42..af607a55 100644 +--- a/cube/android/CMakeLists.txt ++++ b/cube/android/CMakeLists.txt +@@ -43,7 +43,7 @@ target_sources(android_glue PRIVATE + + set_target_properties(vkcube PROPERTIES OUTPUT_NAME "VkCube") + +-target_link_libraries(vkcube PRIVATE ++target_link_libraries(vkcube + android_glue + log + android +diff --git a/cube/cube.c b/cube/cube.c +index 4879317c..255eb5bb 100644 +--- a/cube/cube.c ++++ b/cube/cube.c +@@ -26,6 +26,7 @@ + */ + + #define _GNU_SOURCE ++#include + #include + #include + #include +@@ -33,13 +34,18 @@ + #include + #include + #include ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) + #include +-#if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR) +-#include +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++#include "xlib_loader.h" ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++#include "xcb_loader.h" ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) + #include +-#include "xdg-shell-client-header.h" +-#include "xdg-decoration-client-header.h" ++#include "wayland_loader.h" + #endif + + #ifdef _WIN32 +@@ -290,6 +296,97 @@ char const *to_string(VkPhysicalDeviceType const type) { + } + } + ++typedef enum WSI_PLATFORM { ++ WSI_PLATFORM_AUTO = 0, ++ WSI_PLATFORM_WIN32, ++ WSI_PLATFORM_METAL, ++ WSI_PLATFORM_ANDROID, ++ WSI_PLATFORM_QNX, ++ WSI_PLATFORM_XCB, ++ WSI_PLATFORM_XLIB, ++ WSI_PLATFORM_WAYLAND, ++ WSI_PLATFORM_DIRECTFB, ++ WSI_PLATFORM_DISPLAY, ++ WSI_PLATFORM_INVALID, // Sentinel just to indicate invalid user input ++} WSI_PLATFORM; ++ ++WSI_PLATFORM wsi_from_string(const char *str) { ++ if (strcmp(str, "auto") == 0) return WSI_PLATFORM_AUTO; ++#if defined(VK_USE_PLATFORM_WIN32_KHR) ++ if (strcmp(str, "win32") == 0) return WSI_PLATFORM_WIN32; ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ if (strcmp(str, "metal") == 0) return WSI_PLATFORM_METAL; ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) ++ if (strcmp(str, "android") == 0) return WSI_PLATFORM_ANDROID; ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (strcmp(str, "qnx") == 0) return WSI_PLATFORM_QNX; ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ if (strcmp(str, "xcb") == 0) return WSI_PLATFORM_XCB; ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ if (strcmp(str, "xlib") == 0) return WSI_PLATFORM_XLIB; ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ if (strcmp(str, "wayland") == 0) return WSI_PLATFORM_WAYLAND; ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (strcmp(str, "directfb") == 0) return WSI_PLATFORM_DIRECTFB; ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ if (strcmp(str, "display") == 0) return WSI_PLATFORM_DISPLAY; ++#endif ++ return WSI_PLATFORM_INVALID; ++}; ++ ++const char *wsi_to_string(WSI_PLATFORM wsi_platform) { ++ switch (wsi_platform) { ++ case (WSI_PLATFORM_AUTO): ++ return "auto"; ++#if defined(VK_USE_PLATFORM_WIN32_KHR) ++ case (WSI_PLATFORM_WIN32): ++ return "win32"; ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ case (WSI_PLATFORM_METAL): ++ return "metal"; ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) ++ case (WSI_PLATFORM_ANDROID): ++ return "android"; ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ case (WSI_PLATFORM_QNX): ++ return "qnx"; ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ case (WSI_PLATFORM_XCB): ++ return "xcb"; ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ case (WSI_PLATFORM_XLIB): ++ return "xlib"; ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ case (WSI_PLATFORM_WAYLAND): ++ return "wayland"; ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ case (WSI_PLATFORM_DIRECTFB): ++ return "directfb"; ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ case (WSI_PLATFORM_DISPLAY): ++ return "display"; ++#endif ++ default: ++ return "unknown"; ++ } ++}; ++ + typedef struct { + VkImage image; + VkCommandBuffer cmd; +@@ -309,18 +406,24 @@ struct demo { + char name[APP_NAME_STR_LEN]; // Name to put on the window/icon + HWND window; // hWnd - window handle + POINT minsize; // minimum window size +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) +- Display *display; ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ void *xlib_library; ++ Display *xlib_display; + Window xlib_window; + Atom xlib_wm_delete_window; +-#elif defined(VK_USE_PLATFORM_XCB_KHR) +- Display *display; ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ void *xcb_library; ++ Display *xcb_display; + xcb_connection_t *connection; + xcb_screen_t *screen; + xcb_window_t xcb_window; + xcb_intern_atom_reply_t *atom_wm_delete_window; +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- struct wl_display *display; ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ void *wayland_library; // Dynamic library for wayland ++ struct wl_display *wayland_display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_surface *window; +@@ -333,20 +436,24 @@ struct demo { + struct wl_seat *seat; + struct wl_pointer *pointer; + struct wl_keyboard *keyboard; +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) + IDirectFB *dfb; +- IDirectFBSurface *window; ++ IDirectFBSurface *directfb_window; + IDirectFBEventBuffer *event_buffer; +-#elif defined(VK_USE_PLATFORM_ANDROID_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) + struct ANativeWindow *window; +-#elif defined(VK_USE_PLATFORM_METAL_EXT) ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) + void *caMetalLayer; +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) + screen_context_t screen_context; + screen_window_t screen_window; + screen_event_t screen_event; + #endif +- ++ WSI_PLATFORM wsi_platform; + VkSurfaceKHR surface; + bool prepared; + bool use_staging_buffer; +@@ -2435,35 +2542,49 @@ static void demo_cleanup(struct demo *demo) { + vkDestroySurfaceKHR(demo->inst, demo->surface, NULL); + + #if defined(VK_USE_PLATFORM_XLIB_KHR) +- XDestroyWindow(demo->display, demo->xlib_window); +- XCloseDisplay(demo->display); +-#elif defined(VK_USE_PLATFORM_XCB_KHR) +- xcb_destroy_window(demo->connection, demo->xcb_window); +- xcb_disconnect(demo->connection); +- free(demo->atom_wm_delete_window); +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- if (demo->keyboard) wl_keyboard_destroy(demo->keyboard); +- if (demo->pointer) wl_pointer_destroy(demo->pointer); +- if (demo->seat) wl_seat_destroy(demo->seat); +- xdg_toplevel_destroy(demo->xdg_toplevel); +- xdg_surface_destroy(demo->xdg_surface); +- wl_surface_destroy(demo->window); +- xdg_wm_base_destroy(demo->xdg_wm_base); +- if (demo->xdg_decoration_mgr) { +- zxdg_toplevel_decoration_v1_destroy(demo->toplevel_decoration); +- zxdg_decoration_manager_v1_destroy(demo->xdg_decoration_mgr); +- } +- wl_compositor_destroy(demo->compositor); +- wl_registry_destroy(demo->registry); +- wl_display_disconnect(demo->display); +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) +- demo->event_buffer->Release(demo->event_buffer); +- demo->window->Release(demo->window); +- demo->dfb->Release(demo->dfb); +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) +- screen_destroy_event(demo->screen_event); +- screen_destroy_window(demo->screen_window); +- screen_destroy_context(demo->screen_context); ++ if (demo->wsi_platform == WSI_PLATFORM_XLIB) { ++ XDestroyWindow(demo->xlib_display, demo->xlib_window); ++ XCloseDisplay(demo->xlib_display); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_XCB) { ++ xcb_destroy_window(demo->connection, demo->xcb_window); ++ xcb_disconnect(demo->connection); ++ free(demo->atom_wm_delete_window); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_WAYLAND) { ++ if (demo->keyboard) wl_keyboard_destroy(demo->keyboard); ++ if (demo->pointer) wl_pointer_destroy(demo->pointer); ++ if (demo->seat) wl_seat_destroy(demo->seat); ++ xdg_toplevel_destroy(demo->xdg_toplevel); ++ xdg_surface_destroy(demo->xdg_surface); ++ wl_surface_destroy(demo->window); ++ xdg_wm_base_destroy(demo->xdg_wm_base); ++ if (demo->xdg_decoration_mgr) { ++ zxdg_toplevel_decoration_v1_destroy(demo->toplevel_decoration); ++ zxdg_decoration_manager_v1_destroy(demo->xdg_decoration_mgr); ++ } ++ wl_compositor_destroy(demo->compositor); ++ wl_registry_destroy(demo->registry); ++ wl_display_disconnect(demo->wayland_display); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (demo->wsi_platform == WSI_PLATFORM_DIRECTFB) { ++ demo->event_buffer->Release(demo->event_buffer); ++ demo->directfb_window->Release(demo->directfb_window); ++ demo->dfb->Release(demo->dfb); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (demo->wsi_platform == WSI_PLATFORM_QNX) { ++ screen_destroy_event(demo->screen_event); ++ screen_destroy_window(demo->screen_window); ++ screen_destroy_context(demo->screen_context); ++ } + #endif + + vkDestroyInstance(demo->inst, NULL); +@@ -2640,7 +2761,8 @@ static void demo_create_window(struct demo *demo) { + demo->minsize.x = GetSystemMetrics(SM_CXMINTRACK); + demo->minsize.y = GetSystemMetrics(SM_CYMINTRACK) + 1; + } +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) + static void demo_create_xlib_window(struct demo *demo) { + const char *display_envar = getenv("DISPLAY"); + if (display_envar == NULL || display_envar[0] == '\0') { +@@ -2650,15 +2772,15 @@ static void demo_create_xlib_window(struct demo *demo) { + } + + XInitThreads(); +- demo->display = XOpenDisplay(NULL); ++ demo->xlib_display = XOpenDisplay(NULL); + long visualMask = VisualScreenMask; + int numberOfVisuals; + XVisualInfo vInfoTemplate = {}; +- vInfoTemplate.screen = DefaultScreen(demo->display); +- XVisualInfo *visualInfo = XGetVisualInfo(demo->display, visualMask, &vInfoTemplate, &numberOfVisuals); ++ vInfoTemplate.screen = DefaultScreen(demo->xlib_display); ++ XVisualInfo *visualInfo = XGetVisualInfo(demo->xlib_display, visualMask, &vInfoTemplate, &numberOfVisuals); + + Colormap colormap = +- XCreateColormap(demo->display, RootWindow(demo->display, vInfoTemplate.screen), visualInfo->visual, AllocNone); ++ XCreateColormap(demo->xlib_display, RootWindow(demo->xlib_display, vInfoTemplate.screen), visualInfo->visual, AllocNone); + + XSetWindowAttributes windowAttributes = {}; + windowAttributes.colormap = colormap; +@@ -2666,14 +2788,14 @@ static void demo_create_xlib_window(struct demo *demo) { + windowAttributes.border_pixel = 0; + windowAttributes.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask; + +- demo->xlib_window = XCreateWindow(demo->display, RootWindow(demo->display, vInfoTemplate.screen), 0, 0, demo->width, ++ demo->xlib_window = XCreateWindow(demo->xlib_display, RootWindow(demo->xlib_display, vInfoTemplate.screen), 0, 0, demo->width, + demo->height, 0, visualInfo->depth, InputOutput, visualInfo->visual, + CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, &windowAttributes); + +- XSelectInput(demo->display, demo->xlib_window, ExposureMask | KeyPressMask); +- XMapWindow(demo->display, demo->xlib_window); +- XFlush(demo->display); +- demo->xlib_wm_delete_window = XInternAtom(demo->display, "WM_DELETE_WINDOW", False); ++ XSelectInput(demo->xlib_display, demo->xlib_window, ExposureMask | KeyPressMask); ++ XMapWindow(demo->xlib_display, demo->xlib_window); ++ XFlush(demo->xlib_display); ++ demo->xlib_wm_delete_window = XInternAtom(demo->xlib_display, "WM_DELETE_WINDOW", False); + } + static void demo_handle_xlib_event(struct demo *demo, const XEvent *event) { + switch (event->type) { +@@ -2713,11 +2835,11 @@ static void demo_run_xlib(struct demo *demo) { + XEvent event; + + if (demo->pause) { +- XNextEvent(demo->display, &event); ++ XNextEvent(demo->xlib_display, &event); + demo_handle_xlib_event(demo, &event); + } +- while (XPending(demo->display) > 0) { +- XNextEvent(demo->display, &event); ++ while (XPending(demo->xlib_display) > 0) { ++ XNextEvent(demo->xlib_display, &event); + demo_handle_xlib_event(demo, &event); + } + +@@ -2726,7 +2848,8 @@ static void demo_run_xlib(struct demo *demo) { + if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount) demo->quit = true; + } + } +-#elif defined(VK_USE_PLATFORM_XCB_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) + static void demo_handle_xcb_event(struct demo *demo, const xcb_generic_event_t *event) { + uint8_t event_code = event->response_type & 0x7f; + switch (event_code) { +@@ -2823,26 +2946,27 @@ static void demo_create_xcb_window(struct demo *demo) { + xcb_configure_window(demo->connection, demo->xcb_window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords); + } + // VK_USE_PLATFORM_XCB_KHR +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) + static void demo_run(struct demo *demo) { + while (!demo->quit) { + // Flush any commands to the server +- wl_display_flush(demo->display); ++ wl_display_flush(demo->wayland_display); + + if (demo->pause) { + // block and wait for input +- wl_display_dispatch(demo->display); ++ wl_display_dispatch(demo->wayland_display); + } else { + // Lock the display event queue in case the driver is doing something on another thread + // while we wait, keep pumping events +- while (wl_display_prepare_read(demo->display) != 0) { +- wl_display_dispatch_pending(demo->display); ++ while (wl_display_prepare_read(demo->wayland_display) != 0) { ++ wl_display_dispatch_pending(demo->wayland_display); + } + // Actually do the read from the socket +- wl_display_read_events(demo->display); ++ wl_display_read_events(demo->wayland_display); + + // Pump events +- wl_display_dispatch_pending(demo->display); ++ wl_display_dispatch_pending(demo->wayland_display); + + demo_draw(demo); + demo->curFrame++; +@@ -2883,7 +3007,7 @@ static void handle_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel + + static const struct xdg_toplevel_listener xdg_toplevel_listener = {handle_toplevel_configure, handle_toplevel_close}; + +-static void demo_create_window(struct demo *demo) { ++static void demo_create_wayland_window(struct demo *demo) { + if (!demo->xdg_wm_base) { + printf("Compositor did not provide the standard protocol xdg-wm-base\n"); + fflush(stdout); +@@ -2921,7 +3045,8 @@ static void demo_create_window(struct demo *demo) { + + wl_surface_commit(demo->window); + } +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) + static void demo_create_directfb_window(struct demo *demo) { + DFBResult ret; + +@@ -2944,7 +3069,7 @@ static void demo_create_directfb_window(struct demo *demo) { + desc.caps = DSCAPS_PRIMARY; + desc.width = demo->width; + desc.height = demo->height; +- ret = demo->dfb->CreateSurface(demo->dfb, &desc, &demo->window); ++ ret = demo->dfb->CreateSurface(demo->dfb, &desc, &demo->directfb_window); + if (ret) { + printf("CreateSurface failed to create DirectFB surface interface!\n"); + fflush(stdout); +@@ -2995,14 +3120,16 @@ static void demo_run_directfb(struct demo *demo) { + } + } + } +-#elif defined(VK_USE_PLATFORM_ANDROID_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) + static void demo_run(struct demo *demo) { + if (!demo->prepared) return; + + demo_draw(demo); + demo->curFrame++; + } +-#elif defined(VK_USE_PLATFORM_METAL_EXT) ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) + static void demo_run(struct demo *demo) { + demo_draw(demo); + demo->curFrame++; +@@ -3010,7 +3137,8 @@ static void demo_run(struct demo *demo) { + demo->quit = TRUE; + } + } +-#elif defined(VK_USE_PLATFORM_DISPLAY_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) + static VkResult demo_create_display_surface(struct demo *demo) { + VkResult U_ASSERT_ONLY err; + uint32_t display_count; +@@ -3105,8 +3233,6 @@ static VkResult demo_create_display_surface(struct demo *demo) { + exit(1); + } + +- free(plane_props); +- + VkDisplayPlaneCapabilitiesKHR planeCaps; + vkGetDisplayPlaneCapabilitiesKHR(demo->gpu, mode_props.displayMode, plane_index, &planeCaps); + // Find a supported alpha mode +@@ -3137,6 +3263,8 @@ static VkResult demo_create_display_surface(struct demo *demo) { + create_info.globalAlpha = 1.0f; + create_info.imageExtent = image_extent; + ++ free(plane_props); ++ + return vkCreateDisplayPlaneSurfaceKHR(demo->inst, &create_info, NULL, &demo->surface); + } + +@@ -3150,7 +3278,8 @@ static void demo_run_display(struct demo *demo) { + } + } + } +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) + + #include + +@@ -3256,7 +3385,7 @@ static void demo_run(struct demo *demo) { + } + } + +-static void demo_create_window(struct demo *demo) { ++static void demo_create_screen_window(struct demo *demo) { + const char *idstr = APP_SHORT_NAME; + int size[2]; + int usage = SCREEN_USAGE_VULKAN; +@@ -3360,199 +3489,599 @@ int find_display_gpu(int gpu_number, uint32_t gpu_count, VkPhysicalDevice *physi + return -1; + } + #endif +-static void demo_init_vk(struct demo *demo) { +- VkResult err; +- uint32_t instance_extension_count = 0; +- uint32_t instance_layer_count = 0; +- char *instance_validation_layers[] = {"VK_LAYER_KHRONOS_validation"}; +- demo->enabled_extension_count = 0; +- demo->enabled_layer_count = 0; +- demo->is_minimized = false; +- demo->cmd_pool = VK_NULL_HANDLE; + +- err = volkInitialize(); +- if (err != VK_SUCCESS) { +- ERR_EXIT( +- "Unable to find the Vulkan runtime on the system.\n\n" +- "This likely indicates that no Vulkan capable drivers are installed.", +- "Installation Failure"); +- } +- // Look for validation layers +- VkBool32 validation_found = 0; +- if (demo->validate) { +- err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL); +- assert(!err); ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++static void pointer_handle_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, ++ wl_fixed_t sy) {} + +- if (instance_layer_count > 0) { +- VkLayerProperties *instance_layers = malloc(sizeof(VkLayerProperties) * instance_layer_count); +- err = vkEnumerateInstanceLayerProperties(&instance_layer_count, instance_layers); +- assert(!err); ++static void pointer_handle_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) {} + +- validation_found = demo_check_layers(ARRAY_SIZE(instance_validation_layers), instance_validation_layers, +- instance_layer_count, instance_layers); +- if (validation_found) { +- demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers); +- demo->enabled_layers[0] = "VK_LAYER_KHRONOS_validation"; +- } +- free(instance_layers); +- } ++static void pointer_handle_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) {} + +- if (!validation_found) { +- ERR_EXIT( +- "vkEnumerateInstanceLayerProperties failed to find required validation layer.\n\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +- } ++static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, ++ uint32_t state) { ++ struct demo *demo = data; ++ if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) { ++ xdg_toplevel_move(demo->xdg_toplevel, demo->seat, serial); + } ++} + +- /* Look for instance extensions */ +- VkBool32 surfaceExtFound = 0; +- VkBool32 platformSurfaceExtFound = 0; +- bool portabilityEnumerationActive = false; +- memset(demo->extension_names, 0, sizeof(demo->extension_names)); ++static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {} + +- err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, NULL); +- assert(!err); ++static const struct wl_pointer_listener pointer_listener = { ++ pointer_handle_enter, pointer_handle_leave, pointer_handle_motion, pointer_handle_button, pointer_handle_axis, ++}; + +- if (instance_extension_count > 0) { +- VkExtensionProperties *instance_extensions = malloc(sizeof(VkExtensionProperties) * instance_extension_count); +- err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, instance_extensions); +- assert(!err); +- for (uint32_t i = 0; i < instance_extension_count; i++) { +- if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- surfaceExtFound = 1; +- demo->extension_names[demo->enabled_extension_count++] = VK_KHR_SURFACE_EXTENSION_NAME; +- } +-#if defined(VK_USE_PLATFORM_WIN32_KHR) +- if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- platformSurfaceExtFound = 1; +- demo->extension_names[demo->enabled_extension_count++] = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; +- } +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) +- if (!strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- platformSurfaceExtFound = 1; +- demo->extension_names[demo->enabled_extension_count++] = VK_KHR_XLIB_SURFACE_EXTENSION_NAME; +- } +-#elif defined(VK_USE_PLATFORM_XCB_KHR) +- if (!strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- platformSurfaceExtFound = 1; +- demo->extension_names[demo->enabled_extension_count++] = VK_KHR_XCB_SURFACE_EXTENSION_NAME; +- } +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- platformSurfaceExtFound = 1; +- demo->extension_names[demo->enabled_extension_count++] = VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME; +- } +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) +- if (!strcmp(VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- platformSurfaceExtFound = 1; +- demo->extension_names[demo->enabled_extension_count++] = VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME; +- } +-#elif defined(VK_USE_PLATFORM_DISPLAY_KHR) +- if (!strcmp(VK_KHR_DISPLAY_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- platformSurfaceExtFound = 1; +- demo->extension_names[demo->enabled_extension_count++] = VK_KHR_DISPLAY_EXTENSION_NAME; +- } +-#elif defined(VK_USE_PLATFORM_ANDROID_KHR) +- if (!strcmp(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- platformSurfaceExtFound = 1; +- demo->extension_names[demo->enabled_extension_count++] = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; +- } +-#elif defined(VK_USE_PLATFORM_METAL_EXT) +- if (!strcmp(VK_EXT_METAL_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- platformSurfaceExtFound = 1; +- demo->extension_names[demo->enabled_extension_count++] = VK_EXT_METAL_SURFACE_EXTENSION_NAME; +- } +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) +- if (!strcmp(VK_QNX_SCREEN_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- platformSurfaceExtFound = 1; +- demo->extension_names[demo->enabled_extension_count++] = VK_QNX_SCREEN_SURFACE_EXTENSION_NAME; +- } +-#endif +- if (!strcmp(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- demo->extension_names[demo->enabled_extension_count++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; +- } +- if (!strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- if (demo->validate) { +- demo->extension_names[demo->enabled_extension_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; +- } +- } +- // We want cube to be able to enumerate drivers that support the portability_subset extension, so we have to enable the +- // portability enumeration extension. +- if (!strcmp(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, instance_extensions[i].extensionName)) { +- portabilityEnumerationActive = true; +- demo->extension_names[demo->enabled_extension_count++] = VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME; +- } +- assert(demo->enabled_extension_count < 64); +- } ++static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) {} + +- free(instance_extensions); ++static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, ++ struct wl_array *keys) {} ++ ++static void keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) {} ++ ++static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, ++ uint32_t state) { ++ if (state != WL_KEYBOARD_KEY_STATE_RELEASED) return; ++ struct demo *demo = data; ++ switch (key) { ++ case KEY_ESC: // Escape ++ demo->quit = true; ++ break; ++ case KEY_LEFT: // left arrow key ++ demo->spin_angle -= demo->spin_increment; ++ break; ++ case KEY_RIGHT: // right arrow key ++ demo->spin_angle += demo->spin_increment; ++ break; ++ case KEY_SPACE: // space bar ++ demo->pause = !demo->pause; ++ break; + } ++} + +- if (!surfaceExtFound) { +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); ++static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, ++ uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {} ++ ++static const struct wl_keyboard_listener keyboard_listener = { ++ keyboard_handle_keymap, keyboard_handle_enter, keyboard_handle_leave, keyboard_handle_key, keyboard_handle_modifiers, ++}; ++ ++static void seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps) { ++ // Subscribe to pointer events ++ struct demo *demo = data; ++ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !demo->pointer) { ++ demo->pointer = wl_seat_get_pointer(seat); ++ wl_pointer_add_listener(demo->pointer, &pointer_listener, demo); ++ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && demo->pointer) { ++ wl_pointer_destroy(demo->pointer); ++ demo->pointer = NULL; + } +- if (!platformSurfaceExtFound) { +-#if defined(VK_USE_PLATFORM_WIN32_KHR) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_METAL_EXT) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_EXT_METAL_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_XCB_KHR) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_XCB_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_DISPLAY_KHR) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_DISPLAY_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_ANDROID_KHR) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_ANDROID_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_XLIB_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_QNX_SCREEN_SURFACE_EXTENSION_NAME ++ // Subscribe to keyboard events ++ if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { ++ demo->keyboard = wl_seat_get_keyboard(seat); ++ wl_keyboard_add_listener(demo->keyboard, &keyboard_listener, demo); ++ } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && demo->keyboard) { ++ wl_keyboard_destroy(demo->keyboard); ++ demo->keyboard = NULL; ++ } ++} ++ ++static const struct wl_seat_listener seat_listener = { ++ seat_handle_capabilities, ++}; ++ ++static void wm_base_ping(void *data UNUSED, struct xdg_wm_base *xdg_wm_base, uint32_t serial) { ++ xdg_wm_base_pong(xdg_wm_base, serial); ++} ++ ++static const struct xdg_wm_base_listener wm_base_listener = {wm_base_ping}; ++ ++static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, ++ uint32_t version UNUSED) { ++ struct demo *demo = data; ++ // pickup wayland objects when they appear ++ if (strcmp(interface, wl_compositor_interface.name) == 0) { ++ uint32_t minVersion = version < 4 ? version : 4; ++ demo->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, minVersion); ++ if (demo->VK_KHR_incremental_present_enabled && minVersion < 4) { ++ fprintf(stderr, "Wayland compositor doesn't support VK_KHR_incremental_present, disabling.\n"); ++ demo->VK_KHR_incremental_present_enabled = false; ++ } ++ } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { ++ demo->xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1); ++ xdg_wm_base_add_listener(demo->xdg_wm_base, &wm_base_listener, NULL); ++ } else if (strcmp(interface, wl_seat_interface.name) == 0) { ++ demo->seat = wl_registry_bind(registry, id, &wl_seat_interface, 1); ++ wl_seat_add_listener(demo->seat, &seat_listener, demo); ++ } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { ++ demo->xdg_decoration_mgr = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); ++ } ++} ++ ++static void registry_handle_global_remove(void *data UNUSED, struct wl_registry *registry UNUSED, uint32_t name UNUSED) {} ++ ++static const struct wl_registry_listener registry_listener = {registry_handle_global, registry_handle_global_remove}; ++#endif ++ ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++static const char *demo_init_xcb_connection(struct demo *demo) { ++ demo->xcb_library = initialize_xcb(); ++ if (NULL == demo->xcb_library) { ++ return "Cannot load XCB dynamic library."; ++ } ++ ++ const xcb_setup_t *setup; ++ xcb_screen_iterator_t iter; ++ int scr; ++ ++ const char *display_envar = getenv("DISPLAY"); ++ if (display_envar == NULL || display_envar[0] == '\0') { ++ return "Environment variable DISPLAY requires a valid value.n"; ++ } ++ ++ demo->connection = xcb_connect(NULL, &scr); ++ if (xcb_connection_has_error(demo->connection) > 0) { ++ return "Cannot connect to XCB."; ++ } ++ ++ setup = xcb_get_setup(demo->connection); ++ iter = xcb_setup_roots_iterator(setup); ++ while (scr-- > 0) xcb_screen_next(&iter); ++ ++ demo->screen = iter.data; ++ return NULL; ++} ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++static const char *demo_init_xlib_connection(struct demo *demo) { ++ demo->xlib_library = initialize_xlib(); ++ if (NULL == demo->xlib_library) { ++ return "Cannot load XLIB dynamic library."; ++ } ++ return NULL; ++} ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++static const char *demo_init_wayland_connection(struct demo *demo) { ++ demo->wayland_library = initialize_wayland(); ++ if (NULL == demo->wayland_library) { ++ return "Cannot load wayland dynamic library."; ++ } ++ ++ demo->wayland_display = wl_display_connect(NULL); ++ ++ if (demo->wayland_display == NULL) { ++ return "Cannot connect to wayland."; ++ } ++ ++ demo->registry = wl_display_get_registry(demo->wayland_display); ++ wl_registry_add_listener(demo->registry, ®istry_listener, demo); ++ wl_display_roundtrip(demo->wayland_display); ++ return NULL; ++} ++#endif ++ ++// Check that WSI platforms are available - only necessary when multiple WSI platforms exist, like on linux ++// If the wsi_platform is AUTO, this function also sets wsi_platform to the first available WSI platform ++// Otherwise, it errors out if the specified wsi_platform isn't available ++static void demo_check_and_set_wsi_platform(struct demo *demo) { ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_XCB || demo->wsi_platform == WSI_PLATFORM_AUTO) { ++ bool xcb_extension_available = false; ++ for (uint32_t i = 0; i < demo->enabled_extension_count; i++) { ++ if (strcmp(demo->extension_names[i], VK_KHR_XCB_SURFACE_EXTENSION_NAME) == 0) { ++ xcb_extension_available = true; ++ break; ++ } ++ } ++ if (xcb_extension_available) { ++ const char *error_msg = demo_init_xcb_connection(demo); ++ if (error_msg != NULL) { ++ if (demo->wsi_platform == WSI_PLATFORM_XCB) { ++ fprintf(stderr, "%s\nExiting ...\n", error_msg); ++ fflush(stdout); ++ exit(1); ++ } ++ } else { ++ demo->wsi_platform = WSI_PLATFORM_XCB; ++ return; ++ } ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_XLIB || demo->wsi_platform == WSI_PLATFORM_AUTO) { ++ bool xlib_extension_available = false; ++ for (uint32_t i = 0; i < demo->enabled_extension_count; i++) { ++ if (strcmp(demo->extension_names[i], VK_KHR_XLIB_SURFACE_EXTENSION_NAME) == 0) { ++ xlib_extension_available = true; ++ break; ++ } ++ } ++ if (xlib_extension_available) { ++ const char *error_msg = demo_init_xlib_connection(demo); ++ if (error_msg != NULL) { ++ if (demo->wsi_platform == WSI_PLATFORM_XLIB) { ++ fprintf(stderr, "%s\nExiting ...\n", error_msg); ++ fflush(stdout); ++ exit(1); ++ } ++ } else { ++ demo->wsi_platform = WSI_PLATFORM_XLIB; ++ return; ++ } ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_WAYLAND || demo->wsi_platform == WSI_PLATFORM_AUTO) { ++ bool wayland_extension_available = false; ++ for (uint32_t i = 0; i < demo->enabled_extension_count; i++) { ++ if (strcmp(demo->extension_names[i], VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME) == 0) { ++ wayland_extension_available = true; ++ break; ++ } ++ } ++ if (wayland_extension_available) { ++ const char *error_msg = demo_init_wayland_connection(demo); ++ if (error_msg != NULL) { ++ if (demo->wsi_platform == WSI_PLATFORM_WAYLAND) { ++ fprintf(stderr, "%s\nExiting ...\n", error_msg); ++ fflush(stdout); ++ exit(1); ++ } ++ } else { ++ demo->wsi_platform = WSI_PLATFORM_WAYLAND; ++ return; ++ } ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (demo->wsi_platform == WSI_PLATFORM_DIRECTFB || demo->wsi_platform == WSI_PLATFORM_AUTO) { ++ bool direftfb_extension_available = false; ++ for (uint32_t i = 0; i < demo->enabled_extension_count; i++) { ++ if (strcmp(demo->extension_names[i], VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME) == 0) { ++ direftfb_extension_available = true; ++ break; ++ } ++ } ++ if (direftfb_extension_available) { ++ // Because DirectFB is still linked in, we can assume that it works if we got here ++ demo->wsi_platform = WSI_PLATFORM_DIRECTFB; ++ return; ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_WIN32_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_WIN32 || demo->wsi_platform == WSI_PLATFORM_AUTO) { ++ bool win32_extension_available = false; ++ for (uint32_t i = 0; i < demo->enabled_extension_count; i++) { ++ if (strcmp(demo->extension_names[i], VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == 0) { ++ win32_extension_available = true; ++ break; ++ } ++ } ++ if (win32_extension_available) { ++ demo->wsi_platform = WSI_PLATFORM_WIN32; ++ return; ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ if (demo->wsi_platform == WSI_PLATFORM_METAL || demo->wsi_platform == WSI_PLATFORM_AUTO) { ++ bool metal_extension_available = false; ++ for (uint32_t i = 0; i < demo->enabled_extension_count; i++) { ++ if (strcmp(demo->extension_names[i], VK_EXT_METAL_SURFACE_EXTENSION_NAME) == 0) { ++ metal_extension_available = true; ++ break; ++ } ++ } ++ if (metal_extension_available) { ++ demo->wsi_platform = WSI_PLATFORM_METAL; ++ return; ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_ANDROID || demo->wsi_platform == WSI_PLATFORM_AUTO) { ++ bool android_extension_available = false; ++ for (uint32_t i = 0; i < demo->enabled_extension_count; i++) { ++ if (strcmp(demo->extension_names[i], VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0) { ++ android_extension_available = true; ++ break; ++ } ++ } ++ if (android_extension_available) { ++ demo->wsi_platform = WSI_PLATFORM_ANDROID; ++ return; ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (demo->wsi_platform == WSI_PLATFORM_QNX || demo->wsi_platform == WSI_PLATFORM_AUTO) { ++ bool qnx_extension_available = false; ++ for (uint32_t i = 0; i < demo->enabled_extension_count; i++) { ++ if (strcmp(demo->extension_names[i], VK_QNX_SCREEN_SURFACE_EXTENSION_NAME) == 0) { ++ qnx_extension_available = true; ++ break; ++ } ++ } ++ if (qnx_extension_available) { ++ demo->wsi_platform = WSI_PLATFORM_ANDROID; ++ return; ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_DISPLAY || demo->wsi_platform == WSI_PLATFORM_AUTO) { ++ bool display_extension_available = false; ++ for (uint32_t i = 0; i < demo->enabled_extension_count; i++) { ++ if (strcmp(demo->extension_names[i], VK_KHR_DISPLAY_EXTENSION_NAME) == 0) { ++ display_extension_available = true; ++ break; ++ } ++ } ++ if (display_extension_available) { ++ // Because DISPLAY doesn't require additional libraries, we can assume that it works if we got here ++ demo->wsi_platform = WSI_PLATFORM_DISPLAY; ++ return; ++ } ++ } ++#endif ++} ++ ++static void demo_init_vk(struct demo *demo) { ++ VkResult err; ++ uint32_t instance_extension_count = 0; ++ uint32_t instance_layer_count = 0; ++ char *instance_validation_layers[] = {"VK_LAYER_KHRONOS_validation"}; ++ demo->enabled_extension_count = 0; ++ demo->enabled_layer_count = 0; ++ demo->is_minimized = false; ++ demo->cmd_pool = VK_NULL_HANDLE; ++ ++ err = volkInitialize(); ++ if (err != VK_SUCCESS) { ++ ERR_EXIT( ++ "Unable to find the Vulkan runtime on the system.\n\n" ++ "This likely indicates that no Vulkan capable drivers are installed.", ++ "Installation Failure"); ++ } ++ // Look for validation layers ++ VkBool32 validation_found = 0; ++ if (demo->validate) { ++ err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL); ++ assert(!err); ++ ++ if (instance_layer_count > 0) { ++ VkLayerProperties *instance_layers = malloc(sizeof(VkLayerProperties) * instance_layer_count); ++ err = vkEnumerateInstanceLayerProperties(&instance_layer_count, instance_layers); ++ assert(!err); ++ ++ validation_found = demo_check_layers(ARRAY_SIZE(instance_validation_layers), instance_validation_layers, ++ instance_layer_count, instance_layers); ++ if (validation_found) { ++ demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers); ++ demo->enabled_layers[0] = "VK_LAYER_KHRONOS_validation"; ++ } ++ free(instance_layers); ++ } ++ ++ if (!validation_found) { ++ ERR_EXIT( ++ "vkEnumerateInstanceLayerProperties failed to find required validation layer.\n\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++ } ++ ++ /* Look for instance extensions */ ++ VkBool32 surfaceExtFound = false; ++ VkBool32 platformSurfaceExtFound = false; ++ bool portabilityEnumerationActive = false; ++ memset(demo->extension_names, 0, sizeof(demo->extension_names)); ++ ++ err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, NULL); ++ assert(!err); ++ ++ if (instance_extension_count > 0) { ++ VkExtensionProperties *instance_extensions = malloc(sizeof(VkExtensionProperties) * instance_extension_count); ++ err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, instance_extensions); ++ assert(!err); ++ for (uint32_t i = 0; i < instance_extension_count; i++) { ++ if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) { ++ surfaceExtFound = true; ++ demo->extension_names[demo->enabled_extension_count++] = VK_KHR_SURFACE_EXTENSION_NAME; ++ } ++#if defined(VK_USE_PLATFORM_WIN32_KHR) ++ if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName) && ++ (demo->wsi_platform == WSI_PLATFORM_AUTO || demo->wsi_platform == WSI_PLATFORM_WIN32)) { ++ platformSurfaceExtFound = true; ++ demo->extension_names[demo->enabled_extension_count++] = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; ++ } ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ if (!strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName) && ++ (demo->wsi_platform == WSI_PLATFORM_AUTO || demo->wsi_platform == WSI_PLATFORM_XLIB)) { ++ platformSurfaceExtFound = true; ++ demo->extension_names[demo->enabled_extension_count++] = VK_KHR_XLIB_SURFACE_EXTENSION_NAME; ++ } ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ if (!strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName) && ++ (demo->wsi_platform == WSI_PLATFORM_AUTO || demo->wsi_platform == WSI_PLATFORM_XCB)) { ++ platformSurfaceExtFound = true; ++ demo->extension_names[demo->enabled_extension_count++] = VK_KHR_XCB_SURFACE_EXTENSION_NAME; ++ } ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName) && ++ (demo->wsi_platform == WSI_PLATFORM_AUTO || demo->wsi_platform == WSI_PLATFORM_WAYLAND)) { ++ platformSurfaceExtFound = true; ++ demo->extension_names[demo->enabled_extension_count++] = VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME; ++ } ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (!strcmp(VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName) && ++ (demo->wsi_platform == WSI_PLATFORM_AUTO || demo->wsi_platform == WSI_PLATFORM_DIRECTFB)) { ++ platformSurfaceExtFound = true; ++ demo->extension_names[demo->enabled_extension_count++] = VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME; ++ } ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ if (!strcmp(VK_KHR_DISPLAY_EXTENSION_NAME, instance_extensions[i].extensionName) && ++ (demo->wsi_platform == WSI_PLATFORM_AUTO || demo->wsi_platform == WSI_PLATFORM_DISPLAY)) { ++ platformSurfaceExtFound = true; ++ demo->extension_names[demo->enabled_extension_count++] = VK_KHR_DISPLAY_EXTENSION_NAME; ++ } ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) ++ if (!strcmp(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName) && ++ (demo->wsi_platform == WSI_PLATFORM_AUTO || demo->wsi_platform == WSI_PLATFORM_ANDROID)) { ++ platformSurfaceExtFound = true; ++ demo->extension_names[demo->enabled_extension_count++] = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; ++ } ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ if (!strcmp(VK_EXT_METAL_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName) && ++ (demo->wsi_platform == WSI_PLATFORM_AUTO || demo->wsi_platform == WSI_PLATFORM_METAL)) { ++ platformSurfaceExtFound = true; ++ demo->extension_names[demo->enabled_extension_count++] = VK_EXT_METAL_SURFACE_EXTENSION_NAME; ++ } ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (!strcmp(VK_QNX_SCREEN_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName) && ++ (demo->wsi_platform == WSI_PLATFORM_AUTO || demo->wsi_platform == WSI_PLATFORM_QNX)) { ++ platformSurfaceExtFound = true; ++ demo->extension_names[demo->enabled_extension_count++] = VK_QNX_SCREEN_SURFACE_EXTENSION_NAME; ++ } ++#endif ++ if (!strcmp(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, instance_extensions[i].extensionName)) { ++ demo->extension_names[demo->enabled_extension_count++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; ++ } ++ if (!strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instance_extensions[i].extensionName)) { ++ if (demo->validate) { ++ demo->extension_names[demo->enabled_extension_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; ++ } ++ } ++ // We want cube to be able to enumerate drivers that support the portability_subset extension, so we have to enable ++ // the portability enumeration extension. ++ if (!strcmp(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, instance_extensions[i].extensionName)) { ++ portabilityEnumerationActive = true; ++ demo->extension_names[demo->enabled_extension_count++] = VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME; ++ } ++ assert(demo->enabled_extension_count < 64); ++ } ++ ++ free(instance_extensions); ++ } ++ ++ if (!surfaceExtFound) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_SURFACE_EXTENSION_NAME + " extension.\n\n" + "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" + "Please look at the Getting Started guide for additional information.\n", + "vkCreateInstance Failure"); ++ } ++ if (!platformSurfaceExtFound) { ++#if defined(VK_USE_PLATFORM_WIN32_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_WIN32) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ if (demo->wsi_platform == WSI_PLATFORM_METAL) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_EXT_METAL_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } + #endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_XCB) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_XCB_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_WAYLAND) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_DISPLAY) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_DISPLAY_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_ANDROID) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_ANDROID_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_XLIB) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_XLIB_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (demo->wsi_platform == WSI_PLATFORM_DIRECTFB) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (demo->wsi_platform == WSI_PLATFORM_WIN32) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_QNX_SCREEN_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++ ERR_EXIT( ++ "vkEnumerateInstanceExtensionProperties failed to find any supported WSI surface extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++ ++ bool auto_wsi_platform = demo->wsi_platform == WSI_PLATFORM_AUTO; ++ ++ demo_check_and_set_wsi_platform(demo); ++ ++ // Print a message to indicate the automatically set WSI platform ++ if (auto_wsi_platform && demo->wsi_platform != WSI_PLATFORM_AUTO) { ++ fprintf(stderr, "Selected WSI platform: %s\n", wsi_to_string(demo->wsi_platform)); + } ++ + const VkApplicationInfo app = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = NULL, +@@ -3636,48 +4165,55 @@ static void demo_init_vk(struct demo *demo) { + ERR_EXIT("Specified GPU number is not present", "User Error"); + } + ++ if (demo->wsi_platform == WSI_PLATFORM_DISPLAY) { + #if defined(VK_USE_PLATFORM_DISPLAY_KHR) +- demo->gpu_number = find_display_gpu(demo->gpu_number, gpu_count, physical_devices); +- if (demo->gpu_number < 0) { +- printf("Cannot find any display!\n"); ++ demo->gpu_number = find_display_gpu(demo->gpu_number, gpu_count, physical_devices); ++ if (demo->gpu_number < 0) { ++ printf("Cannot find any display!\n"); ++ fflush(stdout); ++ exit(1); ++ } ++#else ++ printf("WSI selection was set to DISPLAY but vkcube was not compiled with support for the DISPLAY platform, exiting \n"); + fflush(stdout); + exit(1); +- } +-#else +- /* Try to auto select most suitable device */ +- if (demo->gpu_number == -1) { +- uint32_t count_device_type[VK_PHYSICAL_DEVICE_TYPE_CPU + 1]; +- memset(count_device_type, 0, sizeof(count_device_type)); +- +- VkPhysicalDeviceProperties physicalDeviceProperties; +- for (uint32_t i = 0; i < gpu_count; i++) { +- vkGetPhysicalDeviceProperties(physical_devices[i], &physicalDeviceProperties); +- assert(physicalDeviceProperties.deviceType <= VK_PHYSICAL_DEVICE_TYPE_CPU); +- count_device_type[physicalDeviceProperties.deviceType]++; +- } +- +- VkPhysicalDeviceType search_for_device_type = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; +- if (count_device_type[VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU]) { +- search_for_device_type = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; +- } else if (count_device_type[VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU]) { +- search_for_device_type = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU; +- } else if (count_device_type[VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU]) { +- search_for_device_type = VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU; +- } else if (count_device_type[VK_PHYSICAL_DEVICE_TYPE_CPU]) { +- search_for_device_type = VK_PHYSICAL_DEVICE_TYPE_CPU; +- } else if (count_device_type[VK_PHYSICAL_DEVICE_TYPE_OTHER]) { +- search_for_device_type = VK_PHYSICAL_DEVICE_TYPE_OTHER; +- } ++#endif ++ } else { ++ /* Try to auto select most suitable device */ ++ if (demo->gpu_number == -1) { ++ uint32_t count_device_type[VK_PHYSICAL_DEVICE_TYPE_CPU + 1]; ++ memset(count_device_type, 0, sizeof(count_device_type)); ++ ++ VkPhysicalDeviceProperties physicalDeviceProperties; ++ for (uint32_t i = 0; i < gpu_count; i++) { ++ vkGetPhysicalDeviceProperties(physical_devices[i], &physicalDeviceProperties); ++ assert(physicalDeviceProperties.deviceType <= VK_PHYSICAL_DEVICE_TYPE_CPU); ++ count_device_type[physicalDeviceProperties.deviceType]++; ++ } + +- for (uint32_t i = 0; i < gpu_count; i++) { +- vkGetPhysicalDeviceProperties(physical_devices[i], &physicalDeviceProperties); +- if (physicalDeviceProperties.deviceType == search_for_device_type) { +- demo->gpu_number = i; +- break; ++ VkPhysicalDeviceType search_for_device_type = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; ++ if (count_device_type[VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU]) { ++ search_for_device_type = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; ++ } else if (count_device_type[VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU]) { ++ search_for_device_type = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU; ++ } else if (count_device_type[VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU]) { ++ search_for_device_type = VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU; ++ } else if (count_device_type[VK_PHYSICAL_DEVICE_TYPE_CPU]) { ++ search_for_device_type = VK_PHYSICAL_DEVICE_TYPE_CPU; ++ } else if (count_device_type[VK_PHYSICAL_DEVICE_TYPE_OTHER]) { ++ search_for_device_type = VK_PHYSICAL_DEVICE_TYPE_OTHER; ++ } ++ ++ for (uint32_t i = 0; i < gpu_count; i++) { ++ vkGetPhysicalDeviceProperties(physical_devices[i], &physicalDeviceProperties); ++ if (physicalDeviceProperties.deviceType == search_for_device_type) { ++ demo->gpu_number = i; ++ break; ++ } + } + } + } +-#endif ++ + assert(demo->gpu_number >= 0); + demo->gpu = physical_devices[demo->gpu_number]; + { +@@ -3828,81 +4364,108 @@ static void demo_create_device(struct demo *demo) { + } + + static void demo_create_surface(struct demo *demo) { +- VkResult U_ASSERT_ONLY err; ++ VkResult U_ASSERT_ONLY err = VK_SUCCESS; + + // Create a WSI surface for the window: + #if defined(VK_USE_PLATFORM_WIN32_KHR) +- VkWin32SurfaceCreateInfoKHR createInfo; +- createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; +- createInfo.pNext = NULL; +- createInfo.flags = 0; +- createInfo.hinstance = demo->connection; +- createInfo.hwnd = demo->window; +- +- err = vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface); +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- VkWaylandSurfaceCreateInfoKHR createInfo; +- createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; +- createInfo.pNext = NULL; +- createInfo.flags = 0; +- createInfo.display = demo->display; +- createInfo.surface = demo->window; +- +- err = vkCreateWaylandSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface); +-#elif defined(VK_USE_PLATFORM_ANDROID_KHR) +- VkAndroidSurfaceCreateInfoKHR createInfo; +- createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; +- createInfo.pNext = NULL; +- createInfo.flags = 0; +- createInfo.window = (struct ANativeWindow *)(demo->window); +- +- err = vkCreateAndroidSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface); +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) +- VkXlibSurfaceCreateInfoKHR createInfo; +- createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; +- createInfo.pNext = NULL; +- createInfo.flags = 0; +- createInfo.dpy = demo->display; +- createInfo.window = demo->xlib_window; +- +- err = vkCreateXlibSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface); +-#elif defined(VK_USE_PLATFORM_XCB_KHR) +- VkXcbSurfaceCreateInfoKHR createInfo; +- createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; +- createInfo.pNext = NULL; +- createInfo.flags = 0; +- createInfo.connection = demo->connection; +- createInfo.window = demo->xcb_window; +- +- err = vkCreateXcbSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface); +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) +- VkDirectFBSurfaceCreateInfoEXT createInfo; +- createInfo.sType = VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT; +- createInfo.pNext = NULL; +- createInfo.flags = 0; +- createInfo.dfb = demo->dfb; +- createInfo.surface = demo->window; +- +- err = vkCreateDirectFBSurfaceEXT(demo->inst, &createInfo, NULL, &demo->surface); +-#elif defined(VK_USE_PLATFORM_DISPLAY_KHR) +- err = demo_create_display_surface(demo); +-#elif defined(VK_USE_PLATFORM_METAL_EXT) +- VkMetalSurfaceCreateInfoEXT surface; +- surface.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; +- surface.pNext = NULL; +- surface.flags = 0; +- surface.pLayer = demo->caMetalLayer; +- +- err = vkCreateMetalSurfaceEXT(demo->inst, &surface, NULL, &demo->surface); +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) +- VkScreenSurfaceCreateInfoQNX createInfo; +- createInfo.sType = VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX; +- createInfo.pNext = NULL; +- createInfo.flags = 0; +- createInfo.context = demo->screen_context; +- createInfo.window = demo->screen_window; +- +- err = vkCreateScreenSurfaceQNX(demo->inst, &createInfo, NULL, &demo->surface); ++ if (demo->wsi_platform == WSI_PLATFORM_WIN32) { ++ VkWin32SurfaceCreateInfoKHR win32_createInfo; ++ win32_createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; ++ win32_createInfo.pNext = NULL; ++ win32_createInfo.flags = 0; ++ win32_createInfo.hinstance = demo->connection; ++ win32_createInfo.hwnd = demo->window; ++ ++ err = vkCreateWin32SurfaceKHR(demo->inst, &win32_createInfo, NULL, &demo->surface); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_WAYLAND) { ++ VkWaylandSurfaceCreateInfoKHR wayland_createInfo; ++ wayland_createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; ++ wayland_createInfo.pNext = NULL; ++ wayland_createInfo.flags = 0; ++ wayland_createInfo.display = demo->wayland_display; ++ wayland_createInfo.surface = demo->window; ++ ++ err = vkCreateWaylandSurfaceKHR(demo->inst, &wayland_createInfo, NULL, &demo->surface); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_ANDROID) { ++ VkAndroidSurfaceCreateInfoKHR android_createInfo; ++ android_createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; ++ android_createInfo.pNext = NULL; ++ android_createInfo.flags = 0; ++ android_createInfo.window = (struct ANativeWindow *)(demo->window); ++ ++ err = vkCreateAndroidSurfaceKHR(demo->inst, &android_createInfo, NULL, &demo->surface); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_XLIB) { ++ VkXlibSurfaceCreateInfoKHR xlib_createInfo; ++ xlib_createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; ++ xlib_createInfo.pNext = NULL; ++ xlib_createInfo.flags = 0; ++ xlib_createInfo.dpy = demo->xlib_display; ++ xlib_createInfo.window = demo->xlib_window; ++ ++ err = vkCreateXlibSurfaceKHR(demo->inst, &xlib_createInfo, NULL, &demo->surface); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_XCB) { ++ VkXcbSurfaceCreateInfoKHR xcb_createInfo; ++ xcb_createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; ++ xcb_createInfo.pNext = NULL; ++ xcb_createInfo.flags = 0; ++ xcb_createInfo.connection = demo->connection; ++ xcb_createInfo.window = demo->xcb_window; ++ ++ err = vkCreateXcbSurfaceKHR(demo->inst, &xcb_createInfo, NULL, &demo->surface); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (demo->wsi_platform == WSI_PLATFORM_DIRECTFB) { ++ VkDirectFBSurfaceCreateInfoEXT directfb_createInfo; ++ directfb_createInfo.sType = VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT; ++ directfb_createInfo.pNext = NULL; ++ directfb_createInfo.flags = 0; ++ directfb_createInfo.dfb = demo->dfb; ++ directfb_createInfo.surface = demo->directfb_window; ++ ++ err = vkCreateDirectFBSurfaceEXT(demo->inst, &directfb_createInfo, NULL, &demo->surface); ++ } ++ ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ if (demo->wsi_platform == WSI_PLATFORM_DISPLAY) { ++ err = demo_create_display_surface(demo); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ if (demo->wsi_platform == WSI_PLATFORM_METAL) { ++ VkMetalSurfaceCreateInfoEXT metal_createInfo; ++ metal_createInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; ++ metal_createInfo.pNext = NULL; ++ metal_createInfo.flags = 0; ++ metal_createInfo.pLayer = demo->caMetalLayer; ++ ++ err = vkCreateMetalSurfaceEXT(demo->inst, &metal_createInfo, NULL, &demo->surface); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (demo->wsi_platform == WSI_PLATFORM_QNX) { ++ VkScreenSurfaceCreateInfoQNX qnx_createInfo; ++ qnx_createInfo.sType = VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX; ++ qnx_createInfo.pNext = NULL; ++ qnx_createInfo.flags = 0; ++ qnx_createInfo.context = demo->screen_context; ++ qnx_createInfo.window = demo->screen_window; ++ ++ err = vkCreateScreenSurfaceQNX(demo->inst, &qnx_createInfo, NULL, &demo->surface); ++ } + #endif + assert(!err); + } +@@ -4038,159 +4601,6 @@ static void demo_init_vk_swapchain(struct demo *demo) { + vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties); + } + +-#if defined(VK_USE_PLATFORM_WAYLAND_KHR) +-static void pointer_handle_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, +- wl_fixed_t sy) {} +- +-static void pointer_handle_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) {} +- +-static void pointer_handle_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) {} +- +-static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, +- uint32_t state) { +- struct demo *demo = data; +- if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) { +- xdg_toplevel_move(demo->xdg_toplevel, demo->seat, serial); +- } +-} +- +-static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {} +- +-static const struct wl_pointer_listener pointer_listener = { +- pointer_handle_enter, pointer_handle_leave, pointer_handle_motion, pointer_handle_button, pointer_handle_axis, +-}; +- +-static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) {} +- +-static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, +- struct wl_array *keys) {} +- +-static void keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) {} +- +-static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, +- uint32_t state) { +- if (state != WL_KEYBOARD_KEY_STATE_RELEASED) return; +- struct demo *demo = data; +- switch (key) { +- case KEY_ESC: // Escape +- demo->quit = true; +- break; +- case KEY_LEFT: // left arrow key +- demo->spin_angle -= demo->spin_increment; +- break; +- case KEY_RIGHT: // right arrow key +- demo->spin_angle += demo->spin_increment; +- break; +- case KEY_SPACE: // space bar +- demo->pause = !demo->pause; +- break; +- } +-} +- +-static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, +- uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {} +- +-static const struct wl_keyboard_listener keyboard_listener = { +- keyboard_handle_keymap, keyboard_handle_enter, keyboard_handle_leave, keyboard_handle_key, keyboard_handle_modifiers, +-}; +- +-static void seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps) { +- // Subscribe to pointer events +- struct demo *demo = data; +- if ((caps & WL_SEAT_CAPABILITY_POINTER) && !demo->pointer) { +- demo->pointer = wl_seat_get_pointer(seat); +- wl_pointer_add_listener(demo->pointer, &pointer_listener, demo); +- } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && demo->pointer) { +- wl_pointer_destroy(demo->pointer); +- demo->pointer = NULL; +- } +- // Subscribe to keyboard events +- if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { +- demo->keyboard = wl_seat_get_keyboard(seat); +- wl_keyboard_add_listener(demo->keyboard, &keyboard_listener, demo); +- } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && demo->keyboard) { +- wl_keyboard_destroy(demo->keyboard); +- demo->keyboard = NULL; +- } +-} +- +-static const struct wl_seat_listener seat_listener = { +- seat_handle_capabilities, +-}; +- +-static void wm_base_ping(void *data UNUSED, struct xdg_wm_base *xdg_wm_base, uint32_t serial) { +- xdg_wm_base_pong(xdg_wm_base, serial); +-} +- +-static const struct xdg_wm_base_listener wm_base_listener = {wm_base_ping}; +- +-static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, +- uint32_t version UNUSED) { +- struct demo *demo = data; +- // pickup wayland objects when they appear +- if (strcmp(interface, wl_compositor_interface.name) == 0) { +- uint32_t minVersion = version < 4 ? version : 4; +- demo->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, minVersion); +- if (demo->VK_KHR_incremental_present_enabled && minVersion < 4) { +- fprintf(stderr, "Wayland compositor doesn't support VK_KHR_incremental_present, disabling.\n"); +- demo->VK_KHR_incremental_present_enabled = false; +- } +- } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { +- demo->xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1); +- xdg_wm_base_add_listener(demo->xdg_wm_base, &wm_base_listener, NULL); +- } else if (strcmp(interface, wl_seat_interface.name) == 0) { +- demo->seat = wl_registry_bind(registry, id, &wl_seat_interface, 1); +- wl_seat_add_listener(demo->seat, &seat_listener, demo); +- } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { +- demo->xdg_decoration_mgr = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); +- } +-} +- +-static void registry_handle_global_remove(void *data UNUSED, struct wl_registry *registry UNUSED, uint32_t name UNUSED) {} +- +-static const struct wl_registry_listener registry_listener = {registry_handle_global, registry_handle_global_remove}; +-#endif +- +-static void demo_init_connection(struct demo *demo) { +-#if defined(VK_USE_PLATFORM_XCB_KHR) +- const xcb_setup_t *setup; +- xcb_screen_iterator_t iter; +- int scr; +- +- const char *display_envar = getenv("DISPLAY"); +- if (display_envar == NULL || display_envar[0] == '\0') { +- printf("Environment variable DISPLAY requires a valid value.\nExiting ...\n"); +- fflush(stdout); +- exit(1); +- } +- +- demo->connection = xcb_connect(NULL, &scr); +- if (xcb_connection_has_error(demo->connection) > 0) { +- printf("Cannot connect to XCB.\nExiting ...\n"); +- fflush(stdout); +- exit(1); +- } +- +- setup = xcb_get_setup(demo->connection); +- iter = xcb_setup_roots_iterator(setup); +- while (scr-- > 0) xcb_screen_next(&iter); +- +- demo->screen = iter.data; +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- demo->display = wl_display_connect(NULL); +- +- if (demo->display == NULL) { +- printf("Cannot connect to wayland.\nExiting ...\n"); +- fflush(stdout); +- exit(1); +- } +- +- demo->registry = wl_display_get_registry(demo->display); +- wl_registry_add_listener(demo->registry, ®istry_listener, demo); +- wl_display_roundtrip(demo->display); +-#endif +-} +- + static void demo_init(struct demo *demo, int argc, char **argv) { + vec3 eye = {0.0f, 3.0f, 5.0f}; + vec3 origin = {0, 0, 0}; +@@ -4223,7 +4633,7 @@ static void demo_init(struct demo *demo, int argc, char **argv) { + continue; + } + if (strcmp(argv[i], "--xlib") == 0) { +- fprintf(stderr, "--xlib is deprecated and no longer does anything"); ++ fprintf(stderr, "--xlib is deprecated and no longer does anything\n"); + continue; + } + if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX && i < argc - 1 && +@@ -4275,10 +4685,85 @@ static void demo_init(struct demo *demo, int argc, char **argv) { + demo->force_errors = true; + continue; + } +- ++ if ((strcmp(argv[i], "--wsi") == 0) && (i < argc - 1)) { ++ size_t argc_len = strlen(argv[i + 1]); ++ for (size_t argc_i = 0; argc_i < argc_len; argc_i++) { ++ argv[i + 1][argc_i] = tolower(argv[i + 1][argc_i]); ++ } ++ WSI_PLATFORM selection = wsi_from_string(argv[i + 1]); ++ if (selection == WSI_PLATFORM_INVALID) { ++ printf( ++ "The --wsi parameter %s is not a supported WSI platform. The list of available platforms is available from " ++ "--help\n", ++ (const char *)&(argv[i + 1][0])); ++ fflush(stdout); ++ exit(1); ++ } ++ demo->wsi_platform = selection; ++ i++; ++ continue; ++ } + #if defined(ANDROID) + ERR_EXIT("Usage: vkcube [--validate]\n", "Usage"); + #else ++ ++ // Making the help for --wsi nice requires a little extra work since the list depends on what is available at ++ // compile time ++ size_t max_str_len = 100; ++ char *available_wsi_platforms = (char *)malloc(max_str_len); ++ memset(available_wsi_platforms, 0, max_str_len); ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ strncat(available_wsi_platforms, "xcb", max_str_len); ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ if (strlen(available_wsi_platforms) > 0) { ++ strncat(available_wsi_platforms, "|", max_str_len); ++ } ++ strncat(available_wsi_platforms, "xlib", max_str_len); ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ if (strlen(available_wsi_platforms) > 0) { ++ strncat(available_wsi_platforms, "|", max_str_len); ++ } ++ strncat(available_wsi_platforms, "wayland", max_str_len); ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (strlen(available_wsi_platforms) > 0) { ++ strncat(available_wsi_platforms, "|", max_str_len); ++ } ++ strncat(available_wsi_platforms, "directfb", max_str_len); ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ if (strlen(available_wsi_platforms) > 0) { ++ strncat(available_wsi_platforms, "|", max_str_len); ++ } ++ strncat(available_wsi_platforms, "display", max_str_len); ++#endif ++#if defined(VK_USE_PLATFORM_WIN32_KHR) ++ if (strlen(available_wsi_platforms) > 0) { ++ strncat(available_wsi_platforms, "|", max_str_len); ++ } ++ strncat(available_wsi_platforms, "win32", max_str_len); ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) ++ if (strlen(available_wsi_platforms) > 0) { ++ strncat(available_wsi_platforms, "|", max_str_len); ++ } ++ strncat(available_wsi_platforms, "android", max_str_len); ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ if (strlen(available_wsi_platforms) > 0) { ++ strncat(available_wsi_platforms, "|", max_str_len); ++ } ++ strncat(available_wsi_platforms, "metal", max_str_len); ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (strlen(available_wsi_platforms) > 0) { ++ strncat(available_wsi_platforms, "|", max_str_len); ++ } ++ strncat(available_wsi_platforms, "qnx", max_str_len); ++#endif ++ + char *message = + "Usage:\n %s\t[--use_staging] [--validate]\n" + "\t[--break] [--c ] [--suppress_popups]\n" +@@ -4287,19 +4772,20 @@ static void demo_init(struct demo *demo, int argc, char **argv) { + "\t[--present_mode ]\n" + "\t[--width ] [--height ]\n" + "\t[--force_errors]\n" ++ "\t[--wsi <%s>]\n" + "\t\n" + "\t\tVK_PRESENT_MODE_IMMEDIATE_KHR = %d\n" + "\t\tVK_PRESENT_MODE_MAILBOX_KHR = %d\n" + "\t\tVK_PRESENT_MODE_FIFO_KHR = %d\n" + "\t\tVK_PRESENT_MODE_FIFO_RELAXED_KHR = %d\n"; +- int length = snprintf(NULL, 0, message, APP_SHORT_NAME, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR, +- VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR); ++ int length = snprintf(NULL, 0, message, APP_SHORT_NAME, available_wsi_platforms, VK_PRESENT_MODE_IMMEDIATE_KHR, ++ VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR); + char *usage = (char *)malloc(length + 1); + if (!usage) { + exit(1); + } +- snprintf(usage, length + 1, message, APP_SHORT_NAME, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR, +- VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR); ++ snprintf(usage, length + 1, message, APP_SHORT_NAME, available_wsi_platforms, VK_PRESENT_MODE_IMMEDIATE_KHR, ++ VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR); + #if defined(_WIN32) + if (!demo->suppress_popups) MessageBox(NULL, usage, "Usage Error", MB_OK); + #else +@@ -4311,8 +4797,6 @@ static void demo_init(struct demo *demo, int argc, char **argv) { + #endif + } + +- demo_init_connection(demo); +- + demo_init_vk(demo); + + demo->spin_angle = 4.0f; +@@ -4418,7 +4902,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, + return (int)msg.wParam; + } + +-#elif defined(VK_USE_PLATFORM_METAL_EXT) ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) + static void demo_main(struct demo *demo, void *caMetalLayer, int argc, const char *argv[]) { + demo_init(demo, argc, (char **)argv); + demo->caMetalLayer = caMetalLayer; +@@ -4427,7 +4912,8 @@ static void demo_main(struct demo *demo, void *caMetalLayer, int argc, const cha + demo->spin_angle = 0.4f; + } + +-#elif defined(VK_USE_PLATFORM_ANDROID_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) + #include + #include + #include "android_util.h" +@@ -4514,40 +5000,94 @@ void android_main(struct android_app *app) { + } + } + } +-#else ++#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__QNX__) || defined(__GNU__) + int main(int argc, char **argv) { + struct demo demo; + + demo_init(&demo, argc, argv); ++ switch (demo.wsi_platform) { ++ default: ++ case (WSI_PLATFORM_AUTO): ++ fprintf(stderr, ++ "WSI platform should have already been set, indicating a bug. Please set a WSI platform manually with " ++ "--wsi\n"); ++ exit(1); ++ break; + #if defined(VK_USE_PLATFORM_XCB_KHR) +- demo_create_xcb_window(&demo); +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) +- demo_create_xlib_window(&demo); +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- demo_create_window(&demo); +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) +- demo_create_directfb_window(&demo); +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) +- demo_create_window(&demo); ++ case (WSI_PLATFORM_XCB): ++ demo_create_xcb_window(&demo); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ case (WSI_PLATFORM_XLIB): ++ demo_create_xlib_window(&demo); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ case (WSI_PLATFORM_WAYLAND): ++ demo_create_wayland_window(&demo); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ case (WSI_PLATFORM_DIRECTFB): ++ demo_create_directfb_window(&demo); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ case (WSI_PLATFORM_QNX): ++ demo_create_screen_window(&demo); ++ break; + #endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ case (WSI_PLATFORM_DISPLAY): ++ // nothing to do here ++ break; ++#endif ++ } + + demo_init_vk_swapchain(&demo); + + demo_prepare(&demo); + ++ switch (demo.wsi_platform) { ++ default: ++ case (WSI_PLATFORM_AUTO): ++ fprintf(stderr, ++ "WSI platform should have already been set, indicating a bug. Please set a WSI platform manually with " ++ "--wsi\n"); ++ exit(1); ++ break; + #if defined(VK_USE_PLATFORM_XCB_KHR) +- demo_run_xcb(&demo); +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) +- demo_run_xlib(&demo); +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- demo_run(&demo); +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) +- demo_run_directfb(&demo); +-#elif defined(VK_USE_PLATFORM_DISPLAY_KHR) +- demo_run_display(&demo); +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) +- demo_run(&demo); ++ case (WSI_PLATFORM_XCB): ++ demo_run_xcb(&demo); ++ break; + #endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ case (WSI_PLATFORM_XLIB): ++ demo_run_xlib(&demo); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ case (WSI_PLATFORM_WAYLAND): ++ demo_run(&demo); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ case (WSI_PLATFORM_DIRECTFB): ++ demo_run_directfb(&demo); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ case (WSI_PLATFORM_DISPLAY): ++ demo_run_display(&demo); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ case (WSI_PLATFORM_QNX): ++ demo_run(&demo); ++ break; ++#endif ++ } + + demo_cleanup(&demo); + +diff --git a/cube/cube.cpp b/cube/cube.cpp +index 46b6fdb3..024d3eac 100644 +--- a/cube/cube.cpp ++++ b/cube/cube.cpp +@@ -19,14 +19,6 @@ + * Author: Charles Giessen + */ + +-#if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR) +-#include +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +-#include +-#include "xdg-shell-client-header.h" +-#include "xdg-decoration-client-header.h" +-#endif +- + #include + #include + #include +@@ -38,6 +30,17 @@ + #include + #include + ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++#include "xlib_loader.h" ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++#include "xcb_loader.h" ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++#include ++#include "wayland_loader.h" ++#endif ++ + #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 + #define VULKAN_HPP_NO_EXCEPTIONS + #define VULKAN_HPP_TYPESAFE_CONVERSION 1 +@@ -197,6 +200,96 @@ static const float g_uv_buffer_data[] = { + 1.0f, 0.0f, + }; + // clang-format on ++enum class WsiPlatform { ++ auto_ = 0, ++ win32, ++ metal, ++ android, ++ qnx, ++ xcb, ++ xlib, ++ wayland, ++ directfb, ++ display, ++ invalid, // Sentinel just to indicate invalid user input ++}; ++ ++WsiPlatform wsi_from_string(std::string const &str) { ++ if (str == "auto") return WsiPlatform::auto_; ++#if defined(VK_USE_PLATFORM_WIN32_KHR) ++ if (str == "win32") return WsiPlatform::win32; ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ if (str == "metal") return WsiPlatform::metal; ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) ++ if (str == "android") return WsiPlatform::android; ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (str == "qnx") return WsiPlatform::qnx; ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ if (str == "xcb") return WsiPlatform::xcb; ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ if (str == "xlib") return WsiPlatform::xlib; ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ if (str == "wayland") return WsiPlatform::wayland; ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (str == "directfb") return WsiPlatform::directfb; ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ if (str == "display") return WsiPlatform::display; ++#endif ++ return WsiPlatform::invalid; ++}; ++ ++const char *wsi_to_string(WsiPlatform wsi_platform) { ++ switch (wsi_platform) { ++ case (WsiPlatform::auto_): ++ return "auto"; ++#if defined(VK_USE_PLATFORM_WIN32_KHR) ++ case (WsiPlatform::win32): ++ return "win32"; ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ case (WsiPlatform::metal): ++ return "metal"; ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) ++ case (WsiPlatform::android): ++ return "android"; ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ case (WsiPlatform::qnx): ++ return "qnx"; ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ case (WsiPlatform::xcb): ++ return "xcb"; ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ case (WsiPlatform::xlib): ++ return "xlib"; ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ case (WsiPlatform::wayland): ++ return "wayland"; ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ case (WsiPlatform::directfb): ++ return "directfb"; ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ case (WsiPlatform::display): ++ return "display"; ++#endif ++ default: ++ return "unknown"; ++ } ++}; + + struct SwapchainImageResources { + vk::Image image; +@@ -222,7 +315,7 @@ struct Demo { + void prepare_init_cmd(); + void flush_init_cmd(); + void init(int argc, char **argv); +- void init_connection(); ++ void check_and_set_wsi_platform(); + void init_vk(); + void init_vk_swapchain(); + void prepare(); +@@ -260,27 +353,37 @@ struct Demo { + #if defined(VK_USE_PLATFORM_WIN32_KHR) + void run(); + void create_window(); +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ const char *init_xlib_connection(); + void create_xlib_window(); + void handle_xlib_event(const XEvent *event); + void run_xlib(); +-#elif defined(VK_USE_PLATFORM_XCB_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ const char *init_xcb_connection(); + void handle_xcb_event(const xcb_generic_event_t *event); + void run_xcb(); + void create_xcb_window(); +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- void run(); +- void create_window(); +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ const char *init_wayland_connection(); ++ void run_wayland(); ++ void create_wayland_window(); ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) + void handle_directfb_event(const DFBInputEvent *event); + void run_directfb(); + void create_directfb_window(); +-#elif defined(VK_USE_PLATFORM_METAL_EXT) ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) + void run(); +-#elif defined(VK_USE_PLATFORM_DISPLAY_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) + vk::Result create_display_surface(); + void run_display(); +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) + void run(); + void create_window(); + #endif +@@ -290,20 +393,26 @@ struct Demo { + HINSTANCE connection = nullptr; // hInstance - Windows Instance + HWND window = nullptr; // hWnd - window handle + POINT minsize = {0, 0}; // minimum window size +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ void *xlib_library; + Window xlib_window = 0; + Atom xlib_wm_delete_window = 0; +- Display *display = nullptr; +-#elif defined(VK_USE_PLATFORM_XCB_KHR) ++ Display *xlib_display = nullptr; ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ void *xcb_library; + xcb_window_t xcb_window = 0; + xcb_screen_t *screen = nullptr; + xcb_connection_t *connection = nullptr; + xcb_intern_atom_reply_t *atom_wm_delete_window = nullptr; +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- wl_display *display = nullptr; ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ void *wayland_library = nullptr; ++ wl_display *wayland_display = nullptr; + wl_registry *registry = nullptr; + wl_compositor *compositor = nullptr; +- wl_surface *window = nullptr; ++ wl_surface *wayland_window = nullptr; + xdg_wm_base *wm_base = nullptr; + zxdg_decoration_manager_v1 *xdg_decoration_mgr = nullptr; + zxdg_toplevel_decoration_v1 *toplevel_decoration = nullptr; +@@ -313,18 +422,21 @@ struct Demo { + wl_seat *seat = nullptr; + wl_pointer *pointer = nullptr; + wl_keyboard *keyboard = nullptr; +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) + IDirectFB *dfb = nullptr; +- IDirectFBSurface *window = nullptr; ++ IDirectFBSurface *directfb_window = nullptr; + IDirectFBEventBuffer *event_buffer = nullptr; +-#elif defined(VK_USE_PLATFORM_METAL_EXT) ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) + void *caMetalLayer; +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) + screen_context_t screen_context = nullptr; + screen_window_t screen_window = nullptr; + screen_event_t screen_event = nullptr; + #endif +- ++ WsiPlatform wsi_platform = WsiPlatform::auto_; + vk::SurfaceKHR surface; + bool prepared = false; + bool use_staging_buffer = false; +@@ -596,32 +708,44 @@ void Demo::cleanup() { + inst.destroySurfaceKHR(surface); + + #if defined(VK_USE_PLATFORM_XLIB_KHR) +- XDestroyWindow(display, xlib_window); +- XCloseDisplay(display); +-#elif defined(VK_USE_PLATFORM_XCB_KHR) +- xcb_destroy_window(connection, xcb_window); +- xcb_disconnect(connection); +- free(atom_wm_delete_window); +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- if (keyboard) wl_keyboard_destroy(keyboard); +- if (pointer) wl_pointer_destroy(pointer); +- if (seat) wl_seat_destroy(seat); +- xdg_toplevel_destroy(window_toplevel); +- xdg_surface_destroy(window_surface); +- wl_surface_destroy(window); +- xdg_wm_base_destroy(wm_base); +- if (xdg_decoration_mgr) { +- zxdg_toplevel_decoration_v1_destroy(toplevel_decoration); +- zxdg_decoration_manager_v1_destroy(xdg_decoration_mgr); +- } +- wl_compositor_destroy(compositor); +- wl_registry_destroy(registry); +- wl_display_disconnect(display); +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) +- event_buffer->Release(event_buffer); +- window->Release(window); +- dfb->Release(dfb); +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (wsi_platform == WsiPlatform::xlib) { ++ XDestroyWindow(xlib_display, xlib_window); ++ XCloseDisplay(xlib_display); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ if (wsi_platform == WsiPlatform::xcb) { ++ xcb_destroy_window(connection, xcb_window); ++ xcb_disconnect(connection); ++ free(atom_wm_delete_window); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ if (wsi_platform == WsiPlatform::wayland) { ++ if (keyboard) wl_keyboard_destroy(keyboard); ++ if (pointer) wl_pointer_destroy(pointer); ++ if (seat) wl_seat_destroy(seat); ++ xdg_toplevel_destroy(window_toplevel); ++ xdg_surface_destroy(window_surface); ++ wl_surface_destroy(wayland_window); ++ xdg_wm_base_destroy(wm_base); ++ if (xdg_decoration_mgr) { ++ zxdg_toplevel_decoration_v1_destroy(toplevel_decoration); ++ zxdg_decoration_manager_v1_destroy(xdg_decoration_mgr); ++ } ++ wl_compositor_destroy(compositor); ++ wl_registry_destroy(registry); ++ wl_display_disconnect(wayland_display); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (wsi_platform == WsiPlatform::directfb) { ++ event_buffer->Release(event_buffer); ++ directfb_window->Release(directfb_window); ++ dfb->Release(dfb); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) + screen_destroy_event(screen_event); + screen_destroy_window(screen_window); + screen_destroy_context(screen_context); +@@ -887,7 +1011,7 @@ void Demo::init(int argc, char **argv) { + continue; + } + if (strcmp(argv[i], "--xlib") == 0) { +- fprintf(stderr, "--xlib is deprecated and no longer does anything"); ++ fprintf(stderr, "--xlib is deprecated and no longer does anything\n"); + continue; + } + if (strcmp(argv[i], "--c") == 0 && frameCount == UINT32_MAX && i < argc - 1 && +@@ -935,6 +1059,61 @@ void Demo::init(int argc, char **argv) { + force_errors = true; + continue; + } ++ if ((strcmp(argv[i], "--wsi") == 0) && (i < argc - 1)) { ++ std::string selection_input = argv[i + 1]; ++ for (char &c : selection_input) { ++ c = std::tolower(c); ++ } ++ WsiPlatform selection = wsi_from_string(selection_input); ++ if (selection == WsiPlatform::invalid) { ++ printf( ++ "The --wsi parameter %s is not a supported WSI platform. The list of available platforms is available from " ++ "--help\n", ++ (const char *)&(argv[i + 1][0])); ++ fflush(stdout); ++ exit(1); ++ } ++ wsi_platform = selection; ++ i++; ++ continue; ++ } ++ ++ std::string wsi_platforms; ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ wsi_platforms.append("xcb"); ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ if (!wsi_platforms.empty()) wsi_platforms.append("|"); ++ wsi_platforms.append("xlib"); ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ if (!wsi_platforms.empty()) wsi_platforms.append("|"); ++ wsi_platforms.append("wayland"); ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (!wsi_platforms.empty()) wsi_platforms.append("|"); ++ wsi_platforms.append("directfb"); ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ if (!wsi_platforms.empty()) wsi_platforms.append("|"); ++ wsi_platforms.append("display"); ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ if (!wsi_platforms.empty()) wsi_platforms.append("|"); ++ wsi_platforms.append("metal"); ++#endif ++#if defined(VK_USE_PLATFORM_WIN32_KHR) ++ if (!wsi_platforms.empty()) wsi_platforms.append("|"); ++ wsi_platforms.append("win32"); ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) ++ if (!wsi_platforms.empty()) wsi_platforms.append("|"); ++ wsi_platforms.append("android"); ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (!wsi_platforms.empty()) wsi_platforms.append("|"); ++ wsi_platforms.append("qnx"); ++#endif + std::stringstream usage; + usage << "Usage:\n " << APP_SHORT_NAME << "\t[--use_staging] [--validate]\n" + << "\t[--break] [--c ] [--suppress_popups]\n" +@@ -942,6 +1121,7 @@ void Demo::init(int argc, char **argv) { + << "\t[--present_mode ]\n" + << "\t[--width ] [--height ]\n" + << "\t[--force_errors]\n" ++ << "\t[--wsi <" << wsi_platforms << ">]\n" + << "\t\n" + << "\t\tVK_PRESENT_MODE_IMMEDIATE_KHR = " << VK_PRESENT_MODE_IMMEDIATE_KHR << "\n" + << "\t\tVK_PRESENT_MODE_MAILBOX_KHR = " << VK_PRESENT_MODE_MAILBOX_KHR << "\n" +@@ -957,8 +1137,6 @@ void Demo::init(int argc, char **argv) { + exit(1); + } + +- init_connection(); +- + init_vk(); + + spin_angle = 4.0f; +@@ -972,24 +1150,24 @@ void Demo::init(int argc, char **argv) { + projection_matrix[1][1] *= -1; // Flip projection matrix from GL to Vulkan orientation. + } + +-void Demo::init_connection() { + #if defined(VK_USE_PLATFORM_XCB_KHR) ++const char *Demo::init_xcb_connection() { ++ xcb_library = initialize_xcb(); ++ if (NULL == xcb_library) { ++ return "Cannot load XLIB dynamic library."; ++ } + const xcb_setup_t *setup; + xcb_screen_iterator_t iter; + int scr; + + const char *display_envar = getenv("DISPLAY"); + if (display_envar == nullptr || display_envar[0] == '\0') { +- printf("Environment variable DISPLAY requires a valid value.\nExiting ...\n"); +- fflush(stdout); +- exit(1); ++ return "Environment variable DISPLAY requires a valid value."; + } + + connection = xcb_connect(nullptr, &scr); + if (xcb_connection_has_error(connection) > 0) { +- printf("Cannot connect to XCB.\nExiting ...\n"); +- fflush(stdout); +- exit(1); ++ return "Cannot connect to XCB."; + } + + setup = xcb_get_setup(connection); +@@ -997,18 +1175,155 @@ void Demo::init_connection() { + while (scr-- > 0) xcb_screen_next(&iter); + + screen = iter.data; +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- display = wl_display_connect(nullptr); ++ return NULL; ++} ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++const char *Demo::init_xlib_connection() { ++ xlib_library = initialize_xlib(); ++ if (NULL == xlib_library) { ++ return "Cannot load XLIB dynamic library."; ++ } ++ return NULL; ++} ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++const char *Demo::init_wayland_connection() { ++ wayland_library = initialize_wayland(); ++ if (NULL == wayland_library) { ++ return "Cannot load wayland dynamic library."; ++ } ++ wayland_display = wl_display_connect(nullptr); + +- if (display == nullptr) { +- printf("Cannot connect to wayland.\nExiting ...\n"); +- fflush(stdout); +- exit(1); ++ if (wayland_display == nullptr) { ++ return "Cannot connect to wayland."; + } + +- registry = wl_display_get_registry(display); ++ registry = wl_display_get_registry(wayland_display); + wl_registry_add_listener(registry, ®istry_listener, this); +- wl_display_dispatch(display); ++ wl_display_dispatch(wayland_display); ++ return NULL; ++} ++#endif ++ ++void Demo::check_and_set_wsi_platform() { ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ if (wsi_platform == WsiPlatform::xcb || wsi_platform == WsiPlatform::auto_) { ++ auto found = std::find_if(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), ++ [](const char *str) { return 0 == strcmp(str, VK_KHR_XCB_SURFACE_EXTENSION_NAME); }); ++ if (found != enabled_instance_extensions.end()) { ++ const char *error_msg = init_xcb_connection(); ++ if (error_msg != NULL) { ++ if (wsi_platform == WsiPlatform::xcb) { ++ fprintf(stderr, "%s\nExiting ...\n", error_msg); ++ fflush(stdout); ++ exit(1); ++ } ++ } else { ++ wsi_platform = WsiPlatform::xcb; ++ return; ++ } ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ if (wsi_platform == WsiPlatform::xlib || wsi_platform == WsiPlatform::auto_) { ++ auto found = std::find_if(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), ++ [](const char *str) { return 0 == strcmp(str, VK_KHR_XLIB_SURFACE_EXTENSION_NAME); }); ++ if (found != enabled_instance_extensions.end()) { ++ const char *error_msg = init_xlib_connection(); ++ if (error_msg != NULL) { ++ if (wsi_platform == WsiPlatform::xlib) { ++ fprintf(stderr, "%s\nExiting ...\n", error_msg); ++ fflush(stdout); ++ exit(1); ++ } ++ } else { ++ wsi_platform = WsiPlatform::xlib; ++ return; ++ } ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ if (wsi_platform == WsiPlatform::wayland || wsi_platform == WsiPlatform::auto_) { ++ auto found = std::find_if(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), ++ [](const char *str) { return 0 == strcmp(str, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); }); ++ if (found != enabled_instance_extensions.end()) { ++ const char *error_msg = init_wayland_connection(); ++ if (error_msg != NULL) { ++ if (wsi_platform == WsiPlatform::wayland) { ++ fprintf(stderr, "%s\nExiting ...\n", error_msg); ++ fflush(stdout); ++ exit(1); ++ } ++ } else { ++ wsi_platform = WsiPlatform::wayland; ++ return; ++ } ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (wsi_platform == WsiPlatform::directfb || wsi_platform == WsiPlatform::auto_) { ++ auto found = std::find_if(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), ++ [](const char *str) { return 0 == strcmp(str, VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME); }); ++ if (found != enabled_instance_extensions.end()) { ++ // Because DirectFB is still linked in, we can assume that it works if we got here ++ wsi_platform = WsiPlatform::directfb; ++ return; ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_WIN32_KHR) ++ if (wsi_platform == WsiPlatform::win32 || wsi_platform == WsiPlatform::auto_) { ++ auto found = std::find_if(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), ++ [](const char *str) { return 0 == strcmp(str, VK_KHR_WIN32_SURFACE_EXTENSION_NAME); }); ++ if (found != enabled_instance_extensions.end()) { ++ wsi_platform = WsiPlatform::win32; ++ return; ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_ANDROID_KHR) ++ if (wsi_platform == WsiPlatform::android || wsi_platform == WsiPlatform::auto_) { ++ auto found = std::find_if(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), ++ [](const char *str) { return 0 == strcmp(str, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); }); ++ if (found != enabled_instance_extensions.end()) { ++ wsi_platform = WsiPlatform::android; ++ return; ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ if (wsi_platform == WsiPlatform::metal || wsi_platform == WsiPlatform::auto_) { ++ auto found = std::find_if(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), ++ [](const char *str) { return 0 == strcmp(str, VK_EXT_METAL_SURFACE_EXTENSION_NAME); }); ++ if (found != enabled_instance_extensions.end()) { ++ wsi_platform = WsiPlatform::metal; ++ return; ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (wsi_platform == WsiPlatform::qnx || wsi_platform == WsiPlatform::auto_) { ++ auto found = std::find_if(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), ++ [](const char *str) { return 0 == strcmp(str, VK_QNX_SCREEN_SURFACE_EXTENSION_NAME); }); ++ if (found != enabled_instance_extensions.end()) { ++ wsi_platform = WsiPlatform::qnx; ++ return; ++ } ++ } ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ if (wsi_platform == WsiPlatform::display || wsi_platform == WsiPlatform::auto_) { ++ auto found = std::find_if(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), ++ [](const char *str) { return 0 == strcmp(str, VK_KHR_DISPLAY_EXTENSION_NAME); }); ++ if (found != enabled_instance_extensions.end()) { ++ wsi_platform = WsiPlatform::display; ++ return; ++ } ++ } + #endif + } + #if defined(VK_USE_PLATFORM_DISPLAY_KHR) +@@ -1018,13 +1333,13 @@ int find_display_gpu(int gpu_number, const std::vector &phys + if (gpu_number >= 0) { + auto display_props_return = physical_devices[gpu_number].getDisplayPropertiesKHR(); + VERIFY(display_props_return.result == vk::Result::eSuccess); +- display_count = display_props_return.value.size(); ++ display_count = static_cast(display_props_return.value.size()); + } else { + for (uint32_t i = 0; i < physical_devices.size(); i++) { + auto display_props_return = physical_devices[i].getDisplayPropertiesKHR(); + VERIFY(display_props_return.result == vk::Result::eSuccess); + if (display_props_return.value.size() > 0) { +- display_count = display_props_return.value.size(); ++ display_count = static_cast(display_props_return.value.size()); + gpu_return = i; + break; + } +@@ -1181,42 +1496,57 @@ void Demo::init_vk() { + enabled_instance_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); + } + #if defined(VK_USE_PLATFORM_WIN32_KHR) +- else if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, extension.extensionName)) { ++ else if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, extension.extensionName) && ++ (wsi_platform == WsiPlatform::auto_ || wsi_platform == WsiPlatform::win32)) { + platformSurfaceExtFound = 1; + enabled_instance_extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); + } +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) +- else if (!strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, extension.extensionName)) { ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ else if (!strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, extension.extensionName) && ++ (wsi_platform == WsiPlatform::auto_ || wsi_platform == WsiPlatform::xlib)) { + platformSurfaceExtFound = 1; + enabled_instance_extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); + } +-#elif defined(VK_USE_PLATFORM_XCB_KHR) +- else if (!strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME, extension.extensionName)) { ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ else if (!strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME, extension.extensionName) && ++ (wsi_platform == WsiPlatform::auto_ || wsi_platform == WsiPlatform::xcb)) { + platformSurfaceExtFound = 1; + enabled_instance_extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); + } +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- else if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, extension.extensionName)) { ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ else if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, extension.extensionName) && ++ (wsi_platform == WsiPlatform::auto_ || wsi_platform == WsiPlatform::wayland)) { + platformSurfaceExtFound = 1; + enabled_instance_extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); + } +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) +- else if (!strcmp(VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME, extension.extensionName)) { ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ else if (!strcmp(VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME, extension.extensionName) && ++ (wsi_platform == WsiPlatform::auto_ || wsi_platform == WsiPlatform::directfb)) { + platformSurfaceExtFound = 1; + enabled_instance_extensions.push_back(VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME); + } +-#elif defined(VK_USE_PLATFORM_DISPLAY_KHR) +- else if (!strcmp(VK_KHR_DISPLAY_EXTENSION_NAME, extension.extensionName)) { ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ else if (!strcmp(VK_KHR_DISPLAY_EXTENSION_NAME, extension.extensionName) && ++ (wsi_platform == WsiPlatform::auto_ || wsi_platform == WsiPlatform::display)) { + platformSurfaceExtFound = 1; + enabled_instance_extensions.push_back(VK_KHR_DISPLAY_EXTENSION_NAME); + } +-#elif defined(VK_USE_PLATFORM_METAL_EXT) +- else if (!strcmp(VK_EXT_METAL_SURFACE_EXTENSION_NAME, extension.extensionName)) { ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ else if (!strcmp(VK_EXT_METAL_SURFACE_EXTENSION_NAME, extension.extensionName) && ++ (wsi_platform == WsiPlatform::auto_ || wsi_platform == WsiPlatform::metal)) { + platformSurfaceExtFound = 1; + enabled_instance_extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME); + } +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) +- else if (!strcmp(VK_QNX_SCREEN_SURFACE_EXTENSION_NAME, extension.extensionName)) { ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ else if (!strcmp(VK_QNX_SCREEN_SURFACE_EXTENSION_NAME, extension.extensionName) && ++ (wsi_platform == WsiPlatform::auto_ || wsi_platform == WsiPlatform::qnx)) { + platformSurfaceExtFound = 1; + enabled_instance_extensions.push_back(VK_QNX_SCREEN_SURFACE_EXTENSION_NAME); + } +@@ -1233,56 +1563,93 @@ void Demo::init_vk() { + + if (!platformSurfaceExtFound) { + #if defined(VK_USE_PLATFORM_WIN32_KHR) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_XCB_KHR) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_XCB_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_XLIB_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_DISPLAY_KHR) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_DISPLAY_EXTENSION_NAME +- " extension.\n\n" +- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" +- "Please look at the Getting Started guide for additional information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_METAL_EXT) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_EXT_METAL_SURFACE_EXTENSION_NAME +- " extension.\n\nDo you have a compatible " +- "Vulkan installable client driver (ICD) installed?\nPlease " +- "look at the Getting Started guide for additional " +- "information.\n", +- "vkCreateInstance Failure"); +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) +- ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_QNX_SCREEN_SURFACE_EXTENSION_NAME +- " extension.\n\nDo you have a compatible " +- "Vulkan installable client driver (ICD) installed?\nPlease " +- "look at the Getting Started guide for additional " +- "information.\n", +- "vkCreateInstance Failure"); ++ if (wsi_platform == WsiPlatform::win32) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ if (wsi_platform == WsiPlatform::xcb) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_XCB_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ if (wsi_platform == WsiPlatform::wayland) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ if (wsi_platform == WsiPlatform::xlib) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_XLIB_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } + #endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (wsi_platform == WsiPlatform::directfb) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ if (wsi_platform == WsiPlatform::display) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_KHR_DISPLAY_EXTENSION_NAME ++ " extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) ++ if (wsi_platform == WsiPlatform::metal) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_EXT_METAL_SURFACE_EXTENSION_NAME ++ " extension.\n\nDo you have a compatible " ++ "Vulkan installable client driver (ICD) installed?\nPlease " ++ "look at the Getting Started guide for additional " ++ "information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (wsi_platform == WsiPlatform::qnx) { ++ ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " VK_QNX_SCREEN_SURFACE_EXTENSION_NAME ++ " extension.\n\nDo you have a compatible " ++ "Vulkan installable client driver (ICD) installed?\nPlease " ++ "look at the Getting Started guide for additional " ++ "information.\n", ++ "vkCreateInstance Failure"); ++ } ++#endif ++ ERR_EXIT( ++ "vkEnumerateInstanceExtensionProperties failed to find any supported WSI surface extension.\n\n" ++ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n" ++ "Please look at the Getting Started guide for additional information.\n", ++ "vkCreateInstance Failure"); ++ } ++ ++ bool auto_wsi_platform = wsi_platform == WsiPlatform::auto_; ++ ++ check_and_set_wsi_platform(); ++ ++ // Print a message to indicate the automatically set WSI platform ++ if (auto_wsi_platform && wsi_platform != WsiPlatform::auto_) { ++ fprintf(stderr, "Selected WSI platform: %s\n", wsi_to_string(wsi_platform)); + } + + vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | +@@ -1350,46 +1717,53 @@ void Demo::init_vk() { + fprintf(stderr, "GPU %d specified is not present, GPU count = %zu\n", gpu_number, physical_devices.size()); + ERR_EXIT("Specified GPU number is not present", "User Error"); + } ++ ++ if (wsi_platform == WsiPlatform::display) { + #if defined(VK_USE_PLATFORM_DISPLAY_KHR) +- gpu_number = find_display_gpu(gpu_number, physical_devices); +- if (gpu_number < 0) { +- printf("Cannot find any display!\n"); ++ gpu_number = find_display_gpu(gpu_number, physical_devices); ++ if (gpu_number < 0) { ++ printf("Cannot find any display!\n"); ++ fflush(stdout); ++ exit(1); ++ } ++#else ++ printf("WSI selection was set to DISPLAY but vkcubepp was not compiled with support for the DISPLAY platform, exiting \n"); + fflush(stdout); + exit(1); +- } +-#else +- /* Try to auto select most suitable device */ +- if (gpu_number == -1) { +- constexpr uint32_t device_type_count = static_cast(vk::PhysicalDeviceType::eCpu) + 1; +- std::array count_device_type{}; +- +- for (uint32_t i = 0; i < physical_devices.size(); i++) { +- const auto physicalDeviceProperties = physical_devices[i].getProperties(); +- assert(physicalDeviceProperties.deviceType <= vk::PhysicalDeviceType::eCpu); +- count_device_type[static_cast(physicalDeviceProperties.deviceType)]++; +- } ++#endif ++ } else { ++ /* Try to auto select most suitable device */ ++ if (gpu_number == -1) { ++ constexpr uint32_t device_type_count = static_cast(vk::PhysicalDeviceType::eCpu) + 1; ++ std::array count_device_type{}; ++ ++ for (uint32_t i = 0; i < physical_devices.size(); i++) { ++ const auto physicalDeviceProperties = physical_devices[i].getProperties(); ++ assert(physicalDeviceProperties.deviceType <= vk::PhysicalDeviceType::eCpu); ++ count_device_type[static_cast(physicalDeviceProperties.deviceType)]++; ++ } + +- std::array const device_type_preference = { +- vk::PhysicalDeviceType::eDiscreteGpu, vk::PhysicalDeviceType::eIntegratedGpu, vk::PhysicalDeviceType::eVirtualGpu, +- vk::PhysicalDeviceType::eCpu, vk::PhysicalDeviceType::eOther}; ++ std::array const device_type_preference = { ++ vk::PhysicalDeviceType::eDiscreteGpu, vk::PhysicalDeviceType::eIntegratedGpu, vk::PhysicalDeviceType::eVirtualGpu, ++ vk::PhysicalDeviceType::eCpu, vk::PhysicalDeviceType::eOther}; + +- vk::PhysicalDeviceType search_for_device_type = vk::PhysicalDeviceType::eDiscreteGpu; +- for (uint32_t i = 0; i < sizeof(device_type_preference) / sizeof(vk::PhysicalDeviceType); i++) { +- if (count_device_type[static_cast(device_type_preference[i])]) { +- search_for_device_type = device_type_preference[i]; +- break; ++ vk::PhysicalDeviceType search_for_device_type = vk::PhysicalDeviceType::eDiscreteGpu; ++ for (uint32_t i = 0; i < sizeof(device_type_preference) / sizeof(vk::PhysicalDeviceType); i++) { ++ if (count_device_type[static_cast(device_type_preference[i])]) { ++ search_for_device_type = device_type_preference[i]; ++ break; ++ } + } +- } + +- for (uint32_t i = 0; i < physical_devices.size(); i++) { +- const auto physicalDeviceProperties = physical_devices[i].getProperties(); +- if (physicalDeviceProperties.deviceType == search_for_device_type) { +- gpu_number = i; +- break; ++ for (uint32_t i = 0; i < physical_devices.size(); i++) { ++ const auto physicalDeviceProperties = physical_devices[i].getProperties(); ++ if (physicalDeviceProperties.deviceType == search_for_device_type) { ++ gpu_number = i; ++ break; ++ } + } + } + } +-#endif + assert(gpu_number >= 0); + gpu = physical_devices[gpu_number]; + { +@@ -1437,54 +1811,63 @@ void Demo::init_vk() { + void Demo::create_surface() { + // Create a WSI surface for the window: + #if defined(VK_USE_PLATFORM_WIN32_KHR) +- { ++ if (wsi_platform == WsiPlatform::win32) { + auto const createInfo = vk::Win32SurfaceCreateInfoKHR().setHinstance(connection).setHwnd(window); + + auto result = inst.createWin32SurfaceKHR(&createInfo, nullptr, &surface); + VERIFY(result == vk::Result::eSuccess); + } +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- { +- auto const createInfo = vk::WaylandSurfaceCreateInfoKHR().setDisplay(display).setSurface(window); ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ ++ if (wsi_platform == WsiPlatform::wayland) { ++ auto const createInfo = vk::WaylandSurfaceCreateInfoKHR().setDisplay(wayland_display).setSurface(wayland_window); + + auto result = inst.createWaylandSurfaceKHR(&createInfo, nullptr, &surface); + VERIFY(result == vk::Result::eSuccess); ++ return; + } +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) +- { +- auto const createInfo = vk::XlibSurfaceCreateInfoKHR().setDpy(display).setWindow(xlib_window); ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ if (wsi_platform == WsiPlatform::xlib) { ++ auto const createInfo = vk::XlibSurfaceCreateInfoKHR().setDpy(xlib_display).setWindow(xlib_window); + + auto result = inst.createXlibSurfaceKHR(&createInfo, nullptr, &surface); + VERIFY(result == vk::Result::eSuccess); + } +-#elif defined(VK_USE_PLATFORM_XCB_KHR) +- { ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) ++ if (wsi_platform == WsiPlatform::xcb) { + auto const createInfo = vk::XcbSurfaceCreateInfoKHR().setConnection(connection).setWindow(xcb_window); + + auto result = inst.createXcbSurfaceKHR(&createInfo, nullptr, &surface); + VERIFY(result == vk::Result::eSuccess); + } +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) +- { +- auto const createInfo = vk::DirectFBSurfaceCreateInfoEXT().setDfb(dfb).setSurface(window); ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ if (wsi_platform == WsiPlatform::directfb) { ++ auto const createInfo = vk::DirectFBSurfaceCreateInfoEXT().setDfb(dfb).setSurface(directfb_window); + + auto result = inst.createDirectFBSurfaceEXT(&createInfo, nullptr, &surface); + VERIFY(result == vk::Result::eSuccess); + } +-#elif defined(VK_USE_PLATFORM_METAL_EXT) ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) + { + auto const createInfo = vk::MetalSurfaceCreateInfoEXT().setPLayer(static_cast(caMetalLayer)); + + auto result = inst.createMetalSurfaceEXT(&createInfo, nullptr, &surface); + VERIFY(result == vk::Result::eSuccess); + } +-#elif defined(VK_USE_PLATFORM_DISPLAY_KHR) +- { ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ if (wsi_platform == WsiPlatform::display) { + auto result = create_display_surface(); + VERIFY(result == vk::Result::eSuccess); + } +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) +- { ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ if (wsi_platform == WsiPlatform::qnx) { + auto const createInfo = vk::ScreenSurfaceCreateInfoQNX().setContext(screen_context).setWindow(screen_window); + + auto result = inst.createScreenSurfaceQNX(&createInfo, nullptr, &surface); +@@ -2607,7 +2990,8 @@ void Demo::create_window() { + minsize.x = GetSystemMetrics(SM_CXMINTRACK); + minsize.y = GetSystemMetrics(SM_CYMINTRACK) + 1; + } +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) + + void Demo::create_xlib_window() { + const char *display_envar = getenv("DISPLAY"); +@@ -2618,14 +3002,15 @@ void Demo::create_xlib_window() { + } + + XInitThreads(); +- display = XOpenDisplay(nullptr); ++ xlib_display = XOpenDisplay(nullptr); + long visualMask = VisualScreenMask; + int numberOfVisuals; + XVisualInfo vInfoTemplate = {}; +- vInfoTemplate.screen = DefaultScreen(display); +- XVisualInfo *visualInfo = XGetVisualInfo(display, visualMask, &vInfoTemplate, &numberOfVisuals); ++ vInfoTemplate.screen = DefaultScreen(xlib_display); ++ XVisualInfo *visualInfo = XGetVisualInfo(xlib_display, visualMask, &vInfoTemplate, &numberOfVisuals); + +- Colormap colormap = XCreateColormap(display, RootWindow(display, vInfoTemplate.screen), visualInfo->visual, AllocNone); ++ Colormap colormap = ++ XCreateColormap(xlib_display, RootWindow(xlib_display, vInfoTemplate.screen), visualInfo->visual, AllocNone); + + XSetWindowAttributes windowAttributes = {}; + windowAttributes.colormap = colormap; +@@ -2634,13 +3019,13 @@ void Demo::create_xlib_window() { + windowAttributes.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask; + + xlib_window = +- XCreateWindow(display, RootWindow(display, vInfoTemplate.screen), 0, 0, width, height, 0, visualInfo->depth, InputOutput, +- visualInfo->visual, CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, &windowAttributes); ++ XCreateWindow(xlib_display, RootWindow(xlib_display, vInfoTemplate.screen), 0, 0, width, height, 0, visualInfo->depth, ++ InputOutput, visualInfo->visual, CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, &windowAttributes); + +- XSelectInput(display, xlib_window, ExposureMask | KeyPressMask); +- XMapWindow(display, xlib_window); +- XFlush(display); +- xlib_wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False); ++ XSelectInput(xlib_display, xlib_window, ExposureMask | KeyPressMask); ++ XMapWindow(xlib_display, xlib_window); ++ XFlush(xlib_display); ++ xlib_wm_delete_window = XInternAtom(xlib_display, "WM_DELETE_WINDOW", False); + } + + void Demo::handle_xlib_event(const XEvent *event) { +@@ -2683,11 +3068,11 @@ void Demo::run_xlib() { + XEvent event; + + if (pause) { +- XNextEvent(display, &event); ++ XNextEvent(xlib_display, &event); + handle_xlib_event(&event); + } +- while (XPending(display) > 0) { +- XNextEvent(display, &event); ++ while (XPending(xlib_display) > 0) { ++ XNextEvent(xlib_display, &event); + handle_xlib_event(&event); + } + +@@ -2699,7 +3084,8 @@ void Demo::run_xlib() { + } + } + } +-#elif defined(VK_USE_PLATFORM_XCB_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_XCB_KHR) + + void Demo::handle_xcb_event(const xcb_generic_event_t *event) { + uint8_t event_code = event->response_type & 0x7f; +@@ -2799,14 +3185,15 @@ void Demo::create_xcb_window() { + std::array const coords = {100, 100}; + xcb_configure_window(connection, xcb_window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords.data()); + } +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) + +-void Demo::run() { ++void Demo::run_wayland() { + while (!quit) { + if (pause) { +- wl_display_dispatch(display); ++ wl_display_dispatch(wayland_display); + } else { +- wl_display_dispatch_pending(display); ++ wl_display_dispatch_pending(wayland_display); + draw(); + curFrame++; + if (frameCount != UINT32_MAX && curFrame == frameCount) { +@@ -2848,21 +3235,21 @@ static void handle_toplevel_close(void *data, xdg_toplevel *xdg_toplevel) { + + static const xdg_toplevel_listener toplevel_listener = {handle_toplevel_configure, handle_toplevel_close}; + +-void Demo::create_window() { ++void Demo::create_wayland_window() { + if (!wm_base) { + printf("Compositor did not provide the standard protocol xdg-wm-base\n"); + fflush(stdout); + exit(1); + } + +- window = wl_compositor_create_surface(compositor); +- if (!window) { ++ wayland_window = wl_compositor_create_surface(compositor); ++ if (!wayland_window) { + printf("Can not create wayland_surface from compositor!\n"); + fflush(stdout); + exit(1); + } + +- window_surface = xdg_wm_base_get_xdg_surface(wm_base, window); ++ window_surface = xdg_wm_base_get_xdg_surface(wm_base, wayland_window); + if (!window_surface) { + printf("Can not get xdg_surface from wayland_surface!\n"); + fflush(stdout); +@@ -2883,9 +3270,10 @@ void Demo::create_window() { + zxdg_toplevel_decoration_v1_set_mode(toplevel_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } + +- wl_surface_commit(window); ++ wl_surface_commit(wayland_window); + } +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) + + void Demo::handle_directfb_event(const DFBInputEvent *event) { + if (event->type != DIET_KEYPRESS) return; +@@ -2948,7 +3336,7 @@ void Demo::create_directfb_window() { + desc.caps = DSCAPS_PRIMARY; + desc.width = width; + desc.height = height; +- ret = dfb->CreateSurface(dfb, &desc, &window); ++ ret = dfb->CreateSurface(dfb, &desc, &directfb_window); + if (ret) { + printf("CreateSurface failed to create DirectFB surface interface!\n"); + fflush(stdout); +@@ -2962,7 +3350,8 @@ void Demo::create_directfb_window() { + exit(1); + } + } +-#elif defined(VK_USE_PLATFORM_METAL_EXT) ++#endif ++#if defined(VK_USE_PLATFORM_METAL_EXT) + void Demo::run() { + draw(); + curFrame++; +@@ -2970,7 +3359,8 @@ void Demo::run() { + quit = true; + } + } +-#elif defined(VK_USE_PLATFORM_DISPLAY_KHR) ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) + + vk::Result Demo::create_display_surface() { + auto display_properties_return = gpu.getDisplayPropertiesKHR(); +@@ -3078,7 +3468,8 @@ void Demo::run_display() { + } + } + +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) + #include + + void Demo::run() { +@@ -3394,35 +3785,89 @@ int main(int argc, char **argv) { + + demo.init(argc, argv); + ++ switch (demo.wsi_platform) { ++ default: ++ case (WsiPlatform::auto_): ++ fprintf(stderr, ++ "WSI platform should have already been set, indicating a bug. Please set a WSI platform manually with " ++ "--wsi\n"); ++ exit(1); ++ break; + #if defined(VK_USE_PLATFORM_XCB_KHR) +- demo.create_xcb_window(); +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) +- demo.create_xlib_window(); +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- demo.create_window(); +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) +- demo.create_directfb_window(); +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) +- demo.create_window(); ++ case (WsiPlatform::xcb): ++ demo.create_xcb_window(); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ case (WsiPlatform::xlib): ++ demo.create_xlib_window(); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ case (WsiPlatform::wayland): ++ demo.create_wayland_window(); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ case (WsiPlatform::directfb): ++ demo.create_directfb_window(); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ case (WsiPlatform::qnx): ++ demo.create_window(); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ case (WsiPlatform::display): ++ // nothing to do here ++ break; + #endif ++ } + + demo.init_vk_swapchain(); + + demo.prepare(); + ++ switch (demo.wsi_platform) { ++ default: ++ case (WsiPlatform::auto_): ++ fprintf(stderr, ++ "WSI platform should have already been set, indicating a bug. Please set a WSI platform manually with " ++ "--wsi\n"); ++ exit(1); ++ break; + #if defined(VK_USE_PLATFORM_XCB_KHR) +- demo.run_xcb(); +-#elif defined(VK_USE_PLATFORM_XLIB_KHR) +- demo.run_xlib(); +-#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +- demo.run(); +-#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) +- demo.run_directfb(); +-#elif defined(VK_USE_PLATFORM_DISPLAY_KHR) +- demo.run_display(); +-#elif defined(VK_USE_PLATFORM_SCREEN_QNX) +- demo.run(); ++ case (WsiPlatform::xcb): ++ demo.run_xcb(); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_XLIB_KHR) ++ case (WsiPlatform::xlib): ++ demo.run_xlib(); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_WAYLAND_KHR) ++ case (WsiPlatform::wayland): ++ demo.run_wayland(); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) ++ case (WsiPlatform::directfb): ++ demo.run_directfb(); ++ break; ++#endif ++#if defined(VK_USE_PLATFORM_DISPLAY_KHR) ++ case (WsiPlatform::display): ++ demo.run_display(); ++ break; + #endif ++#if defined(VK_USE_PLATFORM_SCREEN_QNX) ++ case (WsiPlatform::qnx): ++ demo.run(); ++ break; ++#endif ++ } + + demo.cleanup(); + +diff --git a/cube/macOS/cube/CMakeLists.txt b/cube/macOS/cube/CMakeLists.txt +index 1fcc6c45..4d8a955e 100644 +--- a/cube/macOS/cube/CMakeLists.txt ++++ b/cube/macOS/cube/CMakeLists.txt +@@ -59,7 +59,7 @@ add_dependencies(vkcube MoltenVK_icd-staging-json) + target_include_directories(vkcube PRIVATE . ${MOLTENVK_DIR}/MoltenVK/include) + + # We do this so vkcube is linked to an individual library and NOT a framework. +-target_link_libraries(vkcube Vulkan::Loader volk::volk_headers "-framework Cocoa -framework QuartzCore") ++target_link_libraries(vkcube "-framework Cocoa -framework QuartzCore") + + # Disable warnings about sprintf + target_compile_options(vkcube PRIVATE -Wno-deprecated-declarations) +diff --git a/cube/macOS/cubepp/CMakeLists.txt b/cube/macOS/cubepp/CMakeLists.txt +index 645d4da9..491031f1 100644 +--- a/cube/macOS/cubepp/CMakeLists.txt ++++ b/cube/macOS/cubepp/CMakeLists.txt +@@ -59,7 +59,7 @@ add_dependencies(vkcubepp MoltenVK_icd-staging-json) + target_include_directories(vkcubepp PRIVATE ${CMAKE_CURRENT_LIST_DIR} ${MOLTENVK_DIR}/MoltenVK/include) + + # We do this so vkcubepp is linked to an individual library and NOT a framework. +-target_link_libraries(vkcubepp Vulkan::Loader volk::volk_headers "-framework Cocoa -framework QuartzCore") ++target_link_libraries(vkcubepp "-framework Cocoa -framework QuartzCore") + + set_target_properties(vkcubepp PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_LIST_DIR}/Info.plist) + +diff --git a/cube/wayland_loader.h b/cube/wayland_loader.h +new file mode 100644 +index 00000000..2afab6e9 +--- /dev/null ++++ b/cube/wayland_loader.h +@@ -0,0 +1,124 @@ ++/* ++ * Copyright (c) 2024 The Khronos Group Inc. ++ * Copyright (c) 2024 Valve Corporation ++ * Copyright (c) 2024 LunarG, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Author: Charles Giessen ++ */ ++ ++#pragma once ++ ++#include ++#include ++#include ++ ++#include ++ ++typedef struct wl_display *(*PFN_wl_display_connect)(const char *name); ++typedef int (*PFN_wl_display_flush)(struct wl_display *display); ++typedef int (*PFN_wl_display_dispatch)(struct wl_display *display); ++typedef int (*PFN_wl_display_prepare_read)(struct wl_display *display); ++typedef int (*PFN_wl_display_dispatch_pending)(struct wl_display *display); ++typedef int (*PFN_wl_display_read_events)(struct wl_display *display); ++typedef void (*PFN_wl_proxy_marshal)(struct wl_proxy *p, uint32_t opcode, ...); ++typedef struct wl_proxy *(*PFN_wl_proxy_marshal_constructor)(struct wl_proxy *proxy, uint32_t opcode, ++ const struct wl_interface *interface, ...); ++typedef struct wl_proxy *(*PFN_wl_proxy_marshal_constructor_versioned)(struct wl_proxy *proxy, uint32_t opcode, ++ const struct wl_interface *interface, uint32_t version, ...); ++typedef struct wl_proxy *(*PFN_wl_proxy_marshal_flags)(struct wl_proxy *proxy, uint32_t opcode, ++ const struct wl_interface *interface, uint32_t version, uint32_t flags, ...); ++typedef uint32_t (*PFN_wl_proxy_get_version)(struct wl_proxy *proxy); ++typedef int (*PFN_wl_proxy_add_listener)(struct wl_proxy *proxy, void (**implementation)(void), void *data); ++typedef void (*PFN_wl_proxy_destroy)(struct wl_proxy *proxy); ++typedef int (*PFN_wl_display_roundtrip)(struct wl_display *display); ++typedef void (*PFN_wl_display_disconnect)(struct wl_display *display); ++ ++static PFN_wl_display_connect cube_wl_display_connect = NULL; ++static PFN_wl_display_flush cube_wl_display_flush = NULL; ++static PFN_wl_display_dispatch cube_wl_display_dispatch = NULL; ++static PFN_wl_display_prepare_read cube_wl_display_prepare_read = NULL; ++static PFN_wl_display_dispatch_pending cube_wl_display_dispatch_pending = NULL; ++static PFN_wl_display_read_events cube_wl_display_read_events = NULL; ++static PFN_wl_proxy_marshal cube_wl_proxy_marshal = NULL; ++static PFN_wl_proxy_marshal_constructor cube_wl_proxy_marshal_constructor = NULL; ++static PFN_wl_proxy_marshal_constructor_versioned cube_wl_proxy_marshal_constructor_versioned = NULL; ++static PFN_wl_proxy_marshal_flags cube_wl_proxy_marshal_flags = NULL; ++static PFN_wl_proxy_get_version cube_wl_proxy_get_version = NULL; ++static PFN_wl_proxy_add_listener cube_wl_proxy_add_listener = NULL; ++static PFN_wl_proxy_destroy cube_wl_proxy_destroy = NULL; ++static PFN_wl_display_roundtrip cube_wl_display_roundtrip = NULL; ++static PFN_wl_display_disconnect cube_wl_display_disconnect = NULL; ++ ++// Use macro's to redefine the PFN's as the functions in client code ++#define wl_display_connect cube_wl_display_connect ++#define wl_display_flush cube_wl_display_flush ++#define wl_display_dispatch cube_wl_display_dispatch ++#define wl_display_prepare_read cube_wl_display_prepare_read ++#define wl_display_dispatch_pending cube_wl_display_dispatch_pending ++#define wl_display_read_events cube_wl_display_read_events ++#define wl_proxy_marshal cube_wl_proxy_marshal ++#define wl_proxy_marshal_constructor cube_wl_proxy_marshal_constructor ++#define wl_proxy_marshal_constructor_versioned cube_wl_proxy_marshal_constructor_versioned ++#define wl_proxy_marshal_flags cube_wl_proxy_marshal_flags ++#define wl_proxy_get_version cube_wl_proxy_get_version ++#define wl_proxy_add_listener cube_wl_proxy_add_listener ++#define wl_proxy_destroy cube_wl_proxy_destroy ++#define wl_display_roundtrip cube_wl_display_roundtrip ++#define wl_display_disconnect cube_wl_display_disconnect ++ ++static inline void *initialize_wayland() { ++ void *wayland_library = NULL; ++#if defined(WAYLAND_LIBRARY) ++ wayland_library = dlopen(WAYLAND_LIBRARY, RTLD_NOW | RTLD_LOCAL); ++#endif ++ if (NULL == wayland_library) { ++ wayland_library = dlopen("libwayland-client.so.0", RTLD_NOW | RTLD_LOCAL); ++ } ++ if (NULL == wayland_library) { ++ wayland_library = dlopen("libwayland-client.so", RTLD_NOW | RTLD_LOCAL); ++ } ++ if (NULL == wayland_library) { ++ return NULL; ++ } ++ ++#ifdef __cplusplus ++#define TYPE_CONVERSION(type) reinterpret_cast ++#else ++#define TYPE_CONVERSION(type) ++#endif ++ cube_wl_display_connect = TYPE_CONVERSION(PFN_wl_display_connect)(dlsym(wayland_library, "wl_display_connect")); ++ cube_wl_display_flush = TYPE_CONVERSION(PFN_wl_display_flush)(dlsym(wayland_library, "wl_display_flush")); ++ cube_wl_display_dispatch = TYPE_CONVERSION(PFN_wl_display_dispatch)(dlsym(wayland_library, "wl_display_dispatch")); ++ cube_wl_display_prepare_read = TYPE_CONVERSION(PFN_wl_display_prepare_read)(dlsym(wayland_library, "wl_display_prepare_read")); ++ cube_wl_display_dispatch_pending = ++ TYPE_CONVERSION(PFN_wl_display_dispatch_pending)(dlsym(wayland_library, "wl_display_dispatch_pending")); ++ cube_wl_display_read_events = TYPE_CONVERSION(PFN_wl_display_read_events)(dlsym(wayland_library, "wl_display_read_events")); ++ cube_wl_proxy_marshal = TYPE_CONVERSION(PFN_wl_proxy_marshal)(dlsym(wayland_library, "wl_proxy_marshal")); ++ cube_wl_proxy_marshal_constructor = ++ TYPE_CONVERSION(PFN_wl_proxy_marshal_constructor)(dlsym(wayland_library, "wl_proxy_marshal_constructor")); ++ cube_wl_proxy_marshal_constructor_versioned = TYPE_CONVERSION(PFN_wl_proxy_marshal_constructor_versioned)( ++ dlsym(wayland_library, "wl_proxy_marshal_constructor_versioned")); ++ cube_wl_proxy_marshal_flags = TYPE_CONVERSION(PFN_wl_proxy_marshal_flags)(dlsym(wayland_library, "wl_proxy_marshal_flags")); ++ cube_wl_proxy_get_version = TYPE_CONVERSION(PFN_wl_proxy_get_version)(dlsym(wayland_library, "wl_proxy_get_version")); ++ cube_wl_proxy_add_listener = TYPE_CONVERSION(PFN_wl_proxy_add_listener)(dlsym(wayland_library, "wl_proxy_add_listener")); ++ cube_wl_proxy_destroy = TYPE_CONVERSION(PFN_wl_proxy_destroy)(dlsym(wayland_library, "wl_proxy_destroy")); ++ cube_wl_display_roundtrip = TYPE_CONVERSION(PFN_wl_display_roundtrip)(dlsym(wayland_library, "wl_display_roundtrip")); ++ cube_wl_display_disconnect = TYPE_CONVERSION(PFN_wl_display_disconnect)(dlsym(wayland_library, "wl_display_disconnect")); ++ ++ return wayland_library; ++} ++ ++#include "xdg-shell-client-header.h" ++#include "xdg-decoration-client-header.h" +diff --git a/cube/xcb_loader.h b/cube/xcb_loader.h +new file mode 100644 +index 00000000..a94d5ab5 +--- /dev/null ++++ b/cube/xcb_loader.h +@@ -0,0 +1,129 @@ ++/* ++ * Copyright (c) 2024 The Khronos Group Inc. ++ * Copyright (c) 2024 Valve Corporation ++ * Copyright (c) 2024 LunarG, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Author: Charles Giessen ++ */ ++ ++#pragma once ++ ++#include ++#include ++ ++#include ++ ++typedef xcb_void_cookie_t (*PFN_xcb_destroy_window)(xcb_connection_t *c, xcb_window_t window); ++typedef void (*PFN_xcb_disconnect)(xcb_connection_t *c); ++typedef int (*PFN_xcb_flush)(xcb_connection_t *c); ++typedef xcb_generic_event_t *(*PFN_xcb_wait_for_event)(xcb_connection_t *c); ++typedef xcb_generic_event_t *(*PFN_xcb_poll_for_event)(xcb_connection_t *c); ++typedef uint32_t (*PFN_xcb_generate_id)(xcb_connection_t *c); ++typedef xcb_void_cookie_t (*PFN_xcb_create_window)(xcb_connection_t *c, uint8_t depth, xcb_window_t wid, xcb_window_t parent, ++ int16_t x, int16_t y, uint16_t width, uint16_t height, uint16_t border_width, ++ uint16_t _class, xcb_visualid_t visual, uint32_t value_mask, ++ const void *value_list); ++typedef xcb_intern_atom_cookie_t (*PFN_xcb_intern_atom)(xcb_connection_t *c, uint8_t only_if_exists, uint16_t name_len, ++ const char *name); ++typedef xcb_intern_atom_reply_t *(*PFN_xcb_intern_atom_reply)(xcb_connection_t *c, xcb_intern_atom_cookie_t cookie /**< */, ++ xcb_generic_error_t **e); ++typedef xcb_void_cookie_t (*PFN_xcb_change_property)(xcb_connection_t *c, uint8_t mode, xcb_window_t window, xcb_atom_t property, ++ xcb_atom_t type, uint8_t format, uint32_t data_len, const void *data); ++typedef xcb_void_cookie_t (*PFN_xcb_map_window)(xcb_connection_t *c, xcb_window_t window); ++typedef xcb_void_cookie_t (*PFN_xcb_configure_window)(xcb_connection_t *c, xcb_window_t window, uint16_t value_mask, ++ const void *value_list); ++typedef xcb_connection_t *(*PFN_xcb_connect)(const char *displayname, int *screenp); ++typedef int (*PFN_xcb_connection_has_error)(xcb_connection_t *c); ++typedef const struct xcb_setup_t *(*PFN_xcb_get_setup)(xcb_connection_t *c); ++typedef xcb_screen_iterator_t (*PFN_xcb_setup_roots_iterator)(const xcb_setup_t *R); ++typedef void (*PFN_xcb_screen_next)(xcb_screen_iterator_t *i); ++ ++static PFN_xcb_destroy_window cube_xcb_destroy_window = NULL; ++static PFN_xcb_disconnect cube_xcb_disconnect = NULL; ++static PFN_xcb_flush cube_xcb_flush = NULL; ++static PFN_xcb_wait_for_event cube_xcb_wait_for_event = NULL; ++static PFN_xcb_poll_for_event cube_xcb_poll_for_event = NULL; ++static PFN_xcb_generate_id cube_xcb_generate_id = NULL; ++static PFN_xcb_create_window cube_xcb_create_window = NULL; ++static PFN_xcb_intern_atom cube_xcb_intern_atom = NULL; ++static PFN_xcb_intern_atom_reply cube_xcb_intern_atom_reply = NULL; ++static PFN_xcb_change_property cube_xcb_change_property = NULL; ++static PFN_xcb_map_window cube_xcb_map_window = NULL; ++static PFN_xcb_configure_window cube_xcb_configure_window = NULL; ++static PFN_xcb_connect cube_xcb_connect = NULL; ++static PFN_xcb_connection_has_error cube_xcb_connection_has_error = NULL; ++static PFN_xcb_get_setup cube_xcb_get_setup = NULL; ++static PFN_xcb_setup_roots_iterator cube_xcb_setup_roots_iterator = NULL; ++static PFN_xcb_screen_next cube_xcb_screen_next = NULL; ++ ++#define xcb_destroy_window cube_xcb_destroy_window ++#define xcb_disconnect cube_xcb_disconnect ++#define xcb_flush cube_xcb_flush ++#define xcb_wait_for_event cube_xcb_wait_for_event ++#define xcb_poll_for_event cube_xcb_poll_for_event ++#define xcb_generate_id cube_xcb_generate_id ++#define xcb_create_window cube_xcb_create_window ++#define xcb_intern_atom cube_xcb_intern_atom ++#define xcb_intern_atom_reply cube_xcb_intern_atom_reply ++#define xcb_change_property cube_xcb_change_property ++#define xcb_map_window cube_xcb_map_window ++#define xcb_configure_window cube_xcb_configure_window ++#define xcb_connect cube_xcb_connect ++#define xcb_connection_has_error cube_xcb_connection_has_error ++#define xcb_get_setup cube_xcb_get_setup ++#define xcb_setup_roots_iterator cube_xcb_setup_roots_iterator ++#define xcb_screen_next cube_xcb_screen_next ++ ++void *initialize_xcb() { ++ void *xcb_library = NULL; ++#if defined(XCB_LIBRARY) ++ xcb_library = dlopen(XCB_LIBRARY, RTLD_NOW | RTLD_LOCAL); ++#endif ++ if (NULL == xcb_library) { ++ xcb_library = dlopen("libxcb.so.1", RTLD_NOW | RTLD_LOCAL); ++ } ++ if (NULL == xcb_library) { ++ xcb_library = dlopen("libxcb.so", RTLD_NOW | RTLD_LOCAL); ++ } ++ if (NULL == xcb_library) { ++ return NULL; ++ } ++ ++#ifdef __cplusplus ++#define TYPE_CONVERSION(type) reinterpret_cast ++#else ++#define TYPE_CONVERSION(type) ++#endif ++ ++ cube_xcb_destroy_window = TYPE_CONVERSION(PFN_xcb_destroy_window)(dlsym(xcb_library, "xcb_destroy_window")); ++ cube_xcb_disconnect = TYPE_CONVERSION(PFN_xcb_disconnect)(dlsym(xcb_library, "xcb_disconnect")); ++ cube_xcb_flush = TYPE_CONVERSION(PFN_xcb_flush)(dlsym(xcb_library, "xcb_flush")); ++ cube_xcb_wait_for_event = TYPE_CONVERSION(PFN_xcb_wait_for_event)(dlsym(xcb_library, "xcb_wait_for_event")); ++ cube_xcb_poll_for_event = TYPE_CONVERSION(PFN_xcb_poll_for_event)(dlsym(xcb_library, "xcb_poll_for_event")); ++ cube_xcb_generate_id = TYPE_CONVERSION(PFN_xcb_generate_id)(dlsym(xcb_library, "xcb_generate_id")); ++ cube_xcb_create_window = TYPE_CONVERSION(PFN_xcb_create_window)(dlsym(xcb_library, "xcb_create_window")); ++ cube_xcb_intern_atom = TYPE_CONVERSION(PFN_xcb_intern_atom)(dlsym(xcb_library, "xcb_intern_atom")); ++ cube_xcb_intern_atom_reply = TYPE_CONVERSION(PFN_xcb_intern_atom_reply)(dlsym(xcb_library, "xcb_intern_atom_reply")); ++ cube_xcb_change_property = TYPE_CONVERSION(PFN_xcb_change_property)(dlsym(xcb_library, "xcb_change_property")); ++ cube_xcb_map_window = TYPE_CONVERSION(PFN_xcb_map_window)(dlsym(xcb_library, "xcb_map_window")); ++ cube_xcb_configure_window = TYPE_CONVERSION(PFN_xcb_configure_window)(dlsym(xcb_library, "xcb_configure_window")); ++ cube_xcb_connect = TYPE_CONVERSION(PFN_xcb_connect)(dlsym(xcb_library, "xcb_connect")); ++ cube_xcb_connection_has_error = TYPE_CONVERSION(PFN_xcb_connection_has_error)(dlsym(xcb_library, "xcb_connection_has_error")); ++ cube_xcb_get_setup = TYPE_CONVERSION(PFN_xcb_get_setup)(dlsym(xcb_library, "xcb_get_setup")); ++ cube_xcb_setup_roots_iterator = TYPE_CONVERSION(PFN_xcb_setup_roots_iterator)(dlsym(xcb_library, "xcb_setup_roots_iterator")); ++ cube_xcb_screen_next = TYPE_CONVERSION(PFN_xcb_screen_next)(dlsym(xcb_library, "xcb_screen_next")); ++ ++ return xcb_library; ++} +diff --git a/cube/xlib_loader.h b/cube/xlib_loader.h +new file mode 100644 +index 00000000..c7874d0e +--- /dev/null ++++ b/cube/xlib_loader.h +@@ -0,0 +1,109 @@ ++/* ++ * Copyright (c) 2024 The Khronos Group Inc. ++ * Copyright (c) 2024 Valve Corporation ++ * Copyright (c) 2024 LunarG, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * Author: Charles Giessen ++ */ ++ ++#pragma once ++ ++#include ++#include ++ ++#include ++ ++typedef int (*PFN_XDestroyWindow)(Display*, Window); ++typedef Display* (*PFN_XOpenDisplay)(_Xconst char*); ++typedef Colormap (*PFN_XCreateColormap)(Display*, Window, Visual*, int); ++typedef Window (*PFN_XCreateWindow)(Display*, Window, int, int, unsigned int, unsigned int, unsigned int, int, unsigned int, ++ Visual*, unsigned long, XSetWindowAttributes*); ++typedef int (*PFN_XSelectInput)(Display*, Window, long); ++typedef int (*PFN_XMapWindow)(Display*, Window); ++typedef Atom (*PFN_XInternAtom)(Display*, _Xconst char*, Bool); ++typedef int (*PFN_XNextEvent)(Display*, XEvent*); ++typedef int (*PFN_XPending)(Display*); ++typedef XVisualInfo* (*PFN_XGetVisualInfo)(Display*, long, XVisualInfo*, int*); ++typedef int (*PFN_XCloseDisplay)(Display* /* display */ ++); ++typedef Status (*PFN_XInitThreads)(void); ++typedef int (*PFN_XFlush)(Display* /* display */ ++); ++ ++static PFN_XDestroyWindow cube_XDestroyWindow = NULL; ++static PFN_XOpenDisplay cube_XOpenDisplay = NULL; ++static PFN_XCreateColormap cube_XCreateColormap = NULL; ++static PFN_XCreateWindow cube_XCreateWindow = NULL; ++static PFN_XSelectInput cube_XSelectInput = NULL; ++static PFN_XMapWindow cube_XMapWindow = NULL; ++static PFN_XInternAtom cube_XInternAtom = NULL; ++static PFN_XNextEvent cube_XNextEvent = NULL; ++static PFN_XPending cube_XPending = NULL; ++static PFN_XGetVisualInfo cube_XGetVisualInfo = NULL; ++static PFN_XCloseDisplay cube_XCloseDisplay = NULL; ++static PFN_XInitThreads cube_XInitThreads = NULL; ++static PFN_XFlush cube_XFlush = NULL; ++ ++#define XDestroyWindow cube_XDestroyWindow ++#define XOpenDisplay cube_XOpenDisplay ++#define XCreateColormap cube_XCreateColormap ++#define XCreateWindow cube_XCreateWindow ++#define XSelectInput cube_XSelectInput ++#define XMapWindow cube_XMapWindow ++#define XInternAtom cube_XInternAtom ++#define XNextEvent cube_XNextEvent ++#define XPending cube_XPending ++#define XGetVisualInfo cube_XGetVisualInfo ++#define XCloseDisplay cube_XCloseDisplay ++#define XInitThreads cube_XInitThreads ++#define XFlush cube_XFlush ++ ++void* initialize_xlib() { ++ void* xlib_library = NULL; ++#if defined(XLIB_LIBRARY) ++ xlib_library = dlopen(XLIB_LIBRARY, RTLD_NOW | RTLD_LOCAL); ++#endif ++ if (NULL == xlib_library) { ++ xlib_library = dlopen("libX11.so.6", RTLD_NOW | RTLD_LOCAL); ++ } ++ if (NULL == xlib_library) { ++ xlib_library = dlopen("libX11.so", RTLD_NOW | RTLD_LOCAL); ++ } ++ if (NULL == xlib_library) { ++ return NULL; ++ } ++ ++#ifdef __cplusplus ++#define TYPE_CONVERSION(type) reinterpret_cast ++#else ++#define TYPE_CONVERSION(type) ++#endif ++ ++ cube_XDestroyWindow = TYPE_CONVERSION(PFN_XDestroyWindow)(dlsym(xlib_library, "XDestroyWindow")); ++ cube_XOpenDisplay = TYPE_CONVERSION(PFN_XOpenDisplay)(dlsym(xlib_library, "XOpenDisplay")); ++ cube_XCreateColormap = TYPE_CONVERSION(PFN_XCreateColormap)(dlsym(xlib_library, "XCreateColormap")); ++ cube_XCreateWindow = TYPE_CONVERSION(PFN_XCreateWindow)(dlsym(xlib_library, "XCreateWindow")); ++ cube_XSelectInput = TYPE_CONVERSION(PFN_XSelectInput)(dlsym(xlib_library, "XSelectInput")); ++ cube_XMapWindow = TYPE_CONVERSION(PFN_XMapWindow)(dlsym(xlib_library, "XMapWindow")); ++ cube_XInternAtom = TYPE_CONVERSION(PFN_XInternAtom)(dlsym(xlib_library, "XInternAtom")); ++ cube_XNextEvent = TYPE_CONVERSION(PFN_XNextEvent)(dlsym(xlib_library, "XNextEvent")); ++ cube_XPending = TYPE_CONVERSION(PFN_XPending)(dlsym(xlib_library, "XPending")); ++ cube_XGetVisualInfo = TYPE_CONVERSION(PFN_XGetVisualInfo)(dlsym(xlib_library, "XGetVisualInfo")); ++ cube_XCloseDisplay = TYPE_CONVERSION(PFN_XCloseDisplay)(dlsym(xlib_library, "XCloseDisplay")); ++ cube_XInitThreads = TYPE_CONVERSION(PFN_XInitThreads)(dlsym(xlib_library, "XInitThreads")); ++ cube_XFlush = TYPE_CONVERSION(PFN_XFlush)(dlsym(xlib_library, "XFlush")); ++ ++ return xlib_library; ++} +-- +2.47.0 + diff --git a/0001-vkcube-Remove-unused-command-line-option.patch b/0001-vkcube-Remove-unused-command-line-option.patch new file mode 100644 index 0000000..ab13038 --- /dev/null +++ b/0001-vkcube-Remove-unused-command-line-option.patch @@ -0,0 +1,46 @@ +From eb9b6043be165f06c7ec78fadbb1ff773c5fc19c Mon Sep 17 00:00:00 2001 +From: Charles Giessen +Date: Fri, 11 Oct 2024 12:26:50 -0500 +Subject: [PATCH] vkcube: Remove unused command line option + +The --validate-checks-disabled flag was unused, so will be removed. +--- + cube/cube.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/cube/cube.c b/cube/cube.c +index 78d0bb55..4879317c 100644 +--- a/cube/cube.c ++++ b/cube/cube.c +@@ -437,7 +437,6 @@ struct demo { + int32_t curFrame; + int32_t frameCount; + bool validate; +- bool validate_checks_disabled; + bool use_break; + bool suppress_popups; + bool force_errors; +@@ -4223,11 +4222,6 @@ static void demo_init(struct demo *demo, int argc, char **argv) { + demo->validate = true; + continue; + } +- if (strcmp(argv[i], "--validate-checks-disabled") == 0) { +- demo->validate = true; +- demo->validate_checks_disabled = true; +- continue; +- } + if (strcmp(argv[i], "--xlib") == 0) { + fprintf(stderr, "--xlib is deprecated and no longer does anything"); + continue; +@@ -4286,7 +4280,7 @@ static void demo_init(struct demo *demo, int argc, char **argv) { + ERR_EXIT("Usage: vkcube [--validate]\n", "Usage"); + #else + char *message = +- "Usage:\n %s\t[--use_staging] [--validate] [--validate-checks-disabled]\n" ++ "Usage:\n %s\t[--use_staging] [--validate]\n" + "\t[--break] [--c ] [--suppress_popups]\n" + "\t[--incremental_present] [--display_timing]\n" + "\t[--gpu_number ]\n" +-- +2.47.0 + diff --git a/sources b/sources index ae54945..ac28191 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (Vulkan-Tools-sdk-1.4.350.0.tar.gz) = 2d2afbcb06bb1ee08ffb3cbe133b531fe6341e90fa0dca4d5459dbdedf201521e798226768a7e307f8b6c08b388114a34a9a581a294f6226ca7a2fcd6f63f813 +SHA512 (Vulkan-Tools-sdk-1.3.296.0.tar.gz) = 66bc89272f150198cd52f2971ad67a2fd6c922ac4bafb420c0d54788ca6bab2246e8a153a09eccce15a87e1fe16fdeef16af1c6b6b13386bff79dd73858f3cae diff --git a/vulkan-tools.spec b/vulkan-tools.spec index 2577e01..4c7ee38 100644 --- a/vulkan-tools.spec +++ b/vulkan-tools.spec @@ -1,5 +1,5 @@ Name: vulkan-tools -Version: 1.4.350.0 +Version: 1.3.296.0 Release: %autorelease Summary: Vulkan tools @@ -7,9 +7,13 @@ License: Apache-2.0 URL: https://github.com/KhronosGroup/Vulkan-Tools Source0: %url/archive/vulkan-sdk-%{version}.tar.gz#/Vulkan-Tools-sdk-%{version}.tar.gz +# vkcube runtime selection support +Patch00: 0001-vkcube-Remove-unused-command-line-option.patch +Patch01: 0001-cube-Support-runtime-selection-of-WSI-platform.patch + BuildRequires: gcc BuildRequires: gcc-c++ -BuildRequires: cmake +BuildRequires: cmake3 BuildRequires: glslang BuildRequires: ninja-build BuildRequires: python%{python3_pkgversion}-devel @@ -36,12 +40,12 @@ Vulkan tools %build -%cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DGLSLANG_INSTALL_DIR=%{_prefix} -%cmake_build +%cmake3 -GNinja -DCMAKE_BUILD_TYPE=Release -DGLSLANG_INSTALL_DIR=%{_prefix} +%cmake3_build %install -%cmake_install +%cmake3_install %files %license LICENSE.txt