From 1237a4c52bd59d1f377b3cc4442c869bac630624 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. --- .github/workflows/tools.yml | 20 +- cube/CMakeLists.txt | 211 ++-- cube/android/CMakeLists.txt | 2 +- cube/cube.c | 1559 +++++++++++++++++++----------- cube/cube.cpp | 856 +++++++++++----- 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, 2130 insertions(+), 884 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/.github/workflows/tools.yml b/.github/workflows/tools.yml index aae55840a..bfdd0ddf7 100644 --- a/.github/workflows/tools.yml +++ b/.github/workflows/tools.yml @@ -38,26 +38,17 @@ jobs: cxx: [ g++ ] config: [ Debug, Release ] os: [ ubuntu-20.04, ubuntu-22.04 ] - cube_wsi: [ XCB ] include: - # Test WAYLAND - - cc: gcc - cxx: g++ - config: Release - os: ubuntu-22.04 - cube_wsi: WAYLAND - # Test clang on ubuntu 20 with XLIB + # Test clang on ubuntu 20 - cc: clang cxx: clang++ config: Debug os: ubuntu-20.04 - cube_wsi: XLIB - # Test clang on ubuntu 22 with the DISPLAY option + # Test clang on ubuntu 22 - cc: clang cxx: clang++ config: Release os: ubuntu-22.04 - cube_wsi: DISPLAY steps: @@ -67,19 +58,18 @@ jobs: python-version: '3.7' - run: | sudo apt-get -qq update - sudo apt install libwayland-dev xorg-dev wayland-protocols + sudo apt install --yes libwayland-dev xorg-dev wayland-protocols - uses: lukka/get-cmake@latest with: cmakeVersion: 3.17.2 - name: Setup ccache uses: hendrikmuhs/ccache-action@v1.2 with: - key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.cc }}-${{matrix.cube_wsi}} + key: ${{ runner.os }}-${{ matrix.config }}-${{ matrix.cc }} - name: Configure run: | cmake -S. -B build -G "Ninja" \ -D CMAKE_BUILD_TYPE=${{matrix.config}} \ - -D CUBE_WSI_SELECTION=${{matrix.cube_wsi}} \ -D UPDATE_DEPS=ON \ -D BUILD_WERROR=ON \ -D INSTALL_ICD=ON \ @@ -231,7 +221,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: '3.10' - - run: sudo apt-get -qq update && sudo apt install libwayland-dev xorg-dev wayland-protocols + - run: sudo apt-get -qq update && sudo apt install --yes libwayland-dev xorg-dev wayland-protocols - run: cmake -S . -B build/ -D UPDATE_DEPS=ON -D UPDATE_DEPS_DIR=external -D TOOLS_CODEGEN=ON - run: cmake --build build --target tools_codegen - run: git diff --exit-code diff --git a/cube/CMakeLists.txt b/cube/CMakeLists.txt index 880cf741c..4ecd3e36e 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 66f75b424..af607a558 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 78d0bb554..09903f65f 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,52 @@ 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; +}; + typedef struct { VkImage image; VkCommandBuffer cmd; @@ -309,18 +361,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 +391,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; @@ -2436,35 +2498,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); @@ -2641,7 +2717,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') { @@ -2651,15 +2728,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; @@ -2667,14 +2744,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) { @@ -2714,11 +2791,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); } @@ -2727,7 +2804,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) { @@ -2824,26 +2902,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++; @@ -2884,7 +2963,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); @@ -2922,7 +3001,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; @@ -2945,7 +3025,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); @@ -2996,14 +3076,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++; @@ -3011,7 +3093,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; @@ -3106,8 +3189,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 @@ -3138,6 +3219,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); } @@ -3151,7 +3234,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 @@ -3257,7 +3341,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; @@ -3361,199 +3445,592 @@ 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"); +#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); } - // 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); +static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {} - 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 const struct wl_pointer_listener pointer_listener = { + pointer_handle_enter, pointer_handle_leave, pointer_handle_motion, pointer_handle_button, pointer_handle_axis, +}; - 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 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; } +} - /* Look for instance extensions */ - VkBool32 surfaceExtFound = 0; - VkBool32 platformSurfaceExtFound = 0; - bool portabilityEnumerationActive = false; - memset(demo->extension_names, 0, sizeof(demo->extension_names)); +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) {} - err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, NULL); - assert(!err); +static const struct wl_keyboard_listener keyboard_listener = { + keyboard_handle_keymap, keyboard_handle_enter, keyboard_handle_leave, keyboard_handle_key, keyboard_handle_modifiers, +}; - 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 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); + } +} - free(instance_extensions); +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."; } - 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"); + 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"; } - if (!platformSurfaceExtFound) { + + 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) - 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 + 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"); } + + demo_check_and_set_wsi_platform(demo); + const VkApplicationInfo app = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pNext = NULL, @@ -3637,48 +4114,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]++; - } +#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]++; + } - 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; - } + 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; + 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]; { @@ -3829,81 +4313,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); } @@ -4039,159 +4550,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}; @@ -4281,10 +4639,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] = toupper(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] [--validate-checks-disabled]\n" "\t[--break] [--c ] [--suppress_popups]\n" @@ -4293,19 +4726,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 @@ -4317,8 +4751,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; @@ -4424,7 +4856,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; @@ -4433,7 +4866,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" @@ -4520,40 +4954,89 @@ 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"); + 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 + } 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"); + 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 46b6fdb31..e5d3ae109 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,51 @@ 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; +}; struct SwapchainImageResources { vk::Image image; @@ -222,7 +270,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 +308,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 +348,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 +377,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 +663,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); @@ -935,6 +1014,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 +1076,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 +1092,6 @@ void Demo::init(int argc, char **argv) { exit(1); } - init_connection(); - init_vk(); spin_angle = 4.0f; @@ -972,24 +1105,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 +1130,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 +1288,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 +1451,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,58 +1518,88 @@ 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"); } + check_and_set_wsi_platform(); + vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | vk::DebugUtilsMessageSeverityFlagBitsEXT::eError); vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | @@ -1350,46 +1665,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 +1759,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 +2938,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 +2950,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 +2967,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 +3016,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 +3032,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 +3133,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 +3183,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 +3218,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 +3284,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 +3298,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 +3307,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 +3416,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 +3733,84 @@ 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"); + 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 + } 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"); + 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 1fcc6c45e..4d8a955e8 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 645d4da9f..491031f17 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 000000000..2afab6e97 --- /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 000000000..a94d5ab56 --- /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 000000000..c7874d0e7 --- /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; +}