diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml index aae55840a..2ede53978 100644 --- a/.github/workflows/tools.yml +++ b/.github/workflows/tools.yml @@ -79,7 +79,6 @@ jobs: 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 \ diff --git a/cube/CMakeLists.txt b/cube/CMakeLists.txt index 880cf741c..4388a4d86 100644 --- a/cube/CMakeLists.txt +++ b/cube/CMakeLists.txt @@ -66,27 +66,55 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux|BSD|GNU") 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)") + option(BUILD_WSI_DISPLAY_SUPPORT "Build DISPLAY WSI support" ON) 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 wayland client protocol header" + OUTPUT wayland-client-header.h + COMMAND ${WAYLAND_SCANNER_EXECUTABLE} + client-header + ${WAYLAND_CODE_PROTOCOL} + ${CMAKE_CURRENT_BINARY_DIR}/wayland-client-header.h + 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} @@ -135,45 +163,23 @@ elseif(ANDROID) elseif(APPLE) add_definitions(-DVK_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() + if(BUILD_WSI_DISPLAY_SUPPORT) + list(APPEND ENABLED_CUBE_PLATFORMS VK_USE_PLATFORM_DISPLAY_KHR) + 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() link_libraries(${API_LOWERCASE} m) @@ -226,7 +232,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 +240,35 @@ 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 PRIVATE 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 + ${CMAKE_CURRENT_BINARY_DIR}/wayland-client-header.h + ${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) + target_link_libraries(vkcube PRIVATE PkgConfig::DirectFB) + endif() include(CheckLibraryExists) CHECK_LIBRARY_EXISTS("rt" clock_gettime "" NEED_RT) if (NEED_RT) target_link_libraries(vkcube PRIVATE 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 +278,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 PRIVATE Vulkan::Headers volk::volk_headers) if (ANDROID) install(TARGETS vkcube DESTINATION ${CMAKE_INSTALL_LIBDIR}) @@ -280,6 +306,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 +327,31 @@ 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 PRIVATE 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 + ${CMAKE_CURRENT_BINARY_DIR}/wayland-client-header.h + ${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) + target_link_libraries(vkcubepp PRIVATE PkgConfig::DirectFB) + endif() else() add_executable(vkcubepp WIN32 @@ -303,9 +360,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 PRIVATE 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 +389,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/cube.c b/cube/cube.c index 78d0bb554..1cd21a4a6 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]; { @@ -3833,77 +4317,104 @@ static void demo_create_surface(struct demo *demo) { // 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" @@ -4525,35 +4959,84 @@ 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..68637288c 100644 --- a/cube/cube.cpp +++ b/cube/cube.cpp @@ -19,12 +19,15 @@ * Author: Charles Giessen */ -#if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR) -#include -#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) +#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 #include @@ -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(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), 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(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), 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(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), + 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(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), + 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(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), 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(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), + 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(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), 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(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), 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(enabled_instance_extensions.begin(), enabled_instance_extensions.end(), VK_KHR_DISPLAY_EXTENSION_NAME); + if (found != enabled_instance_extensions.end()) { + wsi_platform = WsiPlatform::display; + return; + } + } #endif } #if defined(VK_USE_PLATFORM_DISPLAY_KHR) @@ -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..7fa754300 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 PRIVATE "-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..3ec8b1f4e 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 PRIVATE "-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..81e3b6b5d --- /dev/null +++ b/cube/wayland_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 + +#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 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_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_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_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 + +#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; +}