From 47be8064286acb331bb2d92c7b3ba45568007047 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Tue, 14 Sep 2021 11:11:40 -0400 Subject: [PATCH] c/main: Implement WINDOW_DIRECT_WAYLAND --- CMakeLists.txt | 5 +- meson.build | 9 + src/xrt/compositor/CMakeLists.txt | 64 ++- src/xrt/compositor/main/comp_compositor.c | 32 +- src/xrt/compositor/main/comp_settings.c | 6 + src/xrt/compositor/main/comp_settings.h | 1 + src/xrt/compositor/main/comp_window.h | 9 + .../main/comp_window_direct_wayland.c | 459 ++++++++++++++++++ src/xrt/compositor/meson.build | 23 +- src/xrt/include/xrt/meson.build | 2 +- 10 files changed, 580 insertions(+), 30 deletions(-) create mode 100644 src/xrt/compositor/main/comp_window_direct_wayland.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 230438733..6fe88a1ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,6 +102,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") pkg_search_module(WAYLAND wayland-client) pkg_search_module(WAYLAND_SCANNER wayland-scanner) pkg_search_module(WAYLAND_PROTOCOLS wayland-protocols) + pkg_search_module(LIBDRM libdrm) endif() find_package(OpenGL COMPONENTS GLX) pkg_search_module(DBUS dbus-1) @@ -132,7 +133,8 @@ option(XRT_FEATURE_COLOR_LOG "Enable logging in color on supported platforms" ON option(XRT_FEATURE_TRACING "Enable debug tracing on supported platforms" OFF) cmake_dependent_option(CMAKE_INTERPROCEDURAL_OPTIMIZATION "Enable inter-procedural (link-time) optimization" OFF "HAS_IPO" OFF) -cmake_dependent_option(XRT_HAVE_WAYLAND "Enable Wayland support" ON "WAYLAND_FOUND AND WAYLAND_SCANNER_FOUND AND WAYLAND_PROTOCOLS_FOUND" OFF) +cmake_dependent_option(XRT_HAVE_WAYLAND "Enable Wayland support" ON "WAYLAND_FOUND AND WAYLAND_SCANNER_FOUND AND WAYLAND_PROTOCOLS_FOUND AND LIBDRM_FOUND" OFF) +cmake_dependent_option(XRT_HAVE_WAYLAND_DIRECT "Enable Wayland direct support" ON "XRT_HAVE_WAYLAND AND LIBDRM_FOUND AND WAYLAND_PROTOCOLS_VERSION VERSION_GREATER_EQUAL 1,22" OFF) cmake_dependent_option(XRT_HAVE_XLIB "Enable xlib support" ON "X11_FOUND" OFF) cmake_dependent_option(XRT_HAVE_XRANDR "Enable xlib-xrandr support" ON "XRANDR_FOUND" OFF) cmake_dependent_option(XRT_HAVE_XCB "Enable xcb support" ON "XCB_FOUND" OFF) @@ -345,6 +347,7 @@ message(STATUS "# GIT_DESC: ${GIT_DESC}") message(STATUS "#") message(STATUS "# GST (GStreamer): ${XRT_HAVE_GST}") message(STATUS "# WAYLAND: ${XRT_HAVE_WAYLAND}") +message(STATUS "# WAYLAND_DIRECT: ${XRT_HAVE_WAYLAND_DIRECT}") message(STATUS "# XLIB: ${XRT_HAVE_XLIB}") message(STATUS "# XRANDR: ${XRT_HAVE_XRANDR}") message(STATUS "# XCB: ${XRT_HAVE_XCB}") diff --git a/meson.build b/meson.build index c8c0fd35e..deb12b9a5 100644 --- a/meson.build +++ b/meson.build @@ -103,6 +103,7 @@ xcb_randr = dependency('xcb-randr', required: get_option('xcb')) wayland = dependency('wayland-client', required: get_option('wayland')) wayland_protos = dependency('wayland-protocols', required: get_option('wayland')) wayland_scanner = dependency('wayland-scanner', required: get_option('wayland')) +drm = dependency('libdrm', required: get_option('wayland')) if wayland_scanner.found() wayland_scanner = find_program( @@ -143,8 +144,10 @@ build_xcb_xrandr_direct = build_xcb and build_xlib and xcb_randr.found() and x11 build_vk_khr_display = true build_wayland = false +build_wayland_direct = false if get_option('wayland').enabled() or get_option('wayland').auto() build_wayland = wayland.found() and wayland_protos.found() and wayland_scanner.found() + build_wayland_direct = build_wayland and drm.found() and wayland_protos.version().version_compare('>=1.22') endif # For now required on Linux @@ -338,6 +341,12 @@ else message(' wayland: no') endif +if build_wayland_direct + message('wayland_direct: yes') +else + message('wayland_direct: no') +endif + if not get_option('systemd').disabled() and systemd.found() message(' systemd: yes') else diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt index 848815241..c62eeb0bb 100644 --- a/src/xrt/compositor/CMakeLists.txt +++ b/src/xrt/compositor/CMakeLists.txt @@ -150,27 +150,55 @@ if(XRT_FEATURE_COMPOSITOR_MAIN) pkg_get_variable(WL_PROTOS_PKG_DIR wayland-protocols pkgdatadir) pkg_get_variable(WL_SCANNER wayland-scanner wayland_scanner) - set(WL_PROTOS_DIR "${CMAKE_CURRENT_BINARY_DIR}/wayland-protocols/") + set(WL_PROTOS_DIR "${CMAKE_CURRENT_BINARY_DIR}/wayland-protocols") file(MAKE_DIRECTORY "${WL_PROTOS_DIR}") - set(WL_PROTOS_XML "${WL_PROTOS_PKG_DIR}/stable/xdg-shell/xdg-shell.xml") - set(WL_PROTOS_C "${WL_PROTOS_DIR}/xdg-shell.c") - set(WL_PROTOS_H "${WL_PROTOS_DIR}/xdg-shell-client-protocol.h") + set(WL_PROTOS_XML + ${WL_PROTOS_PKG_DIR}/stable/xdg-shell/xdg-shell.xml + ) - add_custom_command( - COMMAND - ${WL_SCANNER} private-code "${WL_PROTOS_XML}" "${WL_PROTOS_C}" - OUTPUT "${WL_PROTOS_C}" VERBATIM) - - add_custom_command( - COMMAND - ${WL_SCANNER} client-header "${WL_PROTOS_XML}" "${WL_PROTOS_H}" - OUTPUT "${WL_PROTOS_H}" VERBATIM) - - set(WL_PROTOS_SRC ${WL_PROTOS_C} ${WL_PROTOS_H}) list(APPEND MAIN_SOURCE_FILES main/comp_window_wayland.c ) + + if (XRT_HAVE_WAYLAND_DIRECT) + list(APPEND WL_PROTOS_XML + ${WL_PROTOS_PKG_DIR}/staging/drm-lease/drm-lease-v1.xml + ) + + list(APPEND MAIN_SOURCE_FILES + main/comp_window_direct_wayland.c + ) + + pkg_check_modules(LIBDRM IMPORTED_TARGET libdrm) + set(WAYLAND_DEPS + ${WAYLAND_LIBRARIES} + PkgConfig::LIBDRM + ) + endif() + + foreach(WL_PROTO_XML ${WL_PROTOS_XML}) + get_filename_component(WL_PROTO ${WL_PROTO_XML} NAME_WLE) + + set(WL_PROTO_C "${WL_PROTOS_DIR}/${WL_PROTO}.c") + set(WL_PROTO_H "${WL_PROTOS_DIR}/${WL_PROTO}-client-protocol.h") + + add_custom_command( + COMMAND + ${WL_SCANNER} private-code "${WL_PROTO_XML}" "${WL_PROTO_C}" + OUTPUT "${WL_PROTO_C}" VERBATIM) + + add_custom_command( + COMMAND + ${WL_SCANNER} client-header "${WL_PROTO_XML}" "${WL_PROTO_H}" + OUTPUT "${WL_PROTO_H}" VERBATIM) + + list(APPEND MAIN_SOURCE_FILES + ${WL_PROTO_C} + ${WL_PROTO_H} + ) + endforeach() + endif() if(ANDROID) list(APPEND MAIN_SOURCE_FILES @@ -178,7 +206,7 @@ if(XRT_FEATURE_COMPOSITOR_MAIN) ) endif() - add_library(comp_main STATIC ${SHADER_HEADERS} ${MAIN_SOURCE_FILES} ${WL_PROTOS_SRC}) + add_library(comp_main STATIC ${SHADER_HEADERS} ${MAIN_SOURCE_FILES}) target_link_libraries(comp_main PUBLIC xrt-interfaces PRIVATE aux_util aux_os aux_vk) target_include_directories(comp_main PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(comp_main SYSTEM PRIVATE @@ -188,7 +216,9 @@ if(XRT_FEATURE_COMPOSITOR_MAIN) if(XRT_HAVE_WAYLAND) target_include_directories(comp_main SYSTEM PRIVATE ${WL_PROTOS_DIR}) - target_link_libraries(comp_main PRIVATE ${WAYLAND_LIBRARIES}) + target_link_libraries(comp_main PRIVATE + ${WAYLAND_DEPS} + ) endif() if(XRT_HAVE_XCB) target_include_directories(comp_main SYSTEM PRIVATE ${XCB_INCLUDE_DIRS}) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index c914b21fc..3bbaca5fe 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -668,7 +668,7 @@ vkGetInstanceProcAddr(VkInstance instance, const char *pName); VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, \ VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, \ VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, \ - VK_KHR_SURFACE_EXTENSION_NAME + VK_KHR_SURFACE_EXTENSION_NAME \ // clang-format on static const char *instance_extensions_none[] = {COMP_INSTANCE_EXTENSIONS_COMMON}; @@ -678,8 +678,18 @@ static const char *instance_extensions_xcb[] = {COMP_INSTANCE_EXTENSIONS_COMMON, #endif #ifdef VK_USE_PLATFORM_WAYLAND_KHR -static const char *instance_extensions_wayland[] = {COMP_INSTANCE_EXTENSIONS_COMMON, - VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME}; +static const char *instance_extensions_wayland[] = { + COMP_INSTANCE_EXTENSIONS_COMMON, + VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, +}; + +static const char *instance_extensions_direct_wayland[] = { + COMP_INSTANCE_EXTENSIONS_COMMON, + VK_KHR_DISPLAY_EXTENSION_NAME, + VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, + VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME, + VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME, +}; #endif #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT @@ -764,6 +774,11 @@ select_instances_extensions(struct comp_compositor *c, const char ***out_exts, u *out_num = ARRAY_SIZE(instance_extensions_none); break; #ifdef VK_USE_PLATFORM_WAYLAND_KHR + case WINDOW_DIRECT_WAYLAND: + *out_exts = instance_extensions_direct_wayland; + *out_num = ARRAY_SIZE(instance_extensions_direct_wayland); + break; + case WINDOW_WAYLAND: *out_exts = instance_extensions_wayland; *out_num = ARRAY_SIZE(instance_extensions_wayland); @@ -1191,6 +1206,10 @@ compositor_init_window_pre_vulkan(struct comp_compositor *c) switch (c->settings.window_type) { case WINDOW_AUTO: #ifdef VK_USE_PLATFORM_WAYLAND_KHR + if (compositor_try_window(c, comp_window_direct_wayland_create(c))) { + c->settings.window_type = WINDOW_DIRECT_WAYLAND; + return true; + } if (compositor_try_window(c, comp_window_wayland_create(c))) { c->settings.window_type = WINDOW_WAYLAND; return true; @@ -1238,6 +1257,13 @@ compositor_init_window_pre_vulkan(struct comp_compositor *c) compositor_try_window(c, comp_window_wayland_create(c)); #else COMP_ERROR(c, "Wayland support not compiled in!"); +#endif + break; + case WINDOW_DIRECT_WAYLAND: +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + compositor_try_window(c, comp_window_direct_wayland_create(c)); +#else + COMP_ERROR(c, "Wayland direct support not compiled in!"); #endif break; case WINDOW_DIRECT_RANDR: diff --git a/src/xrt/compositor/main/comp_settings.c b/src/xrt/compositor/main/comp_settings.c index b02fa16b7..f62208f5a 100644 --- a/src/xrt/compositor/main/comp_settings.c +++ b/src/xrt/compositor/main/comp_settings.c @@ -14,6 +14,7 @@ DEBUG_GET_ONCE_LOG_OPTION(log, "XRT_COMPOSITOR_LOG", U_LOGGING_INFO) DEBUG_GET_ONCE_BOOL_OPTION(print_modes, "XRT_COMPOSITOR_PRINT_MODES", false) DEBUG_GET_ONCE_BOOL_OPTION(force_randr, "XRT_COMPOSITOR_FORCE_RANDR", false) +DEBUG_GET_ONCE_BOOL_OPTION(force_wayland_direct, "XRT_COMPOSITOR_FORCE_WAYLAND_DIRECT", false) DEBUG_GET_ONCE_BOOL_OPTION(force_nvidia, "XRT_COMPOSITOR_FORCE_NVIDIA", false) DEBUG_GET_ONCE_OPTION(nvidia_display, "XRT_COMPOSITOR_FORCE_NVIDIA_DISPLAY", NULL) DEBUG_GET_ONCE_NUM_OPTION(vk_display, "XRT_COMPOSITOR_FORCE_VK_DISPLAY", -1) @@ -78,6 +79,11 @@ comp_settings_init(struct comp_settings *s, struct xrt_device *xdev) s->window_type = WINDOW_DIRECT_RANDR; } + if (debug_get_bool_option_force_wayland_direct()) { + s->window_type = WINDOW_DIRECT_WAYLAND; + } + + if (debug_get_bool_option_force_xcb()) { s->window_type = WINDOW_XCB; // HMD screen tends to be much larger then monitors. diff --git a/src/xrt/compositor/main/comp_settings.h b/src/xrt/compositor/main/comp_settings.h index 4501500b5..4186b437d 100644 --- a/src/xrt/compositor/main/comp_settings.h +++ b/src/xrt/compositor/main/comp_settings.h @@ -44,6 +44,7 @@ enum window_type WINDOW_AUTO, WINDOW_XCB, WINDOW_WAYLAND, + WINDOW_DIRECT_WAYLAND, WINDOW_DIRECT_RANDR, WINDOW_DIRECT_NVIDIA, WINDOW_ANDROID, diff --git a/src/xrt/compositor/main/comp_window.h b/src/xrt/compositor/main/comp_window.h index bb799e80e..60d3178db 100644 --- a/src/xrt/compositor/main/comp_window.h +++ b/src/xrt/compositor/main/comp_window.h @@ -46,6 +46,15 @@ comp_window_xcb_create(struct comp_compositor *c); */ struct comp_target * comp_window_wayland_create(struct comp_compositor *c); + +/*! + * Create a direct surface to a HMD via Wayland. + * + * @ingroup comp + */ +struct comp_target * +comp_window_direct_wayland_create(struct comp_compositor *c); + #endif #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT diff --git a/src/xrt/compositor/main/comp_window_direct_wayland.c b/src/xrt/compositor/main/comp_window_direct_wayland.c new file mode 100644 index 000000000..fd04dd50b --- /dev/null +++ b/src/xrt/compositor/main/comp_window_direct_wayland.c @@ -0,0 +1,459 @@ +// Copyright 2019, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Wayland direct mode code. + * @author Drew DeVault + * @author Lubosz Sarnecki + * @author Simon Zeni + * @ingroup comp + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drm-lease-v1-client-protocol.h" +#include "xrt/xrt_compiler.h" +#include "main/comp_window.h" +#include "main/comp_window_direct.h" + +#ifndef VK_EXT_acquire_drm_display +#error "Wayland direct requires the Vulkan extension VK_EXT_acquire_drm_display" +#endif + +struct direct_wayland_lease +{ + struct comp_window_direct_wayland *w; + + int leased_fd; + bool finished; + struct wp_drm_lease_v1 *lease; +}; + +struct direct_wayland_lease_connector +{ + struct comp_window_direct_wayland *w; + + uint32_t id; + char *name, *description; + struct wp_drm_lease_connector_v1 *connector; + struct direct_wayland_lease_device *dev; + struct direct_wayland_lease_connector *next; +}; + +struct direct_wayland_lease_device +{ + struct comp_window_direct_wayland *w; + + int drm_fd; + char *path; + bool done; + struct wp_drm_lease_device_v1 *device; + struct direct_wayland_lease_connector *connectors; + struct direct_wayland_lease_device *next; +}; + +struct comp_window_direct_wayland +{ + struct comp_target_swapchain base; + + struct wl_display *display; + struct direct_wayland_lease_device *devices; + struct direct_wayland_lease *lease; +}; + +static void +direct_wayland_lease_device_destroy(struct direct_wayland_lease_device *dev) +{ + struct direct_wayland_lease_connector *conn = dev->connectors, *next_conn; + while (conn) { + next_conn = conn->next; + + wp_drm_lease_connector_v1_destroy(conn->connector); + + free(conn->name); + free(conn->description); + free(conn); + + conn = next_conn; + } + + wp_drm_lease_device_v1_destroy(dev->device); + close(dev->drm_fd); + + free(dev->path); + free(dev); +} + +static void +comp_window_direct_wayland_destroy(struct comp_target *w) +{ + struct comp_window_direct_wayland *w_wayland = (struct comp_window_direct_wayland *)w; + + comp_target_swapchain_cleanup(&w_wayland->base); + + struct direct_wayland_lease_device *dev = w_wayland->devices, *next_dev; + while (dev) { + next_dev = dev->next; + direct_wayland_lease_device_destroy(dev); + dev = next_dev; + } + + if (w_wayland->lease) { + close(w_wayland->lease->leased_fd); + wp_drm_lease_v1_destroy(w_wayland->lease->lease); + free(w_wayland->lease); + } + + wl_display_disconnect(w_wayland->display); + free(w_wayland); +} + +static inline struct vk_bundle * +get_vk(struct comp_window_direct_wayland *cww) +{ + return &cww->base.base.c->vk; +} + +static void +_lease_fd(void *data, struct wp_drm_lease_v1 *wp_drm_lease_v1, int32_t leased_fd) +{ + struct direct_wayland_lease *lease = data; + COMP_DEBUG(lease->w->base.base.c, "Lease granted"); + + lease->leased_fd = leased_fd; +} + +static void +_lease_finished(void *data, struct wp_drm_lease_v1 *wp_drm_lease_v1) +{ + struct direct_wayland_lease *lease = data; + if (lease->leased_fd >= 0) { + close(lease->leased_fd); + lease->leased_fd = -1; + } + + COMP_DEBUG(lease->w->base.base.c, "Lease has been terminated"); + lease->finished = true; +} + +static const struct wp_drm_lease_v1_listener lease_listener = { + .lease_fd = _lease_fd, + .finished = _lease_finished, +}; + +static VkResult +comp_window_direct_wayland_create_surface(struct comp_window_direct_wayland *w, + VkSurfaceKHR *surface, + uint32_t width, + uint32_t height) +{ + assert(!w->lease); + + struct vk_bundle *vk = get_vk(w); + VkDisplayKHR _display = VK_NULL_HANDLE; + VkResult ret = VK_ERROR_INCOMPATIBLE_DISPLAY_KHR; + + /* TODO: Choose the connector with an environment variable or from `ct->c->settings.display` */ + + /* Pick the first connector available */ + struct direct_wayland_lease_device *dev = w->devices; + struct direct_wayland_lease_connector *conn = NULL; + while (dev) { + if (dev->connectors) { + conn = dev->connectors; + + COMP_INFO(w->base.base.c, "Using DRM node %s", dev->path); + COMP_INFO(w->base.base.c, "Connector id %d %s (%s)", conn->id, conn->name, conn->description); + break; + } + dev = dev->next; + } + + if (!conn) { + COMP_ERROR(w->base.base.c, "Attempted to create wayland direct surface with no connectors"); + return VK_ERROR_INITIALIZATION_FAILED; + } + + ret = vk->vkGetDrmDisplayEXT(vk->physical_device, dev->drm_fd, conn->id, &_display); + if (ret != VK_SUCCESS) { + COMP_ERROR(w->base.base.c, "vkGetDrmDisplayEXT failed: %s", vk_result_string(ret)); + return ret; + } + + struct wp_drm_lease_request_v1 *request = wp_drm_lease_device_v1_create_lease_request(dev->device); + if (!request) { + COMP_ERROR(w->base.base.c, "Failed to create lease request"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + wp_drm_lease_request_v1_request_connector(request, conn->connector); + + struct direct_wayland_lease *lease = calloc(1, sizeof(struct direct_wayland_lease)); + lease->w = w; + lease->leased_fd = -1; + lease->finished = false; + lease->lease = wp_drm_lease_request_v1_submit(request); + + w->lease = lease; + + wp_drm_lease_v1_add_listener(lease->lease, &lease_listener, lease); + + while (lease->leased_fd < 0 && !lease->finished) { + if (wl_display_dispatch(w->display) == -1) { + COMP_ERROR(w->base.base.c, "wl_display roundtrip failed"); + return VK_ERROR_UNKNOWN; + } + } + + if (lease->finished) { + COMP_ERROR(w->base.base.c, "Failed to lease connector"); + return VK_ERROR_UNKNOWN; + } + + ret = vk->vkAcquireDrmDisplayEXT(vk->physical_device, lease->leased_fd, _display); + if (ret != VK_SUCCESS) { + COMP_ERROR(w->base.base.c, "vkAcquireDrmDisplayEXT failed: %s", vk_result_string(ret)); + return ret; + } + + ret = comp_window_direct_create_surface(&w->base, _display, width, height); + if (ret != VK_SUCCESS) { + COMP_ERROR(w->base.base.c, "Failed to create surface: %s", vk_result_string(ret)); + } + + return ret; +} + +static bool +comp_window_direct_wayland_init_swapchain(struct comp_target *w, uint32_t width, uint32_t height) +{ + struct comp_window_direct_wayland *w_wayland = (struct comp_window_direct_wayland *)w; + VkResult ret; + + ret = comp_window_direct_wayland_create_surface(w_wayland, &w_wayland->base.surface.handle, width, height); + if (ret != VK_SUCCESS) { + COMP_ERROR(w->c, "Failed to create surface!"); + return false; + } + + return true; +} + +static void +comp_window_direct_wayland_flush(struct comp_target *w) +{ + struct comp_window_direct_wayland *w_wayland = (struct comp_window_direct_wayland *)w; + + while (wl_display_prepare_read(w_wayland->display) != 0) + wl_display_dispatch_pending(w_wayland->display); + + if (wl_display_flush(w_wayland->display) < 0 && errno != EAGAIN) { + wl_display_cancel_read(w_wayland->display); + return; + } + + struct pollfd fds[] = { + { + .fd = wl_display_get_fd(w_wayland->display), + .events = POLLIN, + }, + }; + + if (poll(fds, 1, 0) > 0) { + wl_display_read_events(w_wayland->display); + wl_display_dispatch_pending(w_wayland->display); + } else { + wl_display_cancel_read(w_wayland->display); + } +} + +static void +_lease_connector_name(void *data, struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, const char *name) +{ + struct direct_wayland_lease_connector *conn = data; + conn->name = strdup(name); +} + +static void +_lease_connector_description(void *data, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, + const char *description) +{ + struct direct_wayland_lease_connector *conn = data; + if (conn->description) { + free(conn->description); + } + conn->description = strdup(description); +} + +static void +_lease_connector_connector_id(void *data, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, + uint32_t connector_id) +{ + struct direct_wayland_lease_connector *conn = data; + conn->id = connector_id; +} + +static void +_lease_connector_done(void *data, struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1) +{ + struct direct_wayland_lease_connector *conn = data; + COMP_DEBUG(conn->w->base.base.c, "[%s] connector %s (%s) id: %d", conn->dev->path, conn->name, + conn->description, conn->id); +} + +static void +_lease_connector_withdrawn(void *data, struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1) +{ + struct direct_wayland_lease_connector *conn = data; + COMP_ERROR(conn->w->base.base.c, "Connector %s has been withdrawn by the compositor", conn->name); + + /* TODO: handle graceful shutdown, remove the connector from the device */ +} + +static const struct wp_drm_lease_connector_v1_listener lease_connector_listener = { + .name = _lease_connector_name, + .description = _lease_connector_description, + .connector_id = _lease_connector_connector_id, + .done = _lease_connector_done, + .withdrawn = _lease_connector_withdrawn, +}; + +static void +_drm_lease_device_drm_fd(void *data, struct wp_drm_lease_device_v1 *drm_lease_device, int fd) +{ + struct direct_wayland_lease_device *dev = data; + dev->drm_fd = fd; + dev->path = drmGetDeviceNameFromFd2(fd); + COMP_DEBUG(dev->w->base.base.c, "Available DRM lease device: %s", dev->path); +} + +static void +_drm_lease_device_connector(void *data, + struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1) +{ + struct direct_wayland_lease_device *dev = data; + + struct direct_wayland_lease_connector *conn = calloc(1, sizeof(struct direct_wayland_lease_connector)); + conn->connector = wp_drm_lease_connector_v1; + conn->dev = dev; + conn->w = dev->w; + wp_drm_lease_connector_v1_add_listener(conn->connector, &lease_connector_listener, conn); + + conn->next = dev->connectors; + dev->connectors = conn; +} + +static void +_drm_lease_device_done(void *data, struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) +{ + struct direct_wayland_lease_device *dev = data; + dev->done = true; +} + +static void +_drm_lease_device_released(void *data, struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) +{ + struct direct_wayland_lease_device *dev = data; + COMP_ERROR(dev->w->base.base.c, "Releasing lease device %s", dev->path); + direct_wayland_lease_device_destroy(dev); +} + +static const struct wp_drm_lease_device_v1_listener drm_lease_device_listener = { + .drm_fd = _drm_lease_device_drm_fd, + .connector = _drm_lease_device_connector, + .done = _drm_lease_device_done, + .released = _drm_lease_device_released, +}; + +static void +_registry_global_remove_cb(void *data, struct wl_registry *registry, uint32_t name) +{} + +static void +_registry_global_cb(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) +{ + struct comp_window_direct_wayland *w = data; + if (strcmp(interface, wp_drm_lease_device_v1_interface.name) == 0) { + struct direct_wayland_lease_device *dev = calloc(1, sizeof(struct direct_wayland_lease_device)); + dev->device = (struct wp_drm_lease_device_v1 *)wl_registry_bind(registry, name, + &wp_drm_lease_device_v1_interface, 1); + dev->w = w; + dev->drm_fd = -1; + wp_drm_lease_device_v1_add_listener(dev->device, &drm_lease_device_listener, dev); + + dev->next = w->devices; + w->devices = dev; + } +} + +static const struct wl_registry_listener registry_listener = { + .global = _registry_global_cb, + .global_remove = _registry_global_remove_cb, +}; + +static bool +comp_window_direct_wayland_init(struct comp_target *w) +{ + struct comp_window_direct_wayland *w_wayland = (struct comp_window_direct_wayland *)w; + + w_wayland->display = wl_display_connect(NULL); + if (!w_wayland->display) { + COMP_ERROR(w->c, "Failed to connect to Wayland display"); + return false; + } + + struct wl_registry *registry = wl_display_get_registry(w_wayland->display); + wl_registry_add_listener(registry, ®istry_listener, w_wayland); + wl_display_roundtrip(w_wayland->display); + wl_registry_destroy(registry); + + if (!w_wayland->devices) { + COMP_ERROR(w->c, "Compositor is missing drm-lease support"); + return false; + } + + struct direct_wayland_lease_device *dev = w_wayland->devices; + while (dev) { + if (!dev->done) { + wl_display_dispatch(w_wayland->display); + continue; + } + dev = dev->next; + } + + return true; +} + +static void +_update_window_title(struct comp_target *ct, const char *title) +{ + /* Not required in direct mode */ +} + +struct comp_target * +comp_window_direct_wayland_create(struct comp_compositor *c) +{ + struct comp_window_direct_wayland *w = U_TYPED_CALLOC(struct comp_window_direct_wayland); + + comp_target_swapchain_init_and_set_fnptrs(&w->base, COMP_TARGET_FORCE_FAKE_DISPLAY_TIMING); + + w->base.base.name = "wayland-direct"; + w->base.base.destroy = comp_window_direct_wayland_destroy; + w->base.base.flush = comp_window_direct_wayland_flush; + w->base.base.init_pre_vulkan = comp_window_direct_wayland_init; + w->base.base.init_post_vulkan = comp_window_direct_wayland_init_swapchain; + w->base.base.set_title = _update_window_title; + w->base.base.c = c; + + return &w->base.base; +} diff --git a/src/xrt/compositor/meson.build b/src/xrt/compositor/meson.build index 34e36834a..6d2b96065 100644 --- a/src/xrt/compositor/meson.build +++ b/src/xrt/compositor/meson.build @@ -114,20 +114,27 @@ if build_wayland wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') protocols = [ - [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], + wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', ] - foreach p : protocols - xml = join_paths(p) + if build_wayland_direct + protocols += wl_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml' + compositor_srcs += 'main/comp_window_direct_wayland.c' + compositor_deps += drm + endif + + compositor_srcs += 'main/comp_window_wayland.c' + + foreach path : protocols wl_protos_src += custom_target( - xml.underscorify() + '_c', - input: xml, + path.underscorify() + '_c', + input: path, output: '@BASENAME@-protocol.c', command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], ) wl_protos_headers += custom_target( - xml.underscorify() + '_client_h', - input: xml, + path.underscorify() + '_client_h', + input: path, output: '@BASENAME@-client-protocol.h', command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], ) @@ -144,8 +151,8 @@ if build_wayland sources: wl_protos_headers, ) - compositor_srcs += ['main/comp_window_wayland.c'] compositor_deps += [wayland, wl_protos] + endif lib_comp = static_library( diff --git a/src/xrt/include/xrt/meson.build b/src/xrt/include/xrt/meson.build index e33c3bb53..b55979e9f 100644 --- a/src/xrt/include/xrt/meson.build +++ b/src/xrt/include/xrt/meson.build @@ -69,7 +69,7 @@ if has_v4l2_header and 'v4l2' in drivers endif if true - have_conf.set('XRT_HAVE_VULKAN', true) + have_conf.set('XRT_HAVE_VULKAN', true) endif if dbus.found() and not get_option('dbus').disabled()