blob: e9643613b77b010bd311637109234a8fda095526 [file] [log] [blame]
Pekka Paalanen230f3b12014-09-29 14:18:40 -04001/*
2 * Copyright © 2014, 2015 Collabora, Ltd.
3 *
Yong Bakos53361532017-01-23 06:17:44 -08004 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
Pekka Paalanen230f3b12014-09-29 14:18:40 -040011 *
Yong Bakos53361532017-01-23 06:17:44 -080012 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
Pekka Paalanen230f3b12014-09-29 14:18:40 -040024 */
25
26#include "config.h"
27
28#include <assert.h>
Leandro Ribeiro8eb84142021-01-18 19:36:48 -030029#include <errno.h>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030030#include <stdint.h>
Pekka Paalanen230f3b12014-09-29 14:18:40 -040031#include <unistd.h>
Leandro Ribeiro8eb84142021-01-18 19:36:48 -030032#include <string.h>
33#include <sys/mman.h>
Pekka Paalanen230f3b12014-09-29 14:18:40 -040034#include <sys/types.h>
35
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020036#include <libweston/libweston.h>
Pekka Paalanen230f3b12014-09-29 14:18:40 -040037#include "linux-dmabuf.h"
Leandro Ribeiro8eb84142021-01-18 19:36:48 -030038#include "shared/os-compatibility.h"
Marius Vlad56f3a682019-07-10 14:48:39 +030039#include "libweston-internal.h"
Pekka Paalanen4b301fe2021-02-04 17:39:45 +020040#include "shared/weston-drm-fourcc.h"
Pekka Paalanen230f3b12014-09-29 14:18:40 -040041
42static void
43linux_dmabuf_buffer_destroy(struct linux_dmabuf_buffer *buffer)
44{
45 int i;
46
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +000047 for (i = 0; i < buffer->attributes.n_planes; i++) {
48 close(buffer->attributes.fd[i]);
49 buffer->attributes.fd[i] = -1;
Pekka Paalanen230f3b12014-09-29 14:18:40 -040050 }
51
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +000052 buffer->attributes.n_planes = 0;
Pekka Paalanen230f3b12014-09-29 14:18:40 -040053 free(buffer);
54}
55
56static void
57destroy_params(struct wl_resource *params_resource)
58{
59 struct linux_dmabuf_buffer *buffer;
60
61 buffer = wl_resource_get_user_data(params_resource);
62
63 if (!buffer)
64 return;
65
66 linux_dmabuf_buffer_destroy(buffer);
67}
68
69static void
70params_destroy(struct wl_client *client, struct wl_resource *resource)
71{
72 wl_resource_destroy(resource);
73}
74
75static void
76params_add(struct wl_client *client,
77 struct wl_resource *params_resource,
78 int32_t name_fd,
79 uint32_t plane_idx,
80 uint32_t offset,
81 uint32_t stride,
82 uint32_t modifier_hi,
83 uint32_t modifier_lo)
84{
85 struct linux_dmabuf_buffer *buffer;
86
87 buffer = wl_resource_get_user_data(params_resource);
88 if (!buffer) {
89 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +080090 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
Pekka Paalanen230f3b12014-09-29 14:18:40 -040091 "params was already used to create a wl_buffer");
92 close(name_fd);
93 return;
94 }
95
96 assert(buffer->params_resource == params_resource);
97 assert(!buffer->buffer_resource);
98
99 if (plane_idx >= MAX_DMABUF_PLANES) {
100 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800101 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400102 "plane index %u is too high", plane_idx);
103 close(name_fd);
104 return;
105 }
106
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000107 if (buffer->attributes.fd[plane_idx] != -1) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400108 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800109 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400110 "a dmabuf has already been added for plane %u",
111 plane_idx);
112 close(name_fd);
113 return;
114 }
115
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000116 buffer->attributes.fd[plane_idx] = name_fd;
117 buffer->attributes.offset[plane_idx] = offset;
118 buffer->attributes.stride[plane_idx] = stride;
Emre Ucan99ef8162018-01-09 14:00:30 +0100119
120 if (wl_resource_get_version(params_resource) < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION)
leng.fang32af9fc2024-06-13 11:22:15 +0800121 buffer->attributes.modifier[plane_idx] = DRM_FORMAT_MOD_LINEAR;
Emre Ucan99ef8162018-01-09 14:00:30 +0100122 else
123 buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) |
124 modifier_lo;
125
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000126 buffer->attributes.n_planes++;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400127}
128
129static void
130linux_dmabuf_wl_buffer_destroy(struct wl_client *client,
131 struct wl_resource *resource)
132{
133 wl_resource_destroy(resource);
134}
135
136static const struct wl_buffer_interface linux_dmabuf_buffer_implementation = {
137 linux_dmabuf_wl_buffer_destroy
138};
139
140static void
141destroy_linux_dmabuf_wl_buffer(struct wl_resource *resource)
142{
143 struct linux_dmabuf_buffer *buffer;
144
145 buffer = wl_resource_get_user_data(resource);
146 assert(buffer->buffer_resource == resource);
147 assert(!buffer->params_resource);
148
149 if (buffer->user_data_destroy_func)
150 buffer->user_data_destroy_func(buffer);
151
152 linux_dmabuf_buffer_destroy(buffer);
153}
154
155static void
Varad Gautam65c94b82017-04-26 19:15:59 +0530156params_create_common(struct wl_client *client,
157 struct wl_resource *params_resource,
158 uint32_t buffer_id,
159 int32_t width,
160 int32_t height,
161 uint32_t format,
162 uint32_t flags)
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400163{
164 struct linux_dmabuf_buffer *buffer;
165 int i;
166
167 buffer = wl_resource_get_user_data(params_resource);
168
169 if (!buffer) {
170 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800171 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400172 "params was already used to create a wl_buffer");
173 return;
174 }
175
176 assert(buffer->params_resource == params_resource);
177 assert(!buffer->buffer_resource);
178
179 /* Switch the linux_dmabuf_buffer object from params resource to
180 * eventually wl_buffer resource.
181 */
182 wl_resource_set_user_data(buffer->params_resource, NULL);
183 buffer->params_resource = NULL;
184
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000185 if (!buffer->attributes.n_planes) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400186 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800187 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400188 "no dmabuf has been added to the params");
189 goto err_out;
190 }
191
192 /* Check for holes in the dmabufs set (e.g. [0, 1, 3]) */
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000193 for (i = 0; i < buffer->attributes.n_planes; i++) {
194 if (buffer->attributes.fd[i] == -1) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400195 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800196 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400197 "no dmabuf has been added for plane %i", i);
198 goto err_out;
199 }
200 }
201
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000202 buffer->attributes.width = width;
203 buffer->attributes.height = height;
204 buffer->attributes.format = format;
205 buffer->attributes.flags = flags;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400206
limin.tian531dd232025-01-07 12:09:27 +0000207 WESTON_LOGD(COMMON_LOG, "dmabuf:%p fd(%d %d) wxh(%dx%d) format:%u", buffer,
208 buffer->attributes.fd[0], buffer->attributes.fd[1], width, height, format);
209
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400210 if (width < 1 || height < 1) {
211 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800212 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400213 "invalid width %d or height %d", width, height);
214 goto err_out;
215 }
216
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000217 for (i = 0; i < buffer->attributes.n_planes; i++) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400218 off_t size;
219
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000220 if ((uint64_t) buffer->attributes.offset[i] + buffer->attributes.stride[i] > UINT32_MAX) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400221 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800222 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400223 "size overflow for plane %i", i);
224 goto err_out;
225 }
226
227 if (i == 0 &&
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000228 (uint64_t) buffer->attributes.offset[i] +
229 (uint64_t) buffer->attributes.stride[i] * height > UINT32_MAX) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400230 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800231 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400232 "size overflow for plane %i", i);
233 goto err_out;
234 }
235
236 /* Don't report an error as it might be caused
237 * by the kernel not supporting seeking on dmabuf */
leng.fang32af9fc2024-06-13 11:22:15 +0800238 if (buffer->direct_display) {
limin.tian531dd232025-01-07 12:09:27 +0000239 weston_log("direct_display. remove parameter check and gpu import \n");
leng.fang32af9fc2024-06-13 11:22:15 +0800240 goto avoid_gpu_import;
241 }
242
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000243 size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400244 if (size == -1)
Derek Foremanc06389a2016-04-25 09:23:24 -0500245 continue;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400246
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000247 if (buffer->attributes.offset[i] >= size) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400248 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800249 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400250 "invalid offset %i for plane %i",
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000251 buffer->attributes.offset[i], i);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400252 goto err_out;
253 }
254
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000255 if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400256 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800257 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400258 "invalid stride %i for plane %i",
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000259 buffer->attributes.stride[i], i);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400260 goto err_out;
261 }
leng.fang32af9fc2024-06-13 11:22:15 +0800262 weston_log("\n %s %d offset:%d, stride:%d height:%d,size:%d\n", __FUNCTION__, __LINE__,
263 buffer->attributes.offset[i], buffer->attributes.stride[i], height, size);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400264 /* Only valid for first plane as other planes might be
265 * sub-sampled according to fourcc format */
266 if (i == 0 &&
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000267 buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400268 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800269 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400270 "invalid buffer stride or height for plane %i", i);
271 goto err_out;
272 }
273 }
274
Marius Vlad5a701542019-11-16 20:26:52 +0200275 if (buffer->direct_display) {
276 if (!weston_compositor_dmabuf_can_scanout(buffer->compositor,
277 buffer))
278 goto err_failed;
279
280 goto avoid_gpu_import;
281 }
282
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400283 if (!weston_compositor_import_dmabuf(buffer->compositor, buffer))
284 goto err_failed;
285
Marius Vlad5a701542019-11-16 20:26:52 +0200286avoid_gpu_import:
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400287 buffer->buffer_resource = wl_resource_create(client,
288 &wl_buffer_interface,
Varad Gautam65c94b82017-04-26 19:15:59 +0530289 1, buffer_id);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400290 if (!buffer->buffer_resource) {
291 wl_resource_post_no_memory(params_resource);
292 goto err_buffer;
293 }
294
295 wl_resource_set_implementation(buffer->buffer_resource,
296 &linux_dmabuf_buffer_implementation,
297 buffer, destroy_linux_dmabuf_wl_buffer);
298
Varad Gautam65c94b82017-04-26 19:15:59 +0530299 /* send 'created' event when the request is not for an immediate
300 * import, ie buffer_id is zero */
301 if (buffer_id == 0)
302 zwp_linux_buffer_params_v1_send_created(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800303 buffer->buffer_resource);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400304
305 return;
306
307err_buffer:
308 if (buffer->user_data_destroy_func)
309 buffer->user_data_destroy_func(buffer);
310
311err_failed:
Varad Gautam65c94b82017-04-26 19:15:59 +0530312 if (buffer_id == 0)
313 zwp_linux_buffer_params_v1_send_failed(params_resource);
314 else
315 /* since the behavior is left implementation defined by the
316 * protocol in case of create_immed failure due to an unknown cause,
317 * we choose to treat it as a fatal error and immediately kill the
318 * client instead of creating an invalid handle and waiting for it
319 * to be used.
320 */
321 wl_resource_post_error(params_resource,
322 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
323 "importing the supplied dmabufs failed");
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400324
325err_out:
326 linux_dmabuf_buffer_destroy(buffer);
327}
328
Varad Gautam65c94b82017-04-26 19:15:59 +0530329static void
330params_create(struct wl_client *client,
331 struct wl_resource *params_resource,
332 int32_t width,
333 int32_t height,
334 uint32_t format,
335 uint32_t flags)
336{
337 params_create_common(client, params_resource, 0, width, height, format,
338 flags);
339}
340
341static void
342params_create_immed(struct wl_client *client,
343 struct wl_resource *params_resource,
344 uint32_t buffer_id,
345 int32_t width,
346 int32_t height,
347 uint32_t format,
348 uint32_t flags)
349{
350 params_create_common(client, params_resource, buffer_id, width, height,
351 format, flags);
352}
353
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800354static const struct zwp_linux_buffer_params_v1_interface
355zwp_linux_buffer_params_implementation = {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400356 params_destroy,
357 params_add,
Varad Gautam65c94b82017-04-26 19:15:59 +0530358 params_create,
359 params_create_immed
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400360};
361
362static void
363linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource)
364{
365 wl_resource_destroy(resource);
366}
367
368static void
369linux_dmabuf_create_params(struct wl_client *client,
370 struct wl_resource *linux_dmabuf_resource,
371 uint32_t params_id)
372{
373 struct weston_compositor *compositor;
374 struct linux_dmabuf_buffer *buffer;
375 uint32_t version;
376 int i;
377
378 version = wl_resource_get_version(linux_dmabuf_resource);
379 compositor = wl_resource_get_user_data(linux_dmabuf_resource);
380
381 buffer = zalloc(sizeof *buffer);
382 if (!buffer)
383 goto err_out;
384
385 for (i = 0; i < MAX_DMABUF_PLANES; i++)
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000386 buffer->attributes.fd[i] = -1;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400387
388 buffer->compositor = compositor;
389 buffer->params_resource =
390 wl_resource_create(client,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800391 &zwp_linux_buffer_params_v1_interface,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400392 version, params_id);
Marius Vlad5a701542019-11-16 20:26:52 +0200393 buffer->direct_display = false;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400394 if (!buffer->params_resource)
395 goto err_dealloc;
396
397 wl_resource_set_implementation(buffer->params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800398 &zwp_linux_buffer_params_implementation,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400399 buffer, destroy_params);
400
401 return;
402
403err_dealloc:
404 free(buffer);
405
406err_out:
407 wl_resource_post_no_memory(linux_dmabuf_resource);
408}
409
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300410/** Creates dma-buf feedback tranche
411 *
412 * The tranche is added to dma-buf feedback's tranche list
413 *
414 * @param dmabuf_feedback The dma-buf feedback object to which the tranche is added
415 * @param format_table The dma-buf feedback formats table
416 * @param target_device The target device of the new tranche
417 * @param flags The flags of the new tranche
418 * @param preference The preference of the new tranche
419 * @return The tranche created, or NULL on failure
420 */
421WL_EXPORT struct weston_dmabuf_feedback_tranche *
422weston_dmabuf_feedback_tranche_create(struct weston_dmabuf_feedback *dmabuf_feedback,
423 struct weston_dmabuf_feedback_format_table *format_table,
424 dev_t target_device, uint32_t flags,
425 enum weston_dmabuf_feedback_tranche_preference preference)
426{
427 struct weston_dmabuf_feedback_tranche *tranche, *ptr;
428 struct wl_list *pos;
429
430 tranche = zalloc(sizeof(*tranche));
431 if (!tranche) {
432 weston_log("%s: out of memory\n", __func__);
433 return NULL;
434 }
435
Leandro Ribeiro54293022021-10-12 14:48:36 -0300436 tranche->active = true;
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300437 tranche->target_device = target_device;
438 tranche->flags = flags;
439 tranche->preference = preference;
440
441 /* Get the formats indices array */
442 if (flags == 0) {
443 if (wl_array_copy(&tranche->formats_indices,
444 &format_table->renderer_formats_indices) < 0) {
445 weston_log("%s: out of memory\n", __func__);
446 goto err;
447 }
448 } else if (flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT) {
Leandro Ribeiro54293022021-10-12 14:48:36 -0300449 if (wl_array_copy(&tranche->formats_indices,
450 &format_table->scanout_formats_indices) < 0) {
451 weston_log("%s: out of memory\n", __func__);
452 goto err;
453 }
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300454 } else {
455 weston_log("error: for now we just have renderer and scanout "
456 "tranches, can't create other type of tranche\n");
457 goto err;
458 }
459
460 /* The list of tranches is ordered by preference.
461 * Highest preference comes first. */
462 pos = &dmabuf_feedback->tranche_list;
463 wl_list_for_each(ptr, &dmabuf_feedback->tranche_list, link) {
464 pos = &ptr->link;
465 if (ptr->preference <= tranche->preference)
466 break;
467 }
468 wl_list_insert(pos->prev, &tranche->link);
469
470 return tranche;
471
472err:
473 free(tranche);
474 return NULL;
475}
476
477static void
478weston_dmabuf_feedback_tranche_destroy(struct weston_dmabuf_feedback_tranche *tranche)
479{
480 wl_array_release(&tranche->formats_indices);
481 wl_list_remove(&tranche->link);
482 free(tranche);
483}
484
485static int
486format_table_add_renderer_formats(struct weston_dmabuf_feedback_format_table *format_table,
487 const struct weston_drm_format_array *renderer_formats)
488{
489 struct weston_drm_format *fmt;
490 unsigned int num_modifiers;
491 const uint64_t *modifiers;
492 uint16_t index, *index_ptr;
493 unsigned int size;
494 unsigned int i;
495
496 size = sizeof(index) *
497 weston_drm_format_array_count_pairs(renderer_formats);
498
499 if (!wl_array_add(&format_table->renderer_formats_indices, size)) {
500 weston_log("%s: out of memory\n", __func__);
501 return -1;
502 }
503
504 index = 0;
505 wl_array_for_each(fmt, &renderer_formats->arr) {
506 modifiers = weston_drm_format_get_modifiers(fmt, &num_modifiers);
507 for (i = 0; i < num_modifiers; i++) {
508 format_table->data[index].format = fmt->format;
509 format_table->data[index].modifier = modifiers[i];
510 index++;
511 }
512 }
513
514 index = 0;
515 wl_array_for_each(index_ptr, &format_table->renderer_formats_indices)
516 *index_ptr = index++;
517
518 return 0;
519}
520
521/** Creates dma-buf feedback format table
522 *
523 * @param renderer_formats The formats that compose the table
524 * @return The dma-buf feedback format table, or NULL on failure
525 */
526WL_EXPORT struct weston_dmabuf_feedback_format_table *
527weston_dmabuf_feedback_format_table_create(const struct weston_drm_format_array *renderer_formats)
528{
529 struct weston_dmabuf_feedback_format_table *format_table;
530 int ret;
531
532 format_table = zalloc(sizeof(*format_table));
533 if (!format_table) {
534 weston_log("%s: out of memory\n", __func__);
535 return NULL;
536 }
537 wl_array_init(&format_table->renderer_formats_indices);
Leandro Ribeiro54293022021-10-12 14:48:36 -0300538 wl_array_init(&format_table->scanout_formats_indices);
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300539
540 /* Creates formats file table and mmap it */
541 format_table->size = weston_drm_format_array_count_pairs(renderer_formats) *
542 sizeof(*format_table->data);
543 format_table->fd = os_create_anonymous_file(format_table->size);
544 if (format_table->fd < 0) {
545 weston_log("error: failed to create format table file: %s\n",
546 strerror(errno));
547 goto err_fd;
548 }
549 format_table->data = mmap(NULL, format_table->size, PROT_READ | PROT_WRITE,
550 MAP_SHARED, format_table->fd, 0);
551 if (format_table->data == MAP_FAILED) {
552 weston_log("error: mmap for format table failed: %s\n",
553 strerror(errno));
554 goto err_mmap;
555 }
556
557 /* Add renderer formats to file table */
558 ret = format_table_add_renderer_formats(format_table, renderer_formats);
559 if (ret < 0)
560 goto err_formats;
561
562 return format_table;
563
564err_formats:
565 munmap(format_table->data, format_table->size);
566err_mmap:
567 close(format_table->fd);
568err_fd:
569 wl_array_release(&format_table->renderer_formats_indices);
570 free(format_table);
571 return NULL;
572}
573
574/** Destroys dma-buf feedback formats table
575 *
576 * @param format_table The dma-buf feedback format table to destroy
577 */
578WL_EXPORT void
579weston_dmabuf_feedback_format_table_destroy(struct weston_dmabuf_feedback_format_table *format_table)
580{
581 wl_array_release(&format_table->renderer_formats_indices);
Leandro Ribeiro54293022021-10-12 14:48:36 -0300582 wl_array_release(&format_table->scanout_formats_indices);
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300583
584 munmap(format_table->data, format_table->size);
585 close(format_table->fd);
586
587 free(format_table);
588}
589
Leandro Ribeiro54293022021-10-12 14:48:36 -0300590static int
591format_table_get_format_index(struct weston_dmabuf_feedback_format_table *format_table,
592 uint32_t format, uint64_t modifier, uint16_t *index_out)
593{
594 uint16_t index;
595 unsigned int num_elements = format_table->size / sizeof(index);
596
597 for (index = 0; index < num_elements; index++) {
598 if (format_table->data[index].format == format &&
599 format_table->data[index].modifier == modifier) {
600 *index_out = index;
601 return 0;
602 }
603 }
604
605 return -1;
606}
607
608/** Set scanout formats indices in the dma-buf feedback format table
609 *
610 * The table consists of the formats supported by the renderer. A dma-buf
611 * feedback scanout tranche consists of the union of the KMS plane's formats
612 * intersected with the renderer formats. With this function we compute the
613 * indices of these plane's formats in the table and save them in the
614 * table->scanout_formats_indices, allowing us to create scanout tranches.
615 *
616 * @param format_table The dma-buf feedback format table
617 * @param scanout_formats The scanout formats
618 * @return 0 on success, -1 on failure
619 */
620WL_EXPORT int
621weston_dmabuf_feedback_format_table_set_scanout_indices(struct weston_dmabuf_feedback_format_table *format_table,
622 const struct weston_drm_format_array *scanout_formats)
623{
624 struct weston_drm_format *fmt;
625 unsigned int num_modifiers;
626 const uint64_t *modifiers;
627 uint16_t index, *index_ptr;
628 unsigned int i;
629 int ret;
630
631 wl_array_for_each(fmt, &scanout_formats->arr) {
632 modifiers = weston_drm_format_get_modifiers(fmt, &num_modifiers);
633 for (i = 0; i < num_modifiers; i++) {
634 index_ptr =
635 wl_array_add(&format_table->scanout_formats_indices,
636 sizeof(index));
637 if (!index_ptr)
638 goto err;
639
640 ret = format_table_get_format_index(format_table, fmt->format,
641 modifiers[i], &index);
642 if (ret < 0)
643 goto err;
644
645 *index_ptr = index;
646 }
647 }
648
649 return 0;
650
651err:
652 wl_array_release(&format_table->scanout_formats_indices);
653 wl_array_init(&format_table->scanout_formats_indices);
654 return -1;
655}
656
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300657/** Creates dma-buf feedback object
658 *
659 * @param main_device The main device of the dma-buf feedback
660 * @return The dma-buf feedback object created, or NULL on failure
661 */
662WL_EXPORT struct weston_dmabuf_feedback *
663weston_dmabuf_feedback_create(dev_t main_device)
664{
665 struct weston_dmabuf_feedback *dmabuf_feedback;
666
667 dmabuf_feedback = zalloc(sizeof(*dmabuf_feedback));
668 if (!dmabuf_feedback) {
669 weston_log("%s: out of memory\n", __func__);
670 return NULL;
671 }
672
673 dmabuf_feedback->main_device = main_device;
674 wl_list_init(&dmabuf_feedback->tranche_list);
675 wl_list_init(&dmabuf_feedback->resource_list);
676
677 return dmabuf_feedback;
678}
679
680/** Destroy dma-buf feedback object
681 *
682 * @param dmabuf_feedback The dma-buf feedback object to destroy
683 */
684WL_EXPORT void
685weston_dmabuf_feedback_destroy(struct weston_dmabuf_feedback *dmabuf_feedback)
686{
687 struct weston_dmabuf_feedback_tranche *tranche, *tranche_tmp;
688 struct wl_resource *res, *res_tmp;
689
690 wl_list_for_each_safe(tranche, tranche_tmp, &dmabuf_feedback->tranche_list, link)
691 weston_dmabuf_feedback_tranche_destroy(tranche);
692
693 wl_resource_for_each_safe(res, res_tmp, &dmabuf_feedback->resource_list) {
694 wl_list_remove(wl_resource_get_link(res));
695 wl_list_init(wl_resource_get_link(res));
696 }
697
698 free(dmabuf_feedback);
699}
700
Leandro Ribeiro54293022021-10-12 14:48:36 -0300701/** Find tranche in a dma-buf feedback object
702 *
703 * @param dmabuf_feedback The dma-buf feedback object where to look for
704 * @param target_device The target device of the tranche
705 * @param flags The flags of the tranche
706 * @param preference The preference of the tranche
707 * @return The tranche, or NULL if it was not found
708 */
709WL_EXPORT struct weston_dmabuf_feedback_tranche *
710weston_dmabuf_feedback_find_tranche(struct weston_dmabuf_feedback *dmabuf_feedback,
711 dev_t target_device, uint32_t flags,
712 enum weston_dmabuf_feedback_tranche_preference preference)
713{
714 struct weston_dmabuf_feedback_tranche *tranche;
715
716 wl_list_for_each(tranche, &dmabuf_feedback->tranche_list, link)
717 if (tranche->target_device == target_device &&
718 tranche->flags == flags && tranche->preference == preference)
719 return tranche;
720
721 return NULL;
722}
723
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300724static void
725weston_dmabuf_feedback_send(struct weston_dmabuf_feedback *dmabuf_feedback,
726 struct weston_dmabuf_feedback_format_table *format_table,
727 struct wl_resource *res, bool advertise_format_table)
728{
729 struct weston_dmabuf_feedback_tranche *tranche;
730 struct wl_array device;
731 dev_t *dev;
732
733 /* main_device and target_device events need a dev_t as parameter,
734 * but we can't use this directly to communicate with the Wayland
735 * client. The solution is to use a wl_array, which is supported by
736 * Wayland, and add the dev_t as an element of the array. */
737 wl_array_init(&device);
738 dev = wl_array_add(&device, sizeof(*dev));
739 if (!dev) {
740 wl_resource_post_no_memory(res);
741 return;
742 }
743
744 /* format_table event - In Weston, we never modify the dma-buf feedback
745 * format table. So we have this flag in order to advertise the format
746 * table only if the client has just subscribed to receive the events
747 * for this feedback object. When we need to re-send the feedback events
748 * for this client, the table event won't be sent. */
749 if (advertise_format_table)
750 zwp_linux_dmabuf_feedback_v1_send_format_table(res, format_table->fd,
751 format_table->size);
752
753 /* main_device event */
754 *dev = dmabuf_feedback->main_device;
755 zwp_linux_dmabuf_feedback_v1_send_main_device(res, &device);
756
757 /* send events for each tranche */
758 wl_list_for_each(tranche, &dmabuf_feedback->tranche_list, link) {
Leandro Ribeiro54293022021-10-12 14:48:36 -0300759 if (!tranche->active)
760 continue;
761
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300762 /* tranche_target_device event */
763 *dev = tranche->target_device;
764 zwp_linux_dmabuf_feedback_v1_send_tranche_target_device(res, &device);
765
766 /* tranche_flags event */
767 zwp_linux_dmabuf_feedback_v1_send_tranche_flags(res, tranche->flags);
768
769 /* tranche_formats event */
770 zwp_linux_dmabuf_feedback_v1_send_tranche_formats(res, &tranche->formats_indices);
771
772 /* tranche_done_event */
773 zwp_linux_dmabuf_feedback_v1_send_tranche_done(res);
774 }
775
776 /* compositor_done_event */
777 zwp_linux_dmabuf_feedback_v1_send_done(res);
778
779 wl_array_release(&device);
780}
781
Leandro Ribeiro54293022021-10-12 14:48:36 -0300782/** Sends the feedback events for a dma-buf feedback object
783 *
784 * Given a dma-buf feedback object, this will send events to clients that are
785 * subscribed to it. This is useful for the per-surface dma-buf feedback, which
786 * is dynamic and can change throughout compositor's life. These changes results
787 * in the need to resend the feedback events to clients.
788 *
789 * @param dmabuf_feedback The weston_dmabuf_feedback object
790 * @param format_table The dma-buf feedback formats table
791 */
792WL_EXPORT void
793weston_dmabuf_feedback_send_all(struct weston_dmabuf_feedback *dmabuf_feedback,
794 struct weston_dmabuf_feedback_format_table *format_table)
795{
796 struct wl_resource *res;
797
798 wl_resource_for_each(res, &dmabuf_feedback->resource_list)
799 weston_dmabuf_feedback_send(dmabuf_feedback,
800 format_table, res, false);
801}
802
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300803static void
804dmabuf_feedback_resource_destroy(struct wl_resource *resource)
805{
806 wl_list_remove(wl_resource_get_link(resource));
807}
808
809static void
810dmabuf_feedback_destroy(struct wl_client *client, struct wl_resource *resource)
811{
812 wl_resource_destroy(resource);
813}
814
815static const struct zwp_linux_dmabuf_feedback_v1_interface
816zwp_linux_dmabuf_feedback_implementation = {
817 dmabuf_feedback_destroy
818};
819
820static struct wl_resource *
821dmabuf_feedback_resource_create(struct wl_resource *dmabuf_resource,
822 struct wl_client *client, uint32_t dmabuf_feedback_id)
823{
824 struct wl_resource *dmabuf_feedback_res;
825 uint32_t version;
826
827 version = wl_resource_get_version(dmabuf_resource);
828
829 dmabuf_feedback_res =
830 wl_resource_create(client, &zwp_linux_dmabuf_feedback_v1_interface,
831 version, dmabuf_feedback_id);
832 if (!dmabuf_feedback_res)
833 return NULL;
834
835 wl_list_init(wl_resource_get_link(dmabuf_feedback_res));
836 wl_resource_set_implementation(dmabuf_feedback_res,
837 &zwp_linux_dmabuf_feedback_implementation,
838 NULL, dmabuf_feedback_resource_destroy);
839
840 return dmabuf_feedback_res;
841}
842
843static void
844linux_dmabuf_get_default_feedback(struct wl_client *client,
845 struct wl_resource *dmabuf_resource,
846 uint32_t dmabuf_feedback_id)
847{
848 struct weston_compositor *compositor =
849 wl_resource_get_user_data(dmabuf_resource);
850 struct wl_resource *dmabuf_feedback_resource;
851
852 dmabuf_feedback_resource =
853 dmabuf_feedback_resource_create(dmabuf_resource,
854 client, dmabuf_feedback_id);
855 if (!dmabuf_feedback_resource) {
856 wl_resource_post_no_memory(dmabuf_resource);
857 return;
858 }
859
860 weston_dmabuf_feedback_send(compositor->default_dmabuf_feedback,
861 compositor->dmabuf_feedback_format_table,
862 dmabuf_feedback_resource, true);
863}
864
865static void
866linux_dmabuf_get_per_surface_feedback(struct wl_client *client,
867 struct wl_resource *dmabuf_resource,
868 uint32_t dmabuf_feedback_id,
869 struct wl_resource *surface_resource)
870{
871 struct weston_surface *surface =
872 wl_resource_get_user_data(surface_resource);
873 struct wl_resource *dmabuf_feedback_resource;
874
875 dmabuf_feedback_resource =
876 dmabuf_feedback_resource_create(dmabuf_resource,
877 client, dmabuf_feedback_id);
878 if (!dmabuf_feedback_resource) {
879 wl_resource_post_no_memory(dmabuf_resource);
880 return;
881 }
882
883 /* Surface dma-buf feedback is dynamic and may need to be resent to
884 * clients when they change. So we need to keep the resources list */
885 wl_list_insert(&surface->dmabuf_feedback->resource_list,
886 wl_resource_get_link(dmabuf_feedback_resource));
887
888 weston_dmabuf_feedback_send(surface->dmabuf_feedback,
889 surface->compositor->dmabuf_feedback_format_table,
890 dmabuf_feedback_resource, true);
891}
892
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400893/** Get the linux_dmabuf_buffer from a wl_buffer resource
894 *
895 * If the given wl_buffer resource was created through the linux_dmabuf
896 * protocol interface, returns the linux_dmabuf_buffer object. This can
897 * be used as a type check for a wl_buffer.
898 *
899 * \param resource A wl_buffer resource.
900 * \return The linux_dmabuf_buffer if it exists, or NULL otherwise.
901 */
902WL_EXPORT struct linux_dmabuf_buffer *
903linux_dmabuf_buffer_get(struct wl_resource *resource)
904{
905 struct linux_dmabuf_buffer *buffer;
906
907 if (!resource)
908 return NULL;
909
910 if (!wl_resource_instance_of(resource, &wl_buffer_interface,
911 &linux_dmabuf_buffer_implementation))
912 return NULL;
913
914 buffer = wl_resource_get_user_data(resource);
915 assert(buffer);
916 assert(!buffer->params_resource);
917 assert(buffer->buffer_resource == resource);
918
919 return buffer;
920}
921
922/** Set renderer-private data
923 *
924 * Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
925 * a non-NULL user data with a new non-NULL pointer. This is meant to
926 * protect against renderers fighting over linux_dmabuf_buffer user data
927 * ownership.
928 *
929 * The renderer-private data is usually set from the
930 * weston_renderer::import_dmabuf hook.
931 *
932 * \param buffer The linux_dmabuf_buffer object to set for.
933 * \param data The new renderer-private data pointer.
934 * \param func Destructor function to be called for the renderer-private
935 * data when the linux_dmabuf_buffer gets destroyed.
936 *
937 * \sa weston_compositor_import_dmabuf
938 */
939WL_EXPORT void
940linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
941 void *data,
942 dmabuf_user_data_destroy_func func)
943{
944 assert(data == NULL || buffer->user_data == NULL);
945
946 buffer->user_data = data;
947 buffer->user_data_destroy_func = func;
948}
949
950/** Get renderer-private data
951 *
952 * Get the user data from the linux_dmabuf_buffer.
953 *
954 * \param buffer The linux_dmabuf_buffer to query.
955 * \return Renderer-private data pointer.
956 *
957 * \sa linux_dmabuf_buffer_set_user_data
958 */
959WL_EXPORT void *
960linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer)
961{
962 return buffer->user_data;
963}
964
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800965static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_implementation = {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400966 linux_dmabuf_destroy,
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300967 linux_dmabuf_create_params,
968 linux_dmabuf_get_default_feedback,
969 linux_dmabuf_get_per_surface_feedback
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400970};
971
972static void
973bind_linux_dmabuf(struct wl_client *client,
974 void *data, uint32_t version, uint32_t id)
975{
976 struct weston_compositor *compositor = data;
Leandro Ribeiro1b403262021-03-04 17:47:13 -0300977 const struct weston_drm_format_array *supported_formats;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400978 struct wl_resource *resource;
Leandro Ribeiro1b403262021-03-04 17:47:13 -0300979 struct weston_drm_format *fmt;
980 const uint64_t *modifiers;
981 unsigned int num_modifiers;
982 unsigned int i;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400983
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800984 resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400985 version, id);
986 if (resource == NULL) {
987 wl_client_post_no_memory(client);
988 return;
989 }
990
991 wl_resource_set_implementation(resource, &linux_dmabuf_implementation,
992 compositor, NULL);
993
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300994 /* Advertise formats/modifiers. From version 4 onwards, we should not send
995 * zwp_linux_dmabuf_v1_send_modifier and zwp_linux_dmabuf_v1_send_format
996 * events, instead we must send the dma-buf feedback events. */
997 if (version >= 4)
998 return;
999
Leandro Ribeiro18f53ab2021-10-18 11:27:54 -03001000 /* If we got here, it means that the renderer is able to import dma-buf
1001 * buffers, and so it must have get_supported_formats() set. */
1002 assert(compositor->renderer->get_supported_formats != NULL);
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001003 supported_formats = compositor->renderer->get_supported_formats(compositor);
Leandro Ribeiro18f53ab2021-10-18 11:27:54 -03001004
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001005 wl_array_for_each(fmt, &supported_formats->arr) {
1006 modifiers = weston_drm_format_get_modifiers(fmt, &num_modifiers);
leng.fang32af9fc2024-06-13 11:22:15 +08001007 if (fmt->format == DRM_FORMAT_NV12 || fmt->format == DRM_FORMAT_NV21) {
1008 if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION)
1009 zwp_linux_dmabuf_v1_send_modifier(resource, fmt->format, 0, 0);
1010 else
1011 zwp_linux_dmabuf_v1_send_format(resource, fmt->format);
1012 continue;
1013 }
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001014 for (i = 0; i < num_modifiers; i++) {
Michael Tretterb0a749d2018-01-17 17:54:31 +01001015 if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001016 uint32_t modifier_lo = modifiers[i] & 0xFFFFFFFF;
1017 uint32_t modifier_hi = modifiers[i] >> 32;
Michael Tretterb0a749d2018-01-17 17:54:31 +01001018 zwp_linux_dmabuf_v1_send_modifier(resource,
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001019 fmt->format,
Michael Tretterb0a749d2018-01-17 17:54:31 +01001020 modifier_hi,
1021 modifier_lo);
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001022 } else if (modifiers[i] == DRM_FORMAT_MOD_LINEAR ||
1023 modifiers[i] == DRM_FORMAT_MOD_INVALID) {
Michael Tretterb0a749d2018-01-17 17:54:31 +01001024 zwp_linux_dmabuf_v1_send_format(resource,
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001025 fmt->format);
Michael Tretterb0a749d2018-01-17 17:54:31 +01001026 }
Varad Gautam41b4b8f2017-04-26 19:17:17 +05301027 }
Varad Gautam41b4b8f2017-04-26 19:17:17 +05301028 }
Pekka Paalanen230f3b12014-09-29 14:18:40 -04001029}
1030
1031/** Advertise linux_dmabuf support
1032 *
Jonas Ådahl57e48f02015-11-17 16:00:28 +08001033 * Calling this initializes the zwp_linux_dmabuf protocol support, so that
Pekka Paalanen230f3b12014-09-29 14:18:40 -04001034 * the interface will be advertised to clients. Essentially it creates a
1035 * global. Do not call this function multiple times in the compositor's
1036 * lifetime. There is no way to deinit explicitly, globals will be reaped
1037 * when the wl_display gets destroyed.
1038 *
1039 * \param compositor The compositor to init for.
1040 * \return Zero on success, -1 on failure.
1041 */
1042WL_EXPORT int
1043linux_dmabuf_setup(struct weston_compositor *compositor)
1044{
Leandro Ribeiro8eb84142021-01-18 19:36:48 -03001045 int max_version;
1046
1047 /* If we were able to create the default dma-buf feedback for the
1048 * compositor, that means that we are able to advertise dma-buf feedback
1049 * events. In such case we support the version 4 of the protocol. */
1050 max_version = compositor->default_dmabuf_feedback ? 4 : 3;
1051
Pekka Paalanen230f3b12014-09-29 14:18:40 -04001052 if (!wl_global_create(compositor->wl_display,
Leandro Ribeiro8eb84142021-01-18 19:36:48 -03001053 &zwp_linux_dmabuf_v1_interface,
1054 max_version, compositor, bind_linux_dmabuf))
Pekka Paalanen230f3b12014-09-29 14:18:40 -04001055 return -1;
1056
1057 return 0;
1058}
1059
1060/** Resolve an internal compositor error by disconnecting the client.
1061 *
1062 * This function is used in cases when the dmabuf-based wl_buffer
1063 * turns out unusable and there is no fallback path. This is used by
1064 * renderers which are the fallback path in the first place.
1065 *
1066 * It is possible the fault is caused by a compositor bug, the underlying
1067 * graphics stack bug or normal behaviour, or perhaps a client mistake.
1068 * In any case, the options are to either composite garbage or nothing,
1069 * or disconnect the client. This is a helper function for the latter.
1070 *
Bryce Harringtonba63fae2016-07-06 15:30:54 -07001071 * The error is sent as an INVALID_OBJECT error on the client's wl_display.
Pekka Paalanen230f3b12014-09-29 14:18:40 -04001072 *
1073 * \param buffer The linux_dmabuf_buffer that is unusable.
1074 * \param msg A custom error message attached to the protocol error.
1075 */
1076WL_EXPORT void
1077linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
1078 const char *msg)
1079{
1080 struct wl_client *client;
1081 struct wl_resource *display_resource;
1082 uint32_t id;
1083
1084 assert(buffer->buffer_resource);
1085 id = wl_resource_get_id(buffer->buffer_resource);
1086 client = wl_resource_get_client(buffer->buffer_resource);
1087 display_resource = wl_client_get_object(client, 1);
1088
1089 assert(display_resource);
1090 wl_resource_post_error(display_resource,
1091 WL_DISPLAY_ERROR_INVALID_OBJECT,
1092 "linux_dmabuf server error with "
1093 "wl_buffer@%u: %s", id, msg);
1094}