blob: cdfba41afd994684f96516be28222cb75f3d1e15 [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>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030029#include <stdint.h>
Pekka Paalanen230f3b12014-09-29 14:18:40 -040030#include <unistd.h>
31#include <sys/types.h>
32
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020033#include <libweston/libweston.h>
Pekka Paalanen230f3b12014-09-29 14:18:40 -040034#include "linux-dmabuf.h"
Jonas Ådahl57e48f02015-11-17 16:00:28 +080035#include "linux-dmabuf-unstable-v1-server-protocol.h"
Marius Vlad56f3a682019-07-10 14:48:39 +030036#include "libweston-internal.h"
Pekka Paalanen4b301fe2021-02-04 17:39:45 +020037#include "shared/weston-drm-fourcc.h"
Pekka Paalanen230f3b12014-09-29 14:18:40 -040038
39static void
40linux_dmabuf_buffer_destroy(struct linux_dmabuf_buffer *buffer)
41{
42 int i;
43
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +000044 for (i = 0; i < buffer->attributes.n_planes; i++) {
45 close(buffer->attributes.fd[i]);
46 buffer->attributes.fd[i] = -1;
Pekka Paalanen230f3b12014-09-29 14:18:40 -040047 }
48
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +000049 buffer->attributes.n_planes = 0;
Pekka Paalanen230f3b12014-09-29 14:18:40 -040050 free(buffer);
51}
52
53static void
54destroy_params(struct wl_resource *params_resource)
55{
56 struct linux_dmabuf_buffer *buffer;
57
58 buffer = wl_resource_get_user_data(params_resource);
59
60 if (!buffer)
61 return;
62
63 linux_dmabuf_buffer_destroy(buffer);
64}
65
66static void
67params_destroy(struct wl_client *client, struct wl_resource *resource)
68{
69 wl_resource_destroy(resource);
70}
71
72static void
73params_add(struct wl_client *client,
74 struct wl_resource *params_resource,
75 int32_t name_fd,
76 uint32_t plane_idx,
77 uint32_t offset,
78 uint32_t stride,
79 uint32_t modifier_hi,
80 uint32_t modifier_lo)
81{
82 struct linux_dmabuf_buffer *buffer;
83
84 buffer = wl_resource_get_user_data(params_resource);
85 if (!buffer) {
86 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +080087 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
Pekka Paalanen230f3b12014-09-29 14:18:40 -040088 "params was already used to create a wl_buffer");
89 close(name_fd);
90 return;
91 }
92
93 assert(buffer->params_resource == params_resource);
94 assert(!buffer->buffer_resource);
95
96 if (plane_idx >= MAX_DMABUF_PLANES) {
97 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +080098 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
Pekka Paalanen230f3b12014-09-29 14:18:40 -040099 "plane index %u is too high", plane_idx);
100 close(name_fd);
101 return;
102 }
103
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000104 if (buffer->attributes.fd[plane_idx] != -1) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400105 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800106 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400107 "a dmabuf has already been added for plane %u",
108 plane_idx);
109 close(name_fd);
110 return;
111 }
112
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000113 buffer->attributes.fd[plane_idx] = name_fd;
114 buffer->attributes.offset[plane_idx] = offset;
115 buffer->attributes.stride[plane_idx] = stride;
Emre Ucan99ef8162018-01-09 14:00:30 +0100116
117 if (wl_resource_get_version(params_resource) < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION)
118 buffer->attributes.modifier[plane_idx] = DRM_FORMAT_MOD_INVALID;
119 else
120 buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) |
121 modifier_lo;
122
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000123 buffer->attributes.n_planes++;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400124}
125
126static void
127linux_dmabuf_wl_buffer_destroy(struct wl_client *client,
128 struct wl_resource *resource)
129{
130 wl_resource_destroy(resource);
131}
132
133static const struct wl_buffer_interface linux_dmabuf_buffer_implementation = {
134 linux_dmabuf_wl_buffer_destroy
135};
136
137static void
138destroy_linux_dmabuf_wl_buffer(struct wl_resource *resource)
139{
140 struct linux_dmabuf_buffer *buffer;
141
142 buffer = wl_resource_get_user_data(resource);
143 assert(buffer->buffer_resource == resource);
144 assert(!buffer->params_resource);
145
146 if (buffer->user_data_destroy_func)
147 buffer->user_data_destroy_func(buffer);
148
149 linux_dmabuf_buffer_destroy(buffer);
150}
151
152static void
Varad Gautam65c94b82017-04-26 19:15:59 +0530153params_create_common(struct wl_client *client,
154 struct wl_resource *params_resource,
155 uint32_t buffer_id,
156 int32_t width,
157 int32_t height,
158 uint32_t format,
159 uint32_t flags)
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400160{
161 struct linux_dmabuf_buffer *buffer;
162 int i;
163
164 buffer = wl_resource_get_user_data(params_resource);
165
166 if (!buffer) {
167 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800168 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400169 "params was already used to create a wl_buffer");
170 return;
171 }
172
173 assert(buffer->params_resource == params_resource);
174 assert(!buffer->buffer_resource);
175
176 /* Switch the linux_dmabuf_buffer object from params resource to
177 * eventually wl_buffer resource.
178 */
179 wl_resource_set_user_data(buffer->params_resource, NULL);
180 buffer->params_resource = NULL;
181
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000182 if (!buffer->attributes.n_planes) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400183 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800184 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400185 "no dmabuf has been added to the params");
186 goto err_out;
187 }
188
189 /* Check for holes in the dmabufs set (e.g. [0, 1, 3]) */
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000190 for (i = 0; i < buffer->attributes.n_planes; i++) {
191 if (buffer->attributes.fd[i] == -1) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400192 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800193 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400194 "no dmabuf has been added for plane %i", i);
195 goto err_out;
196 }
197 }
198
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000199 buffer->attributes.width = width;
200 buffer->attributes.height = height;
201 buffer->attributes.format = format;
202 buffer->attributes.flags = flags;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400203
204 if (width < 1 || height < 1) {
205 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800206 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400207 "invalid width %d or height %d", width, height);
208 goto err_out;
209 }
210
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000211 for (i = 0; i < buffer->attributes.n_planes; i++) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400212 off_t size;
213
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000214 if ((uint64_t) buffer->attributes.offset[i] + buffer->attributes.stride[i] > UINT32_MAX) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400215 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800216 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400217 "size overflow for plane %i", i);
218 goto err_out;
219 }
220
221 if (i == 0 &&
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000222 (uint64_t) buffer->attributes.offset[i] +
223 (uint64_t) buffer->attributes.stride[i] * height > UINT32_MAX) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400224 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800225 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400226 "size overflow for plane %i", i);
227 goto err_out;
228 }
229
230 /* Don't report an error as it might be caused
231 * by the kernel not supporting seeking on dmabuf */
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000232 size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400233 if (size == -1)
Derek Foremanc06389a2016-04-25 09:23:24 -0500234 continue;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400235
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000236 if (buffer->attributes.offset[i] >= size) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400237 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800238 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400239 "invalid offset %i for plane %i",
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000240 buffer->attributes.offset[i], i);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400241 goto err_out;
242 }
243
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000244 if (buffer->attributes.offset[i] + buffer->attributes.stride[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 stride %i for plane %i",
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000248 buffer->attributes.stride[i], i);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400249 goto err_out;
250 }
251
252 /* Only valid for first plane as other planes might be
253 * sub-sampled according to fourcc format */
254 if (i == 0 &&
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000255 buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > 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 buffer stride or height for plane %i", i);
259 goto err_out;
260 }
261 }
262
Marius Vlad5a701542019-11-16 20:26:52 +0200263 if (buffer->direct_display) {
264 if (!weston_compositor_dmabuf_can_scanout(buffer->compositor,
265 buffer))
266 goto err_failed;
267
268 goto avoid_gpu_import;
269 }
270
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400271 if (!weston_compositor_import_dmabuf(buffer->compositor, buffer))
272 goto err_failed;
273
Marius Vlad5a701542019-11-16 20:26:52 +0200274avoid_gpu_import:
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400275 buffer->buffer_resource = wl_resource_create(client,
276 &wl_buffer_interface,
Varad Gautam65c94b82017-04-26 19:15:59 +0530277 1, buffer_id);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400278 if (!buffer->buffer_resource) {
279 wl_resource_post_no_memory(params_resource);
280 goto err_buffer;
281 }
282
283 wl_resource_set_implementation(buffer->buffer_resource,
284 &linux_dmabuf_buffer_implementation,
285 buffer, destroy_linux_dmabuf_wl_buffer);
286
Varad Gautam65c94b82017-04-26 19:15:59 +0530287 /* send 'created' event when the request is not for an immediate
288 * import, ie buffer_id is zero */
289 if (buffer_id == 0)
290 zwp_linux_buffer_params_v1_send_created(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800291 buffer->buffer_resource);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400292
293 return;
294
295err_buffer:
296 if (buffer->user_data_destroy_func)
297 buffer->user_data_destroy_func(buffer);
298
299err_failed:
Varad Gautam65c94b82017-04-26 19:15:59 +0530300 if (buffer_id == 0)
301 zwp_linux_buffer_params_v1_send_failed(params_resource);
302 else
303 /* since the behavior is left implementation defined by the
304 * protocol in case of create_immed failure due to an unknown cause,
305 * we choose to treat it as a fatal error and immediately kill the
306 * client instead of creating an invalid handle and waiting for it
307 * to be used.
308 */
309 wl_resource_post_error(params_resource,
310 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
311 "importing the supplied dmabufs failed");
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400312
313err_out:
314 linux_dmabuf_buffer_destroy(buffer);
315}
316
Varad Gautam65c94b82017-04-26 19:15:59 +0530317static void
318params_create(struct wl_client *client,
319 struct wl_resource *params_resource,
320 int32_t width,
321 int32_t height,
322 uint32_t format,
323 uint32_t flags)
324{
325 params_create_common(client, params_resource, 0, width, height, format,
326 flags);
327}
328
329static void
330params_create_immed(struct wl_client *client,
331 struct wl_resource *params_resource,
332 uint32_t buffer_id,
333 int32_t width,
334 int32_t height,
335 uint32_t format,
336 uint32_t flags)
337{
338 params_create_common(client, params_resource, buffer_id, width, height,
339 format, flags);
340}
341
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800342static const struct zwp_linux_buffer_params_v1_interface
343zwp_linux_buffer_params_implementation = {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400344 params_destroy,
345 params_add,
Varad Gautam65c94b82017-04-26 19:15:59 +0530346 params_create,
347 params_create_immed
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400348};
349
350static void
351linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource)
352{
353 wl_resource_destroy(resource);
354}
355
356static void
357linux_dmabuf_create_params(struct wl_client *client,
358 struct wl_resource *linux_dmabuf_resource,
359 uint32_t params_id)
360{
361 struct weston_compositor *compositor;
362 struct linux_dmabuf_buffer *buffer;
363 uint32_t version;
364 int i;
365
366 version = wl_resource_get_version(linux_dmabuf_resource);
367 compositor = wl_resource_get_user_data(linux_dmabuf_resource);
368
369 buffer = zalloc(sizeof *buffer);
370 if (!buffer)
371 goto err_out;
372
373 for (i = 0; i < MAX_DMABUF_PLANES; i++)
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000374 buffer->attributes.fd[i] = -1;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400375
376 buffer->compositor = compositor;
377 buffer->params_resource =
378 wl_resource_create(client,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800379 &zwp_linux_buffer_params_v1_interface,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400380 version, params_id);
Marius Vlad5a701542019-11-16 20:26:52 +0200381 buffer->direct_display = false;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400382 if (!buffer->params_resource)
383 goto err_dealloc;
384
385 wl_resource_set_implementation(buffer->params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800386 &zwp_linux_buffer_params_implementation,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400387 buffer, destroy_params);
388
389 return;
390
391err_dealloc:
392 free(buffer);
393
394err_out:
395 wl_resource_post_no_memory(linux_dmabuf_resource);
396}
397
398/** Get the linux_dmabuf_buffer from a wl_buffer resource
399 *
400 * If the given wl_buffer resource was created through the linux_dmabuf
401 * protocol interface, returns the linux_dmabuf_buffer object. This can
402 * be used as a type check for a wl_buffer.
403 *
404 * \param resource A wl_buffer resource.
405 * \return The linux_dmabuf_buffer if it exists, or NULL otherwise.
406 */
407WL_EXPORT struct linux_dmabuf_buffer *
408linux_dmabuf_buffer_get(struct wl_resource *resource)
409{
410 struct linux_dmabuf_buffer *buffer;
411
412 if (!resource)
413 return NULL;
414
415 if (!wl_resource_instance_of(resource, &wl_buffer_interface,
416 &linux_dmabuf_buffer_implementation))
417 return NULL;
418
419 buffer = wl_resource_get_user_data(resource);
420 assert(buffer);
421 assert(!buffer->params_resource);
422 assert(buffer->buffer_resource == resource);
423
424 return buffer;
425}
426
427/** Set renderer-private data
428 *
429 * Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
430 * a non-NULL user data with a new non-NULL pointer. This is meant to
431 * protect against renderers fighting over linux_dmabuf_buffer user data
432 * ownership.
433 *
434 * The renderer-private data is usually set from the
435 * weston_renderer::import_dmabuf hook.
436 *
437 * \param buffer The linux_dmabuf_buffer object to set for.
438 * \param data The new renderer-private data pointer.
439 * \param func Destructor function to be called for the renderer-private
440 * data when the linux_dmabuf_buffer gets destroyed.
441 *
442 * \sa weston_compositor_import_dmabuf
443 */
444WL_EXPORT void
445linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
446 void *data,
447 dmabuf_user_data_destroy_func func)
448{
449 assert(data == NULL || buffer->user_data == NULL);
450
451 buffer->user_data = data;
452 buffer->user_data_destroy_func = func;
453}
454
455/** Get renderer-private data
456 *
457 * Get the user data from the linux_dmabuf_buffer.
458 *
459 * \param buffer The linux_dmabuf_buffer to query.
460 * \return Renderer-private data pointer.
461 *
462 * \sa linux_dmabuf_buffer_set_user_data
463 */
464WL_EXPORT void *
465linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer)
466{
467 return buffer->user_data;
468}
469
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800470static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_implementation = {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400471 linux_dmabuf_destroy,
472 linux_dmabuf_create_params
473};
474
475static void
476bind_linux_dmabuf(struct wl_client *client,
477 void *data, uint32_t version, uint32_t id)
478{
479 struct weston_compositor *compositor = data;
Leandro Ribeiro1b403262021-03-04 17:47:13 -0300480 const struct weston_drm_format_array *supported_formats;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400481 struct wl_resource *resource;
Leandro Ribeiro1b403262021-03-04 17:47:13 -0300482 struct weston_drm_format *fmt;
483 const uint64_t *modifiers;
484 unsigned int num_modifiers;
485 unsigned int i;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400486
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800487 resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400488 version, id);
489 if (resource == NULL) {
490 wl_client_post_no_memory(client);
491 return;
492 }
493
494 wl_resource_set_implementation(resource, &linux_dmabuf_implementation,
495 compositor, NULL);
496
Leandro Ribeiro18f53ab2021-10-18 11:27:54 -0300497 /* If we got here, it means that the renderer is able to import dma-buf
498 * buffers, and so it must have get_supported_formats() set. */
499 assert(compositor->renderer->get_supported_formats != NULL);
Leandro Ribeiro1b403262021-03-04 17:47:13 -0300500 supported_formats = compositor->renderer->get_supported_formats(compositor);
Leandro Ribeiro18f53ab2021-10-18 11:27:54 -0300501
502 /* Advertise the formats/modifiers */
Leandro Ribeiro1b403262021-03-04 17:47:13 -0300503 wl_array_for_each(fmt, &supported_formats->arr) {
504 modifiers = weston_drm_format_get_modifiers(fmt, &num_modifiers);
505 for (i = 0; i < num_modifiers; i++) {
Michael Tretterb0a749d2018-01-17 17:54:31 +0100506 if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
Leandro Ribeiro1b403262021-03-04 17:47:13 -0300507 uint32_t modifier_lo = modifiers[i] & 0xFFFFFFFF;
508 uint32_t modifier_hi = modifiers[i] >> 32;
Michael Tretterb0a749d2018-01-17 17:54:31 +0100509 zwp_linux_dmabuf_v1_send_modifier(resource,
Leandro Ribeiro1b403262021-03-04 17:47:13 -0300510 fmt->format,
Michael Tretterb0a749d2018-01-17 17:54:31 +0100511 modifier_hi,
512 modifier_lo);
Leandro Ribeiro1b403262021-03-04 17:47:13 -0300513 } else if (modifiers[i] == DRM_FORMAT_MOD_LINEAR ||
514 modifiers[i] == DRM_FORMAT_MOD_INVALID) {
Michael Tretterb0a749d2018-01-17 17:54:31 +0100515 zwp_linux_dmabuf_v1_send_format(resource,
Leandro Ribeiro1b403262021-03-04 17:47:13 -0300516 fmt->format);
Michael Tretterb0a749d2018-01-17 17:54:31 +0100517 }
Varad Gautam41b4b8f2017-04-26 19:17:17 +0530518 }
Varad Gautam41b4b8f2017-04-26 19:17:17 +0530519 }
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400520}
521
522/** Advertise linux_dmabuf support
523 *
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800524 * Calling this initializes the zwp_linux_dmabuf protocol support, so that
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400525 * the interface will be advertised to clients. Essentially it creates a
526 * global. Do not call this function multiple times in the compositor's
527 * lifetime. There is no way to deinit explicitly, globals will be reaped
528 * when the wl_display gets destroyed.
529 *
530 * \param compositor The compositor to init for.
531 * \return Zero on success, -1 on failure.
532 */
533WL_EXPORT int
534linux_dmabuf_setup(struct weston_compositor *compositor)
535{
536 if (!wl_global_create(compositor->wl_display,
Varad Gautam41b4b8f2017-04-26 19:17:17 +0530537 &zwp_linux_dmabuf_v1_interface, 3,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400538 compositor, bind_linux_dmabuf))
539 return -1;
540
541 return 0;
542}
543
544/** Resolve an internal compositor error by disconnecting the client.
545 *
546 * This function is used in cases when the dmabuf-based wl_buffer
547 * turns out unusable and there is no fallback path. This is used by
548 * renderers which are the fallback path in the first place.
549 *
550 * It is possible the fault is caused by a compositor bug, the underlying
551 * graphics stack bug or normal behaviour, or perhaps a client mistake.
552 * In any case, the options are to either composite garbage or nothing,
553 * or disconnect the client. This is a helper function for the latter.
554 *
Bryce Harringtonba63fae2016-07-06 15:30:54 -0700555 * The error is sent as an INVALID_OBJECT error on the client's wl_display.
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400556 *
557 * \param buffer The linux_dmabuf_buffer that is unusable.
558 * \param msg A custom error message attached to the protocol error.
559 */
560WL_EXPORT void
561linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
562 const char *msg)
563{
564 struct wl_client *client;
565 struct wl_resource *display_resource;
566 uint32_t id;
567
568 assert(buffer->buffer_resource);
569 id = wl_resource_get_id(buffer->buffer_resource);
570 client = wl_resource_get_client(buffer->buffer_resource);
571 display_resource = wl_client_get_object(client, 1);
572
573 assert(display_resource);
574 wl_resource_post_error(display_resource,
575 WL_DISPLAY_ERROR_INVALID_OBJECT,
576 "linux_dmabuf server error with "
577 "wl_buffer@%u: %s", id, msg);
578}