summaryrefslogtreecommitdiff
path: root/src/lib/efl_wl/dmabuf.c
diff options
context:
space:
mode:
authorMike Blumenkrantz <zmike@osg.samsung.com>2017-06-30 14:59:21 -0400
committerMike Blumenkrantz <zmike@osg.samsung.com>2017-06-30 14:59:55 -0400
commitc2fde93c9ef1108c0809a538cf2ec482ed8369a9 (patch)
treed9879e4ebea4d25cda1a6cc1268461ad0d669c3b /src/lib/efl_wl/dmabuf.c
parent3775a9645da7e92599babccfe8454304cec367b7 (diff)
efl_wl: a multiseat wayland compositor in an evas smart object
build when wayland support is enabled and provide two test/demo cases beta api @feature Reviewed-By: Cedric BAIL <cedric@osg.samsung.com>
Diffstat (limited to 'src/lib/efl_wl/dmabuf.c')
-rw-r--r--src/lib/efl_wl/dmabuf.c513
1 files changed, 513 insertions, 0 deletions
diff --git a/src/lib/efl_wl/dmabuf.c b/src/lib/efl_wl/dmabuf.c
new file mode 100644
index 0000000000..a451179d53
--- /dev/null
+++ b/src/lib/efl_wl/dmabuf.c
@@ -0,0 +1,513 @@
1/* Shamelessly stolen from weston and modified, original license boiler plate
2 * follows.
3 */
4
5#if defined(__clang__)
6# pragma clang diagnostic ignored "-Wunused-parameter"
7#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4
8# pragma GCC diagnostic ignored "-Wunused-parameter"
9#endif
10
11
12/*
13 * Copyright © 2014, 2015 Collabora, Ltd.
14 *
15 * Permission to use, copy, modify, distribute, and sell this software and
16 * its documentation for any purpose is hereby granted without fee, provided
17 * that the above copyright notice appear in all copies and that both that
18 * copyright notice and this permission notice appear in supporting
19 * documentation, and that the name of the copyright holders not be used in
20 * advertising or publicity pertaining to distribution of the software
21 * without specific, written prior permission. The copyright holders make
22 * no representations about the suitability of this software for any
23 * purpose. It is provided "as is" without express or implied warranty.
24 *
25 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
26 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
27 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
28 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
29 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
30 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
31 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 */
33
34#include <sys/mman.h>
35
36#include <assert.h>
37
38#include "linux-dmabuf-unstable-v1-server-protocol.h"
39#include <stdlib.h>
40#include <stdio.h>
41#include <unistd.h>
42#include "dmabuf.h"
43#include <Eina.h>
44
45__attribute__ ((visibility("hidden"))) Eina_Bool comp_dmabuf_test(struct linux_dmabuf_buffer *dmabuf);
46
47static void
48linux_dmabuf_buffer_destroy(struct linux_dmabuf_buffer *buffer)
49{
50 int i;
51
52 for (i = 0; i < buffer->attributes.n_planes; i++) {
53 close(buffer->attributes.fd[i]);
54 buffer->attributes.fd[i] = -1;
55 }
56
57 buffer->attributes.n_planes = 0;
58
59 free(buffer);
60}
61
62static void
63destroy_params(struct wl_resource *params_resource)
64{
65 struct linux_dmabuf_buffer *buffer;
66
67 buffer = wl_resource_get_user_data(params_resource);
68
69 if (!buffer)
70 return;
71
72 linux_dmabuf_buffer_destroy(buffer);
73}
74
75static void
76params_destroy(struct wl_client *client, struct wl_resource *resource)
77{
78 wl_resource_destroy(resource);
79}
80
81static void
82params_add(struct wl_client *client,
83 struct wl_resource *params_resource,
84 int32_t name_fd,
85 uint32_t plane_idx,
86 uint32_t offset,
87 uint32_t stride,
88 uint32_t modifier_hi,
89 uint32_t modifier_lo)
90{
91 struct linux_dmabuf_buffer *buffer;
92
93 buffer = wl_resource_get_user_data(params_resource);
94 if (!buffer) {
95 wl_resource_post_error(params_resource,
96 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
97 "params was already used to create a wl_buffer");
98 close(name_fd);
99 return;
100 }
101
102 assert(buffer->params_resource == params_resource);
103 assert(!buffer->buffer_resource);
104
105 if (plane_idx >= MAX_DMABUF_PLANES) {
106 wl_resource_post_error(params_resource,
107 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
108 "plane index %u is too high", plane_idx);
109 close(name_fd);
110 return;
111 }
112
113 if (buffer->attributes.fd[plane_idx] != -1) {
114 wl_resource_post_error(params_resource,
115 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
116 "a dmabuf has already been added for plane %u",
117 plane_idx);
118 close(name_fd);
119 return;
120 }
121
122 buffer->attributes.fd[plane_idx] = name_fd;
123 buffer->attributes.offset[plane_idx] = offset;
124 buffer->attributes.stride[plane_idx] = stride;
125 buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) |
126 modifier_lo;
127 buffer->attributes.n_planes++;
128}
129
130static void
131linux_dmabuf_wl_buffer_destroy(struct wl_client *client,
132 struct wl_resource *resource)
133{
134 wl_resource_destroy(resource);
135}
136
137static const struct wl_buffer_interface linux_dmabuf_buffer_implementation = {
138 linux_dmabuf_wl_buffer_destroy
139};
140
141static void
142destroy_linux_dmabuf_wl_buffer(struct wl_resource *resource)
143{
144 struct linux_dmabuf_buffer *buffer;
145
146 buffer = wl_resource_get_user_data(resource);
147 assert(buffer->buffer_resource == resource);
148 assert(!buffer->params_resource);
149
150 if (buffer->user_data_destroy_func)
151 buffer->user_data_destroy_func(buffer);
152
153 linux_dmabuf_buffer_destroy(buffer);
154}
155
156static void
157params_create(struct wl_client *client,
158 struct wl_resource *params_resource,
159 int32_t width,
160 int32_t height,
161 uint32_t format,
162 uint32_t flags)
163{
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,
171 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
172 "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
185 if (!buffer->attributes.n_planes) {
186 wl_resource_post_error(params_resource,
187 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
188 "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]) */
193 for (i = 0; i < buffer->attributes.n_planes; i++) {
194 if (buffer->attributes.fd[i] == -1) {
195 wl_resource_post_error(params_resource,
196 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
197 "no dmabuf has been added for plane %i", i);
198 goto err_out;
199 }
200 }
201
202 buffer->attributes.version = 1;
203 buffer->attributes.width = width;
204 buffer->attributes.height = height;
205 buffer->attributes.format = format;
206 buffer->attributes.flags = flags;
207
208 if (width < 1 || height < 1) {
209 wl_resource_post_error(params_resource,
210 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
211 "invalid width %d or height %d", width, height);
212 goto err_out;
213 }
214
215 for (i = 0; i < buffer->attributes.n_planes; i++) {
216 off_t size;
217
218 if ((uint64_t) buffer->attributes.offset[i] + buffer->attributes.stride[i] > UINT32_MAX) {
219 wl_resource_post_error(params_resource,
220 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
221 "size overflow for plane %i", i);
222 goto err_out;
223 }
224
225 if (i == 0 &&
226 (uint64_t) buffer->attributes.offset[i] +
227 (uint64_t) buffer->attributes.stride[i] * height > UINT32_MAX) {
228 wl_resource_post_error(params_resource,
229 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
230 "size overflow for plane %i", i);
231 goto err_out;
232 }
233
234 /* Don't report an error as it might be caused
235 * by the kernel not supporting seeking on dmabuf */
236 size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
237 if (size == -1)
238 continue;
239
240 if (buffer->attributes.offset[i] >= size) {
241 wl_resource_post_error(params_resource,
242 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
243 "invalid offset %i for plane %i",
244 buffer->attributes.offset[i], i);
245 goto err_out;
246 }
247
248 if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) {
249 wl_resource_post_error(params_resource,
250 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
251 "invalid stride %i for plane %i",
252 buffer->attributes.stride[i], i);
253 goto err_out;
254 }
255
256 /* Only valid for first plane as other planes might be
257 * sub-sampled according to fourcc format */
258 if (i == 0 &&
259 buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) {
260 wl_resource_post_error(params_resource,
261 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
262 "invalid buffer stride or height for plane %i", i);
263 goto err_out;
264 }
265 }
266
267 /* XXX: Some additional sanity checks could be done with respect
268 * to the fourcc format. A centralized collection (kernel or
269 * libdrm) would be useful to avoid code duplication for these
270 * checks (e.g. drm_format_num_planes).
271 */
272
273 if (!comp_dmabuf_test(buffer))
274 goto err_failed;
275
276 buffer->buffer_resource = wl_resource_create(client,
277 &wl_buffer_interface,
278 1, 0);
279 if (!buffer->buffer_resource) {
280 wl_resource_post_no_memory(params_resource);
281 goto err_buffer;
282 }
283
284 wl_resource_set_implementation(buffer->buffer_resource,
285 &linux_dmabuf_buffer_implementation,
286 buffer, destroy_linux_dmabuf_wl_buffer);
287
288 zwp_linux_buffer_params_v1_send_created(params_resource,
289 buffer->buffer_resource);
290
291 return;
292
293err_buffer:
294 if (buffer->user_data_destroy_func)
295 buffer->user_data_destroy_func(buffer);
296
297err_failed:
298 zwp_linux_buffer_params_v1_send_failed(params_resource);
299
300err_out:
301 linux_dmabuf_buffer_destroy(buffer);
302}
303
304static const struct zwp_linux_buffer_params_v1_interface
305zwp_linux_buffer_params_implementation = {
306 params_destroy,
307 params_add,
308 params_create
309};
310
311static void
312linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource)
313{
314 wl_resource_destroy(resource);
315}
316
317static void
318linux_dmabuf_create_params(struct wl_client *client,
319 struct wl_resource *linux_dmabuf_resource,
320 uint32_t params_id)
321{
322 void *compositor;
323 struct linux_dmabuf_buffer *buffer;
324 uint32_t version;
325 int i;
326
327 version = wl_resource_get_version(linux_dmabuf_resource);
328 compositor = wl_resource_get_user_data(linux_dmabuf_resource);
329
330 buffer = calloc(1, sizeof *buffer);
331 if (!buffer)
332 goto err_out;
333
334 for (i = 0; i < MAX_DMABUF_PLANES; i++)
335 buffer->attributes.fd[i] = -1;
336
337 buffer->compositor = compositor;
338 buffer->params_resource =
339 wl_resource_create(client,
340 &zwp_linux_buffer_params_v1_interface,
341 version, params_id);
342 if (!buffer->params_resource)
343 goto err_dealloc;
344
345 wl_resource_set_implementation(buffer->params_resource,
346 &zwp_linux_buffer_params_implementation,
347 buffer, destroy_params);
348
349 return;
350
351err_dealloc:
352 free(buffer);
353
354err_out:
355 wl_resource_post_no_memory(linux_dmabuf_resource);
356}
357
358/** Get the linux_dmabuf_buffer from a wl_buffer resource
359 *
360 * If the given wl_buffer resource was created through the linux_dmabuf
361 * protocol interface, returns the linux_dmabuf_buffer object. This can
362 * be used as a type check for a wl_buffer.
363 *
364 * \param resource A wl_buffer resource.
365 * \return The linux_dmabuf_buffer if it exists, or NULL otherwise.
366 */
367struct linux_dmabuf_buffer *
368linux_dmabuf_buffer_get(struct wl_resource *resource)
369{
370 struct linux_dmabuf_buffer *buffer;
371
372 if (!resource)
373 return NULL;
374
375 if (!wl_resource_instance_of(resource, &wl_buffer_interface,
376 &linux_dmabuf_buffer_implementation))
377 return NULL;
378
379 buffer = wl_resource_get_user_data(resource);
380 assert(buffer);
381 assert(!buffer->params_resource);
382 assert(buffer->buffer_resource == resource);
383
384 return buffer;
385}
386
387/** Set renderer-private data
388 *
389 * Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
390 * a non-NULL user data with a new non-NULL pointer. This is meant to
391 * protect against renderers fighting over linux_dmabuf_buffer user data
392 * ownership.
393 *
394 * The renderer-private data is usually set from the
395 * weston_renderer::import_dmabuf hook.
396 *
397 * \param buffer The linux_dmabuf_buffer object to set for.
398 * \param data The new renderer-private data pointer.
399 * \param func Destructor function to be called for the renderer-private
400 * data when the linux_dmabuf_buffer gets destroyed.
401 *
402 * \sa weston_compositor_import_dmabuf
403 */
404void
405linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
406 void *data,
407 dmabuf_user_data_destroy_func func)
408{
409 assert(data == NULL || buffer->user_data == NULL);
410
411 buffer->user_data = data;
412 buffer->user_data_destroy_func = func;
413}
414
415/** Get renderer-private data
416 *
417 * Get the user data from the linux_dmabuf_buffer.
418 *
419 * \param buffer The linux_dmabuf_buffer to query.
420 * \return Renderer-private data pointer.
421 *
422 * \sa linux_dmabuf_buffer_set_user_data
423 */
424void *
425linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer)
426{
427 return buffer->user_data;
428}
429
430static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_implementation = {
431 linux_dmabuf_destroy,
432 linux_dmabuf_create_params
433};
434
435static void
436bind_linux_dmabuf(struct wl_client *client,
437 void *data, uint32_t version, uint32_t id)
438{
439 void *compositor = data;
440 struct wl_resource *resource;
441
442 resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface,
443 version, id);
444 if (resource == NULL) {
445 wl_client_post_no_memory(client);
446 return;
447 }
448
449 wl_resource_set_implementation(resource, &linux_dmabuf_implementation,
450 compositor, NULL);
451
452 /* EGL_EXT_image_dma_buf_import does not provide a way to query the
453 * supported pixel formats. */
454 /* XXX: send formats */
455}
456
457/** Advertise linux_dmabuf support
458 *
459 * Calling this initializes the zwp_linux_dmabuf protocol support, so that
460 * the interface will be advertised to clients. Essentially it creates a
461 * global. Do not call this function multiple times in the compositor's
462 * lifetime. There is no way to deinit explicitly, globals will be reaped
463 * when the wl_display gets destroyed.
464 *
465 * \param compositor The compositor to init for.
466 * \return Zero on success, -1 on failure.
467 */
468int
469linux_dmabuf_setup(struct wl_display *display, void *comp)
470{
471 if (!wl_global_create(display,
472 &zwp_linux_dmabuf_v1_interface, 1,
473 comp, bind_linux_dmabuf))
474 return -1;
475
476 return 0;
477}
478
479/** Resolve an internal compositor error by disconnecting the client.
480 *
481 * This function is used in cases when the dmabuf-based wl_buffer
482 * turns out unusable and there is no fallback path. This is used by
483 * renderers which are the fallback path in the first place.
484 *
485 * It is possible the fault is caused by a compositor bug, the underlying
486 * graphics stack bug or normal behaviour, or perhaps a client mistake.
487 * In any case, the options are to either composite garbage or nothing,
488 * or disconnect the client. This is a helper function for the latter.
489 *
490 * The error is sent as a INVALID_OBJECT error on the client's wl_display.
491 *
492 * \param buffer The linux_dmabuf_buffer that is unusable.
493 * \param msg A custom error message attached to the protocol error.
494 */
495void
496linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
497 const char *msg)
498{
499 struct wl_client *client;
500 struct wl_resource *display_resource;
501 uint32_t id;
502
503 assert(buffer->buffer_resource);
504 id = wl_resource_get_id(buffer->buffer_resource);
505 client = wl_resource_get_client(buffer->buffer_resource);
506 display_resource = wl_client_get_object(client, 1);
507
508 assert(display_resource);
509 wl_resource_post_error(display_resource,
510 WL_DISPLAY_ERROR_INVALID_OBJECT,
511 "linux_dmabuf server error with "
512 "wl_buffer@%u: %s", id, msg);
513}