The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at prediction 406 lines 11 kB view raw
1// Copyright 2019-2020, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Wayland window code. 6 * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 7 * @author Jakob Bornecrantz <jakob@collabora.com> 8 * @ingroup comp_main 9 */ 10 11#include <errno.h> 12#include <linux/input.h> 13#include <poll.h> 14#include <stdlib.h> 15#include <string.h> 16#include <wayland-client.h> 17 18#include "xdg-shell-client-protocol.h" 19#include "xrt/xrt_compiler.h" 20#include "main/comp_window.h" 21#include "util/u_misc.h" 22 23 24/* 25 * 26 * Private structs. 27 * 28 */ 29 30/*! 31 * A Wayland connection and window. 32 * 33 * @implements comp_target_swapchain 34 */ 35struct comp_window_wayland 36{ 37 struct comp_target_swapchain base; 38 39 struct wl_display *display; 40 struct wl_compositor *compositor; 41 struct wl_surface *surface; 42 43 struct xdg_wm_base *wm_base; 44 struct xdg_surface *xdg_surface; 45 struct xdg_toplevel *xdg_toplevel; 46 47 bool fullscreen_requested; 48}; 49 50 51/* 52 * 53 * Pre declare functions. 54 * 55 */ 56 57static void 58comp_window_wayland_destroy(struct comp_target *ct); 59 60static bool 61comp_window_wayland_init(struct comp_target *ct); 62 63static void 64comp_window_wayland_update_window_title(struct comp_target *ct, const char *title); 65 66static void 67comp_window_wayland_registry_global(struct comp_window_wayland *w, 68 struct wl_registry *registry, 69 uint32_t name, 70 const char *interface); 71 72static void 73comp_window_wayland_fullscreen(struct comp_window_wayland *w); 74 75static bool 76comp_window_wayland_init_swapchain(struct comp_target *ct, uint32_t width, uint32_t height); 77 78static VkResult 79comp_window_wayland_create_surface(struct comp_window_wayland *w, VkSurfaceKHR *out_surface); 80 81static void 82comp_window_wayland_flush(struct comp_target *ct); 83 84static void 85comp_window_wayland_configure(struct comp_window_wayland *w, int32_t width, int32_t height); 86 87 88/* 89 * 90 * Functions. 91 * 92 */ 93 94static inline struct vk_bundle * 95get_vk(struct comp_window_wayland *cww) 96{ 97 return &cww->base.base.c->base.vk; 98} 99 100struct comp_target * 101comp_window_wayland_create(struct comp_compositor *c) 102{ 103 struct comp_window_wayland *w = U_TYPED_CALLOC(struct comp_window_wayland); 104 105 // The display timing code hasn't been tested on Wayland and may be broken. 106 comp_target_swapchain_init_and_set_fnptrs(&w->base, COMP_TARGET_FORCE_FAKE_DISPLAY_TIMING); 107 108 w->base.base.name = "wayland"; 109 w->base.display = VK_NULL_HANDLE; 110 w->base.base.destroy = comp_window_wayland_destroy; 111 w->base.base.flush = comp_window_wayland_flush; 112 w->base.base.init_pre_vulkan = comp_window_wayland_init; 113 w->base.base.init_post_vulkan = comp_window_wayland_init_swapchain; 114 w->base.base.set_title = comp_window_wayland_update_window_title; 115 w->base.base.c = c; 116 117 return &w->base.base; 118} 119 120static void 121comp_window_wayland_destroy(struct comp_target *ct) 122{ 123 struct comp_window_wayland *cww = (struct comp_window_wayland *)ct; 124 125 comp_target_swapchain_cleanup(&cww->base); 126 127 if (cww->xdg_toplevel) { 128 xdg_toplevel_destroy(cww->xdg_toplevel); 129 } 130 if (cww->xdg_surface) { 131 xdg_surface_destroy(cww->xdg_surface); 132 } 133 if (cww->wm_base) { 134 xdg_wm_base_destroy(cww->wm_base); 135 } 136 if (cww->surface) { 137 wl_surface_destroy(cww->surface); 138 cww->surface = NULL; 139 } 140 if (cww->compositor) { 141 wl_compositor_destroy(cww->compositor); 142 cww->compositor = NULL; 143 } 144 if (cww->display) { 145 wl_display_disconnect(cww->display); 146 cww->display = NULL; 147 } 148 149 free(ct); 150} 151 152static void 153comp_window_wayland_update_window_title(struct comp_target *ct, const char *title) 154{ 155 struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)ct; 156 xdg_toplevel_set_title(w_wayland->xdg_toplevel, title); 157} 158 159static void 160comp_window_wayland_fullscreen(struct comp_window_wayland *w) 161{ 162 xdg_toplevel_set_fullscreen(w->xdg_toplevel, NULL); 163 wl_surface_commit(w->surface); 164} 165 166static void 167_xdg_surface_configure_cb(void *data, struct xdg_surface *surface, uint32_t serial) 168{ 169 xdg_surface_ack_configure(surface, serial); 170} 171 172static void 173_xdg_toplevel_configure_cb( 174 void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *states) 175{ 176 struct comp_window_wayland *w = (struct comp_window_wayland *)data; 177 comp_window_wayland_configure(w, width, height); 178} 179 180static const struct xdg_surface_listener xdg_surface_listener = { 181 _xdg_surface_configure_cb, 182}; 183 184static void 185_xdg_toplevel_close_cb(void *data, struct xdg_toplevel *toplevel) 186{} 187 188static const struct xdg_toplevel_listener xdg_toplevel_listener = { 189 _xdg_toplevel_configure_cb, 190 _xdg_toplevel_close_cb, 191#if XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION >= 4 192 NULL, 193#endif 194#if XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION >= 5 195 NULL, 196#endif 197}; 198 199static void 200_xdg_wm_base_ping_cb(void *data, struct xdg_wm_base *wm_base, uint32_t serial) 201{ 202 xdg_wm_base_pong(wm_base, serial); 203} 204 205static const struct xdg_wm_base_listener xdg_wm_base_listener = { 206 _xdg_wm_base_ping_cb, 207}; 208 209static bool 210comp_window_wayland_init_swapchain(struct comp_target *ct, uint32_t width, uint32_t height) 211{ 212 struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)ct; 213 VkResult ret; 214 215 ret = comp_window_wayland_create_surface(w_wayland, &w_wayland->base.surface.handle); 216 if (ret != VK_SUCCESS) { 217 COMP_ERROR(ct->c, "Failed to create surface!"); 218 return false; 219 } 220 221 xdg_toplevel_set_min_size(w_wayland->xdg_toplevel, width, height); 222 xdg_toplevel_set_max_size(w_wayland->xdg_toplevel, width, height); 223 224 return true; 225} 226 227static VkResult 228comp_window_wayland_create_surface(struct comp_window_wayland *w, VkSurfaceKHR *out_surface) 229{ 230 struct vk_bundle *vk = get_vk(w); 231 VkResult ret; 232 233 VkWaylandSurfaceCreateInfoKHR surface_info = { 234 .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 235 .display = w->display, 236 .surface = w->surface, 237 }; 238 239 VkSurfaceKHR surface = VK_NULL_HANDLE; 240 ret = vk->vkCreateWaylandSurfaceKHR( // 241 vk->instance, // 242 &surface_info, // 243 NULL, // 244 &surface); // 245 if (ret != VK_SUCCESS) { 246 COMP_ERROR(w->base.base.c, "vkCreateWaylandSurfaceKHR: %s", vk_result_string(ret)); 247 return ret; 248 } 249 250 VK_NAME_SURFACE(vk, surface, "comp_window_wayland surface"); 251 *out_surface = surface; 252 253 return VK_SUCCESS; 254} 255 256static void 257comp_window_wayland_flush(struct comp_target *ct) 258{ 259 struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)ct; 260 261 while (wl_display_prepare_read(w_wayland->display) != 0) 262 wl_display_dispatch_pending(w_wayland->display); 263 if (wl_display_flush(w_wayland->display) < 0 && errno != EAGAIN) { 264 wl_display_cancel_read(w_wayland->display); 265 return; 266 } 267 268 struct pollfd fds[] = { 269 { 270 .fd = wl_display_get_fd(w_wayland->display), 271 .events = POLLIN, 272 .revents = 0, 273 }, 274 }; 275 276 if (poll(fds, 1, 0) > 0) { 277 wl_display_read_events(w_wayland->display); 278 wl_display_dispatch_pending(w_wayland->display); 279 } else { 280 wl_display_cancel_read(w_wayland->display); 281 } 282} 283 284static void 285_registry_global_remove_cb(void *data, struct wl_registry *registry, uint32_t name) 286{} 287 288static void 289_registry_global_cb(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) 290{ 291 struct comp_window_wayland *w = (struct comp_window_wayland *)data; 292 // vik_log_d("Interface: %s Version %d", interface, version); 293 comp_window_wayland_registry_global(w, registry, name, interface); 294} 295 296static const struct wl_registry_listener registry_listener = { 297 _registry_global_cb, 298 _registry_global_remove_cb, 299}; 300 301static void 302comp_window_wayland_registry_global(struct comp_window_wayland *w, 303 struct wl_registry *registry, 304 uint32_t name, 305 const char *interface) 306{ 307 if (strcmp(interface, "wl_compositor") == 0) { 308 w->compositor = (struct wl_compositor *)wl_registry_bind(registry, name, &wl_compositor_interface, 4); 309 } else if (strcmp(interface, "xdg_wm_base") == 0) { 310 w->wm_base = (struct xdg_wm_base *)wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); 311 xdg_wm_base_add_listener(w->wm_base, &xdg_wm_base_listener, w); 312 } 313} 314 315static bool 316comp_window_wayland_init(struct comp_target *ct) 317{ 318 struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)ct; 319 320 w_wayland->display = wl_display_connect(NULL); 321 if (!w_wayland->display) { 322 return false; 323 } 324 325 struct wl_registry *registry = wl_display_get_registry(w_wayland->display); 326 wl_registry_add_listener(registry, &registry_listener, w_wayland); 327 328 wl_display_roundtrip(w_wayland->display); 329 330 wl_registry_destroy(registry); 331 332 w_wayland->surface = wl_compositor_create_surface(w_wayland->compositor); 333 334 if (!w_wayland->wm_base) { 335 COMP_ERROR(ct->c, "Compositor is missing xdg-shell support"); 336 } 337 338 w_wayland->xdg_surface = xdg_wm_base_get_xdg_surface(w_wayland->wm_base, w_wayland->surface); 339 340 xdg_surface_add_listener(w_wayland->xdg_surface, &xdg_surface_listener, w_wayland); 341 342 w_wayland->xdg_toplevel = xdg_surface_get_toplevel(w_wayland->xdg_surface); 343 344 xdg_toplevel_add_listener(w_wayland->xdg_toplevel, &xdg_toplevel_listener, w_wayland); 345 /* basic defaults */ 346 xdg_toplevel_set_app_id(w_wayland->xdg_toplevel, "openxr"); 347 xdg_toplevel_set_title(w_wayland->xdg_toplevel, "OpenXR application"); 348 349 wl_surface_commit(w_wayland->surface); 350 351 return true; 352} 353 354static void 355comp_window_wayland_configure(struct comp_window_wayland *w, int32_t width, int32_t height) 356{ 357 if (w->base.base.c->settings.fullscreen && !w->fullscreen_requested) { 358 COMP_DEBUG(w->base.base.c, "Setting full screen"); 359 comp_window_wayland_fullscreen(w); 360 w->fullscreen_requested = true; 361 } 362} 363 364 365/* 366 * 367 * Factory 368 * 369 */ 370 371static const char *instance_extensions[] = { 372 VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, 373}; 374 375static bool 376detect(const struct comp_target_factory *ctf, struct comp_compositor *c) 377{ 378 return false; 379} 380 381static bool 382create_target(const struct comp_target_factory *ctf, struct comp_compositor *c, struct comp_target **out_ct) 383{ 384 struct comp_target *ct = comp_window_wayland_create(c); 385 if (ct == NULL) { 386 return false; 387 } 388 389 *out_ct = ct; 390 391 return true; 392} 393 394const struct comp_target_factory comp_target_factory_wayland = { 395 .name = "Wayland Windowed", 396 .identifier = "wayland", 397 .requires_vulkan_for_create = false, 398 .is_deferred = false, 399 .required_instance_version = 0, 400 .required_instance_extensions = instance_extensions, 401 .required_instance_extension_count = ARRAY_SIZE(instance_extensions), 402 .optional_device_extensions = NULL, 403 .optional_device_extension_count = 0, 404 .detect = detect, 405 .create_target = create_target, 406};