• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2014, 2015 Collabora, Ltd.
3  *
4  * 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:
11  *
12  * 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.
24  */
25 
26 #include "config.h"
27 
28 #include <assert.h>
29 #include <stdint.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 
33 #include <libweston/libweston.h>
34 #include "linux-dmabuf.h"
35 #include "linux-dmabuf-unstable-v1-server-protocol.h"
36 #include "libweston-internal.h"
37 
38 static void
linux_dmabuf_buffer_destroy(struct linux_dmabuf_buffer * buffer)39 linux_dmabuf_buffer_destroy(struct linux_dmabuf_buffer *buffer)
40 {
41 	int i;
42 
43 	for (i = 0; i < buffer->attributes.n_planes; i++) {
44 		close(buffer->attributes.fd[i]);
45 		buffer->attributes.fd[i] = -1;
46 	}
47 
48 	buffer->attributes.n_planes = 0;
49 
50 	if (buffer->attributes.buffer_handle != NULL) {
51         free(buffer->attributes.buffer_handle);
52 	}
53 	free(buffer);
54 }
55 
56 static void
destroy_params(struct wl_resource * params_resource)57 destroy_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 
69 static void
params_destroy(struct wl_client * client,struct wl_resource * resource)70 params_destroy(struct wl_client *client, struct wl_resource *resource)
71 {
72 	wl_resource_destroy(resource);
73 }
74 
75 static void
params_add(struct wl_client * client,struct wl_resource * params_resource,int32_t name_fd,uint32_t plane_idx,uint32_t offset,uint32_t stride,uint32_t modifier_hi,uint32_t modifier_lo)76 params_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,
90 			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
91 			"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,
101 			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
102 			"plane index %u is too high", plane_idx);
103 		close(name_fd);
104 		return;
105 	}
106 
107 	if (buffer->attributes.fd[plane_idx] != -1) {
108 		wl_resource_post_error(params_resource,
109 			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
110 			"a dmabuf has already been added for plane %u",
111 			plane_idx);
112 		close(name_fd);
113 		return;
114 	}
115 
116 	buffer->attributes.fd[plane_idx] = name_fd;
117 	buffer->attributes.offset[plane_idx] = offset;
118 	buffer->attributes.stride[plane_idx] = stride;
119 
120 	if (wl_resource_get_version(params_resource) < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION)
121 		buffer->attributes.modifier[plane_idx] = DRM_FORMAT_MOD_INVALID;
122 	else
123 		buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) |
124 							 modifier_lo;
125 
126 	buffer->attributes.n_planes++;
127 }
128 
129 static void
params_add_buffer_handle(struct wl_client * client,struct wl_resource * params_resource,int32_t fd,int32_t width,int32_t stride,int32_t height,int32_t size,int32_t format,uint32_t usage_hi,uint32_t usage_lo,uint32_t phyaddr_hi,uint32_t phyaddr_lo,int32_t key,struct wl_array * reservefds,struct wl_array * reserveints)130 params_add_buffer_handle(struct wl_client *client, struct wl_resource *params_resource,
131 	int32_t fd, int32_t width, int32_t stride, int32_t height, int32_t size,
132 	int32_t format, uint32_t usage_hi, uint32_t usage_lo, uint32_t phyaddr_hi,
133 	uint32_t phyaddr_lo, int32_t key, struct wl_array *reservefds, struct wl_array *reserveints)
134 {
135 	struct linux_dmabuf_buffer *buffer;
136 	buffer = wl_resource_get_user_data(params_resource);
137 	if (!buffer) {
138 		wl_resource_post_error(params_resource,
139 			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
140 			"params was already used to create a wl_buffer");
141 		return;
142 	}
143 
144 	uint32_t reserveFds = reservefds->size / sizeof(uint32_t);
145 	uint32_t reserveInts = reserveints->size / sizeof(uint32_t);
146 
147 	buffer->attributes.buffer_handle = zalloc((sizeof(BufferHandle)) + (reserveFds + reserveInts) * sizeof(int32_t));
148 	if (!buffer->attributes.buffer_handle) {
149 		wl_resource_post_no_memory(params_resource);
150 		return;
151 	}
152 
153 	buffer->attributes.buffer_handle->fd = buffer->attributes.fd[0];
154 	buffer->attributes.buffer_handle->width = width;
155 	buffer->attributes.buffer_handle->stride = stride;
156 	buffer->attributes.buffer_handle->height = height;
157 	buffer->attributes.buffer_handle->size = size;
158 	buffer->attributes.buffer_handle->format = format;
159 	buffer->attributes.buffer_handle->usage = ((uint64_t)(usage_hi) << 32) | usage_lo;
160 	buffer->attributes.buffer_handle->phyAddr = ((uint64_t)(phyaddr_hi) << 32) | phyaddr_lo;;
161 	buffer->attributes.buffer_handle->key = key;
162 	buffer->attributes.buffer_handle->reserveFds = reserveFds;
163 	buffer->attributes.buffer_handle->reserveInts = reserveInts;
164 
165 	uint32_t *p;
166 	int i = 0;
167 	wl_array_for_each(p, reservefds) {
168 		buffer->attributes.buffer_handle->reserve[i] = *p;
169 		i++;
170 	}
171 	wl_array_for_each(p, reserveints) {
172 		buffer->attributes.buffer_handle->reserve[i] = *p;
173 		i++;
174 	}
175 }
176 
177 static void
linux_dmabuf_wl_buffer_destroy(struct wl_client * client,struct wl_resource * resource)178 linux_dmabuf_wl_buffer_destroy(struct wl_client *client,
179 			       struct wl_resource *resource)
180 {
181 	wl_resource_destroy(resource);
182 }
183 
184 static const struct wl_buffer_interface linux_dmabuf_buffer_implementation = {
185 	linux_dmabuf_wl_buffer_destroy
186 };
187 
188 static void
destroy_linux_dmabuf_wl_buffer(struct wl_resource * resource)189 destroy_linux_dmabuf_wl_buffer(struct wl_resource *resource)
190 {
191 	struct linux_dmabuf_buffer *buffer;
192 
193 	buffer = wl_resource_get_user_data(resource);
194 	assert(buffer->buffer_resource == resource);
195 	assert(!buffer->params_resource);
196 
197 	if (buffer->user_data_destroy_func)
198 		buffer->user_data_destroy_func(buffer);
199 
200 	linux_dmabuf_buffer_destroy(buffer);
201 }
202 
203 static void
params_create_common(struct wl_client * client,struct wl_resource * params_resource,uint32_t buffer_id,int32_t width,int32_t height,uint32_t format,uint32_t flags)204 params_create_common(struct wl_client *client,
205 		     struct wl_resource *params_resource,
206 		     uint32_t buffer_id,
207 		     int32_t width,
208 		     int32_t height,
209 		     uint32_t format,
210 		     uint32_t flags)
211 {
212 	struct linux_dmabuf_buffer *buffer;
213 	int i;
214 
215 	buffer = wl_resource_get_user_data(params_resource);
216 
217 	if (!buffer) {
218 		wl_resource_post_error(params_resource,
219 			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
220 			"params was already used to create a wl_buffer");
221 		return;
222 	}
223 
224 	assert(buffer->params_resource == params_resource);
225 	assert(!buffer->buffer_resource);
226 
227 	/* Switch the linux_dmabuf_buffer object from params resource to
228 	 * eventually wl_buffer resource.
229 	 */
230 	wl_resource_set_user_data(buffer->params_resource, NULL);
231 	buffer->params_resource = NULL;
232 
233 	if (!buffer->attributes.n_planes) {
234 		wl_resource_post_error(params_resource,
235 			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
236 			"no dmabuf has been added to the params");
237 		goto err_out;
238 	}
239 
240 	/* Check for holes in the dmabufs set (e.g. [0, 1, 3]) */
241 	for (i = 0; i < buffer->attributes.n_planes; i++) {
242 		if (buffer->attributes.fd[i] == -1) {
243 			wl_resource_post_error(params_resource,
244 				ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
245 				"no dmabuf has been added for plane %i", i);
246 			goto err_out;
247 		}
248 	}
249 
250 	buffer->attributes.width = width;
251 	buffer->attributes.height = height;
252 	buffer->attributes.format = format;
253 	buffer->attributes.flags = flags;
254 
255 	if (width < 1 || height < 1) {
256 		wl_resource_post_error(params_resource,
257 			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
258 			"invalid width %d or height %d", width, height);
259 		goto err_out;
260 	}
261 
262 	for (i = 0; i < buffer->attributes.n_planes; i++) {
263 		off_t size;
264 
265 		if ((uint64_t) buffer->attributes.offset[i] + buffer->attributes.stride[i] > UINT32_MAX) {
266 			wl_resource_post_error(params_resource,
267 				ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
268 				"size overflow for plane %i", i);
269 			goto err_out;
270 		}
271 
272 		if (i == 0 &&
273 		   (uint64_t) buffer->attributes.offset[i] +
274 		   (uint64_t) buffer->attributes.stride[i] * height > UINT32_MAX) {
275 			wl_resource_post_error(params_resource,
276 				ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
277 				"size overflow for plane %i", i);
278 			goto err_out;
279 		}
280 
281 		/* Don't report an error as it might be caused
282 		 * by the kernel not supporting seeking on dmabuf */
283 		size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
284 		if (size == -1)
285 			continue;
286 
287 		if (buffer->attributes.offset[i] >= size) {
288 			wl_resource_post_error(params_resource,
289 				ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
290 				"invalid offset %i for plane %i",
291 				buffer->attributes.offset[i], i);
292 			goto err_out;
293 		}
294 
295 		if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) {
296 			wl_resource_post_error(params_resource,
297 				ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
298 				"invalid stride %i for plane %i",
299 				buffer->attributes.stride[i], i);
300 			goto err_out;
301 		}
302 
303 		/* Only valid for first plane as other planes might be
304 		 * sub-sampled according to fourcc format */
305 		if (i == 0 &&
306 		    buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) {
307 			wl_resource_post_error(params_resource,
308 				ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
309 				"invalid buffer stride or height for plane %i", i);
310 			goto err_out;
311 		}
312 	}
313 
314 	if (buffer->direct_display) {
315 		if (!weston_compositor_dmabuf_can_scanout(buffer->compositor,
316 							  buffer))
317 			goto err_failed;
318 
319 		goto avoid_gpu_import;
320 	}
321 
322 	if (!weston_compositor_import_dmabuf(buffer->compositor, buffer))
323 		goto err_failed;
324 
325 avoid_gpu_import:
326 	buffer->buffer_resource = wl_resource_create(client,
327 						     &wl_buffer_interface,
328 						     1, buffer_id);
329 	if (!buffer->buffer_resource) {
330 		wl_resource_post_no_memory(params_resource);
331 		goto err_buffer;
332 	}
333 
334 	wl_resource_set_implementation(buffer->buffer_resource,
335 				       &linux_dmabuf_buffer_implementation,
336 				       buffer, destroy_linux_dmabuf_wl_buffer);
337 
338 	/* send 'created' event when the request is not for an immediate
339 	 * import, ie buffer_id is zero */
340 	if (buffer_id == 0)
341 		zwp_linux_buffer_params_v1_send_created(params_resource,
342 						buffer->buffer_resource);
343 
344 	return;
345 
346 err_buffer:
347 	if (buffer->user_data_destroy_func)
348 		buffer->user_data_destroy_func(buffer);
349 
350 err_failed:
351 	if (buffer_id == 0)
352 		zwp_linux_buffer_params_v1_send_failed(params_resource);
353 	else
354 		/* since the behavior is left implementation defined by the
355 		 * protocol in case of create_immed failure due to an unknown cause,
356 		 * we choose to treat it as a fatal error and immediately kill the
357 		 * client instead of creating an invalid handle and waiting for it
358 		 * to be used.
359 		 */
360 		wl_resource_post_error(params_resource,
361 			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
362 			"importing the supplied dmabufs failed");
363 
364 err_out:
365 	linux_dmabuf_buffer_destroy(buffer);
366 }
367 
368 static void
params_create(struct wl_client * client,struct wl_resource * params_resource,int32_t width,int32_t height,uint32_t format,uint32_t flags)369 params_create(struct wl_client *client,
370 	      struct wl_resource *params_resource,
371 	      int32_t width,
372 	      int32_t height,
373 	      uint32_t format,
374 	      uint32_t flags)
375 {
376 	params_create_common(client, params_resource, 0, width, height, format,
377 			     flags);
378 }
379 
380 static void
params_create_immed(struct wl_client * client,struct wl_resource * params_resource,uint32_t buffer_id,int32_t width,int32_t height,uint32_t format,uint32_t flags)381 params_create_immed(struct wl_client *client,
382 		    struct wl_resource *params_resource,
383 		    uint32_t buffer_id,
384 		    int32_t width,
385 		    int32_t height,
386 		    uint32_t format,
387 		    uint32_t flags)
388 {
389 	params_create_common(client, params_resource, buffer_id, width, height,
390 			     format, flags);
391 }
392 
393 static const struct zwp_linux_buffer_params_v1_interface
394 zwp_linux_buffer_params_implementation = {
395 	params_destroy,
396 	params_add,
397 	params_add_buffer_handle,
398 	params_create,
399 	params_create_immed
400 };
401 
402 static void
linux_dmabuf_destroy(struct wl_client * client,struct wl_resource * resource)403 linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource)
404 {
405 	wl_resource_destroy(resource);
406 }
407 
408 static void
linux_dmabuf_create_params(struct wl_client * client,struct wl_resource * linux_dmabuf_resource,uint32_t params_id)409 linux_dmabuf_create_params(struct wl_client *client,
410 			   struct wl_resource *linux_dmabuf_resource,
411 			   uint32_t params_id)
412 {
413 	struct weston_compositor *compositor;
414 	struct linux_dmabuf_buffer *buffer;
415 	uint32_t version;
416 	int i;
417 
418 	version = wl_resource_get_version(linux_dmabuf_resource);
419 	compositor = wl_resource_get_user_data(linux_dmabuf_resource);
420 
421 	buffer = zalloc(sizeof *buffer);
422 	if (!buffer)
423 		goto err_out;
424 
425 	for (i = 0; i < MAX_DMABUF_PLANES; i++)
426 		buffer->attributes.fd[i] = -1;
427 
428 	buffer->compositor = compositor;
429 	buffer->params_resource =
430 		wl_resource_create(client,
431 				   &zwp_linux_buffer_params_v1_interface,
432 				   version, params_id);
433 	buffer->direct_display = false;
434 	if (!buffer->params_resource)
435 		goto err_dealloc;
436 
437 	wl_resource_set_implementation(buffer->params_resource,
438 				       &zwp_linux_buffer_params_implementation,
439 				       buffer, destroy_params);
440 
441 	return;
442 
443 err_dealloc:
444 	free(buffer);
445 
446 err_out:
447 	wl_resource_post_no_memory(linux_dmabuf_resource);
448 }
449 
450 /** Get the linux_dmabuf_buffer from a wl_buffer resource
451  *
452  * If the given wl_buffer resource was created through the linux_dmabuf
453  * protocol interface, returns the linux_dmabuf_buffer object. This can
454  * be used as a type check for a wl_buffer.
455  *
456  * \param resource A wl_buffer resource.
457  * \return The linux_dmabuf_buffer if it exists, or NULL otherwise.
458  */
459 WL_EXPORT struct linux_dmabuf_buffer *
linux_dmabuf_buffer_get(struct wl_resource * resource)460 linux_dmabuf_buffer_get(struct wl_resource *resource)
461 {
462 	struct linux_dmabuf_buffer *buffer;
463 
464 	if (!resource)
465 		return NULL;
466 
467 	if (!wl_resource_instance_of(resource, &wl_buffer_interface,
468 				     &linux_dmabuf_buffer_implementation))
469 		return NULL;
470 
471 	buffer = wl_resource_get_user_data(resource);
472 	assert(buffer);
473 	assert(!buffer->params_resource);
474 	assert(buffer->buffer_resource == resource);
475 
476 	return buffer;
477 }
478 
479 /** Set renderer-private data
480  *
481  * Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
482  * a non-NULL user data with a new non-NULL pointer. This is meant to
483  * protect against renderers fighting over linux_dmabuf_buffer user data
484  * ownership.
485  *
486  * The renderer-private data is usually set from the
487  * weston_renderer::import_dmabuf hook.
488  *
489  * \param buffer The linux_dmabuf_buffer object to set for.
490  * \param data The new renderer-private data pointer.
491  * \param func Destructor function to be called for the renderer-private
492  *             data when the linux_dmabuf_buffer gets destroyed.
493  *
494  * \sa weston_compositor_import_dmabuf
495  */
496 WL_EXPORT void
linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer * buffer,void * data,dmabuf_user_data_destroy_func func)497 linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
498 				  void *data,
499 				  dmabuf_user_data_destroy_func func)
500 {
501 	assert(data == NULL || buffer->user_data == NULL);
502 
503 	buffer->user_data = data;
504 	buffer->user_data_destroy_func = func;
505 }
506 
507 /** Get renderer-private data
508  *
509  * Get the user data from the linux_dmabuf_buffer.
510  *
511  * \param buffer The linux_dmabuf_buffer to query.
512  * \return Renderer-private data pointer.
513  *
514  * \sa linux_dmabuf_buffer_set_user_data
515  */
516 WL_EXPORT void *
linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer * buffer)517 linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer)
518 {
519 	return buffer->user_data;
520 }
521 
522 static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_implementation = {
523 	linux_dmabuf_destroy,
524 	linux_dmabuf_create_params
525 };
526 
527 static void
bind_linux_dmabuf(struct wl_client * client,void * data,uint32_t version,uint32_t id)528 bind_linux_dmabuf(struct wl_client *client,
529 		  void *data, uint32_t version, uint32_t id)
530 {
531 	struct weston_compositor *compositor = data;
532 	struct wl_resource *resource;
533 	int *formats = NULL;
534 	uint64_t *modifiers = NULL;
535 	int num_formats, num_modifiers;
536 	uint64_t modifier_invalid = DRM_FORMAT_MOD_INVALID;
537 	int i, j;
538 
539 	resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface,
540 				      version, id);
541 	if (resource == NULL) {
542 		wl_client_post_no_memory(client);
543 		return;
544 	}
545 
546 	wl_resource_set_implementation(resource, &linux_dmabuf_implementation,
547 				       compositor, NULL);
548 
549 	/*
550 	 * Use EGL_EXT_image_dma_buf_import_modifiers to query and advertise
551 	 * format/modifier codes.
552 	 */
553 	compositor->renderer->query_dmabuf_formats(compositor, &formats,
554 						   &num_formats);
555 
556 	for (i = 0; i < num_formats; i++) {
557 		compositor->renderer->query_dmabuf_modifiers(compositor,
558 							     formats[i],
559 							     &modifiers,
560 							     &num_modifiers);
561 
562 		/* send DRM_FORMAT_MOD_INVALID token when no modifiers are supported
563 		 * for this format */
564 		if (num_modifiers == 0) {
565 			num_modifiers = 1;
566 			modifiers = &modifier_invalid;
567 		}
568 		for (j = 0; j < num_modifiers; j++) {
569 			if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
570 				uint32_t modifier_lo = modifiers[j] & 0xFFFFFFFF;
571 				uint32_t modifier_hi = modifiers[j] >> 32;
572 				zwp_linux_dmabuf_v1_send_modifier(resource,
573 								  formats[i],
574 								  modifier_hi,
575 								  modifier_lo);
576 			} else if (modifiers[j] == DRM_FORMAT_MOD_LINEAR ||
577 				   modifiers == &modifier_invalid) {
578 				zwp_linux_dmabuf_v1_send_format(resource,
579 								formats[i]);
580 			}
581 		}
582 		if (modifiers != &modifier_invalid)
583 			free(modifiers);
584 	}
585 	free(formats);
586 }
587 
588 /** Advertise linux_dmabuf support
589  *
590  * Calling this initializes the zwp_linux_dmabuf protocol support, so that
591  * the interface will be advertised to clients. Essentially it creates a
592  * global. Do not call this function multiple times in the compositor's
593  * lifetime. There is no way to deinit explicitly, globals will be reaped
594  * when the wl_display gets destroyed.
595  *
596  * \param compositor The compositor to init for.
597  * \return Zero on success, -1 on failure.
598  */
599 WL_EXPORT int
linux_dmabuf_setup(struct weston_compositor * compositor)600 linux_dmabuf_setup(struct weston_compositor *compositor)
601 {
602 	if (!wl_global_create(compositor->wl_display,
603 			      &zwp_linux_dmabuf_v1_interface, 3,
604 			      compositor, bind_linux_dmabuf))
605 		return -1;
606 
607 	return 0;
608 }
609 
610 /** Resolve an internal compositor error by disconnecting the client.
611  *
612  * This function is used in cases when the dmabuf-based wl_buffer
613  * turns out unusable and there is no fallback path. This is used by
614  * renderers which are the fallback path in the first place.
615  *
616  * It is possible the fault is caused by a compositor bug, the underlying
617  * graphics stack bug or normal behaviour, or perhaps a client mistake.
618  * In any case, the options are to either composite garbage or nothing,
619  * or disconnect the client. This is a helper function for the latter.
620  *
621  * The error is sent as an INVALID_OBJECT error on the client's wl_display.
622  *
623  * \param buffer The linux_dmabuf_buffer that is unusable.
624  * \param msg A custom error message attached to the protocol error.
625  */
626 WL_EXPORT void
linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer * buffer,const char * msg)627 linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
628 				      const char *msg)
629 {
630 	struct wl_client *client;
631 	struct wl_resource *display_resource;
632 	uint32_t id;
633 
634 	assert(buffer->buffer_resource);
635 	id = wl_resource_get_id(buffer->buffer_resource);
636 	client = wl_resource_get_client(buffer->buffer_resource);
637 	display_resource = wl_client_get_object(client, 1);
638 
639 	assert(display_resource);
640 	wl_resource_post_error(display_resource,
641 			       WL_DISPLAY_ERROR_INVALID_OBJECT,
642 			       "linux_dmabuf server error with "
643 			       "wl_buffer@%u: %s", id, msg);
644 }
645