blob: 083f4e7247c2ee2ebbca2c4009189ac1deef4596 [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
207 if (width < 1 || height < 1) {
208 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800209 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400210 "invalid width %d or height %d", width, height);
211 goto err_out;
212 }
213
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000214 for (i = 0; i < buffer->attributes.n_planes; i++) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400215 off_t size;
216
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000217 if ((uint64_t) buffer->attributes.offset[i] + buffer->attributes.stride[i] > UINT32_MAX) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400218 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800219 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400220 "size overflow for plane %i", i);
221 goto err_out;
222 }
223
224 if (i == 0 &&
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000225 (uint64_t) buffer->attributes.offset[i] +
226 (uint64_t) buffer->attributes.stride[i] * height > UINT32_MAX) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400227 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800228 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400229 "size overflow for plane %i", i);
230 goto err_out;
231 }
232
233 /* Don't report an error as it might be caused
234 * by the kernel not supporting seeking on dmabuf */
leng.fang32af9fc2024-06-13 11:22:15 +0800235 if (buffer->direct_display) {
236 weston_log("\n direct_display. remove parameter check and gpu import \n");
237 goto avoid_gpu_import;
238 }
239
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000240 size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400241 if (size == -1)
Derek Foremanc06389a2016-04-25 09:23:24 -0500242 continue;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400243
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000244 if (buffer->attributes.offset[i] >= size) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400245 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800246 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400247 "invalid offset %i for plane %i",
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000248 buffer->attributes.offset[i], i);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400249 goto err_out;
250 }
251
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000252 if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400253 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800254 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400255 "invalid stride %i for plane %i",
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000256 buffer->attributes.stride[i], i);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400257 goto err_out;
258 }
leng.fang32af9fc2024-06-13 11:22:15 +0800259 weston_log("\n %s %d offset:%d, stride:%d height:%d,size:%d\n", __FUNCTION__, __LINE__,
260 buffer->attributes.offset[i], buffer->attributes.stride[i], height, size);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400261 /* Only valid for first plane as other planes might be
262 * sub-sampled according to fourcc format */
263 if (i == 0 &&
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000264 buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400265 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800266 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400267 "invalid buffer stride or height for plane %i", i);
268 goto err_out;
269 }
270 }
271
Marius Vlad5a701542019-11-16 20:26:52 +0200272 if (buffer->direct_display) {
273 if (!weston_compositor_dmabuf_can_scanout(buffer->compositor,
274 buffer))
275 goto err_failed;
276
277 goto avoid_gpu_import;
278 }
279
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400280 if (!weston_compositor_import_dmabuf(buffer->compositor, buffer))
281 goto err_failed;
282
Marius Vlad5a701542019-11-16 20:26:52 +0200283avoid_gpu_import:
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400284 buffer->buffer_resource = wl_resource_create(client,
285 &wl_buffer_interface,
Varad Gautam65c94b82017-04-26 19:15:59 +0530286 1, buffer_id);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400287 if (!buffer->buffer_resource) {
288 wl_resource_post_no_memory(params_resource);
289 goto err_buffer;
290 }
291
292 wl_resource_set_implementation(buffer->buffer_resource,
293 &linux_dmabuf_buffer_implementation,
294 buffer, destroy_linux_dmabuf_wl_buffer);
295
Varad Gautam65c94b82017-04-26 19:15:59 +0530296 /* send 'created' event when the request is not for an immediate
297 * import, ie buffer_id is zero */
298 if (buffer_id == 0)
299 zwp_linux_buffer_params_v1_send_created(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800300 buffer->buffer_resource);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400301
302 return;
303
304err_buffer:
305 if (buffer->user_data_destroy_func)
306 buffer->user_data_destroy_func(buffer);
307
308err_failed:
Varad Gautam65c94b82017-04-26 19:15:59 +0530309 if (buffer_id == 0)
310 zwp_linux_buffer_params_v1_send_failed(params_resource);
311 else
312 /* since the behavior is left implementation defined by the
313 * protocol in case of create_immed failure due to an unknown cause,
314 * we choose to treat it as a fatal error and immediately kill the
315 * client instead of creating an invalid handle and waiting for it
316 * to be used.
317 */
318 wl_resource_post_error(params_resource,
319 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
320 "importing the supplied dmabufs failed");
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400321
322err_out:
323 linux_dmabuf_buffer_destroy(buffer);
324}
325
Varad Gautam65c94b82017-04-26 19:15:59 +0530326static void
327params_create(struct wl_client *client,
328 struct wl_resource *params_resource,
329 int32_t width,
330 int32_t height,
331 uint32_t format,
332 uint32_t flags)
333{
334 params_create_common(client, params_resource, 0, width, height, format,
335 flags);
336}
337
338static void
339params_create_immed(struct wl_client *client,
340 struct wl_resource *params_resource,
341 uint32_t buffer_id,
342 int32_t width,
343 int32_t height,
344 uint32_t format,
345 uint32_t flags)
346{
347 params_create_common(client, params_resource, buffer_id, width, height,
348 format, flags);
349}
350
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800351static const struct zwp_linux_buffer_params_v1_interface
352zwp_linux_buffer_params_implementation = {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400353 params_destroy,
354 params_add,
Varad Gautam65c94b82017-04-26 19:15:59 +0530355 params_create,
356 params_create_immed
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400357};
358
359static void
360linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource)
361{
362 wl_resource_destroy(resource);
363}
364
365static void
366linux_dmabuf_create_params(struct wl_client *client,
367 struct wl_resource *linux_dmabuf_resource,
368 uint32_t params_id)
369{
370 struct weston_compositor *compositor;
371 struct linux_dmabuf_buffer *buffer;
372 uint32_t version;
373 int i;
374
375 version = wl_resource_get_version(linux_dmabuf_resource);
376 compositor = wl_resource_get_user_data(linux_dmabuf_resource);
377
378 buffer = zalloc(sizeof *buffer);
379 if (!buffer)
380 goto err_out;
381
382 for (i = 0; i < MAX_DMABUF_PLANES; i++)
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000383 buffer->attributes.fd[i] = -1;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400384
385 buffer->compositor = compositor;
386 buffer->params_resource =
387 wl_resource_create(client,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800388 &zwp_linux_buffer_params_v1_interface,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400389 version, params_id);
Marius Vlad5a701542019-11-16 20:26:52 +0200390 buffer->direct_display = false;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400391 if (!buffer->params_resource)
392 goto err_dealloc;
393
394 wl_resource_set_implementation(buffer->params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800395 &zwp_linux_buffer_params_implementation,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400396 buffer, destroy_params);
397
398 return;
399
400err_dealloc:
401 free(buffer);
402
403err_out:
404 wl_resource_post_no_memory(linux_dmabuf_resource);
405}
406
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300407/** Creates dma-buf feedback tranche
408 *
409 * The tranche is added to dma-buf feedback's tranche list
410 *
411 * @param dmabuf_feedback The dma-buf feedback object to which the tranche is added
412 * @param format_table The dma-buf feedback formats table
413 * @param target_device The target device of the new tranche
414 * @param flags The flags of the new tranche
415 * @param preference The preference of the new tranche
416 * @return The tranche created, or NULL on failure
417 */
418WL_EXPORT struct weston_dmabuf_feedback_tranche *
419weston_dmabuf_feedback_tranche_create(struct weston_dmabuf_feedback *dmabuf_feedback,
420 struct weston_dmabuf_feedback_format_table *format_table,
421 dev_t target_device, uint32_t flags,
422 enum weston_dmabuf_feedback_tranche_preference preference)
423{
424 struct weston_dmabuf_feedback_tranche *tranche, *ptr;
425 struct wl_list *pos;
426
427 tranche = zalloc(sizeof(*tranche));
428 if (!tranche) {
429 weston_log("%s: out of memory\n", __func__);
430 return NULL;
431 }
432
Leandro Ribeiro54293022021-10-12 14:48:36 -0300433 tranche->active = true;
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300434 tranche->target_device = target_device;
435 tranche->flags = flags;
436 tranche->preference = preference;
437
438 /* Get the formats indices array */
439 if (flags == 0) {
440 if (wl_array_copy(&tranche->formats_indices,
441 &format_table->renderer_formats_indices) < 0) {
442 weston_log("%s: out of memory\n", __func__);
443 goto err;
444 }
445 } else if (flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT) {
Leandro Ribeiro54293022021-10-12 14:48:36 -0300446 if (wl_array_copy(&tranche->formats_indices,
447 &format_table->scanout_formats_indices) < 0) {
448 weston_log("%s: out of memory\n", __func__);
449 goto err;
450 }
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300451 } else {
452 weston_log("error: for now we just have renderer and scanout "
453 "tranches, can't create other type of tranche\n");
454 goto err;
455 }
456
457 /* The list of tranches is ordered by preference.
458 * Highest preference comes first. */
459 pos = &dmabuf_feedback->tranche_list;
460 wl_list_for_each(ptr, &dmabuf_feedback->tranche_list, link) {
461 pos = &ptr->link;
462 if (ptr->preference <= tranche->preference)
463 break;
464 }
465 wl_list_insert(pos->prev, &tranche->link);
466
467 return tranche;
468
469err:
470 free(tranche);
471 return NULL;
472}
473
474static void
475weston_dmabuf_feedback_tranche_destroy(struct weston_dmabuf_feedback_tranche *tranche)
476{
477 wl_array_release(&tranche->formats_indices);
478 wl_list_remove(&tranche->link);
479 free(tranche);
480}
481
482static int
483format_table_add_renderer_formats(struct weston_dmabuf_feedback_format_table *format_table,
484 const struct weston_drm_format_array *renderer_formats)
485{
486 struct weston_drm_format *fmt;
487 unsigned int num_modifiers;
488 const uint64_t *modifiers;
489 uint16_t index, *index_ptr;
490 unsigned int size;
491 unsigned int i;
492
493 size = sizeof(index) *
494 weston_drm_format_array_count_pairs(renderer_formats);
495
496 if (!wl_array_add(&format_table->renderer_formats_indices, size)) {
497 weston_log("%s: out of memory\n", __func__);
498 return -1;
499 }
500
501 index = 0;
502 wl_array_for_each(fmt, &renderer_formats->arr) {
503 modifiers = weston_drm_format_get_modifiers(fmt, &num_modifiers);
504 for (i = 0; i < num_modifiers; i++) {
505 format_table->data[index].format = fmt->format;
506 format_table->data[index].modifier = modifiers[i];
507 index++;
508 }
509 }
510
511 index = 0;
512 wl_array_for_each(index_ptr, &format_table->renderer_formats_indices)
513 *index_ptr = index++;
514
515 return 0;
516}
517
518/** Creates dma-buf feedback format table
519 *
520 * @param renderer_formats The formats that compose the table
521 * @return The dma-buf feedback format table, or NULL on failure
522 */
523WL_EXPORT struct weston_dmabuf_feedback_format_table *
524weston_dmabuf_feedback_format_table_create(const struct weston_drm_format_array *renderer_formats)
525{
526 struct weston_dmabuf_feedback_format_table *format_table;
527 int ret;
528
529 format_table = zalloc(sizeof(*format_table));
530 if (!format_table) {
531 weston_log("%s: out of memory\n", __func__);
532 return NULL;
533 }
534 wl_array_init(&format_table->renderer_formats_indices);
Leandro Ribeiro54293022021-10-12 14:48:36 -0300535 wl_array_init(&format_table->scanout_formats_indices);
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300536
537 /* Creates formats file table and mmap it */
538 format_table->size = weston_drm_format_array_count_pairs(renderer_formats) *
539 sizeof(*format_table->data);
540 format_table->fd = os_create_anonymous_file(format_table->size);
541 if (format_table->fd < 0) {
542 weston_log("error: failed to create format table file: %s\n",
543 strerror(errno));
544 goto err_fd;
545 }
546 format_table->data = mmap(NULL, format_table->size, PROT_READ | PROT_WRITE,
547 MAP_SHARED, format_table->fd, 0);
548 if (format_table->data == MAP_FAILED) {
549 weston_log("error: mmap for format table failed: %s\n",
550 strerror(errno));
551 goto err_mmap;
552 }
553
554 /* Add renderer formats to file table */
555 ret = format_table_add_renderer_formats(format_table, renderer_formats);
556 if (ret < 0)
557 goto err_formats;
558
559 return format_table;
560
561err_formats:
562 munmap(format_table->data, format_table->size);
563err_mmap:
564 close(format_table->fd);
565err_fd:
566 wl_array_release(&format_table->renderer_formats_indices);
567 free(format_table);
568 return NULL;
569}
570
571/** Destroys dma-buf feedback formats table
572 *
573 * @param format_table The dma-buf feedback format table to destroy
574 */
575WL_EXPORT void
576weston_dmabuf_feedback_format_table_destroy(struct weston_dmabuf_feedback_format_table *format_table)
577{
578 wl_array_release(&format_table->renderer_formats_indices);
Leandro Ribeiro54293022021-10-12 14:48:36 -0300579 wl_array_release(&format_table->scanout_formats_indices);
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300580
581 munmap(format_table->data, format_table->size);
582 close(format_table->fd);
583
584 free(format_table);
585}
586
Leandro Ribeiro54293022021-10-12 14:48:36 -0300587static int
588format_table_get_format_index(struct weston_dmabuf_feedback_format_table *format_table,
589 uint32_t format, uint64_t modifier, uint16_t *index_out)
590{
591 uint16_t index;
592 unsigned int num_elements = format_table->size / sizeof(index);
593
594 for (index = 0; index < num_elements; index++) {
595 if (format_table->data[index].format == format &&
596 format_table->data[index].modifier == modifier) {
597 *index_out = index;
598 return 0;
599 }
600 }
601
602 return -1;
603}
604
605/** Set scanout formats indices in the dma-buf feedback format table
606 *
607 * The table consists of the formats supported by the renderer. A dma-buf
608 * feedback scanout tranche consists of the union of the KMS plane's formats
609 * intersected with the renderer formats. With this function we compute the
610 * indices of these plane's formats in the table and save them in the
611 * table->scanout_formats_indices, allowing us to create scanout tranches.
612 *
613 * @param format_table The dma-buf feedback format table
614 * @param scanout_formats The scanout formats
615 * @return 0 on success, -1 on failure
616 */
617WL_EXPORT int
618weston_dmabuf_feedback_format_table_set_scanout_indices(struct weston_dmabuf_feedback_format_table *format_table,
619 const struct weston_drm_format_array *scanout_formats)
620{
621 struct weston_drm_format *fmt;
622 unsigned int num_modifiers;
623 const uint64_t *modifiers;
624 uint16_t index, *index_ptr;
625 unsigned int i;
626 int ret;
627
628 wl_array_for_each(fmt, &scanout_formats->arr) {
629 modifiers = weston_drm_format_get_modifiers(fmt, &num_modifiers);
630 for (i = 0; i < num_modifiers; i++) {
631 index_ptr =
632 wl_array_add(&format_table->scanout_formats_indices,
633 sizeof(index));
634 if (!index_ptr)
635 goto err;
636
637 ret = format_table_get_format_index(format_table, fmt->format,
638 modifiers[i], &index);
639 if (ret < 0)
640 goto err;
641
642 *index_ptr = index;
643 }
644 }
645
646 return 0;
647
648err:
649 wl_array_release(&format_table->scanout_formats_indices);
650 wl_array_init(&format_table->scanout_formats_indices);
651 return -1;
652}
653
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300654/** Creates dma-buf feedback object
655 *
656 * @param main_device The main device of the dma-buf feedback
657 * @return The dma-buf feedback object created, or NULL on failure
658 */
659WL_EXPORT struct weston_dmabuf_feedback *
660weston_dmabuf_feedback_create(dev_t main_device)
661{
662 struct weston_dmabuf_feedback *dmabuf_feedback;
663
664 dmabuf_feedback = zalloc(sizeof(*dmabuf_feedback));
665 if (!dmabuf_feedback) {
666 weston_log("%s: out of memory\n", __func__);
667 return NULL;
668 }
669
670 dmabuf_feedback->main_device = main_device;
671 wl_list_init(&dmabuf_feedback->tranche_list);
672 wl_list_init(&dmabuf_feedback->resource_list);
673
674 return dmabuf_feedback;
675}
676
677/** Destroy dma-buf feedback object
678 *
679 * @param dmabuf_feedback The dma-buf feedback object to destroy
680 */
681WL_EXPORT void
682weston_dmabuf_feedback_destroy(struct weston_dmabuf_feedback *dmabuf_feedback)
683{
684 struct weston_dmabuf_feedback_tranche *tranche, *tranche_tmp;
685 struct wl_resource *res, *res_tmp;
686
687 wl_list_for_each_safe(tranche, tranche_tmp, &dmabuf_feedback->tranche_list, link)
688 weston_dmabuf_feedback_tranche_destroy(tranche);
689
690 wl_resource_for_each_safe(res, res_tmp, &dmabuf_feedback->resource_list) {
691 wl_list_remove(wl_resource_get_link(res));
692 wl_list_init(wl_resource_get_link(res));
693 }
694
695 free(dmabuf_feedback);
696}
697
Leandro Ribeiro54293022021-10-12 14:48:36 -0300698/** Find tranche in a dma-buf feedback object
699 *
700 * @param dmabuf_feedback The dma-buf feedback object where to look for
701 * @param target_device The target device of the tranche
702 * @param flags The flags of the tranche
703 * @param preference The preference of the tranche
704 * @return The tranche, or NULL if it was not found
705 */
706WL_EXPORT struct weston_dmabuf_feedback_tranche *
707weston_dmabuf_feedback_find_tranche(struct weston_dmabuf_feedback *dmabuf_feedback,
708 dev_t target_device, uint32_t flags,
709 enum weston_dmabuf_feedback_tranche_preference preference)
710{
711 struct weston_dmabuf_feedback_tranche *tranche;
712
713 wl_list_for_each(tranche, &dmabuf_feedback->tranche_list, link)
714 if (tranche->target_device == target_device &&
715 tranche->flags == flags && tranche->preference == preference)
716 return tranche;
717
718 return NULL;
719}
720
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300721static void
722weston_dmabuf_feedback_send(struct weston_dmabuf_feedback *dmabuf_feedback,
723 struct weston_dmabuf_feedback_format_table *format_table,
724 struct wl_resource *res, bool advertise_format_table)
725{
726 struct weston_dmabuf_feedback_tranche *tranche;
727 struct wl_array device;
728 dev_t *dev;
729
730 /* main_device and target_device events need a dev_t as parameter,
731 * but we can't use this directly to communicate with the Wayland
732 * client. The solution is to use a wl_array, which is supported by
733 * Wayland, and add the dev_t as an element of the array. */
734 wl_array_init(&device);
735 dev = wl_array_add(&device, sizeof(*dev));
736 if (!dev) {
737 wl_resource_post_no_memory(res);
738 return;
739 }
740
741 /* format_table event - In Weston, we never modify the dma-buf feedback
742 * format table. So we have this flag in order to advertise the format
743 * table only if the client has just subscribed to receive the events
744 * for this feedback object. When we need to re-send the feedback events
745 * for this client, the table event won't be sent. */
746 if (advertise_format_table)
747 zwp_linux_dmabuf_feedback_v1_send_format_table(res, format_table->fd,
748 format_table->size);
749
750 /* main_device event */
751 *dev = dmabuf_feedback->main_device;
752 zwp_linux_dmabuf_feedback_v1_send_main_device(res, &device);
753
754 /* send events for each tranche */
755 wl_list_for_each(tranche, &dmabuf_feedback->tranche_list, link) {
Leandro Ribeiro54293022021-10-12 14:48:36 -0300756 if (!tranche->active)
757 continue;
758
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300759 /* tranche_target_device event */
760 *dev = tranche->target_device;
761 zwp_linux_dmabuf_feedback_v1_send_tranche_target_device(res, &device);
762
763 /* tranche_flags event */
764 zwp_linux_dmabuf_feedback_v1_send_tranche_flags(res, tranche->flags);
765
766 /* tranche_formats event */
767 zwp_linux_dmabuf_feedback_v1_send_tranche_formats(res, &tranche->formats_indices);
768
769 /* tranche_done_event */
770 zwp_linux_dmabuf_feedback_v1_send_tranche_done(res);
771 }
772
773 /* compositor_done_event */
774 zwp_linux_dmabuf_feedback_v1_send_done(res);
775
776 wl_array_release(&device);
777}
778
Leandro Ribeiro54293022021-10-12 14:48:36 -0300779/** Sends the feedback events for a dma-buf feedback object
780 *
781 * Given a dma-buf feedback object, this will send events to clients that are
782 * subscribed to it. This is useful for the per-surface dma-buf feedback, which
783 * is dynamic and can change throughout compositor's life. These changes results
784 * in the need to resend the feedback events to clients.
785 *
786 * @param dmabuf_feedback The weston_dmabuf_feedback object
787 * @param format_table The dma-buf feedback formats table
788 */
789WL_EXPORT void
790weston_dmabuf_feedback_send_all(struct weston_dmabuf_feedback *dmabuf_feedback,
791 struct weston_dmabuf_feedback_format_table *format_table)
792{
793 struct wl_resource *res;
794
795 wl_resource_for_each(res, &dmabuf_feedback->resource_list)
796 weston_dmabuf_feedback_send(dmabuf_feedback,
797 format_table, res, false);
798}
799
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300800static void
801dmabuf_feedback_resource_destroy(struct wl_resource *resource)
802{
803 wl_list_remove(wl_resource_get_link(resource));
804}
805
806static void
807dmabuf_feedback_destroy(struct wl_client *client, struct wl_resource *resource)
808{
809 wl_resource_destroy(resource);
810}
811
812static const struct zwp_linux_dmabuf_feedback_v1_interface
813zwp_linux_dmabuf_feedback_implementation = {
814 dmabuf_feedback_destroy
815};
816
817static struct wl_resource *
818dmabuf_feedback_resource_create(struct wl_resource *dmabuf_resource,
819 struct wl_client *client, uint32_t dmabuf_feedback_id)
820{
821 struct wl_resource *dmabuf_feedback_res;
822 uint32_t version;
823
824 version = wl_resource_get_version(dmabuf_resource);
825
826 dmabuf_feedback_res =
827 wl_resource_create(client, &zwp_linux_dmabuf_feedback_v1_interface,
828 version, dmabuf_feedback_id);
829 if (!dmabuf_feedback_res)
830 return NULL;
831
832 wl_list_init(wl_resource_get_link(dmabuf_feedback_res));
833 wl_resource_set_implementation(dmabuf_feedback_res,
834 &zwp_linux_dmabuf_feedback_implementation,
835 NULL, dmabuf_feedback_resource_destroy);
836
837 return dmabuf_feedback_res;
838}
839
840static void
841linux_dmabuf_get_default_feedback(struct wl_client *client,
842 struct wl_resource *dmabuf_resource,
843 uint32_t dmabuf_feedback_id)
844{
845 struct weston_compositor *compositor =
846 wl_resource_get_user_data(dmabuf_resource);
847 struct wl_resource *dmabuf_feedback_resource;
848
849 dmabuf_feedback_resource =
850 dmabuf_feedback_resource_create(dmabuf_resource,
851 client, dmabuf_feedback_id);
852 if (!dmabuf_feedback_resource) {
853 wl_resource_post_no_memory(dmabuf_resource);
854 return;
855 }
856
857 weston_dmabuf_feedback_send(compositor->default_dmabuf_feedback,
858 compositor->dmabuf_feedback_format_table,
859 dmabuf_feedback_resource, true);
860}
861
862static void
863linux_dmabuf_get_per_surface_feedback(struct wl_client *client,
864 struct wl_resource *dmabuf_resource,
865 uint32_t dmabuf_feedback_id,
866 struct wl_resource *surface_resource)
867{
868 struct weston_surface *surface =
869 wl_resource_get_user_data(surface_resource);
870 struct wl_resource *dmabuf_feedback_resource;
871
872 dmabuf_feedback_resource =
873 dmabuf_feedback_resource_create(dmabuf_resource,
874 client, dmabuf_feedback_id);
875 if (!dmabuf_feedback_resource) {
876 wl_resource_post_no_memory(dmabuf_resource);
877 return;
878 }
879
880 /* Surface dma-buf feedback is dynamic and may need to be resent to
881 * clients when they change. So we need to keep the resources list */
882 wl_list_insert(&surface->dmabuf_feedback->resource_list,
883 wl_resource_get_link(dmabuf_feedback_resource));
884
885 weston_dmabuf_feedback_send(surface->dmabuf_feedback,
886 surface->compositor->dmabuf_feedback_format_table,
887 dmabuf_feedback_resource, true);
888}
889
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400890/** Get the linux_dmabuf_buffer from a wl_buffer resource
891 *
892 * If the given wl_buffer resource was created through the linux_dmabuf
893 * protocol interface, returns the linux_dmabuf_buffer object. This can
894 * be used as a type check for a wl_buffer.
895 *
896 * \param resource A wl_buffer resource.
897 * \return The linux_dmabuf_buffer if it exists, or NULL otherwise.
898 */
899WL_EXPORT struct linux_dmabuf_buffer *
900linux_dmabuf_buffer_get(struct wl_resource *resource)
901{
902 struct linux_dmabuf_buffer *buffer;
903
904 if (!resource)
905 return NULL;
906
907 if (!wl_resource_instance_of(resource, &wl_buffer_interface,
908 &linux_dmabuf_buffer_implementation))
909 return NULL;
910
911 buffer = wl_resource_get_user_data(resource);
912 assert(buffer);
913 assert(!buffer->params_resource);
914 assert(buffer->buffer_resource == resource);
915
916 return buffer;
917}
918
919/** Set renderer-private data
920 *
921 * Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
922 * a non-NULL user data with a new non-NULL pointer. This is meant to
923 * protect against renderers fighting over linux_dmabuf_buffer user data
924 * ownership.
925 *
926 * The renderer-private data is usually set from the
927 * weston_renderer::import_dmabuf hook.
928 *
929 * \param buffer The linux_dmabuf_buffer object to set for.
930 * \param data The new renderer-private data pointer.
931 * \param func Destructor function to be called for the renderer-private
932 * data when the linux_dmabuf_buffer gets destroyed.
933 *
934 * \sa weston_compositor_import_dmabuf
935 */
936WL_EXPORT void
937linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
938 void *data,
939 dmabuf_user_data_destroy_func func)
940{
941 assert(data == NULL || buffer->user_data == NULL);
942
943 buffer->user_data = data;
944 buffer->user_data_destroy_func = func;
945}
946
947/** Get renderer-private data
948 *
949 * Get the user data from the linux_dmabuf_buffer.
950 *
951 * \param buffer The linux_dmabuf_buffer to query.
952 * \return Renderer-private data pointer.
953 *
954 * \sa linux_dmabuf_buffer_set_user_data
955 */
956WL_EXPORT void *
957linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer)
958{
959 return buffer->user_data;
960}
961
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800962static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_implementation = {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400963 linux_dmabuf_destroy,
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300964 linux_dmabuf_create_params,
965 linux_dmabuf_get_default_feedback,
966 linux_dmabuf_get_per_surface_feedback
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400967};
968
969static void
970bind_linux_dmabuf(struct wl_client *client,
971 void *data, uint32_t version, uint32_t id)
972{
973 struct weston_compositor *compositor = data;
Leandro Ribeiro1b403262021-03-04 17:47:13 -0300974 const struct weston_drm_format_array *supported_formats;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400975 struct wl_resource *resource;
Leandro Ribeiro1b403262021-03-04 17:47:13 -0300976 struct weston_drm_format *fmt;
977 const uint64_t *modifiers;
978 unsigned int num_modifiers;
979 unsigned int i;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400980
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800981 resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400982 version, id);
983 if (resource == NULL) {
984 wl_client_post_no_memory(client);
985 return;
986 }
987
988 wl_resource_set_implementation(resource, &linux_dmabuf_implementation,
989 compositor, NULL);
990
Leandro Ribeiro8eb84142021-01-18 19:36:48 -0300991 /* Advertise formats/modifiers. From version 4 onwards, we should not send
992 * zwp_linux_dmabuf_v1_send_modifier and zwp_linux_dmabuf_v1_send_format
993 * events, instead we must send the dma-buf feedback events. */
994 if (version >= 4)
995 return;
996
Leandro Ribeiro18f53ab2021-10-18 11:27:54 -0300997 /* If we got here, it means that the renderer is able to import dma-buf
998 * buffers, and so it must have get_supported_formats() set. */
999 assert(compositor->renderer->get_supported_formats != NULL);
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001000 supported_formats = compositor->renderer->get_supported_formats(compositor);
Leandro Ribeiro18f53ab2021-10-18 11:27:54 -03001001
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001002 wl_array_for_each(fmt, &supported_formats->arr) {
1003 modifiers = weston_drm_format_get_modifiers(fmt, &num_modifiers);
leng.fang32af9fc2024-06-13 11:22:15 +08001004 if (fmt->format == DRM_FORMAT_NV12 || fmt->format == DRM_FORMAT_NV21) {
1005 if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION)
1006 zwp_linux_dmabuf_v1_send_modifier(resource, fmt->format, 0, 0);
1007 else
1008 zwp_linux_dmabuf_v1_send_format(resource, fmt->format);
1009 continue;
1010 }
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001011 for (i = 0; i < num_modifiers; i++) {
Michael Tretterb0a749d2018-01-17 17:54:31 +01001012 if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001013 uint32_t modifier_lo = modifiers[i] & 0xFFFFFFFF;
1014 uint32_t modifier_hi = modifiers[i] >> 32;
Michael Tretterb0a749d2018-01-17 17:54:31 +01001015 zwp_linux_dmabuf_v1_send_modifier(resource,
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001016 fmt->format,
Michael Tretterb0a749d2018-01-17 17:54:31 +01001017 modifier_hi,
1018 modifier_lo);
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001019 } else if (modifiers[i] == DRM_FORMAT_MOD_LINEAR ||
1020 modifiers[i] == DRM_FORMAT_MOD_INVALID) {
Michael Tretterb0a749d2018-01-17 17:54:31 +01001021 zwp_linux_dmabuf_v1_send_format(resource,
Leandro Ribeiro1b403262021-03-04 17:47:13 -03001022 fmt->format);
Michael Tretterb0a749d2018-01-17 17:54:31 +01001023 }
Varad Gautam41b4b8f2017-04-26 19:17:17 +05301024 }
Varad Gautam41b4b8f2017-04-26 19:17:17 +05301025 }
Pekka Paalanen230f3b12014-09-29 14:18:40 -04001026}
1027
1028/** Advertise linux_dmabuf support
1029 *
Jonas Ådahl57e48f02015-11-17 16:00:28 +08001030 * Calling this initializes the zwp_linux_dmabuf protocol support, so that
Pekka Paalanen230f3b12014-09-29 14:18:40 -04001031 * the interface will be advertised to clients. Essentially it creates a
1032 * global. Do not call this function multiple times in the compositor's
1033 * lifetime. There is no way to deinit explicitly, globals will be reaped
1034 * when the wl_display gets destroyed.
1035 *
1036 * \param compositor The compositor to init for.
1037 * \return Zero on success, -1 on failure.
1038 */
1039WL_EXPORT int
1040linux_dmabuf_setup(struct weston_compositor *compositor)
1041{
Leandro Ribeiro8eb84142021-01-18 19:36:48 -03001042 int max_version;
1043
1044 /* If we were able to create the default dma-buf feedback for the
1045 * compositor, that means that we are able to advertise dma-buf feedback
1046 * events. In such case we support the version 4 of the protocol. */
1047 max_version = compositor->default_dmabuf_feedback ? 4 : 3;
1048
Pekka Paalanen230f3b12014-09-29 14:18:40 -04001049 if (!wl_global_create(compositor->wl_display,
Leandro Ribeiro8eb84142021-01-18 19:36:48 -03001050 &zwp_linux_dmabuf_v1_interface,
1051 max_version, compositor, bind_linux_dmabuf))
Pekka Paalanen230f3b12014-09-29 14:18:40 -04001052 return -1;
1053
1054 return 0;
1055}
1056
1057/** Resolve an internal compositor error by disconnecting the client.
1058 *
1059 * This function is used in cases when the dmabuf-based wl_buffer
1060 * turns out unusable and there is no fallback path. This is used by
1061 * renderers which are the fallback path in the first place.
1062 *
1063 * It is possible the fault is caused by a compositor bug, the underlying
1064 * graphics stack bug or normal behaviour, or perhaps a client mistake.
1065 * In any case, the options are to either composite garbage or nothing,
1066 * or disconnect the client. This is a helper function for the latter.
1067 *
Bryce Harringtonba63fae2016-07-06 15:30:54 -07001068 * The error is sent as an INVALID_OBJECT error on the client's wl_display.
Pekka Paalanen230f3b12014-09-29 14:18:40 -04001069 *
1070 * \param buffer The linux_dmabuf_buffer that is unusable.
1071 * \param msg A custom error message attached to the protocol error.
1072 */
1073WL_EXPORT void
1074linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
1075 const char *msg)
1076{
1077 struct wl_client *client;
1078 struct wl_resource *display_resource;
1079 uint32_t id;
1080
1081 assert(buffer->buffer_resource);
1082 id = wl_resource_get_id(buffer->buffer_resource);
1083 client = wl_resource_get_client(buffer->buffer_resource);
1084 display_resource = wl_client_get_object(client, 1);
1085
1086 assert(display_resource);
1087 wl_resource_post_error(display_resource,
1088 WL_DISPLAY_ERROR_INVALID_OBJECT,
1089 "linux_dmabuf server error with "
1090 "wl_buffer@%u: %s", id, msg);
1091}