2 * Copyright 2021 Eric Engestrom
3 * Copyright 2023 Collabora, Ltd.
4 * SPDX-License-Identifier: MIT
15 #include <wayland-client.h>
16 #include "linux-dmabuf-unstable-v1-client-protocol.h"
18 #include "piglit-util.h"
21 #define MIN(a, b) ((a) < (b) ? (a) : (b))
23 struct wayland_display_target
{
24 unsigned int roundtrips_needed
;
25 struct wl_display
*dpy
;
26 struct wl_registry
*registry
;
27 struct zwp_linux_dmabuf_v1
*dmabuf
;
28 struct zwp_linux_dmabuf_feedback_v1
*feedback
;
30 char *primary_driver_name
;
35 open_drm_by_devid(dev_t devid
)
41 err
= drmGetDeviceFromDevId(devid
, 0, &device
);
43 printf("libdrm reports no devices for our devid\n");
44 piglit_report_result(PIGLIT_FAIL
);
47 if (device
->available_nodes
& (1 << DRM_NODE_RENDER
))
48 ret
= open(device
->nodes
[DRM_NODE_RENDER
], O_RDWR
);
49 if (ret
== -1 && device
->available_nodes
& (1 << DRM_NODE_PRIMARY
))
50 ret
= open(device
->nodes
[DRM_NODE_PRIMARY
], O_RDWR
);
52 printf("Couldn't open any libdrm devices for our devid\n");
53 piglit_report_result(PIGLIT_FAIL
);
56 drmFreeDevice(&device
);
63 feedback_handle_done(void *_data
, struct zwp_linux_dmabuf_feedback_v1
*feedback
)
65 struct wayland_display_target
*data
= _data
;
67 /* We've got all our feedback events now, so we can remove the roundtrip we
68 * added when binding the interface */
69 data
->feedback_done
= true;
73 feedback_handle_format_table(void *_data
,
74 struct zwp_linux_dmabuf_feedback_v1
*feedback
,
75 int fd
, uint32_t size
)
77 /* We don't need the format table for anything */
82 feedback_handle_main_device(void *_data
,
83 struct zwp_linux_dmabuf_feedback_v1
*feedback
,
84 struct wl_array
*dev_array
)
86 struct wayland_display_target
*data
= _data
;
87 drmVersionPtr version
;
91 /* This is basically a malformed compositor */
92 if (dev_array
->size
!= sizeof(dev
)) {
93 printf("Expected main_device size to be %zu (dev_t), but it was %zu\n",
94 sizeof(dev
), dev_array
->size
);
95 piglit_report_result(PIGLIT_FAIL
);
98 memcpy(&dev
, dev_array
->data
, sizeof(dev
));
99 fd
= open_drm_by_devid(dev
);
101 printf("Couldn't open DRM device for main_device\n");
102 piglit_report_result(PIGLIT_FAIL
);
105 version
= drmGetVersion(fd
);
106 if (!version
|| !version
->name_len
|| !version
->name
) {
107 printf("drmGetVersion failed\n");
108 piglit_report_result(PIGLIT_FAIL
);
111 data
->primary_driver_name
= malloc(version
->name_len
+ 1);
112 assert(data
->primary_driver_name
);
113 memcpy(data
->primary_driver_name
, version
->name
, version
->name_len
);
114 data
->primary_driver_name
[version
->name_len
] = '\0';
116 drmFreeVersion(version
);
121 feedback_handle_tranche_done(void *_data
,
122 struct zwp_linux_dmabuf_feedback_v1
*feedback
)
124 /* We don't care about the content of the format/modifier tranches */
128 feedback_handle_tranche_target_device(void *_data
,
129 struct zwp_linux_dmabuf_feedback_v1
*feedback
,
130 struct wl_array
*dev_arr
)
132 /* We don't care about per-tranche target devices (e.g. scanout) */
136 feedback_handle_tranche_formats(void *_data
,
137 struct zwp_linux_dmabuf_feedback_v1
*feedback
,
138 struct wl_array
*indices
)
140 /* We don't care about per-tranche formats */
144 feedback_handle_tranche_flags(void *_data
,
145 struct zwp_linux_dmabuf_feedback_v1
*feedback
,
148 /* We don't care about per-tranche flags */
151 static const struct zwp_linux_dmabuf_feedback_v1_listener feedback_listener
= {
152 feedback_handle_done
,
153 feedback_handle_format_table
,
154 feedback_handle_main_device
,
155 feedback_handle_tranche_done
,
156 feedback_handle_tranche_target_device
,
157 feedback_handle_tranche_formats
,
158 feedback_handle_tranche_flags
,
162 registry_handle_global(void *_data
, struct wl_registry
*registry
,
163 uint32_t name
, const char *interface
, uint32_t version
)
165 struct wayland_display_target
*data
= _data
;
167 if (strcmp(interface
, "zwp_linux_dmabuf_v1") == 0 && version
>= 4) {
168 data
->dmabuf
= wl_registry_bind(data
->registry
, name
,
169 &zwp_linux_dmabuf_v1_interface
,
171 data
->feedback
= zwp_linux_dmabuf_v1_get_default_feedback(data
->dmabuf
);
172 zwp_linux_dmabuf_feedback_v1_add_listener(data
->feedback
,
175 /* Need another roundtrip to collect the feedback events */
176 data
->roundtrips_needed
++;
181 registry_handle_remove(void *_data
, struct wl_registry
*registry
, uint32_t name
)
185 static const struct wl_registry_listener registry_listener
= {
186 registry_handle_global
,
187 registry_handle_remove
194 const char *expected_driver_name
= NULL
;
195 struct wayland_display_target data
;
197 memset(&data
, 0, sizeof(data
));
199 expected_driver_name
= getenv("PIGLIT_WAYLAND_EXPECTED_DRIVER");
200 if (!expected_driver_name
) {
201 printf("$PIGLIT_WAYLAND_EXPECTED_DRIVER must be set to run this test\n");
202 piglit_report_result(PIGLIT_SKIP
);
205 /* Connect to $WAYLAND_DISPLAY or $WAYLAND_SOCKET */
206 data
.dpy
= wl_display_connect(NULL
);
208 printf("Could not connect to Wayland display\n");
209 piglit_report_result(PIGLIT_SKIP
);
212 /* The registry advertises the available interfaces */
213 data
.registry
= wl_display_get_registry(data
.dpy
);
214 assert(data
.registry
);
215 wl_registry_add_listener(data
.registry
, ®istry_listener
, &data
);
217 /* Listen for the wl_registry advertisements to get supported interfaces */
218 wl_display_roundtrip(data
.dpy
);
221 printf("zwp_linux_dmabuf_v1 is not available\n");
222 piglit_report_result(PIGLIT_SKIP
);
225 /* Wait until we receive the zwp_linux_dmabuf_feedback_v1.done event */
226 while (!data
.feedback_done
)
227 wl_display_roundtrip(data
.dpy
);
229 if (!data
.primary_driver_name
||
230 strcmp(data
.primary_driver_name
, expected_driver_name
) != 0) {
231 printf("Got driver name %s, wanted %s\n", data
.primary_driver_name
,
232 expected_driver_name
);
233 piglit_report_result(PIGLIT_FAIL
);
236 free(data
.primary_driver_name
);
237 zwp_linux_dmabuf_feedback_v1_destroy(data
.feedback
);
238 zwp_linux_dmabuf_v1_destroy(data
.dmabuf
);
239 wl_registry_destroy(data
.registry
);
240 wl_display_disconnect(data
.dpy
);
242 piglit_report_result(PIGLIT_PASS
);