Added a supporting of wayland wsi to cube, tri and smoke.
Change-Id: Ifa291d334cb1ed54018573c970078051c6867d96
Signed-off-by: Mun Gwan-gyeong <elongbug@gmail.com>
--- /dev/null
+# Try to find Wayland on a Unix system
+#
+# This will define:
+#
+# WAYLAND_FOUND - True if Wayland is found
+# WAYLAND_LIBRARIES - Link these to use Wayland
+# WAYLAND_INCLUDE_DIR - Include directory for Wayland
+# WAYLAND_DEFINITIONS - Compiler flags for using Wayland
+#
+# In addition the following more fine grained variables will be defined:
+#
+# WAYLAND_CLIENT_FOUND WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES
+# WAYLAND_SERVER_FOUND WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES
+# WAYLAND_EGL_FOUND WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES
+#
+# Copyright (c) 2013 Martin Gräßlin <mgraesslin@kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+IF (NOT WIN32)
+ IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES)
+ # In the cache already
+ SET(WAYLAND_FIND_QUIETLY TRUE)
+ ENDIF ()
+
+ # Use pkg-config to get the directories and then use these values
+ # in the FIND_PATH() and FIND_LIBRARY() calls
+ FIND_PACKAGE(PkgConfig)
+ PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl wayland-cursor)
+
+ SET(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS})
+
+ FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
+ FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
+ FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
+ FIND_PATH(WAYLAND_CURSOR_INCLUDE_DIR NAMES wayland-cursor.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
+
+ FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
+ FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
+ FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
+ FIND_LIBRARY(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
+
+ set(WAYLAND_INCLUDE_DIR ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_SERVER_INCLUDE_DIR} ${WAYLAND_EGL_INCLUDE_DIR} ${WAYLAND_CURSOR_INCLUDE_DIR})
+
+ set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES})
+
+ list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIR)
+
+ include(FindPackageHandleStandardArgs)
+
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CLIENT DEFAULT_MSG WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_SERVER DEFAULT_MSG WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_EGL DEFAULT_MSG WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CURSOR DEFAULT_MSG WAYLAND_CURSOR_LIBRARIES WAYLAND_CURSOR_INCLUDE_DIR)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIR)
+
+ MARK_AS_ADVANCED(
+ WAYLAND_INCLUDE_DIR WAYLAND_LIBRARIES
+ WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES
+ WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES
+ WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES
+ WAYLAND_CURSOR_INCLUDE_DIR WAYLAND_CURSOR_LIBRARIES
+ )
+
+ENDIF ()
if(NOT WIN32)
- find_package(XCB REQUIRED)
- find_package(X11 REQUIRED)
+ if (BUILD_WSI_XCB_SUPPORT)
+ find_package(XCB REQUIRED)
+ endif()
+ if (BUILD_WSI_XLIB_SUPPORT)
+ find_package(X11 REQUIRED)
+ endif()
+ if (BUILD_WSI_WAYLAND_SUPPORT)
+ find_package(Wayland REQUIRED)
+ endif()
endif()
file(GLOB TEXTURES
endif()
if(NOT WIN32)
- include_directories (
- ${XCB_INCLUDE_DIRS}
- ${X11_INCLUDE_DIRS}
- "${PROJECT_SOURCE_DIR}/icd/common"
- )
- link_libraries(${XCB_LIBRARIES} ${X11_LIBRARIES} vulkan m)
+ if(BUILD_WSI_XCB_SUPPORT)
+ include_directories(${XCB_INCLUDE_DIRS})
+ link_libraries(${XCB_LIBRARIES})
+ endif()
+ if(BUILD_WSI_XLIB_SUPPORT)
+ include_directories(${X11_INCLUDE_DIRS})
+ link_libraries(${X11_LIBRARIES})
+ endif()
+ if(BUILD_WSI_WAYLAND_SUPPORT)
+ include_directories(${WAYLAND_CLIENT_INCLUDE_DIR})
+ link_libraries(${WAYLAND_CLIENT_LIBRARIES})
+ endif()
+
+ include_directories ("${PROJECT_SOURCE_DIR}/icd/common")
+ link_libraries(vulkan m)
endif()
if(WIN32)
include_directories (
- /*
- * Copyright (c) 2015-2016 The Khronos Group Inc.
- * Copyright (c) 2015-2016 Valve Corporation
- * Copyright (c) 2015-2016 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: Chia-I Wu <olv@lunarg.com>
- * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
- * Author: Ian Elliott <ian@LunarG.com>
- * Author: Jon Ashburn <jon@lunarg.com>
- */
+/*
+* Copyright (c) 2015-2016 The Khronos Group Inc.
+* Copyright (c) 2015-2016 Valve Corporation
+* Copyright (c) 2015-2016 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: Chia-I Wu <olv@lunarg.com>
+* Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
+* Author: Ian Elliott <ian@LunarG.com>
+* Author: Jon Ashburn <jon@lunarg.com>
+* Author: Gwan-gyeong Mun <elongbug@gmail.com>
+*/
#define _GNU_SOURCE
#include <stdio.h>
#define U_ASSERT_ONLY
#endif
+#if defined(__GNUC__)
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
#ifdef _WIN32
#define ERR_EXIT(err_msg, err_class) \
do { \
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;
+ struct wl_registry *registry;
+ struct wl_compositor *compositor;
+ struct wl_surface *window;
+ struct wl_shell *shell;
+ struct wl_shell_surface *shell_surface;
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
ANativeWindow* window;
#endif
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)
+ wl_shell_surface_destroy(demo->shell_surface);
+ wl_surface_destroy(demo->window);
+ wl_shell_destroy(demo->shell);
+ wl_compositor_destroy(demo->compositor);
+ wl_registry_destroy(demo->registry);
+ wl_display_disconnect(demo->display);
#endif
}
xcb_configure_window(demo->connection, demo->xcb_window,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);
}
+#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
+static void demo_run(struct demo *demo) {
+ while (!demo->quit) {
+ // Wait for work to finish before updating MVP.
+ vkDeviceWaitIdle(demo->device);
+ demo_update_data_buffer(demo);
+
+ demo_draw(demo);
+
+ // Wait for work to finish before updating MVP.
+ vkDeviceWaitIdle(demo->device);
+ demo->curFrame++;
+ if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount)
+ demo->quit = true;
+ }
+}
+
+static void handle_ping(void *data UNUSED,
+ struct wl_shell_surface *shell_surface,
+ uint32_t serial) {
+ wl_shell_surface_pong(shell_surface, serial);
+}
+
+static void handle_configure(void *data UNUSED,
+ struct wl_shell_surface *shell_surface UNUSED,
+ uint32_t edges UNUSED, int32_t width UNUSED,
+ int32_t height UNUSED) {}
+
+static void handle_popup_done(void *data UNUSED,
+ struct wl_shell_surface *shell_surface UNUSED) {}
+
+static const struct wl_shell_surface_listener shell_surface_listener = {
+ handle_ping, handle_configure, handle_popup_done};
+
+static void demo_create_window(struct demo *demo) {
+ demo->window = wl_compositor_create_surface(demo->compositor);
+ if (!demo->window) {
+ printf("Can not create wayland_surface from compositor!\n");
+ fflush(stdout);
+ exit(1);
+ }
+
+ demo->shell_surface = wl_shell_get_shell_surface(demo->shell, demo->window);
+ if (!demo->shell_surface) {
+ printf("Can not get shell_surface from wayland_surface!\n");
+ fflush(stdout);
+ exit(1);
+ }
+ wl_shell_surface_add_listener(demo->shell_surface, &shell_surface_listener,
+ demo);
+ wl_shell_surface_set_toplevel(demo->shell_surface);
+ wl_shell_surface_set_title(demo->shell_surface, APP_SHORT_NAME);
+}
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
static void demo_run(struct demo *demo) {
if (!demo->prepared)
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)) {
+ platformSurfaceExtFound = 1;
+ demo->extension_names[demo->enabled_extension_count++] =
+ VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
+ }
+#endif
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
if (!strcmp(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
instance_extensions[i].extensionName)) {
"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\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_ANDROID_KHR)
ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
"the " VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
err =
vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
+#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) && !defined(VK_USE_PLATFORM_XCB_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;
vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
}
+#if defined(VK_USE_PLATFORM_WAYLAND_KHR) && !defined(VK_USE_PLATFORM_XCB_KHR)
+static void registry_handle_global(void *data, struct wl_registry *registry,
+ uint32_t name, const char *interface,
+ uint32_t version UNUSED) {
+ struct demo *demo = data;
+ if (strcmp(interface, "wl_compositor") == 0) {
+ demo->compositor =
+ wl_registry_bind(registry, name, &wl_compositor_interface, 3);
+ /* Todo: When xdg_shell protocol has stablized, we should move wl_shell
+ * tp xdg_shell */
+ } else if (strcmp(interface, "wl_shell") == 0) {
+ demo->shell = wl_registry_bind(registry, name, &wl_shell_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_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 find a compatible Vulkan installable client driver "
+ "(ICD).\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_dispatch(demo->display);
#endif
}
struct demo demo;
demo_init(&demo, argc, argv);
+#if defined(VK_USE_PLATFORM_XLIB_KHR) | defined(VK_USE_PLATFORM_XCB_KHR)
if (demo.use_xlib)
demo_create_xlib_window(&demo);
else
demo_create_xcb_window(&demo);
+#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
+ demo_create_window(&demo);
+#endif
demo_init_vk_swapchain(&demo);
demo_prepare(&demo);
+#if defined(VK_USE_PLATFORM_XLIB_KHR) | defined(VK_USE_PLATFORM_XCB_KHR)
if (demo.use_xlib)
demo_run_xlib(&demo);
else
demo_run_xcb(&demo);
+#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
+ demo_run(&demo);
+#endif
demo_cleanup(&demo);
else()
list(APPEND libraries PRIVATE -ldl -lrt)
- find_package(XCB REQUIRED)
+ if(BUILD_WSI_XCB_SUPPORT)
+ find_package(XCB REQUIRED)
- list(APPEND sources ShellXcb.cpp ShellXcb.h)
- list(APPEND definitions PRIVATE -DVK_USE_PLATFORM_XCB_KHR)
- list(APPEND includes PRIVATE ${XCB_INCLUDES})
- list(APPEND libraries PRIVATE ${XCB_LIBRARIES})
+ list(APPEND sources ShellXcb.cpp ShellXcb.h)
+ list(APPEND definitions PRIVATE -DVK_USE_PLATFORM_XCB_KHR)
+ list(APPEND includes PRIVATE ${XCB_INCLUDES})
+ list(APPEND libraries PRIVATE ${XCB_LIBRARIES})
+ elseif(BUILD_WSI_WAYLAND_SUPPORT)
+ find_package(Wayland REQUIRED)
+
+ list(APPEND sources ShellWayland.cpp ShellWayland.h)
+ list(APPEND definitions PRIVATE -DVK_USE_PLATFORM_WAYLAND_KHR)
+ list(APPEND includes PRIVATE ${WAYLAND_CLIENT_INCLUDE_DIR})
+ list(APPEND libraries PRIVATE ${WAYLAND_CLIENT_LIBRARIES})
+ endif()
endif()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/demos)
return 0;
}
+#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
+
+#include "ShellWayland.h"
+
+int main(int argc, char **argv) {
+ Game *game = create_game(argc, argv);
+ {
+ ShellWayland shell(*game);
+ shell.run();
+ }
+ delete game;
+
+ return 0;
+}
+
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
#include <android/log.h>
--- /dev/null
+/*
+ * Copyright (C) 2016 Google, 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.
+ */
+
+#include <cassert>
+#include <dlfcn.h>
+#include <sstream>
+#include <time.h>
+
+#include "Game.h"
+#include "Helpers.h"
+#include "ShellWayland.h"
+#include <stdio.h>
+#include <string.h>
+
+/* Unused attribute / variable MACRO.
+ Some methods of classes' heirs do not need all fuction parameters.
+ This triggers warning on GCC platfoms. This macro will silence them.
+*/
+#if defined(__GNUC__)
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+namespace {
+
+class PosixTimer {
+ public:
+ PosixTimer() { reset(); }
+
+ void reset() { clock_gettime(CLOCK_MONOTONIC, &start_); }
+
+ double get() const {
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ constexpr long one_s_in_ns = 1000 * 1000 * 1000;
+ constexpr double one_s_in_ns_d = static_cast<double>(one_s_in_ns);
+
+ time_t s = now.tv_sec - start_.tv_sec;
+ long ns;
+ if (now.tv_nsec > start_.tv_nsec) {
+ ns = now.tv_nsec - start_.tv_nsec;
+ } else {
+ assert(s > 0);
+ s--;
+ ns = one_s_in_ns - (start_.tv_nsec - now.tv_nsec);
+ }
+
+ return static_cast<double>(s) + static_cast<double>(ns) / one_s_in_ns_d;
+ }
+
+ private:
+ struct timespec start_;
+};
+
+} // namespace
+
+const struct wl_registry_listener ShellWayland::registry_listener_ = {
+ ShellWayland::handle_global, ShellWayland::handle_global_remove};
+
+const struct wl_shell_surface_listener ShellWayland::shell_surface_listener_ = {
+ ShellWayland::handle_ping, ShellWayland::handle_configure,
+ ShellWayland::handle_popup_done};
+
+void ShellWayland::handle_global(void *data, struct wl_registry *registry,
+ uint32_t id, const char *interface,
+ uint32_t version UNUSED) {
+ ShellWayland *_this = static_cast<ShellWayland *>(data);
+
+ if (!strcmp(interface, "wl_compositor"))
+ _this->compositor_ = static_cast<struct wl_compositor *>(
+ wl_registry_bind(registry, id, &wl_compositor_interface, 3));
+ /* Todo: When xdg_shell protocol has stablized, we should move wl_shell tp
+ * xdg_shell */
+ else if (!strcmp(interface, "wl_shell"))
+ _this->shell_ = static_cast<struct wl_shell *>(
+ wl_registry_bind(registry, id, &wl_shell_interface, 1));
+}
+
+void ShellWayland::handle_global_remove(void *data UNUSED,
+ struct wl_registry *registry UNUSED,
+ uint32_t name UNUSED) {}
+
+void ShellWayland::handle_ping(void *data UNUSED,
+ struct wl_shell_surface *shell_surface,
+ uint32_t serial) {
+ wl_shell_surface_pong(shell_surface, serial);
+}
+
+void ShellWayland::handle_configure(
+ void *data UNUSED, struct wl_shell_surface *shell_surface UNUSED,
+ uint32_t edges UNUSED, int32_t width UNUSED, int32_t height UNUSED) {}
+
+void ShellWayland::handle_popup_done(
+ void *data UNUSED, struct wl_shell_surface *shell_surface UNUSED) {}
+
+ShellWayland::ShellWayland(Game &game) : Shell(game) {
+ instance_extensions_.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
+
+ init_connection();
+ init_vk();
+}
+
+ShellWayland::~ShellWayland() {
+ cleanup_vk();
+ dlclose(lib_handle_);
+
+ if (shell_surface_)
+ wl_shell_surface_destroy(shell_surface_);
+ if (surface_)
+ wl_surface_destroy(surface_);
+ if (shell_)
+ wl_shell_destroy(shell_);
+ if (compositor_)
+ wl_compositor_destroy(compositor_);
+ if (registry_)
+ wl_registry_destroy(registry_);
+ if (display_)
+ wl_display_disconnect(display_);
+}
+
+void ShellWayland::init_connection() {
+ try {
+ display_ = wl_display_connect(NULL);
+ if (!display_)
+ throw std::runtime_error("failed to connect to the display server");
+
+ registry_ = wl_display_get_registry(display_);
+ if (!registry_)
+ throw std::runtime_error("failed to get registry");
+
+ wl_registry_add_listener(registry_, ®istry_listener_, this);
+ wl_display_roundtrip(display_);
+
+ if (!compositor_)
+ throw std::runtime_error("failed to bind compositor");
+
+ if (!shell_)
+ throw std::runtime_error("failed to bind shell");
+ } catch (...) {
+ if (shell_)
+ wl_shell_destroy(shell_);
+ if (compositor_)
+ wl_compositor_destroy(compositor_);
+ if (registry_)
+ wl_registry_destroy(registry_);
+ if (display_)
+ wl_display_disconnect(display_);
+
+ throw;
+ }
+}
+
+void ShellWayland::create_window() {
+ surface_ = wl_compositor_create_surface(compositor_);
+ if (!surface_)
+ throw std::runtime_error("failed to create surface");
+
+ shell_surface_ = wl_shell_get_shell_surface(shell_, surface_);
+ if (!shell_surface_)
+ throw std::runtime_error("failed to shell_surface");
+
+ wl_shell_surface_add_listener(shell_surface_, &shell_surface_listener_,
+ this);
+ // set title
+ wl_shell_surface_set_title(shell_surface_, settings_.name.c_str());
+ wl_shell_surface_set_toplevel(shell_surface_);
+}
+
+PFN_vkGetInstanceProcAddr ShellWayland::load_vk() {
+ const char filename[] = "libvulkan.so";
+ void *handle, *symbol;
+
+#ifdef UNINSTALLED_LOADER
+ handle = dlopen(UNINSTALLED_LOADER, RTLD_LAZY);
+ if (!handle)
+ handle = dlopen(filename, RTLD_LAZY);
+#else
+ handle = dlopen(filename, RTLD_LAZY);
+#endif
+
+ if (handle)
+ symbol = dlsym(handle, "vkGetInstanceProcAddr");
+
+ if (!handle || !symbol) {
+ std::stringstream ss;
+ ss << "failed to load " << dlerror();
+
+ if (handle)
+ dlclose(handle);
+
+ throw std::runtime_error(ss.str());
+ }
+
+ lib_handle_ = handle;
+
+ return reinterpret_cast<PFN_vkGetInstanceProcAddr>(symbol);
+}
+
+bool ShellWayland::can_present(VkPhysicalDevice phy, uint32_t queue_family) {
+ return vk::GetPhysicalDeviceWaylandPresentationSupportKHR(phy, queue_family,
+ display_);
+}
+
+VkSurfaceKHR ShellWayland::create_surface(VkInstance instance) {
+ VkWaylandSurfaceCreateInfoKHR surface_info = {};
+ surface_info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
+ surface_info.display = display_;
+ surface_info.surface = surface_;
+
+ VkSurfaceKHR surface;
+ vk::assert_success(vk::CreateWaylandSurfaceKHR(instance, &surface_info,
+ nullptr, &surface));
+
+ return surface;
+}
+
+void ShellWayland::loop_wait() {
+ while (true) {
+ if (quit_)
+ break;
+
+ acquire_back_buffer();
+ present_back_buffer();
+ }
+}
+
+void ShellWayland::loop_poll() {
+ PosixTimer timer;
+
+ double current_time = timer.get();
+ double profile_start_time = current_time;
+ int profile_present_count = 0;
+
+ while (true) {
+ if (quit_)
+ break;
+
+ acquire_back_buffer();
+
+ double t = timer.get();
+ add_game_time(static_cast<float>(t - current_time));
+
+ present_back_buffer();
+
+ current_time = t;
+
+ profile_present_count++;
+ if (current_time - profile_start_time >= 5.0) {
+ const double fps =
+ profile_present_count / (current_time - profile_start_time);
+ std::stringstream ss;
+ ss << profile_present_count << " presents in "
+ << current_time - profile_start_time << " seconds "
+ << "(FPS: " << fps << ")";
+ log(LOG_INFO, ss.str().c_str());
+
+ profile_start_time = current_time;
+ profile_present_count = 0;
+ }
+ }
+}
+
+void ShellWayland::run() {
+ create_window();
+ create_context();
+ resize_swapchain(settings_.initial_width, settings_.initial_height);
+
+ quit_ = false;
+ if (settings_.animate)
+ loop_poll();
+ else
+ loop_wait();
+
+ destroy_context();
+}
--- /dev/null
+/*
+ * Copyright (C) 2016 Google, 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.
+ */
+
+#ifndef SHELL_WAYLAND_H
+#define SHELL_WAYLAND_H
+
+#include "Shell.h"
+
+class ShellWayland : public Shell {
+ public:
+ ShellWayland(Game &game);
+ ~ShellWayland();
+
+ void run();
+ void quit() { quit_ = true; }
+
+ private:
+ void init_connection();
+
+ PFN_vkGetInstanceProcAddr load_vk();
+ bool can_present(VkPhysicalDevice phy, uint32_t queue_family);
+
+ void create_window();
+ VkSurfaceKHR create_surface(VkInstance instance);
+
+ void loop_wait();
+ void loop_poll();
+
+ void *lib_handle_;
+ bool quit_;
+
+ struct wl_display *display_;
+ struct wl_registry *registry_;
+ struct wl_compositor *compositor_;
+ struct wl_shell *shell_;
+ struct wl_surface *surface_;
+ struct wl_shell_surface *shell_surface_;
+
+ static void handle_global(void *data, struct wl_registry *registry,
+ uint32_t id, const char *interface,
+ uint32_t version);
+ static void handle_global_remove(void *data, struct wl_registry *registry,
+ uint32_t name);
+ static void handle_ping(void *data, struct wl_shell_surface *shell_surface,
+ uint32_t serial);
+ static void handle_configure(void *data,
+ struct wl_shell_surface *shell_surface,
+ uint32_t edges, int32_t width, int32_t height);
+ static void handle_popup_done(void *data,
+ struct wl_shell_surface *shell_surface);
+
+ static const struct wl_registry_listener registry_listener_;
+ static const struct wl_shell_surface_listener shell_surface_listener_;
+};
+
+#endif // SHELL_WAYLAND_H
* Author: Ian Elliott <ian@LunarG.com>
* Author: Jon Ashburn <jon@lunarg.com>
* Author: Piers Daniell <pdaniell@nvidia.com>
+ * Author: Gwan-gyeong Mun <elongbug@gmail.com>
*/
/*
* Draw a textured triangle with depth testing. This is written against Intel
#define U_ASSERT_ONLY
#endif
+#if defined(__GNUC__)
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
#ifdef _WIN32
#define ERR_EXIT(err_msg, err_class) \
do { \
xcb_screen_t *screen;
xcb_window_t window;
xcb_intern_atom_reply_t *atom_wm_delete_window;
+#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
+ struct wl_display *display;
+ struct wl_registry *registry;
+ struct wl_compositor *compositor;
+ struct wl_surface *window;
+ struct wl_shell *shell;
+ struct wl_shell_surface *shell_surface;
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
ANativeWindow* window;
#endif
xcb_map_window(demo->connection, demo->window);
}
+#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
+static void demo_run(struct demo *demo) {
+
+ while (!demo->quit) {
+ demo_draw(demo);
+
+ if (demo->depthStencil > 0.99f)
+ demo->depthIncrement = -0.001f;
+ if (demo->depthStencil < 0.8f)
+ demo->depthIncrement = 0.001f;
+
+ demo->depthStencil += demo->depthIncrement;
+
+ // Wait for work to finish before updating MVP.
+ vkDeviceWaitIdle(demo->device);
+ demo->curFrame++;
+ if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount)
+ demo->quit = true;
+ }
+}
+
+static void handle_ping(void *data UNUSED,
+ struct wl_shell_surface *shell_surface,
+ uint32_t serial) {
+ wl_shell_surface_pong(shell_surface, serial);
+}
+
+static void handle_configure(void *data UNUSED,
+ struct wl_shell_surface *shell_surface UNUSED,
+ uint32_t edges UNUSED, int32_t width UNUSED,
+ int32_t height UNUSED) {}
+
+static void handle_popup_done(void *data UNUSED,
+ struct wl_shell_surface *shell_surface UNUSED) {}
+
+static const struct wl_shell_surface_listener shell_surface_listener = {
+ handle_ping, handle_configure, handle_popup_done};
+
+static void demo_create_window(struct demo *demo) {
+ demo->window = wl_compositor_create_surface(demo->compositor);
+ if (!demo->window) {
+ printf("Can not create wayland_surface from compositor!\n");
+ fflush(stdout);
+ exit(1);
+ }
+
+ demo->shell_surface = wl_shell_get_shell_surface(demo->shell, demo->window);
+ if (!demo->shell_surface) {
+ printf("Can not get shell_surface from wayland_surface!\n");
+ fflush(stdout);
+ exit(1);
+ }
+ wl_shell_surface_add_listener(demo->shell_surface, &shell_surface_listener,
+ demo);
+ wl_shell_surface_set_toplevel(demo->shell_surface);
+ wl_shell_surface_set_title(demo->shell_surface, APP_SHORT_NAME);
+}
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
static void demo_run(struct demo *demo) {
if (!demo->prepared)
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_ANDROID_KHR)
if (!strcmp(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
instance_extensions[i].extensionName)) {
"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\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_ANDROID_KHR)
ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
"the " VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
createInfo.window = demo->window;
err = vkCreateXcbSurfaceKHR(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;
vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
}
+#if defined(VK_USE_PLATFORM_WAYLAND_KHR) && !defined(VK_USE_PLATFORM_XCB_KHR)
+static void registry_handle_global(void *data, struct wl_registry *registry,
+ uint32_t name, const char *interface,
+ uint32_t version UNUSED) {
+ struct demo *demo = data;
+ if (strcmp(interface, "wl_compositor") == 0) {
+ demo->compositor =
+ wl_registry_bind(registry, name, &wl_compositor_interface, 3);
+ /* Todo: When xdg_shell protocol has stablized, we should move wl_shell
+ * tp xdg_shell */
+ } else if (strcmp(interface, "wl_shell") == 0) {
+ demo->shell = wl_registry_bind(registry, name, &wl_shell_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_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 find a compatible Vulkan installable client driver "
+ "(ICD).\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_dispatch(demo->display);
#endif // _WIN32
}
xcb_destroy_window(demo->connection, demo->window);
xcb_disconnect(demo->connection);
free(demo->atom_wm_delete_window);
+#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
+ wl_shell_surface_destroy(demo->shell_surface);
+ wl_surface_destroy(demo->window);
+ wl_shell_destroy(demo->shell);
+ wl_compositor_destroy(demo->compositor);
+ wl_registry_destroy(demo->registry);
+ wl_display_disconnect(demo->display);
#endif
}
}
-#elif defined(VK_USE_PLATFORM_XCB_KHR)
+#elif defined(VK_USE_PLATFORM_XCB_KHR) | defined(VK_USE_PLATFORM_WAYLAND_KHR)
int main(const int argc, const char *argv[]) {
struct demo demo;