linux-dmabuf-v1: upgrade to minor version 6

- Set the SAMPLING flag when appropriate
- Stop sending the main_device event
- Expose the buffer's sampling device in struct wlr_dmabuf_v1_buffer
- Check tranches are well-formed according to the protocol
- Add a fallback for main_device, grabbing the first SAMPLING
  tranche's target_device

Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/work_items/4099
This commit is contained in:
Simon Ser 2026-05-31 12:44:39 +02:00
parent bd99e8c2bd
commit 3e8aed0d87
2 changed files with 77 additions and 12 deletions

View file

@ -24,7 +24,10 @@ struct wlr_dmabuf_v1_buffer {
struct wl_resource *resource; // can be NULL if the client destroyed it
struct wlr_dmabuf_attributes attributes;
const dev_t *sampling_device; // can be NULL if unknown
struct {
dev_t sampling_device_value;
struct wl_listener release;
} WLR_PRIVATE;
};
@ -37,7 +40,7 @@ struct wlr_dmabuf_v1_buffer *wlr_dmabuf_v1_buffer_try_from_buffer_resource(
struct wl_resource *buffer_resource);
struct wlr_linux_dmabuf_feedback_v1 {
dev_t main_device;
dev_t main_device; // unused for >= v6
struct wl_array tranches; // struct wlr_linux_dmabuf_feedback_v1_tranche
};

View file

