fix(wayland): support DMA-BUF modifiers for wlroots capture (#5132)

This commit is contained in:
Joe Knockenhauer
2026-06-09 11:23:26 -04:00
committed by GitHub
parent 6bc2701160
commit c2b5513a5f
3 changed files with 38 additions and 4 deletions
+27 -2
View File
@@ -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<std::uint32_t, std::vector<std::uint64_t>> *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);
+10 -1
View File
@@ -6,6 +6,9 @@
// standard includes
#include <bitset>
#include <cstdint>
#include <map>
#include <vector>
#ifdef SUNSHINE_BUILD_WAYLAND
#include <linux-dmabuf-unstable-v1.h>
@@ -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<std::uint32_t, std::vector<std::uint64_t>> *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<std::uint32_t, std::vector<std::uint64_t>> *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<std::unique_ptr<monitor_t>> monitors;
std::map<std::uint32_t, std::vector<std::uint64_t>> 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<MAX_INTERFACES> interface;
wl_registry_listener listener;
zwp_linux_dmabuf_v1_listener dmabuf_listener;
};
class display_t {
+1 -1
View File
@@ -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<std::chrono::milliseconds>(to - std::chrono::steady_clock::now());
if (remaining_time_ms.count() < 0 || !display.dispatch(remaining_time_ms)) {