diff --git a/src/platform/linux/wayland.cpp b/src/platform/linux/wayland.cpp index f933606189d..25b65525f8f 100644 --- a/src/platform/linux/wayland.cpp +++ b/src/platform/linux/wayland.cpp @@ -176,6 +176,10 @@ namespace wl { listener { &CLASS_CALL(interface_t, add_interface), &CLASS_CALL(interface_t, del_interface) + }, + dmabuf_listener { + &CLASS_CALL(interface_t, dmabuf_format), + &CLASS_CALL(interface_t, dmabuf_modifier) } { } @@ -183,6 +187,14 @@ namespace wl { wl_registry_add_listener(registry, &listener, this); } + void interface_t::dmabuf_format(zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, uint32_t format) { + } + + void interface_t::dmabuf_modifier(zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo) { + uint64_t modifier = ((uint64_t)modifier_hi << 32) | modifier_lo; + supported_modifiers[format].push_back(modifier); + } + void interface_t::add_interface( wl_registry *registry, std::uint32_t id, @@ -210,7 +222,8 @@ namespace wl { this->interface[WLR_EXPORT_DMABUF] = true; } else if (!std::strcmp(interface, zwp_linux_dmabuf_v1_interface.name)) { BOOST_LOG(info) << "[wayland] 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); + dmabuf_interface = (zwp_linux_dmabuf_v1 *) wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, std::min(version, 3u)); + zwp_linux_dmabuf_v1_add_listener(dmabuf_interface, &dmabuf_listener, this); this->interface[LINUX_DMABUF] = true; } @@ -275,10 +288,12 @@ namespace wl { void dmabuf_t::listen( zwlr_screencopy_manager_v1 *screencopy_manager, zwp_linux_dmabuf_v1 *dmabuf_interface, + const std::map> *supported_modifiers, wl_output *output, bool blend_cursor ) { this->dmabuf_interface = dmabuf_interface; + this->supported_modifiers = supported_modifiers; // Reset state shm_info.supported = false; dmabuf_info.supported = false; @@ -357,7 +372,17 @@ namespace wl { } // Create GBM buffer - current_bo = gbm_bo_create(gbm_device, dmabuf_info.width, dmabuf_info.height, dmabuf_info.format, GBM_BO_USE_RENDERING); + if (supported_modifiers) { + auto it = supported_modifiers->find(dmabuf_info.format); + if (it != supported_modifiers->end() && !it->second.empty()) { + current_bo = gbm_bo_create_with_modifiers(gbm_device, dmabuf_info.width, dmabuf_info.height, dmabuf_info.format, it->second.data(), it->second.size()); + } + } + + if (!current_bo) { + 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); diff --git a/src/platform/linux/wayland.h b/src/platform/linux/wayland.h index 286c247bb52..11b16b76d53 100644 --- a/src/platform/linux/wayland.h +++ b/src/platform/linux/wayland.h @@ -6,6 +6,9 @@ // standard includes #include +#include +#include +#include #ifdef SUNSHINE_BUILD_WAYLAND #include @@ -50,7 +53,7 @@ namespace wl { dmabuf_t &operator=(const dmabuf_t &) = delete; dmabuf_t &operator=(dmabuf_t &&) = delete; - void listen(zwlr_screencopy_manager_v1 *screencopy_manager, zwp_linux_dmabuf_v1 *dmabuf_interface, wl_output *output, bool blend_cursor = false); + void listen(zwlr_screencopy_manager_v1 *screencopy_manager, zwp_linux_dmabuf_v1 *dmabuf_interface, const std::map> *supported_modifiers, 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); @@ -76,6 +79,7 @@ namespace wl { void create_and_copy_dmabuf(zwlr_screencopy_frame_v1 *frame); zwp_linux_dmabuf_v1 *dmabuf_interface {nullptr}; + const std::map> *supported_modifiers {nullptr}; struct { bool supported {false}; @@ -158,7 +162,11 @@ namespace wl { return interface[bit]; } + void dmabuf_format(zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, uint32_t format); + void dmabuf_modifier(zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo); + std::vector> monitors; + std::map> supported_modifiers; zwlr_screencopy_manager_v1 *screencopy_manager {nullptr}; zwp_linux_dmabuf_v1 *dmabuf_interface {nullptr}; zxdg_output_manager_v1 *output_manager {nullptr}; @@ -169,6 +177,7 @@ namespace wl { std::bitset interface; wl_registry_listener listener; + zwp_linux_dmabuf_v1_listener dmabuf_listener; }; class display_t { diff --git a/src/platform/linux/wlgrab.cpp b/src/platform/linux/wlgrab.cpp index 90b4ba8444b..f99e81c65b4 100644 --- a/src/platform/linux/wlgrab.cpp +++ b/src/platform/linux/wlgrab.cpp @@ -132,7 +132,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.screencopy_manager, interface.dmabuf_interface, output, cursor); + dmabuf.listen(interface.screencopy_manager, interface.dmabuf_interface, &interface.supported_modifiers, 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)) {