@ -21,13 +21,15 @@
#include <wlr/backend/drm.h>
#endif
#define LINUX_DMABUF_VERSION 5
#define LINUX_DMABUF_VERSION 6
struct wlr_linux_buffer_params_v1 {
struct wl_resource *resource;
struct wlr_linux_dmabuf_v1 *linux_dmabuf;
struct wlr_dmabuf_attributes attributes;
bool has_modifier;
bool has_sampling_device;
dev_t sampling_device;
};
struct wlr_linux_dmabuf_feedback_v1_compiled_tranche {
@ -37,7 +39,7 @@ struct wlr_linux_dmabuf_feedback_v1_compiled_tranche {
};
struct wlr_linux_dmabuf_feedback_v1_compiled {
dev_t main_device;
dev_t main_device; // for < v6
int table_fd;
size_t table_size;
@ -241,6 +243,8 @@ static void params_create_common(struct wl_resource *params_resource,
struct wlr_dmabuf_attributes attribs = params->attributes;
struct wlr_linux_dmabuf_v1 *linux_dmabuf = params->linux_dmabuf;
bool has_sampling_device = params->has_sampling_device;
dev_t sampling_device = params->sampling_device;
// Make the params resource inert
wl_resource_set_user_data(params_resource, NULL);
@ -371,6 +375,11 @@ static void params_create_common(struct wl_resource *params_resource,
buffer->release.notify = buffer_handle_release;
wl_signal_add(&buffer->base.events.release, &buffer->release);
if (has_sampling_device) {
buffer->sampling_device_value = sampling_device;
buffer->sampling_device = &buffer->sampling_device_value;
}
/* send 'created' event when the request is not for an immediate
* import, that is buffer_id is zero */
if (buffer_id == 0) {
@ -412,11 +421,34 @@ static void params_create_immed(struct wl_client *client,
format, flags);
}
static void params_set_sampling_device(struct wl_client *client,
struct wl_resource *params_resource, struct wl_array *devid_arr) {
struct wlr_linux_buffer_params_v1 *params =
params_from_resource(params_resource);
if (!params) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
"params was already used to create a wl_buffer");
return;
}
if (devid_arr->size != sizeof(dev_t)) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DEV_T_SIZE,
"invalid dev_t size");
return;
}
params->has_sampling_device = true;
memcpy(&params->sampling_device, devid_arr->data, sizeof(params->sampling_device));
}
static const struct zwp_linux_buffer_params_v1_interface buffer_params_impl = {
.destroy = params_destroy,
.add = params_add,
.create = params_create,
.create_immed = params_create_immed,
.set_sampling_device = params_set_sampling_device,
};
static void params_handle_resource_destroy(struct wl_resource *resource) {
@ -507,7 +539,7 @@ static ssize_t get_drm_format_set_index(const struct wlr_drm_format_set *set,
}
static struct wlr_linux_dmabuf_feedback_v1_compiled *feedback_compile(
const struct wlr_linux_dmabuf_feedback_v1 *feedback) {
const struct wlr_linux_dmabuf_feedback_v1 *feedback, uint32_t version) {
const struct wlr_linux_dmabuf_feedback_v1_tranche *tranches = feedback->tranches.data;
size_t tranches_len = feedback->tranches.size / sizeof(struct wlr_linux_dmabuf_feedback_v1_tranche);
assert(tranches_len > 0);
@ -578,11 +610,27 @@ static struct wlr_linux_dmabuf_feedback_v1_compiled *feedback_compile(
compiled->table_size = table_size;
// Build the indices lists for all tranches
bool has_sampling_tranche = false;
for (size_t i = 0; i < tranches_len; i++) {
const struct wlr_linux_dmabuf_feedback_v1_tranche *tranche = &tranches[i];
struct wlr_linux_dmabuf_feedback_v1_compiled_tranche *compiled_tranche =
&compiled->tranches[i];
if (version >= ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SAMPLING_SINCE_VERSION) {
if (tranche->flags == 0) {
wlr_log(WLR_ERROR, "Tranche flags must not be zero");
goto error_compiled;
}
if (tranche->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SAMPLING) {
if (!has_sampling_tranche) {
// For backwards compat with < v6
compiled->main_device = tranche->target_device;
}
has_sampling_tranche = true;
}
}
compiled_tranche->target_device = tranche->target_device;
compiled_tranche->flags = tranche->flags;
@ -613,6 +661,12 @@ static struct wlr_linux_dmabuf_feedback_v1_compiled *feedback_compile(
compiled_tranche->indices.size = n * sizeof(uint16_t);
}
if (version >= ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SAMPLING_SINCE_VERSION &&
!has_sampling_tranche) {
wlr_log(WLR_ERROR, "Missing a SAMPLING tranche");
goto error_compiled;
}
wlr_drm_format_set_finish(&all_formats);
return compiled;
@ -645,7 +699,11 @@ static void feedback_tranche_send(
.data = (void *)&tranche->target_device,
};
zwp_linux_dmabuf_feedback_v1_send_tranche_target_device(resource, &dev_array);
zwp_linux_dmabuf_feedback_v1_send_tranche_flags(resource, tranche->flags);
uint32_t flags = tranche->flags;
if (wl_resource_get_version(resource) < ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SAMPLING_SINCE_VERSION) {
flags &= ~ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SAMPLING;
}
zwp_linux_dmabuf_feedback_v1_send_tranche_flags(resource, flags);
zwp_linux_dmabuf_feedback_v1_send_tranche_formats(resource,
(struct wl_array *)&tranche->indices);
zwp_linux_dmabuf_feedback_v1_send_tranche_done(resource);
@ -653,11 +711,13 @@ static void feedback_tranche_send(
static void feedback_send(const struct wlr_linux_dmabuf_feedback_v1_compiled *feedback,
struct wl_resource *resource) {
struct wl_array dev_array = {
.size = sizeof(feedback->main_device),
.data = (void *)&feedback->main_device,
};
zwp_linux_dmabuf_feedback_v1_send_main_device(resource, &dev_array);
if (wl_resource_get_version(resource) < 6) {
struct wl_array dev_array = {
.size = sizeof(feedback->main_device),
.data = (void *)&feedback->main_device,
};
zwp_linux_dmabuf_feedback_v1_send_main_device(resource, &dev_array);
}
zwp_linux_dmabuf_feedback_v1_send_format_table(resource,
feedback->table_fd, feedback->table_size);
@ -886,7 +946,8 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
static bool set_default_feedback(struct wlr_linux_dmabuf_v1 *linux_dmabuf,
const struct wlr_linux_dmabuf_feedback_v1 *feedback) {
struct wlr_linux_dmabuf_feedback_v1_compiled *compiled = feedback_compile(feedback);
struct wlr_linux_dmabuf_feedback_v1_compiled *compiled =
feedback_compile(feedback, wl_global_get_version(linux_dmabuf->global));
if (compiled == NULL) {
return false;
}
@ -1025,7 +1086,7 @@ bool wlr_linux_dmabuf_v1_set_surface_feedback(
struct wlr_linux_dmabuf_feedback_v1_compiled *compiled = NULL;
if (feedback != NULL) {
compiled = feedback_compile(feedback);
compiled = feedback_compile(feedback, wl_global_get_version(linux_dmabuf->global));
if (compiled == NULL) {
return false;
}
@ -1163,6 +1224,7 @@ bool wlr_linux_dmabuf_feedback_v1_init_with_options(struct wlr_linux_dmabuf_feed
}
tranche->target_device = renderer_dev;
tranche->flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SAMPLING;
if (!wlr_drm_format_set_copy(&tranche->formats, renderer_formats)) {
goto error;
}