blob: d63f109b43785d1eff372ae83ff90d7f0fcb3165 [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 Paalanen230f3b12014-09-29 14:18:40 -040037
38static void
39linux_dmabuf_buffer_destroy(struct linux_dmabuf_buffer *buffer)
40{
41 int i;
42
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +000043 for (i = 0; i < buffer->attributes.n_planes; i++) {
44 close(buffer->attributes.fd[i]);
45 buffer->attributes.fd[i] = -1;
Pekka Paalanen230f3b12014-09-29 14:18:40 -040046 }
47
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +000048 buffer->attributes.n_planes = 0;
Pekka Paalanen230f3b12014-09-29 14:18:40 -040049 free(buffer);
50}
51
52static void
53destroy_params(struct wl_resource *params_resource)
54{
55 struct linux_dmabuf_buffer *buffer;
56
57 buffer = wl_resource_get_user_data(params_resource);
58
59 if (!buffer)
60 return;
61
62 linux_dmabuf_buffer_destroy(buffer);
63}
64
65static void
66params_destroy(struct wl_client *client, struct wl_resource *resource)
67{
68 wl_resource_destroy(resource);
69}
70
71static void
72params_add(struct wl_client *client,
73 struct wl_resource *params_resource,
74 int32_t name_fd,
75 uint32_t plane_idx,
76 uint32_t offset,
77 uint32_t stride,
78 uint32_t modifier_hi,
79 uint32_t modifier_lo)
80{
81 struct linux_dmabuf_buffer *buffer;
82
83 buffer = wl_resource_get_user_data(params_resource);
84 if (!buffer) {
85 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +080086 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
Pekka Paalanen230f3b12014-09-29 14:18:40 -040087 "params was already used to create a wl_buffer");
88 close(name_fd);
89 return;
90 }
91
92 assert(buffer->params_resource == params_resource);
93 assert(!buffer->buffer_resource);
94
95 if (plane_idx >= MAX_DMABUF_PLANES) {
96 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +080097 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
Pekka Paalanen230f3b12014-09-29 14:18:40 -040098 "plane index %u is too high", plane_idx);
99 close(name_fd);
100 return;
101 }
102
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000103 if (buffer->attributes.fd[plane_idx] != -1) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400104 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800105 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400106 "a dmabuf has already been added for plane %u",
107 plane_idx);
108 close(name_fd);
109 return;
110 }
111
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000112 buffer->attributes.fd[plane_idx] = name_fd;
113 buffer->attributes.offset[plane_idx] = offset;
114 buffer->attributes.stride[plane_idx] = stride;
Emre Ucan99ef8162018-01-09 14:00:30 +0100115
116 if (wl_resource_get_version(params_resource) < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION)
117 buffer->attributes.modifier[plane_idx] = DRM_FORMAT_MOD_INVALID;
118 else
119 buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) |
120 modifier_lo;
121
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000122 buffer->attributes.n_planes++;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400123}
124
125static void
126linux_dmabuf_wl_buffer_destroy(struct wl_client *client,
127 struct wl_resource *resource)
128{
129 wl_resource_destroy(resource);
130}
131
132static const struct wl_buffer_interface linux_dmabuf_buffer_implementation = {
133 linux_dmabuf_wl_buffer_destroy
134};
135
136static void
137destroy_linux_dmabuf_wl_buffer(struct wl_resource *resource)
138{
139 struct linux_dmabuf_buffer *buffer;
140
141 buffer = wl_resource_get_user_data(resource);
142 assert(buffer->buffer_resource == resource);
143 assert(!buffer->params_resource);
144
145 if (buffer->user_data_destroy_func)
146 buffer->user_data_destroy_func(buffer);
147
148 linux_dmabuf_buffer_destroy(buffer);
149}
150
151static void
Varad Gautam65c94b82017-04-26 19:15:59 +0530152params_create_common(struct wl_client *client,
153 struct wl_resource *params_resource,
154 uint32_t buffer_id,
155 int32_t width,
156 int32_t height,
157 uint32_t format,
158 uint32_t flags)
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400159{
160 struct linux_dmabuf_buffer *buffer;
161 int i;
162
163 buffer = wl_resource_get_user_data(params_resource);
164
165 if (!buffer) {
166 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800167 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400168 "params was already used to create a wl_buffer");
169 return;
170 }
171
172 assert(buffer->params_resource == params_resource);
173 assert(!buffer->buffer_resource);
174
175 /* Switch the linux_dmabuf_buffer object from params resource to
176 * eventually wl_buffer resource.
177 */
178 wl_resource_set_user_data(buffer->params_resource, NULL);
179 buffer->params_resource = NULL;
180
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000181 if (!buffer->attributes.n_planes) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400182 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800183 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400184 "no dmabuf has been added to the params");
185 goto err_out;
186 }
187
188 /* Check for holes in the dmabufs set (e.g. [0, 1, 3]) */
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000189 for (i = 0; i < buffer->attributes.n_planes; i++) {
190 if (buffer->attributes.fd[i] == -1) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400191 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800192 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400193 "no dmabuf has been added for plane %i", i);
194 goto err_out;
195 }
196 }
197
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000198 buffer->attributes.width = width;
199 buffer->attributes.height = height;
200 buffer->attributes.format = format;
201 buffer->attributes.flags = flags;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400202
203 if (width < 1 || height < 1) {
204 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800205 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400206 "invalid width %d or height %d", width, height);
207 goto err_out;
208 }
209
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000210 for (i = 0; i < buffer->attributes.n_planes; i++) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400211 off_t size;
212
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000213 if ((uint64_t) buffer->attributes.offset[i] + buffer->attributes.stride[i] > UINT32_MAX) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400214 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800215 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400216 "size overflow for plane %i", i);
217 goto err_out;
218 }
219
220 if (i == 0 &&
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000221 (uint64_t) buffer->attributes.offset[i] +
222 (uint64_t) buffer->attributes.stride[i] * height > UINT32_MAX) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400223 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800224 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400225 "size overflow for plane %i", i);
226 goto err_out;
227 }
228
229 /* Don't report an error as it might be caused
230 * by the kernel not supporting seeking on dmabuf */
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000231 size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400232 if (size == -1)
Derek Foremanc06389a2016-04-25 09:23:24 -0500233 continue;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400234
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000235 if (buffer->attributes.offset[i] >= size) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400236 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800237 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400238 "invalid offset %i for plane %i",
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000239 buffer->attributes.offset[i], i);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400240 goto err_out;
241 }
242
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000243 if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400244 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800245 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400246 "invalid stride %i for plane %i",
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000247 buffer->attributes.stride[i], i);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400248 goto err_out;
249 }
250
251 /* Only valid for first plane as other planes might be
252 * sub-sampled according to fourcc format */
253 if (i == 0 &&
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000254 buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400255 wl_resource_post_error(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800256 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400257 "invalid buffer stride or height for plane %i", i);
258 goto err_out;
259 }
260 }
261
262 /* XXX: Some additional sanity checks could be done with respect
263 * to the fourcc format. A centralized collection (kernel or
264 * libdrm) would be useful to avoid code duplication for these
265 * checks (e.g. drm_format_num_planes).
266 */
267
268 if (!weston_compositor_import_dmabuf(buffer->compositor, buffer))
269 goto err_failed;
270
271 buffer->buffer_resource = wl_resource_create(client,
272 &wl_buffer_interface,
Varad Gautam65c94b82017-04-26 19:15:59 +0530273 1, buffer_id);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400274 if (!buffer->buffer_resource) {
275 wl_resource_post_no_memory(params_resource);
276 goto err_buffer;
277 }
278
279 wl_resource_set_implementation(buffer->buffer_resource,
280 &linux_dmabuf_buffer_implementation,
281 buffer, destroy_linux_dmabuf_wl_buffer);
282
Varad Gautam65c94b82017-04-26 19:15:59 +0530283 /* send 'created' event when the request is not for an immediate
284 * import, ie buffer_id is zero */
285 if (buffer_id == 0)
286 zwp_linux_buffer_params_v1_send_created(params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800287 buffer->buffer_resource);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400288
289 return;
290
291err_buffer:
292 if (buffer->user_data_destroy_func)
293 buffer->user_data_destroy_func(buffer);
294
295err_failed:
Varad Gautam65c94b82017-04-26 19:15:59 +0530296 if (buffer_id == 0)
297 zwp_linux_buffer_params_v1_send_failed(params_resource);
298 else
299 /* since the behavior is left implementation defined by the
300 * protocol in case of create_immed failure due to an unknown cause,
301 * we choose to treat it as a fatal error and immediately kill the
302 * client instead of creating an invalid handle and waiting for it
303 * to be used.
304 */
305 wl_resource_post_error(params_resource,
306 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
307 "importing the supplied dmabufs failed");
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400308
309err_out:
310 linux_dmabuf_buffer_destroy(buffer);
311}
312
Varad Gautam65c94b82017-04-26 19:15:59 +0530313static void
314params_create(struct wl_client *client,
315 struct wl_resource *params_resource,
316 int32_t width,
317 int32_t height,
318 uint32_t format,
319 uint32_t flags)
320{
321 params_create_common(client, params_resource, 0, width, height, format,
322 flags);
323}
324
325static void
326params_create_immed(struct wl_client *client,
327 struct wl_resource *params_resource,
328 uint32_t buffer_id,
329 int32_t width,
330 int32_t height,
331 uint32_t format,
332 uint32_t flags)
333{
334 params_create_common(client, params_resource, buffer_id, width, height,
335 format, flags);
336}
337
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800338static const struct zwp_linux_buffer_params_v1_interface
339zwp_linux_buffer_params_implementation = {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400340 params_destroy,
341 params_add,
Varad Gautam65c94b82017-04-26 19:15:59 +0530342 params_create,
343 params_create_immed
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400344};
345
346static void
347linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource)
348{
349 wl_resource_destroy(resource);
350}
351
352static void
353linux_dmabuf_create_params(struct wl_client *client,
354 struct wl_resource *linux_dmabuf_resource,
355 uint32_t params_id)
356{
357 struct weston_compositor *compositor;
358 struct linux_dmabuf_buffer *buffer;
359 uint32_t version;
360 int i;
361
362 version = wl_resource_get_version(linux_dmabuf_resource);
363 compositor = wl_resource_get_user_data(linux_dmabuf_resource);
364
365 buffer = zalloc(sizeof *buffer);
366 if (!buffer)
367 goto err_out;
368
369 for (i = 0; i < MAX_DMABUF_PLANES; i++)
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +0000370 buffer->attributes.fd[i] = -1;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400371
372 buffer->compositor = compositor;
373 buffer->params_resource =
374 wl_resource_create(client,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800375 &zwp_linux_buffer_params_v1_interface,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400376 version, params_id);
377 if (!buffer->params_resource)
378 goto err_dealloc;
379
380 wl_resource_set_implementation(buffer->params_resource,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800381 &zwp_linux_buffer_params_implementation,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400382 buffer, destroy_params);
383
384 return;
385
386err_dealloc:
387 free(buffer);
388
389err_out:
390 wl_resource_post_no_memory(linux_dmabuf_resource);
391}
392
393/** Get the linux_dmabuf_buffer from a wl_buffer resource
394 *
395 * If the given wl_buffer resource was created through the linux_dmabuf
396 * protocol interface, returns the linux_dmabuf_buffer object. This can
397 * be used as a type check for a wl_buffer.
398 *
399 * \param resource A wl_buffer resource.
400 * \return The linux_dmabuf_buffer if it exists, or NULL otherwise.
401 */
402WL_EXPORT struct linux_dmabuf_buffer *
403linux_dmabuf_buffer_get(struct wl_resource *resource)
404{
405 struct linux_dmabuf_buffer *buffer;
406
407 if (!resource)
408 return NULL;
409
410 if (!wl_resource_instance_of(resource, &wl_buffer_interface,
411 &linux_dmabuf_buffer_implementation))
412 return NULL;
413
414 buffer = wl_resource_get_user_data(resource);
415 assert(buffer);
416 assert(!buffer->params_resource);
417 assert(buffer->buffer_resource == resource);
418
419 return buffer;
420}
421
422/** Set renderer-private data
423 *
424 * Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
425 * a non-NULL user data with a new non-NULL pointer. This is meant to
426 * protect against renderers fighting over linux_dmabuf_buffer user data
427 * ownership.
428 *
429 * The renderer-private data is usually set from the
430 * weston_renderer::import_dmabuf hook.
431 *
432 * \param buffer The linux_dmabuf_buffer object to set for.
433 * \param data The new renderer-private data pointer.
434 * \param func Destructor function to be called for the renderer-private
435 * data when the linux_dmabuf_buffer gets destroyed.
436 *
437 * \sa weston_compositor_import_dmabuf
438 */
439WL_EXPORT void
440linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
441 void *data,
442 dmabuf_user_data_destroy_func func)
443{
444 assert(data == NULL || buffer->user_data == NULL);
445
446 buffer->user_data = data;
447 buffer->user_data_destroy_func = func;
448}
449
450/** Get renderer-private data
451 *
452 * Get the user data from the linux_dmabuf_buffer.
453 *
454 * \param buffer The linux_dmabuf_buffer to query.
455 * \return Renderer-private data pointer.
456 *
457 * \sa linux_dmabuf_buffer_set_user_data
458 */
459WL_EXPORT void *
460linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer)
461{
462 return buffer->user_data;
463}
464
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800465static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_implementation = {
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400466 linux_dmabuf_destroy,
467 linux_dmabuf_create_params
468};
469
470static void
471bind_linux_dmabuf(struct wl_client *client,
472 void *data, uint32_t version, uint32_t id)
473{
474 struct weston_compositor *compositor = data;
475 struct wl_resource *resource;
Varad Gautam41b4b8f2017-04-26 19:17:17 +0530476 int *formats = NULL;
477 uint64_t *modifiers = NULL;
478 int num_formats, num_modifiers;
479 uint64_t modifier_invalid = DRM_FORMAT_MOD_INVALID;
480 int i, j;
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400481
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800482 resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400483 version, id);
484 if (resource == NULL) {
485 wl_client_post_no_memory(client);
486 return;
487 }
488
489 wl_resource_set_implementation(resource, &linux_dmabuf_implementation,
490 compositor, NULL);
491
Varad Gautam41b4b8f2017-04-26 19:17:17 +0530492 /*
493 * Use EGL_EXT_image_dma_buf_import_modifiers to query and advertise
494 * format/modifier codes.
495 */
496 compositor->renderer->query_dmabuf_formats(compositor, &formats,
497 &num_formats);
498
499 for (i = 0; i < num_formats; i++) {
500 compositor->renderer->query_dmabuf_modifiers(compositor,
501 formats[i],
502 &modifiers,
503 &num_modifiers);
504
505 /* send DRM_FORMAT_MOD_INVALID token when no modifiers are supported
506 * for this format */
507 if (num_modifiers == 0) {
508 num_modifiers = 1;
509 modifiers = &modifier_invalid;
510 }
511 for (j = 0; j < num_modifiers; j++) {
Michael Tretterb0a749d2018-01-17 17:54:31 +0100512 if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
513 uint32_t modifier_lo = modifiers[j] & 0xFFFFFFFF;
514 uint32_t modifier_hi = modifiers[j] >> 32;
515 zwp_linux_dmabuf_v1_send_modifier(resource,
516 formats[i],
517 modifier_hi,
518 modifier_lo);
519 } else if (modifiers[j] == DRM_FORMAT_MOD_LINEAR ||
520 modifiers == &modifier_invalid) {
521 zwp_linux_dmabuf_v1_send_format(resource,
522 formats[i]);
523 }
Varad Gautam41b4b8f2017-04-26 19:17:17 +0530524 }
Derek Foremancd052a62017-06-26 14:44:54 -0500525 if (modifiers != &modifier_invalid)
526 free(modifiers);
Varad Gautam41b4b8f2017-04-26 19:17:17 +0530527 }
528 free(formats);
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400529}
530
531/** Advertise linux_dmabuf support
532 *
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800533 * Calling this initializes the zwp_linux_dmabuf protocol support, so that
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400534 * the interface will be advertised to clients. Essentially it creates a
535 * global. Do not call this function multiple times in the compositor's
536 * lifetime. There is no way to deinit explicitly, globals will be reaped
537 * when the wl_display gets destroyed.
538 *
539 * \param compositor The compositor to init for.
540 * \return Zero on success, -1 on failure.
541 */
542WL_EXPORT int
543linux_dmabuf_setup(struct weston_compositor *compositor)
544{
545 if (!wl_global_create(compositor->wl_display,
Varad Gautam41b4b8f2017-04-26 19:17:17 +0530546 &zwp_linux_dmabuf_v1_interface, 3,
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400547 compositor, bind_linux_dmabuf))
548 return -1;
549
550 return 0;
551}
552
553/** Resolve an internal compositor error by disconnecting the client.
554 *
555 * This function is used in cases when the dmabuf-based wl_buffer
556 * turns out unusable and there is no fallback path. This is used by
557 * renderers which are the fallback path in the first place.
558 *
559 * It is possible the fault is caused by a compositor bug, the underlying
560 * graphics stack bug or normal behaviour, or perhaps a client mistake.
561 * In any case, the options are to either composite garbage or nothing,
562 * or disconnect the client. This is a helper function for the latter.
563 *
Bryce Harringtonba63fae2016-07-06 15:30:54 -0700564 * The error is sent as an INVALID_OBJECT error on the client's wl_display.
Pekka Paalanen230f3b12014-09-29 14:18:40 -0400565 *
566 * \param buffer The linux_dmabuf_buffer that is unusable.
567 * \param msg A custom error message attached to the protocol error.
568 */
569WL_EXPORT void
570linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
571 const char *msg)
572{
573 struct wl_client *client;
574 struct wl_resource *display_resource;
575 uint32_t id;
576
577 assert(buffer->buffer_resource);
578 id = wl_resource_get_id(buffer->buffer_resource);
579 client = wl_resource_get_client(buffer->buffer_resource);
580 display_resource = wl_client_get_object(client, 1);
581
582 assert(display_resource);
583 wl_resource_post_error(display_resource,
584 WL_DISPLAY_ERROR_INVALID_OBJECT,
585 "linux_dmabuf server error with "
586 "wl_buffer@%u: %s", id, msg);
587}