diff options
| author | Mun Gwan-gyeong <elongbug@gmail.com> | 2016-06-27 05:34:44 +0900 |
|---|---|---|
| committer | Dustin Graves <dustin@lunarg.com> | 2016-06-29 17:03:48 -0600 |
| commit | 6f01c553d3a93e8c505cb8557db1d0ade5eb6645 (patch) | |
| tree | 208fe65a8f5e6fb9058e5cef74e1247839675969 | |
| parent | 04bf6b0684a05b0cfa49dbea77846ced120ffb5a (diff) | |
| download | usermoji-6f01c553d3a93e8c505cb8557db1d0ade5eb6645.tar.xz | |
demos: GH692 Added a supporting of wayland wsi
Added a supporting of wayland wsi to cube, tri and smoke.
Change-Id: Ifa291d334cb1ed54018573c970078051c6867d96
Signed-off-by: Mun Gwan-gyeong <elongbug@gmail.com>
| -rw-r--r-- | cmake/FindWayland.cmake | 66 | ||||
| -rw-r--r-- | demos/CMakeLists.txt | 32 | ||||
| -rw-r--r-- | demos/cube.c | 188 | ||||
| -rw-r--r-- | demos/smoke/CMakeLists.txt | 19 | ||||
| -rw-r--r-- | demos/smoke/Main.cpp | 15 | ||||
| -rw-r--r-- | demos/smoke/ShellWayland.cpp | 290 | ||||
| -rw-r--r-- | demos/smoke/ShellWayland.h | 69 | ||||
| -rw-r--r-- | demos/tri.c | 141 |
8 files changed, 784 insertions, 36 deletions
diff --git a/cmake/FindWayland.cmake b/cmake/FindWayland.cmake new file mode 100644 index 00000000..f93218b8 --- /dev/null +++ b/cmake/FindWayland.cmake @@ -0,0 +1,66 @@ +# 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 () diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 652efb75..26e86fb8 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -1,6 +1,13 @@ 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 @@ -80,12 +87,21 @@ else() 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 ( diff --git a/demos/cube.c b/demos/cube.c index f669962d..f675ca5a 100644 --- a/demos/cube.c +++ b/demos/cube.c @@ -1,25 +1,26 @@ - /* - * 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> @@ -58,6 +59,12 @@ #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 { \ @@ -301,6 +308,13 @@ struct demo { 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 @@ -1932,6 +1946,13 @@ static void demo_cleanup(struct demo *demo) { 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 } @@ -2293,6 +2314,59 @@ 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); } +#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) @@ -2454,6 +2528,14 @@ static void demo_init_vk(struct demo *demo) { 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)) { @@ -2501,6 +2583,14 @@ static void demo_init_vk(struct demo *demo) { "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 @@ -2758,6 +2848,16 @@ static void demo_init_vk_swapchain(struct demo *demo) { 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; @@ -2889,6 +2989,29 @@ static void demo_init_vk_swapchain(struct demo *demo) { 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; @@ -2909,6 +3032,19 @@ static void demo_init_connection(struct demo *demo) { 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 } @@ -3140,19 +3276,27 @@ int main(int argc, char **argv) { 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); diff --git a/demos/smoke/CMakeLists.txt b/demos/smoke/CMakeLists.txt index 04aae19b..4dc90cd1 100644 --- a/demos/smoke/CMakeLists.txt +++ b/demos/smoke/CMakeLists.txt @@ -62,12 +62,21 @@ if(WIN32) 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) diff --git a/demos/smoke/Main.cpp b/demos/smoke/Main.cpp index 7118c8e0..a59ff1b4 100644 --- a/demos/smoke/Main.cpp +++ b/demos/smoke/Main.cpp @@ -45,6 +45,21 @@ int main(int argc, char **argv) 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> diff --git a/demos/smoke/ShellWayland.cpp b/demos/smoke/ShellWayland.cpp new file mode 100644 index 00000000..0d4bcbcf --- /dev/null +++ b/demos/smoke/ShellWayland.cpp @@ -0,0 +1,290 @@ +/* + * 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(); +} diff --git a/demos/smoke/ShellWayland.h b/demos/smoke/ShellWayland.h new file mode 100644 index 00000000..ab7f279a --- /dev/null +++ b/demos/smoke/ShellWayland.h @@ -0,0 +1,69 @@ +/* + * 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 diff --git a/demos/tri.c b/demos/tri.c index ed2f1287..91c76ab9 100644 --- a/demos/tri.c +++ b/demos/tri.c @@ -21,6 +21,7 @@ * 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 @@ -63,6 +64,12 @@ #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 { \ @@ -150,6 +157,13 @@ struct demo { 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 @@ -1764,6 +1778,63 @@ static void demo_create_window(struct demo *demo) { 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) @@ -1910,6 +1981,13 @@ static void demo_init_vk(struct demo *demo) { 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)) { @@ -1957,6 +2035,14 @@ static void demo_init_vk(struct demo *demo) { "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 @@ -2203,6 +2289,16 @@ static void demo_init_vk_swapchain(struct demo *demo) { 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; @@ -2302,6 +2398,29 @@ static void demo_init_vk_swapchain(struct demo *demo) { 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; @@ -2322,6 +2441,19 @@ static void demo_init_connection(struct demo *demo) { 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 } @@ -2426,6 +2558,13 @@ static void demo_cleanup(struct demo *demo) { 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 } @@ -2635,7 +2774,7 @@ void android_main(struct android_app *app) } -#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; |
