From b43a9b8efb44fd69f32d79ae52e224f455aae1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Glet?= <63368174+gorgbus@users.noreply.github.com> Date: Mon, 14 Apr 2025 15:56:21 +0200 Subject: [PATCH] fix(linux): headless monitors on wayland (#3783) --- cmake/compile_definitions/linux.cmake | 5 +- packaging/linux/fedora/Sunshine.spec | 1 + packaging/sunshine.rb | 1 + scripts/linux_build.sh | 2 + src/platform/linux/wayland.cpp | 335 ++++++++++++++++++++++---- src/platform/linux/wayland.h | 143 +++++------ src/platform/linux/wlgrab.cpp | 2 +- 7 files changed, 359 insertions(+), 130 deletions(-) diff --git a/cmake/compile_definitions/linux.cmake b/cmake/compile_definitions/linux.cmake index 62ca61a6..152466d8 100644 --- a/cmake/compile_definitions/linux.cmake +++ b/cmake/compile_definitions/linux.cmake @@ -137,7 +137,8 @@ if(WAYLAND_FOUND) endif() GEN_WAYLAND("${WAYLAND_PROTOCOLS_DIR}" "unstable/xdg-output" xdg-output-unstable-v1) - GEN_WAYLAND("${CMAKE_SOURCE_DIR}/third-party/wlr-protocols" "unstable" wlr-export-dmabuf-unstable-v1) + GEN_WAYLAND("${WAYLAND_PROTOCOLS_DIR}" "unstable/linux-dmabuf" linux-dmabuf-unstable-v1) + GEN_WAYLAND("${CMAKE_SOURCE_DIR}/third-party/wlr-protocols" "unstable" wlr-screencopy-unstable-v1) include_directories( SYSTEM @@ -145,7 +146,7 @@ if(WAYLAND_FOUND) ${CMAKE_BINARY_DIR}/generated-src ) - list(APPEND PLATFORM_LIBRARIES ${WAYLAND_LIBRARIES}) + list(APPEND PLATFORM_LIBRARIES ${WAYLAND_LIBRARIES} gbm) list(APPEND PLATFORM_TARGET_FILES "${CMAKE_SOURCE_DIR}/src/platform/linux/wlgrab.cpp" "${CMAKE_SOURCE_DIR}/src/platform/linux/wayland.h" diff --git a/packaging/linux/fedora/Sunshine.spec b/packaging/linux/fedora/Sunshine.spec index 910c4fce..3becff3b 100644 --- a/packaging/linux/fedora/Sunshine.spec +++ b/packaging/linux/fedora/Sunshine.spec @@ -35,6 +35,7 @@ BuildRequires: libXrandr-devel BuildRequires: libXtst-devel BuildRequires: git BuildRequires: mesa-libGL-devel +BuildRequires: mesa-libgbm-devel BuildRequires: miniupnpc-devel BuildRequires: npm BuildRequires: numactl-devel diff --git a/packaging/sunshine.rb b/packaging/sunshine.rb index dd96392a..81e42b09 100644 --- a/packaging/sunshine.rb +++ b/packaging/sunshine.rb @@ -51,6 +51,7 @@ class @PROJECT_NAME@ < Formula depends_on "libxinerama" depends_on "libxrandr" depends_on "libxtst" + depends_on "mesa" depends_on "numactl" depends_on "pulseaudio" depends_on "systemd" diff --git a/scripts/linux_build.sh b/scripts/linux_build.sh index e6a62d7e..4cb071ec 100644 --- a/scripts/linux_build.sh +++ b/scripts/linux_build.sh @@ -105,6 +105,7 @@ function add_debain_based_deps() { "libcurl4-openssl-dev" "libdrm-dev" # KMS "libevdev-dev" + "libgbm-dev" "libminiupnpc-dev" "libnotify-dev" "libnuma-dev" @@ -175,6 +176,7 @@ function add_fedora_deps() { "libXrandr-devel" # X11 "libXtst-devel" # X11 "mesa-libGL-devel" + "mesa-libgbm-devel" "miniupnpc-devel" "ninja-build" "npm" diff --git a/src/platform/linux/wayland.cpp b/src/platform/linux/wayland.cpp index c6e02d72..4fa05a27 100644 --- a/src/platform/linux/wayland.cpp +++ b/src/platform/linux/wayland.cpp @@ -6,9 +6,14 @@ #include // platform includes +#include +#include +#include #include +#include #include #include +#include // local includes #include "graphics.h" @@ -37,6 +42,12 @@ namespace wl { #define CLASS_CALL(c, m) classCall + // Define buffer params listener + static const struct zwp_linux_buffer_params_v1_listener params_listener = { + .created = dmabuf_t::buffer_params_created, + .failed = dmabuf_t::buffer_params_failed + }; + int display_t::init(const char *display_name) { if (!display_name) { display_name = std::getenv("WAYLAND_DISPLAY"); @@ -136,7 +147,13 @@ namespace wl { BOOST_LOG(info) << "Logical size: "sv << width << 'x' << height; } - void monitor_t::wl_mode(wl_output *wl_output, std::uint32_t flags, std::int32_t width, std::int32_t height, std::int32_t refresh) { + void monitor_t::wl_mode( + wl_output *wl_output, + std::uint32_t flags, + std::int32_t width, + std::int32_t height, + std::int32_t refresh + ) { viewport.width = width; viewport.height = height; @@ -151,6 +168,8 @@ namespace wl { interface_t::interface_t() noexcept : + screencopy_manager {nullptr}, + dmabuf_interface {nullptr}, output_manager {nullptr}, listener { &CLASS_CALL(interface_t, add_interface), @@ -162,7 +181,12 @@ namespace wl { wl_registry_add_listener(registry, &listener, this); } - void interface_t::add_interface(wl_registry *registry, std::uint32_t id, const char *interface, std::uint32_t version) { + void interface_t::add_interface( + wl_registry *registry, + std::uint32_t id, + const char *interface, + std::uint32_t version + ) { BOOST_LOG(debug) << "Available interface: "sv << interface << '(' << id << ") version "sv << version; if (!std::strcmp(interface, wl_output_interface.name)) { @@ -177,11 +201,16 @@ namespace wl { output_manager = (zxdg_output_manager_v1 *) wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, version); this->interface[XDG_OUTPUT] = true; - } else if (!std::strcmp(interface, zwlr_export_dmabuf_manager_v1_interface.name)) { + } else if (!std::strcmp(interface, zwlr_screencopy_manager_v1_interface.name)) { BOOST_LOG(info) << "Found interface: "sv << interface << '(' << id << ") version "sv << version; - dmabuf_manager = (zwlr_export_dmabuf_manager_v1 *) wl_registry_bind(registry, id, &zwlr_export_dmabuf_manager_v1_interface, version); + screencopy_manager = (zwlr_screencopy_manager_v1 *) wl_registry_bind(registry, id, &zwlr_screencopy_manager_v1_interface, version); this->interface[WLR_EXPORT_DMABUF] = true; + } else if (!std::strcmp(interface, zwp_linux_dmabuf_v1_interface.name)) { + BOOST_LOG(info) << "Found interface: "sv << interface << '(' << id << ") version "sv << version; + dmabuf_interface = (zwp_linux_dmabuf_v1 *) wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, version); + + this->interface[LINUX_DMABUF] = true; } } @@ -189,94 +218,306 @@ namespace wl { BOOST_LOG(info) << "Delete: "sv << id; } + // Initialize GBM + bool dmabuf_t::init_gbm() { + if (gbm_device) { + return true; + } + + // Find render node + drmDevice *devices[16]; + int n = drmGetDevices2(0, devices, 16); + if (n <= 0) { + BOOST_LOG(error) << "No DRM devices found"sv; + return false; + } + + int drm_fd = -1; + for (int i = 0; i < n; i++) { + if (devices[i]->available_nodes & (1 << DRM_NODE_RENDER)) { + drm_fd = open(devices[i]->nodes[DRM_NODE_RENDER], O_RDWR); + if (drm_fd >= 0) { + break; + } + } + } + drmFreeDevices(devices, n); + + if (drm_fd < 0) { + BOOST_LOG(error) << "Failed to open DRM render node"sv; + return false; + } + + gbm_device = gbm_create_device(drm_fd); + if (!gbm_device) { + close(drm_fd); + BOOST_LOG(error) << "Failed to create GBM device"sv; + return false; + } + + return true; + } + + // Cleanup GBM + void dmabuf_t::cleanup_gbm() { + if (current_bo) { + gbm_bo_destroy(current_bo); + current_bo = nullptr; + } + + if (current_wl_buffer) { + wl_buffer_destroy(current_wl_buffer); + current_wl_buffer = nullptr; + } + } + dmabuf_t::dmabuf_t(): status {READY}, frames {}, current_frame {&frames[0]}, listener { - &CLASS_CALL(dmabuf_t, frame), - &CLASS_CALL(dmabuf_t, object), + &CLASS_CALL(dmabuf_t, buffer), + &CLASS_CALL(dmabuf_t, flags), &CLASS_CALL(dmabuf_t, ready), - &CLASS_CALL(dmabuf_t, cancel) + &CLASS_CALL(dmabuf_t, failed), + &CLASS_CALL(dmabuf_t, damage), + &CLASS_CALL(dmabuf_t, linux_dmabuf), + &CLASS_CALL(dmabuf_t, buffer_done), } { } - void dmabuf_t::listen(zwlr_export_dmabuf_manager_v1 *dmabuf_manager, wl_output *output, bool blend_cursor) { - auto frame = zwlr_export_dmabuf_manager_v1_capture_output(dmabuf_manager, blend_cursor, output); - zwlr_export_dmabuf_frame_v1_add_listener(frame, &listener, this); + // Start capture + void dmabuf_t::listen( + zwlr_screencopy_manager_v1 *screencopy_manager, + zwp_linux_dmabuf_v1 *dmabuf_interface, + wl_output *output, + bool blend_cursor + ) { + this->dmabuf_interface = dmabuf_interface; + // Reset state + shm_info.supported = false; + dmabuf_info.supported = false; + + // Create new frame + auto frame = zwlr_screencopy_manager_v1_capture_output( + screencopy_manager, + blend_cursor ? 1 : 0, + output + ); + + // Store frame data pointer for callbacks + zwlr_screencopy_frame_v1_set_user_data(frame, this); + + // Add listener + zwlr_screencopy_frame_v1_add_listener(frame, &listener, this); status = WAITING; } dmabuf_t::~dmabuf_t() { + cleanup_gbm(); + for (auto &frame : frames) { frame.destroy(); } + + if (gbm_device) { + // We should close the DRM FD, but it's owned by GBM + gbm_device_destroy(gbm_device); + gbm_device = nullptr; + } } - void dmabuf_t::frame( - zwlr_export_dmabuf_frame_v1 *frame, - std::uint32_t width, - std::uint32_t height, - std::uint32_t x, - std::uint32_t y, - std::uint32_t buffer_flags, - std::uint32_t flags, + // Buffer format callback + void dmabuf_t::buffer( + zwlr_screencopy_frame_v1 *frame, + uint32_t format, + uint32_t width, + uint32_t height, + uint32_t stride + ) { + shm_info.supported = true; + shm_info.format = format; + shm_info.width = width; + shm_info.height = height; + shm_info.stride = stride; + + BOOST_LOG(debug) << "Screencopy supports SHM format: "sv << format; + } + + // DMA-BUF format callback + void dmabuf_t::linux_dmabuf( + zwlr_screencopy_frame_v1 *frame, std::uint32_t format, - std::uint32_t high, - std::uint32_t low, - std::uint32_t obj_count + std::uint32_t width, + std::uint32_t height ) { - auto next_frame = get_next_frame(); + dmabuf_info.supported = true; + dmabuf_info.format = format; + dmabuf_info.width = width; + dmabuf_info.height = height; - next_frame->sd.fourcc = format; - next_frame->sd.width = width; - next_frame->sd.height = height; - next_frame->sd.modifier = (((std::uint64_t) high) << 32) | low; + BOOST_LOG(debug) << "Screencopy supports DMA-BUF format: "sv << format; } - void dmabuf_t::object( - zwlr_export_dmabuf_frame_v1 *frame, - std::uint32_t index, - std::int32_t fd, - std::uint32_t size, - std::uint32_t offset, - std::uint32_t stride, - std::uint32_t plane_index - ) { - auto next_frame = get_next_frame(); - - next_frame->sd.fds[plane_index] = fd; - next_frame->sd.pitches[plane_index] = stride; - next_frame->sd.offsets[plane_index] = offset; + // Flags callback + void dmabuf_t::flags(zwlr_screencopy_frame_v1 *frame, std::uint32_t flags) { + y_invert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT; + BOOST_LOG(debug) << "Frame flags: "sv << flags << (y_invert ? " (y_invert)" : ""); } + // DMA-BUF creation helper + void dmabuf_t::create_and_copy_dmabuf(zwlr_screencopy_frame_v1 *frame) { + if (!init_gbm()) { + BOOST_LOG(error) << "Failed to initialize GBM"sv; + zwlr_screencopy_frame_v1_destroy(frame); + status = REINIT; + return; + } + + // Create GBM buffer + current_bo = gbm_bo_create(gbm_device, dmabuf_info.width, dmabuf_info.height, dmabuf_info.format, GBM_BO_USE_RENDERING); + if (!current_bo) { + BOOST_LOG(error) << "Failed to create GBM buffer"sv; + zwlr_screencopy_frame_v1_destroy(frame); + status = REINIT; + return; + } + + // Get buffer info + int fd = gbm_bo_get_fd(current_bo); + if (fd < 0) { + BOOST_LOG(error) << "Failed to get buffer FD"sv; + gbm_bo_destroy(current_bo); + current_bo = nullptr; + zwlr_screencopy_frame_v1_destroy(frame); + status = REINIT; + return; + } + + uint32_t stride = gbm_bo_get_stride(current_bo); + uint64_t modifier = gbm_bo_get_modifier(current_bo); + + // Store in surface descriptor for later use + auto next_frame = get_next_frame(); + next_frame->sd.fds[0] = fd; + next_frame->sd.pitches[0] = stride; + next_frame->sd.offsets[0] = 0; + next_frame->sd.modifier = modifier; + + // Create linux-dmabuf buffer + auto params = zwp_linux_dmabuf_v1_create_params(dmabuf_interface); + zwp_linux_buffer_params_v1_add(params, fd, 0, 0, stride, modifier >> 32, modifier & 0xffffffff); + + // Add listener for buffer creation + zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, frame); + + // Create Wayland buffer (async - callback will handle copy) + zwp_linux_buffer_params_v1_create(params, dmabuf_info.width, dmabuf_info.height, dmabuf_info.format, 0); + } + + // Buffer done callback - time to create buffer + void dmabuf_t::buffer_done(zwlr_screencopy_frame_v1 *frame) { + auto next_frame = get_next_frame(); + + // Prefer DMA-BUF if supported + if (dmabuf_info.supported && dmabuf_interface) { + // Store format info first + next_frame->sd.fourcc = dmabuf_info.format; + next_frame->sd.width = dmabuf_info.width; + next_frame->sd.height = dmabuf_info.height; + + // Create and start copy + create_and_copy_dmabuf(frame); + } else if (shm_info.supported) { + // SHM fallback would go here + BOOST_LOG(warning) << "SHM capture not implemented"sv; + zwlr_screencopy_frame_v1_destroy(frame); + status = REINIT; + } else { + BOOST_LOG(error) << "No supported buffer types"sv; + zwlr_screencopy_frame_v1_destroy(frame); + status = REINIT; + } + } + + // Buffer params created callback + void dmabuf_t::buffer_params_created( + void *data, + struct zwp_linux_buffer_params_v1 *params, + struct wl_buffer *buffer + ) { + auto frame = static_cast(data); + auto self = static_cast(zwlr_screencopy_frame_v1_get_user_data(frame)); + + // Store for cleanup + self->current_wl_buffer = buffer; + + // Start the actual copy + zwlr_screencopy_frame_v1_copy(frame, buffer); + } + + // Buffer params failed callback + void dmabuf_t::buffer_params_failed( + void *data, + struct zwp_linux_buffer_params_v1 *params + ) { + auto frame = static_cast(data); + auto self = static_cast(zwlr_screencopy_frame_v1_get_user_data(frame)); + + BOOST_LOG(error) << "Failed to create buffer from params"sv; + self->cleanup_gbm(); + + zwlr_screencopy_frame_v1_destroy(frame); + self->status = REINIT; + } + + // Ready callback void dmabuf_t::ready( - zwlr_export_dmabuf_frame_v1 *frame, + zwlr_screencopy_frame_v1 *frame, std::uint32_t tv_sec_hi, std::uint32_t tv_sec_lo, std::uint32_t tv_nsec ) { - zwlr_export_dmabuf_frame_v1_destroy(frame); + BOOST_LOG(debug) << "Frame ready"sv; + // Frame is ready for use, GBM buffer now contains screen content current_frame->destroy(); current_frame = get_next_frame(); + // Keep the GBM buffer alive but destroy the Wayland objects + if (current_wl_buffer) { + wl_buffer_destroy(current_wl_buffer); + current_wl_buffer = nullptr; + } + + cleanup_gbm(); + + zwlr_screencopy_frame_v1_destroy(frame); status = READY; } - void dmabuf_t::cancel( - zwlr_export_dmabuf_frame_v1 *frame, - std::uint32_t reason - ) { - zwlr_export_dmabuf_frame_v1_destroy(frame); + // Failed callback + void dmabuf_t::failed(zwlr_screencopy_frame_v1 *frame) { + BOOST_LOG(error) << "Frame capture failed"sv; + // Clean up resources + cleanup_gbm(); auto next_frame = get_next_frame(); next_frame->destroy(); + zwlr_screencopy_frame_v1_destroy(frame); status = REINIT; } + void dmabuf_t::damage( + zwlr_screencopy_frame_v1 *frame, + std::uint32_t x, + std::uint32_t y, + std::uint32_t width, + std::uint32_t height + ) {}; + void frame_t::destroy() { for (auto x = 0; x < 4; ++x) { if (sd.fds[x] >= 0) { diff --git a/src/platform/linux/wayland.h b/src/platform/linux/wayland.h index 6a6986f6..08d5acbd 100644 --- a/src/platform/linux/wayland.h +++ b/src/platform/linux/wayland.h @@ -8,7 +8,8 @@ #include #ifdef SUNSHINE_BUILD_WAYLAND - #include + #include + #include #include #endif @@ -27,9 +28,9 @@ namespace wl { class frame_t { public: frame_t(); - egl::surface_descriptor_t sd; - void destroy(); + + egl::surface_descriptor_t sd; }; class dmabuf_t { @@ -40,104 +41,91 @@ namespace wl { REINIT, ///< Reinitialize the frame }; + dmabuf_t(); + ~dmabuf_t(); + dmabuf_t(dmabuf_t &&) = delete; dmabuf_t(const dmabuf_t &) = delete; - dmabuf_t &operator=(const dmabuf_t &) = delete; dmabuf_t &operator=(dmabuf_t &&) = delete; - dmabuf_t(); + void listen(zwlr_screencopy_manager_v1 *screencopy_manager, zwp_linux_dmabuf_v1 *dmabuf_interface, wl_output *output, bool blend_cursor = false); + static void buffer_params_created(void *data, struct zwp_linux_buffer_params_v1 *params, struct wl_buffer *wl_buffer); + static void buffer_params_failed(void *data, struct zwp_linux_buffer_params_v1 *params); + void buffer(zwlr_screencopy_frame_v1 *frame, std::uint32_t format, std::uint32_t width, std::uint32_t height, std::uint32_t stride); + void linux_dmabuf(zwlr_screencopy_frame_v1 *frame, std::uint32_t format, std::uint32_t width, std::uint32_t height); + void buffer_done(zwlr_screencopy_frame_v1 *frame); + void flags(zwlr_screencopy_frame_v1 *frame, std::uint32_t flags); + void damage(zwlr_screencopy_frame_v1 *frame, std::uint32_t x, std::uint32_t y, std::uint32_t width, std::uint32_t height); + void ready(zwlr_screencopy_frame_v1 *frame, std::uint32_t tv_sec_hi, std::uint32_t tv_sec_lo, std::uint32_t tv_nsec); + void failed(zwlr_screencopy_frame_v1 *frame); - void listen(zwlr_export_dmabuf_manager_v1 *dmabuf_manager, wl_output *output, bool blend_cursor = false); - - ~dmabuf_t(); - - void frame( - zwlr_export_dmabuf_frame_v1 *frame, - std::uint32_t width, - std::uint32_t height, - std::uint32_t x, - std::uint32_t y, - std::uint32_t buffer_flags, - std::uint32_t flags, - std::uint32_t format, - std::uint32_t high, - std::uint32_t low, - std::uint32_t obj_count - ); - - void object( - zwlr_export_dmabuf_frame_v1 *frame, - std::uint32_t index, - std::int32_t fd, - std::uint32_t size, - std::uint32_t offset, - std::uint32_t stride, - std::uint32_t plane_index - ); - - void ready( - zwlr_export_dmabuf_frame_v1 *frame, - std::uint32_t tv_sec_hi, - std::uint32_t tv_sec_lo, - std::uint32_t tv_nsec - ); - - void cancel( - zwlr_export_dmabuf_frame_v1 *frame, - std::uint32_t reason - ); - - inline frame_t *get_next_frame() { + frame_t *get_next_frame() { return current_frame == &frames[0] ? &frames[1] : &frames[0]; } status_e status; - std::array frames; frame_t *current_frame; + zwlr_screencopy_frame_v1_listener listener; - zwlr_export_dmabuf_frame_v1_listener listener; + private: + bool init_gbm(); + void cleanup_gbm(); + void create_and_copy_dmabuf(zwlr_screencopy_frame_v1 *frame); + + zwp_linux_dmabuf_v1 *dmabuf_interface {nullptr}; + + struct { + bool supported {false}; + std::uint32_t format; + std::uint32_t width; + std::uint32_t height; + std::uint32_t stride; + } shm_info; + + struct { + bool supported {false}; + std::uint32_t format; + std::uint32_t width; + std::uint32_t height; + } dmabuf_info; + + struct gbm_device *gbm_device {nullptr}; + struct gbm_bo *current_bo {nullptr}; + struct wl_buffer *current_wl_buffer {nullptr}; + bool y_invert {false}; }; class monitor_t { public: + explicit monitor_t(wl_output *output); + monitor_t(monitor_t &&) = delete; monitor_t(const monitor_t &) = delete; - monitor_t &operator=(const monitor_t &) = delete; monitor_t &operator=(monitor_t &&) = delete; - monitor_t(wl_output *output); - + void listen(zxdg_output_manager_v1 *output_manager); void xdg_name(zxdg_output_v1 *, const char *name); void xdg_description(zxdg_output_v1 *, const char *description); void xdg_position(zxdg_output_v1 *, std::int32_t x, std::int32_t y); void xdg_size(zxdg_output_v1 *, std::int32_t width, std::int32_t height); - void xdg_done(zxdg_output_v1 *) { - } + void xdg_done(zxdg_output_v1 *) {} - void wl_geometry(wl_output *wl_output, std::int32_t x, std::int32_t y, std::int32_t physical_width, std::int32_t physical_height, std::int32_t subpixel, const char *make, const char *model, std::int32_t transform) { - } + void wl_geometry(wl_output *wl_output, std::int32_t x, std::int32_t y, std::int32_t physical_width, std::int32_t physical_height, std::int32_t subpixel, const char *make, const char *model, std::int32_t transform) {} void wl_mode(wl_output *wl_output, std::uint32_t flags, std::int32_t width, std::int32_t height, std::int32_t refresh); - void wl_done(wl_output *wl_output) { - } + void wl_done(wl_output *wl_output) {} - void wl_scale(wl_output *wl_output, std::int32_t factor) { - } - - void listen(zxdg_output_manager_v1 *output_manager); + void wl_scale(wl_output *wl_output, std::int32_t factor) {} wl_output *output; - std::string name; std::string description; - platf::touch_port_t viewport; - wl_output_listener wl_listener; zxdg_output_v1_listener xdg_listener; }; @@ -151,35 +139,34 @@ namespace wl { public: enum interface_e { XDG_OUTPUT, ///< xdg-output - WLR_EXPORT_DMABUF, ///< Export dmabuf + WLR_EXPORT_DMABUF, ///< screencopy manager + LINUX_DMABUF, ///< linux-dmabuf protocol MAX_INTERFACES, ///< Maximum number of interfaces }; + interface_t() noexcept; + interface_t(interface_t &&) = delete; interface_t(const interface_t &) = delete; - interface_t &operator=(const interface_t &) = delete; interface_t &operator=(interface_t &&) = delete; - interface_t() noexcept; - void listen(wl_registry *registry); - std::vector> monitors; - - zwlr_export_dmabuf_manager_v1 *dmabuf_manager; - zxdg_output_manager_v1 *output_manager; - bool operator[](interface_e bit) const { return interface[bit]; } + std::vector> monitors; + zwlr_screencopy_manager_v1 *screencopy_manager {nullptr}; + zwp_linux_dmabuf_v1 *dmabuf_interface {nullptr}; + zxdg_output_manager_v1 *output_manager {nullptr}; + private: void add_interface(wl_registry *registry, std::uint32_t id, const char *interface, std::uint32_t version); void del_interface(wl_registry *registry, uint32_t id); std::bitset interface; - wl_registry_listener listener; }; @@ -212,7 +199,6 @@ namespace wl { }; std::vector> monitors(const char *display_name = nullptr); - int init(); } // namespace wl #else @@ -223,21 +209,18 @@ struct zxdg_output_manager_v1; namespace wl { class monitor_t { public: + monitor_t(wl_output *output); + monitor_t(monitor_t &&) = delete; monitor_t(const monitor_t &) = delete; - monitor_t &operator=(const monitor_t &) = delete; monitor_t &operator=(monitor_t &&) = delete; - monitor_t(wl_output *output); - void listen(zxdg_output_manager_v1 *output_manager); wl_output *output; - std::string name; std::string description; - platf::touch_port_t viewport; }; diff --git a/src/platform/linux/wlgrab.cpp b/src/platform/linux/wlgrab.cpp index b867b908..9ef3e09f 100644 --- a/src/platform/linux/wlgrab.cpp +++ b/src/platform/linux/wlgrab.cpp @@ -90,7 +90,7 @@ namespace wl { auto to = std::chrono::steady_clock::now() + timeout; // Dispatch events until we get a new frame or the timeout expires - dmabuf.listen(interface.dmabuf_manager, output, cursor); + dmabuf.listen(interface.screencopy_manager, interface.dmabuf_interface, output, cursor); do { auto remaining_time_ms = std::chrono::duration_cast(to - std::chrono::steady_clock::now()); if (remaining_time_ms.count() < 0 || !display.dispatch(remaining_time_ms)) {