Merge branch 'dmabuf-target-device' into 'main'

Draft: wayland/wsi: linux-dmabuf version 6

See merge request mesa/mesa!33344
This commit is contained in:
Victoria Brekenfeld 2026-05-08 02:09:59 +02:00
commit 6c78782e29
12 changed files with 279 additions and 88 deletions

View file

@ -48,7 +48,7 @@
#include "dri_screen.h"
#ifdef HAVE_WAYLAND_PLATFORM
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "linux-dmabuf-v1-client-protocol.h"
#if HAVE_BIND_WL_DISPLAY
#include "wayland-drm-client-protocol.h"
#include "wayland-drm.h"

View file

@ -285,8 +285,9 @@ struct dri2_egl_display {
struct wp_presentation *wp_presentation;
struct dri2_wl_formats formats;
struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback;
struct dmabuf_feedback_format_table format_table;
struct dmabuf_feedback dmabuf_feedback;
char *device_name;
dev_t display_device_dev;
bool is_render_node;
clockid_t presentation_clock_id;
#endif

View file

@ -37,6 +37,7 @@
#include <unistd.h>
#include "util/libdrm.h"
#include "drm-uapi/drm_fourcc.h"
#include "util/u_dynarray.h"
#include <sys/mman.h>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_wayland.h>
@ -56,7 +57,7 @@
#include "dri_util.h"
#include <loader_wayland_helper.h>
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "linux-dmabuf-v1-client-protocol.h"
#ifdef HAVE_BIND_WL_DISPLAY
#include "wayland-drm-client-protocol.h"
#endif
@ -1217,8 +1218,8 @@ create_dri_image_from_dmabuf_feedback(struct dri2_egl_surface *dri2_surf,
{
uint32_t flags;
/* We don't have valid dma-buf feedback, so return */
if (dri2_surf->dmabuf_feedback.main_device == 0)
/* We don't have any tranches for our surface dma-buf feedback, so return */
if (util_dynarray_num_elements(&dri2_surf->dmabuf_feedback.tranches, struct dmabuf_feedback_tranche) == 0)
return;
/* Iterates through the dma-buf feedback to pick a new set of modifiers. The
@ -1709,6 +1710,16 @@ create_wl_buffer(struct dri2_egl_display *dri2_dpy,
if (dri2_surf)
wl_proxy_set_queue((struct wl_proxy *)params, dri2_surf->wl_queue);
if (wl_proxy_get_version((struct wl_proxy *)dri2_dpy->wl_dmabuf) >=
ZWP_LINUX_BUFFER_PARAMS_V1_SET_SAMPLING_DEVICE_SINCE_VERSION) {
struct wl_array dev;
wl_array_init(&dev);
wl_array_add(&dev, sizeof(dev_t));
memcpy(dev.data, &dri2_dpy->display_device_dev, sizeof(dev_t));
zwp_linux_buffer_params_v1_set_sampling_device(params, &dev);
wl_array_release(&dev);
}
for (i = 0; i < num_planes; i++) {
struct dri_image *p_image;
int stride, offset;
@ -2157,26 +2168,24 @@ default_dmabuf_feedback_format_table(
int32_t fd, uint32_t size)
{
struct dri2_egl_display *dri2_dpy = data;
struct dmabuf_feedback *feedback = &dri2_dpy->dmabuf_feedback;
dri2_dpy->format_table.size = size;
dri2_dpy->format_table.data =
feedback->format_table.size = size;
feedback->format_table.data =
mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
}
static void
default_dmabuf_feedback_main_device(
void *data, struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
struct wl_array *device)
dri2_wl_init_display_dev(
struct dri2_egl_display *dri2_dpy,
dev_t dev)
{
struct dri2_egl_display *dri2_dpy = data;
char *node;
int fd;
dev_t dev;
/* Given the device, look for a render node and try to open it. */
memcpy(&dev, device->data, sizeof(dev));
node = loader_get_render_node(dev);
if (!node)
return;
@ -2186,6 +2195,7 @@ default_dmabuf_feedback_main_device(
return;
}
dri2_dpy->display_device_dev = dev;
dri2_dpy->device_name = node;
dri2_dpy->fd_render_gpu = fd;
#ifdef HAVE_BIND_WL_DISPLAY
@ -2193,12 +2203,27 @@ default_dmabuf_feedback_main_device(
#endif
}
static void
default_dmabuf_feedback_main_device(
void *data, struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
struct wl_array *device)
{
struct dri2_egl_display *dri2_dpy = data;
struct dmabuf_feedback *feedback = &dri2_dpy->dmabuf_feedback;
memcpy(&feedback->main_device, device->data, sizeof(feedback->main_device));
dri2_wl_init_display_dev(dri2_dpy, feedback->main_device);
}
static void
default_dmabuf_feedback_tranche_target_device(
void *data, struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
struct wl_array *device)
{
/* ignore this event */
struct dri2_egl_display *dri2_dpy = data;
struct dmabuf_feedback *feedback = &dri2_dpy->dmabuf_feedback;
memcpy(&feedback->pending_tranche.target_device, device->data, sizeof(feedback->pending_tranche.target_device));
}
static void
@ -2206,7 +2231,10 @@ default_dmabuf_feedback_tranche_flags(
void *data, struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
uint32_t flags)
{
/* ignore this event */
struct dri2_egl_display *dri2_dpy = data;
struct dmabuf_feedback *feedback = &dri2_dpy->dmabuf_feedback;
feedback->pending_tranche.flags = flags;
}
static void
@ -2215,18 +2243,19 @@ default_dmabuf_feedback_tranche_formats(
struct wl_array *indices)
{
struct dri2_egl_display *dri2_dpy = data;
struct dmabuf_feedback *feedback = &dri2_dpy->dmabuf_feedback;
uint64_t *modifier_ptr, modifier;
uint32_t format;
uint16_t *index;
int visual_idx;
if (dri2_dpy->format_table.data == MAP_FAILED) {
if (feedback->format_table.data == MAP_FAILED) {
_eglLog(_EGL_WARNING, "wayland-egl: we could not map the format table "
"so we won't be able to use this batch of dma-buf "
"feedback events.");
return;
}
if (dri2_dpy->format_table.data == NULL) {
if (feedback->format_table.data == NULL) {
_eglLog(_EGL_WARNING,
"wayland-egl: compositor didn't advertise a format "
"table, so we won't be able to use this batch of dma-buf "
@ -2235,8 +2264,8 @@ default_dmabuf_feedback_tranche_formats(
}
wl_array_for_each (index, indices) {
format = dri2_dpy->format_table.data[*index].format;
modifier = dri2_dpy->format_table.data[*index].modifier;
format = feedback->format_table.data[*index].format;
modifier = feedback->format_table.data[*index].modifier;
/* skip formats that we don't support */
visual_idx = dri2_wl_visual_idx_from_fourcc(format);
@ -2254,15 +2283,20 @@ static void
default_dmabuf_feedback_tranche_done(
void *data, struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
{
/* ignore this event */
struct dri2_egl_display *dri2_dpy = data;
struct dmabuf_feedback *feedback = &dri2_dpy->dmabuf_feedback;
/* Add tranche to array of tranches. */
util_dynarray_append(&feedback->tranches,
feedback->pending_tranche);
dmabuf_feedback_tranche_init(&feedback->pending_tranche);
}
static void
default_dmabuf_feedback_done(
void *data, struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
{
/* ignore this event */
}
{}
static const struct zwp_linux_dmabuf_feedback_v1_listener
dmabuf_feedback_listener = {
@ -2304,7 +2338,7 @@ registry_handle_global_drm(void *data, struct wl_registry *registry,
version >= 3) {
dri2_dpy->wl_dmabuf = wl_registry_bind(
registry, name, &zwp_linux_dmabuf_v1_interface,
MIN2(version, ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION));
MIN2(version, ZWP_LINUX_BUFFER_PARAMS_V1_SET_SAMPLING_DEVICE_SINCE_VERSION));
zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener,
dri2_dpy);
} else if (strcmp(interface, wp_presentation_interface.name) == 0) {
@ -2618,7 +2652,9 @@ dri2_initialize_wayland_drm_extensions(struct dri2_egl_display *dri2_dpy)
if (dri2_dpy->wl_dmabuf &&
zwp_linux_dmabuf_v1_get_version(dri2_dpy->wl_dmabuf) >=
ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION) {
dmabuf_feedback_format_table_init(&dri2_dpy->format_table);
if (dmabuf_feedback_init(&dri2_dpy->dmabuf_feedback) < 0) {
return false;
}
dri2_dpy->wl_dmabuf_feedback =
zwp_linux_dmabuf_v1_get_default_feedback(dri2_dpy->wl_dmabuf);
zwp_linux_dmabuf_feedback_v1_add_listener(
@ -2628,11 +2664,20 @@ dri2_initialize_wayland_drm_extensions(struct dri2_egl_display *dri2_dpy)
if (roundtrip(dri2_dpy) < 0)
return false;
/* Destroy the default dma-buf feedback and the format table. */
/* Destroy the default dma-buf feedback. */
if (dri2_dpy->wl_dmabuf_feedback) {
zwp_linux_dmabuf_feedback_v1_destroy(dri2_dpy->wl_dmabuf_feedback);
dri2_dpy->wl_dmabuf_feedback = NULL;
dmabuf_feedback_format_table_fini(&dri2_dpy->format_table);
/* For dmabuf v6 we don't get a main device, use the first tranch suitable for sampling as default */
if (dri2_dpy->fd_render_gpu == -1) {
util_dynarray_foreach(&dri2_dpy->dmabuf_feedback.tranches, struct dmabuf_feedback_tranche, tranche) {
if ((tranche->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SAMPLING) != 0) {
dri2_wl_init_display_dev(dri2_dpy, tranche->target_device);
break;
}
}
}
}
#ifdef HAVE_BIND_WL_DISPLAY
@ -2661,6 +2706,8 @@ static EGLBoolean
dri2_initialize_wayland_drm(_EGLDisplay *disp)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
dev_t preferred_dev_id = 0;
drmDevicePtr render_dev = NULL, preferred_dev = NULL, tranche_dev = NULL;
if (dri2_wl_formats_init(&dri2_dpy->formats) < 0)
goto cleanup;
@ -2697,8 +2744,43 @@ dri2_initialize_wayland_drm(_EGLDisplay *disp)
if (!dri2_initialize_wayland_drm_extensions(dri2_dpy))
goto cleanup;
loader_get_user_preferred_fd(&dri2_dpy->fd_render_gpu,
&dri2_dpy->fd_display_gpu);
if (drmGetDevice2(dri2_dpy->fd_render_gpu, 0, &render_dev) != 0)
goto cleanup;
if (loader_get_user_preferred_device(render_dev, &preferred_dev_id))
{
bool found_matching_tranche = false;
if (drmGetDeviceFromDevId(preferred_dev_id, 0, &preferred_dev) < 0) {
goto cleanup;
}
/* check if the compositor can sample from the new device */
util_dynarray_foreach(&dri2_dpy->dmabuf_feedback.tranches, struct dmabuf_feedback_tranche, tranche) {
if ((tranche->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SAMPLING) != 0) {
if (drmGetDeviceFromDevId(tranche->target_device, 0, &tranche_dev) < 0) {
continue;
}
if (!found_matching_tranche && loader_drm_devices_match(preferred_dev, tranche_dev)) {
close(dri2_dpy->fd_render_gpu);
dri2_wl_init_display_dev(dri2_dpy, tranche->target_device);
found_matching_tranche = true;
}
drmFreeDevice(&tranche_dev);
}
}
dri2_dpy->fd_display_gpu = dri2_dpy->fd_render_gpu;
if (!found_matching_tranche) {
// fallback to copying
dri2_dpy->fd_render_gpu = loader_open_device(preferred_dev->nodes[DRM_NODE_RENDER]);
}
drmFreeDevice(&preferred_dev);
} else {
dri2_dpy->fd_display_gpu = dri2_dpy->fd_render_gpu;
}
drmFreeDevice(&render_dev);
if (dri2_dpy->fd_render_gpu != dri2_dpy->fd_display_gpu) {
free(dri2_dpy->device_name);
@ -2781,6 +2863,9 @@ dri2_initialize_wayland_drm(_EGLDisplay *disp)
return EGL_TRUE;
cleanup:
if (render_dev) drmFreeDevice(&render_dev);
if (preferred_dev) drmFreeDevice(&preferred_dev);
if (tranche_dev) drmFreeDevice(&tranche_dev);
return EGL_FALSE;
}
@ -3291,7 +3376,6 @@ dri2_initialize_wayland(_EGLDisplay *disp)
void
dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy)
{
dri2_wl_formats_fini(&dri2_dpy->formats);
if (dri2_dpy->wp_presentation)
wp_presentation_destroy(dri2_dpy->wp_presentation);
#ifdef HAVE_BIND_WL_DISPLAY
@ -3300,6 +3384,7 @@ dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy)
#endif
if (dri2_dpy->wl_dmabuf)
zwp_linux_dmabuf_v1_destroy(dri2_dpy->wl_dmabuf);
dmabuf_feedback_fini(&dri2_dpy->dmabuf_feedback);
if (dri2_dpy->wl_shm)
wl_shm_destroy(dri2_dpy->wl_shm);
if (dri2_dpy->wl_registry) {

View file

@ -122,7 +122,7 @@ if with_dri
deps_for_egl += [dep_wayland_client, dep_wayland_server, dep_wayland_egl_headers]
link_for_egl += libloader_wayland_helper
files_egl += files('drivers/dri2/platform_wayland.c')
files_egl += wp_files['linux-dmabuf-unstable-v1']
files_egl += wp_files['linux-dmabuf-v1']
files_egl += wp_files['presentation-time']
if with_wayland_bind_display
files_egl += [wayland_drm_client_protocol_h]

View file

@ -37,6 +37,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
#include <xf86drm.h>
#include <sys/param.h>
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
@ -48,7 +49,6 @@
#include "mesa_interface.h"
#include "loader.h"
#include "util/drm_is_nouveau.h"
#include "util/libdrm.h"
#include "util/os_file.h"
#include "util/os_misc.h"
#include "util/u_debug.h"
@ -450,13 +450,20 @@ static char *drm_get_id_path_tag_for_fd(int fd)
return tag;
}
bool loader_get_user_preferred_fd(int *fd_render_gpu, int *original_fd)
bool loader_drm_devices_match(drmDevicePtr dev1, drmDevicePtr dev2)
{
char *tag = drm_construct_id_path_tag(dev1);
return drm_device_matches_tag(dev2, tag);
}
bool loader_get_user_preferred_device(drmDevicePtr default_dev, dev_t *preferred_dev_id)
{
const char *dri_prime = os_get_option("DRI_PRIME");
bool debug = debug_get_bool_option("DRI_PRIME_DEBUG", false);
char *default_tag = NULL;
drmDevicePtr devices[MAX_DRM_DEVICES];
int i, num_devices, fd = -1;
int i, num_devices = -1;
struct stat sbuf;
struct {
enum {
PRIME_IS_INTEGER,
@ -502,7 +509,7 @@ bool loader_get_user_preferred_fd(int *fd_render_gpu, int *original_fd)
}
}
default_tag = drm_get_id_path_tag_for_fd(*fd_render_gpu);
default_tag = drm_construct_id_path_tag(default_dev);
if (default_tag == NULL)
goto err;
@ -607,20 +614,58 @@ bool loader_get_user_preferred_fd(int *fd_render_gpu, int *original_fd)
log_(debug ? _LOADER_WARNING : _LOADER_INFO,
"selected (%s)\n", devices[i]->nodes[DRM_NODE_RENDER]);
fd = loader_open_device(devices[i]->nodes[DRM_NODE_RENDER]);
if (fd < 0) {
log_(debug ? _LOADER_WARNING : _LOADER_INFO,
"DRI_PRIME: failed to open '%s'\n",
devices[i]->nodes[DRM_NODE_RENDER]);
char *preferred_node = devices[i]->nodes[DRM_NODE_RENDER];
if (stat(preferred_node, &sbuf) != 0) {
goto err;
}
*preferred_dev_id = sbuf.st_rdev;
break;
}
drmFreeDevices(devices, num_devices);
if (i == num_devices || fd < 0)
if (i == num_devices)
goto err;
bool is_render_and_display_gpu_diff = !!strcmp(default_tag, prime.str);
free(default_tag);
free(prime.str);
return is_render_and_display_gpu_diff;
err:
log_(debug ? _LOADER_WARNING : _LOADER_INFO,
"DRI_PRIME: error. Using the default GPU\n");
free(default_tag);
free(prime.str);
no_prime_gpu_offloading:
return false;
}
bool loader_get_user_preferred_fd(int *fd_render_gpu, int *original_fd)
{
int fd = -1;
bool is_render_and_display_gpu_diff;
dev_t preferred_dev_id = 0;
drmDevicePtr render_dev, preferred_dev;
bool debug = debug_get_bool_option("DRI_PRIME_DEBUG", false);
if (drmGetDevice2(*fd_render_gpu, 0, &render_dev) != 0)
return false;
is_render_and_display_gpu_diff = loader_get_user_preferred_device(render_dev, &preferred_dev_id);
if (drmGetDeviceFromDevId(preferred_dev_id, 0, &preferred_dev) != 0) {
drmFreeDevice(&render_dev);
return false;
};
fd = loader_open_device(preferred_dev->nodes[DRM_NODE_RENDER]);
if (fd < 0) {
log_(debug ? _LOADER_WARNING : _LOADER_INFO,
"DRI_PRIME: failed to open '%s'\n",
render_dev->nodes[DRM_NODE_RENDER]);
drmFreeDevice(&render_dev);
drmFreeDevice(&preferred_dev);
return false;
}
if (original_fd) {
if (is_render_and_display_gpu_diff) {
*original_fd = *fd_render_gpu;
@ -634,18 +679,9 @@ bool loader_get_user_preferred_fd(int *fd_render_gpu, int *original_fd)
*fd_render_gpu = fd;
}
free(default_tag);
free(prime.str);
drmFreeDevice(&render_dev);
drmFreeDevice(&preferred_dev);
return is_render_and_display_gpu_diff;
err:
log_(debug ? _LOADER_WARNING : _LOADER_INFO,
"DRI_PRIME: error. Using the default GPU\n");
free(default_tag);
free(prime.str);
no_prime_gpu_offloading:
if (original_fd)
*original_fd = *fd_render_gpu;
return false;
}
static bool

View file

@ -30,6 +30,7 @@
#include <stdbool.h>
#include <sys/stat.h>
#include <stddef.h>
#include <xf86drm.h>
#include "mesa_interface.h"
#ifdef __cplusplus
@ -75,6 +76,9 @@ loader_open_driver_lib(const char *driver_name,
char *
loader_get_device_name_for_fd(int fd);
bool
loader_drm_devices_match(drmDevicePtr dev1, drmDevicePtr dev2);
/* For dri prime gpu offloading this function will take current render fd and possibly
* update it with new prime gpu offloading fd. For dri prime gpu offloading optionally
* this function can return the original fd. Also this function returns true/false based
@ -84,6 +88,14 @@ loader_get_device_name_for_fd(int fd);
bool
loader_get_user_preferred_fd(int *fd_render_gpu, int *original_fd);
/* For dri prime offloading this function will take a default device and possibly set
* the user preferred device for prime gpu offloading. This function returns true/false
* based on if the default device is different from the preferred one.
*/
bool
loader_get_user_preferred_device(drmDevicePtr default_dev, dev_t *preferred_dev_id);
/* for logging.. keep this aligned with egllog.h so we can just use
* _eglLog directly.
*/

View file

@ -7,7 +7,7 @@ if with_platform_wayland
wp_protos = {
'fifo-v1': mod_wl.find_protocol('fifo', state : 'staging', version : 1),
'commit-timing-v1': mod_wl.find_protocol('commit-timing', state : 'staging', version : 1),
'linux-dmabuf-unstable-v1': mod_wl.find_protocol('linux-dmabuf', state : 'unstable', version : 1),
'linux-dmabuf-v1': mod_wl.find_protocol('linux-dmabuf', state : 'stable', version : 1),
'presentation-time': mod_wl.find_protocol('presentation-time'),
'tearing-control-v1': mod_wl.find_protocol('tearing-control', state : 'staging', version : 1),
'linux-drm-syncobj-v1': mod_wl.find_protocol('linux-drm-syncobj', state : 'staging', version : 1),

View file

@ -31,7 +31,7 @@
#include <unistd.h>
#include <xf86drm.h>
#include "device_select.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "linux-dmabuf-v1-client-protocol.h"
struct device_select_wayland_info {
#ifdef HAVE_BIND_WL_DISPLAY

View file

@ -20,7 +20,7 @@ if with_platform_wayland
vklayer_files += [ wayland_drm_client_protocol_h, wayland_drm_protocol_c ]
vklayer_flags += [ '-DHAVE_BIND_WL_DISPLAY' ]
endif
vklayer_files += wp_files['linux-dmabuf-unstable-v1']
vklayer_files += wp_files['linux-dmabuf-v1']
vklayer_deps += dep_wayland_client
endif

View file

@ -18,7 +18,7 @@ if with_platform_wayland
files_vulkan_wsi += files('wsi_common_wayland.c')
files_vulkan_wsi += wp_files['fifo-v1']
files_vulkan_wsi += wp_files['commit-timing-v1']
files_vulkan_wsi += wp_files['linux-dmabuf-unstable-v1']
files_vulkan_wsi += wp_files['linux-dmabuf-v1']
files_vulkan_wsi += wp_files['presentation-time']
files_vulkan_wsi += wp_files['tearing-control-v1']
links_vulkan_wsi += libloader_wayland_helper

View file

@ -43,7 +43,7 @@
#include "wsi_common_private.h"
#include "fifo-v1-client-protocol.h"
#include "commit-timing-v1-client-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "linux-dmabuf-v1-client-protocol.h"
#include "presentation-time-client-protocol.h"
#include "linux-drm-syncobj-v1-client-protocol.h"
#include "tearing-control-v1-client-protocol.h"
@ -114,7 +114,7 @@ struct wsi_wl_display {
struct wp_color_manager_v1 *color_manager;
struct dmabuf_feedback_format_table format_table;
struct dmabuf_feedback dmabuf_feedback;
struct u_vector color_primaries;
struct u_vector color_transfer_funcs;
@ -137,7 +137,7 @@ struct wsi_wl_display {
bool sw;
dev_t main_device;
dev_t display_device_dev;
bool same_gpu;
clockid_t presentation_clock_id;
@ -854,9 +854,10 @@ default_dmabuf_feedback_format_table(void *data,
int32_t fd, uint32_t size)
{
struct wsi_wl_display *display = data;
struct dmabuf_feedback *feedback = &display->dmabuf_feedback;
display->format_table.size = size;
display->format_table.data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
feedback->format_table.size = size;
feedback->format_table.data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
}
@ -867,9 +868,10 @@ default_dmabuf_feedback_main_device(void *data,
struct wl_array *device)
{
struct wsi_wl_display *display = data;
struct dmabuf_feedback *feedback = &display->dmabuf_feedback;
assert(device->size == sizeof(dev_t));
memcpy(&display->main_device, device->data, device->size);
memcpy(&feedback->main_device, device->data, device->size);
}
static void
@ -877,7 +879,10 @@ default_dmabuf_feedback_tranche_target_device(void *data,
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
struct wl_array *device)
{
/* ignore this event */
struct wsi_wl_display *display = data;
struct dmabuf_feedback *feedback = &display->dmabuf_feedback;
memcpy(&feedback->pending_tranche.target_device, device->data, sizeof(feedback->pending_tranche.target_device));
}
static void
@ -885,7 +890,10 @@ default_dmabuf_feedback_tranche_flags(void *data,
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
uint32_t flags)
{
/* ignore this event */
struct wsi_wl_display *display = data;
struct dmabuf_feedback *feedback = &display->dmabuf_feedback;
feedback->pending_tranche.flags = flags;
}
static void
@ -894,19 +902,20 @@ default_dmabuf_feedback_tranche_formats(void *data,
struct wl_array *indices)
{
struct wsi_wl_display *display = data;
struct dmabuf_feedback *feedback = &display->dmabuf_feedback;
uint32_t format;
uint64_t modifier;
uint16_t *index;
/* We couldn't map the format table or the compositor didn't advertise it,
* so we have to ignore the feedback. */
if (display->format_table.data == MAP_FAILED ||
display->format_table.data == NULL)
if (feedback->format_table.data == MAP_FAILED ||
feedback->format_table.data == NULL)
return;
wl_array_for_each(index, indices) {
format = display->format_table.data[*index].format;
modifier = display->format_table.data[*index].modifier;
format = feedback->format_table.data[*index].format;
modifier = feedback->format_table.data[*index].modifier;
wsi_wl_display_add_drm_format_modifier(display, &display->formats,
format, modifier);
}
@ -916,15 +925,20 @@ static void
default_dmabuf_feedback_tranche_done(void *data,
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
{
/* ignore this event */
struct wsi_wl_display *display = data;
struct dmabuf_feedback *feedback = &display->dmabuf_feedback;
/* Add tranche to array of tranches. */
util_dynarray_append(&feedback->tranches,
feedback->pending_tranche);
dmabuf_feedback_tranche_init(&feedback->pending_tranche);
}
static void
default_dmabuf_feedback_done(void *data,
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
{
/* ignore this event */
}
{}
static const struct zwp_linux_dmabuf_feedback_v1_listener
dmabuf_feedback_listener = {
@ -1453,7 +1467,7 @@ registry_handle_global(void *data, struct wl_registry *registry,
if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0 && version >= 3) {
display->wl_dmabuf =
wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface,
MIN2(version, ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION));
MIN2(version, ZWP_LINUX_BUFFER_PARAMS_V1_SET_SAMPLING_DEVICE_SINCE_VERSION));
zwp_linux_dmabuf_v1_add_listener(display->wl_dmabuf,
&dmabuf_listener, display);
} else if (strcmp(interface, wp_linux_drm_syncobj_manager_v1_interface.name) == 0) {
@ -1609,7 +1623,7 @@ wsi_wl_display_init(struct wsi_wayland *wsi_wl,
/* Get the default dma-buf feedback */
if (display->wl_dmabuf && zwp_linux_dmabuf_v1_get_version(display->wl_dmabuf) >=
ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION) {
dmabuf_feedback_format_table_init(&display->format_table);
dmabuf_feedback_init(&display->dmabuf_feedback);
display->wl_dmabuf_feedback =
zwp_linux_dmabuf_v1_get_default_feedback(display->wl_dmabuf);
zwp_linux_dmabuf_feedback_v1_add_listener(display->wl_dmabuf_feedback,
@ -1623,13 +1637,42 @@ wsi_wl_display_init(struct wsi_wayland *wsi_wl,
/* Apparently some wayland compositor do not send the render
* device node but the primary, so test against both.
*/
display->same_gpu =
(wsi_wl->wsi->drm_info.hasRender &&
major(display->main_device) == wsi_wl->wsi->drm_info.renderMajor &&
minor(display->main_device) == wsi_wl->wsi->drm_info.renderMinor) ||
(wsi_wl->wsi->drm_info.hasPrimary &&
major(display->main_device) == wsi_wl->wsi->drm_info.primaryMajor &&
minor(display->main_device) == wsi_wl->wsi->drm_info.primaryMinor);
if (wl_proxy_get_version((struct wl_proxy *)display->wl_dmabuf) >=
ZWP_LINUX_BUFFER_PARAMS_V1_SET_SAMPLING_DEVICE_SINCE_VERSION)
{
/*
For dmabuf v6 we don't get a main device, so we use the first one the compositor can sample from
as default and then try to figure out, if we can use our gpu directly.
*/
util_dynarray_foreach(&display->dmabuf_feedback.tranches, struct dmabuf_feedback_tranche, tranche) {
if ((tranche->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SAMPLING) != 0 && !display->display_device_dev) {
display->same_gpu = false; // if this actually is the same_gpu, we'll figure out in the next loop
display->display_device_dev = tranche->target_device;
}
if ((tranche->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SAMPLING) != 0 &&
((wsi_wl->wsi->drm_info.hasRender &&
major(tranche->target_device) == wsi_wl->wsi->drm_info.renderMajor &&
minor(tranche->target_device) == wsi_wl->wsi->drm_info.renderMinor) ||
(wsi_wl->wsi->drm_info.hasPrimary &&
major(tranche->target_device) == wsi_wl->wsi->drm_info.primaryMajor &&
minor(tranche->target_device) == wsi_wl->wsi->drm_info.primaryMinor)))
{
display->display_device_dev = tranche->target_device;
display->same_gpu = true;
break;
}
}
} else {
display->same_gpu =
(wsi_wl->wsi->drm_info.hasRender &&
major(display->dmabuf_feedback.main_device) == wsi_wl->wsi->drm_info.renderMajor &&
minor(display->dmabuf_feedback.main_device) == wsi_wl->wsi->drm_info.renderMinor) ||
(wsi_wl->wsi->drm_info.hasPrimary &&
major(display->dmabuf_feedback.main_device) == wsi_wl->wsi->drm_info.primaryMajor &&
minor(display->dmabuf_feedback.main_device) == wsi_wl->wsi->drm_info.primaryMinor);
display->display_device_dev = display->dmabuf_feedback.main_device;
}
}
}
@ -1667,7 +1710,7 @@ out:
if (display->wl_dmabuf_feedback) {
zwp_linux_dmabuf_feedback_v1_destroy(display->wl_dmabuf_feedback);
display->wl_dmabuf_feedback = NULL;
dmabuf_feedback_format_table_fini(&display->format_table);
dmabuf_feedback_fini(&display->dmabuf_feedback);
}
return VK_SUCCESS;
@ -2229,8 +2272,8 @@ pick_format_from_surface_dmabuf_feedback(struct wsi_wl_surface *wsi_wl_surface,
{
struct wsi_wl_format *f = NULL;
/* If the main_device was not advertised, we don't have valid feedback */
if (wsi_wl_surface->dmabuf_feedback.main_device == 0)
/* We don't have any tranches for our surface dma-buf feedback, so return */
if (util_dynarray_num_elements(&wsi_wl_surface->dmabuf_feedback.tranches, struct dmabuf_feedback_tranche) == 0)
return NULL;
util_dynarray_foreach(&wsi_wl_surface->dmabuf_feedback.tranches,
@ -3500,6 +3543,17 @@ wsi_wl_image_init(struct wsi_wl_swapchain *chain,
if (!params)
goto fail_image;
if (wl_proxy_get_version((struct wl_proxy *)display->wl_dmabuf) >=
ZWP_LINUX_BUFFER_PARAMS_V1_SET_SAMPLING_DEVICE_SINCE_VERSION)
{
struct wl_array dev;
wl_array_init(&dev);
wl_array_add(&dev, sizeof(dev_t));
memcpy(dev.data, &display->display_device_dev, sizeof(dev_t));
zwp_linux_buffer_params_v1_set_sampling_device(params, &dev);
wl_array_release(&dev);
}
for (int i = 0; i < image->base.num_planes; i++) {
zwp_linux_buffer_params_v1_add(params,
image->base.dma_buf_fd,

View file

@ -1,8 +1,11 @@
[wrap-file]
[wrap-git]
directory = wayland-protocols-1.41
source_url = https://gitlab.freedesktop.org/wayland/wayland-protocols/-/releases/1.41/downloads/wayland-protocols-1.41.tar.xz
source_filename = wayland-protocols-1.41.tar.xz
source_hash = 2786b6b1b79965e313f2c289c12075b9ed700d41844810c51afda10ee329576b
#source_url = https://gitlab.freedesktop.org/wayland/wayland-protocols/-/releases/1.41/downloads/wayland-protocols-1.41.tar.xz
#source_filename = wayland-protocols-1.41.tar.xz
#source_hash = 2786b6b1b79965e313f2c289c12075b9ed700d41844810c51afda10ee329576b
url = https://gitlab.freedesktop.org/Zamundaaa/wayland-protocols.git
revision = work/multi-gpu-dmabuf
depth = 1
[provide]
wayland-protocols = wayland_protocols