OSDN Git Service

Fix a typo
[android-x86/hardware-intel-common-vaapi.git] / src / i965_output_wayland.c
1 /*
2  * Copyright (C) 2012 Intel Corporation. All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * 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, sub license, 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 portions
14  * of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <va/va_backend.h>
29 #include <va/va_backend_wayland.h>
30 #include <wayland-client.h>
31 #include <wayland-drm-client-protocol.h>
32 #include "intel_driver.h"
33 #include "i965_output_wayland.h"
34 #include "i965_drv_video.h"
35 #include "i965_defines.h"
36 #include "dso_utils.h"
37
38 /* We need mesa's libEGL, first try the soname of a glvnd enabled mesa build */
39 #define LIBEGL_NAME             "libEGL_mesa.so.0"
40 /* Then fallback to plain libEGL.so.1 (which might not be mesa) */
41 #define LIBEGL_NAME_FALLBACK    "libEGL.so.1"
42 #define LIBWAYLAND_CLIENT_NAME  "libwayland-client.so.0"
43
44 typedef uint32_t (*wl_display_get_global_func)(struct wl_display *display,
45                                                const char *interface, uint32_t version);
46 typedef struct wl_event_queue *(*wl_display_create_queue_func)(struct wl_display *display);
47 typedef void (*wl_display_roundtrip_queue_func)(struct wl_display *display,
48                                                 struct wl_event_queue *queue);
49 typedef void (*wl_event_queue_destroy_func)(struct wl_event_queue *queue);
50 typedef void *(*wl_proxy_create_wrapper_func)(struct wl_proxy *proxy);
51 typedef void(*wl_proxy_wrapper_destroy_func)(void *proxy);
52 typedef struct wl_proxy *(*wl_proxy_create_func)(struct wl_proxy *factory,
53                                                  const struct wl_interface *interface);
54 typedef void (*wl_proxy_destroy_func)(struct wl_proxy *proxy);
55 typedef void (*wl_proxy_marshal_func)(struct wl_proxy *p, uint32_t opcode, ...);
56 typedef int (*wl_proxy_add_listener_func)(struct wl_proxy *proxy,
57                                           void (**implementation)(void), void *data);
58 typedef void (*wl_proxy_set_queue_func)(struct wl_proxy *proxy, struct wl_event_queue *queue);
59
60 struct wl_vtable {
61     const struct wl_interface        *buffer_interface;
62     const struct wl_interface        *drm_interface;
63     const struct wl_interface        *registry_interface;
64     wl_display_create_queue_func      display_create_queue;
65     wl_display_roundtrip_queue_func   display_roundtrip_queue;
66     wl_event_queue_destroy_func       event_queue_destroy;
67     wl_proxy_create_wrapper_func      proxy_create_wrapper;
68     wl_proxy_wrapper_destroy_func     proxy_wrapper_destroy;
69     wl_proxy_create_func              proxy_create;
70     wl_proxy_destroy_func             proxy_destroy;
71     wl_proxy_marshal_func             proxy_marshal;
72     wl_proxy_add_listener_func        proxy_add_listener;
73     wl_proxy_set_queue_func           proxy_set_queue;
74 };
75
76 struct va_wl_output {
77     struct dso_handle     *libegl_handle;
78     struct dso_handle     *libwl_client_handle;
79     struct wl_vtable       vtable;
80     struct wl_event_queue *queue;
81     struct wl_drm         *wl_drm;
82     uint32_t               wl_drm_name;
83     struct wl_registry    *wl_registry;
84 };
85
86 /* These function are copied and adapted from the version inside
87  * wayland-client-protocol.h
88  */
89 static void *
90 registry_bind(
91     struct wl_vtable          *wl_vtable,
92     struct wl_registry        *wl_registry,
93     uint32_t                   name,
94     const struct wl_interface *interface,
95     uint32_t                   version
96 )
97 {
98     struct wl_proxy *id;
99
100     id = wl_vtable->proxy_create((struct wl_proxy *) wl_registry,
101                                  interface);
102     if (!id)
103         return NULL;
104
105     wl_vtable->proxy_marshal((struct wl_proxy *) wl_registry,
106                              WL_REGISTRY_BIND, name, interface->name,
107                              version, id);
108
109     return (void *) id;
110 }
111
112 static struct wl_registry *
113 display_get_registry(
114     struct wl_vtable  *wl_vtable,
115     struct wl_display *wl_display
116 )
117 {
118     struct wl_proxy *callback;
119
120     callback = wl_vtable->proxy_create((struct wl_proxy *) wl_display,
121                                        wl_vtable->registry_interface);
122     if (!callback)
123         return NULL;
124
125     wl_vtable->proxy_marshal((struct wl_proxy *) wl_display,
126                              WL_DISPLAY_GET_REGISTRY, callback);
127
128     return (struct wl_registry *) callback;
129 }
130
131 static int
132 registry_add_listener(
133     struct wl_vtable                  *wl_vtable,
134     struct wl_registry                *wl_registry,
135     const struct wl_registry_listener *listener,
136     void                              *data
137 )
138 {
139     return wl_vtable->proxy_add_listener((struct wl_proxy *) wl_registry,
140                                          (void (**)(void)) listener, data);
141 }
142
143 static void
144 registry_handle_global(
145     void               *data,
146     struct wl_registry *registry,
147     uint32_t            name,
148     const char         *interface,
149     uint32_t            version
150 )
151 {
152     VADriverContextP ctx = data;
153     struct i965_driver_data * const i965 = i965_driver_data(ctx);
154     struct va_wl_output * const wl_output = i965->wl_output;
155     struct wl_vtable * const wl_vtable = &wl_output->vtable;
156
157     if (strcmp(interface, "wl_drm") == 0) {
158         wl_output->wl_drm_name = name;
159         wl_output->wl_drm = registry_bind(wl_vtable, wl_output->wl_registry,
160                                           name, wl_vtable->drm_interface,
161                                           (version < 2) ? version : 2);
162     }
163 }
164
165 static void
166 registry_handle_global_remove(
167     void               *data,
168     struct wl_registry *registry,
169     uint32_t            name
170 )
171 {
172     VADriverContextP ctx = data;
173     struct i965_driver_data * const i965 = i965_driver_data(ctx);
174     struct va_wl_output * const wl_output = i965->wl_output;
175
176     if (wl_output->wl_drm && name == wl_output->wl_drm_name) {
177         wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_drm);
178         wl_output->wl_drm = NULL;
179     }
180 }
181
182 static const struct wl_registry_listener registry_listener = {
183     registry_handle_global,
184     registry_handle_global_remove
185 };
186
187 /* Ensure wl_drm instance is created */
188 static bool
189 ensure_wl_output(VADriverContextP ctx)
190 {
191     struct i965_driver_data * const i965 = i965_driver_data(ctx);
192     struct va_wl_output * const wl_output = i965->wl_output;
193     struct wl_vtable * const wl_vtable = &wl_output->vtable;
194     struct wl_display *display_wrapper;
195
196     if (wl_output->wl_drm)
197         return true;
198
199     if (wl_output->queue) {
200         wl_output->vtable.event_queue_destroy(wl_output->queue);
201         wl_output->queue = NULL;
202     }
203     wl_output->queue = wl_vtable->display_create_queue(ctx->native_dpy);
204     if (!wl_output->queue)
205         return false;
206
207     display_wrapper = wl_vtable->proxy_create_wrapper(ctx->native_dpy);
208     if (!display_wrapper)
209         return false;
210     wl_vtable->proxy_set_queue((struct wl_proxy *) display_wrapper, wl_output->queue);
211
212     if (wl_output->wl_registry) {
213         wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_registry);
214         wl_output->wl_registry = NULL;
215     }
216     wl_output->wl_registry = display_get_registry(wl_vtable, display_wrapper);
217     wl_vtable->proxy_wrapper_destroy(display_wrapper);
218     registry_add_listener(wl_vtable, wl_output->wl_registry,
219                           &registry_listener, ctx);
220     wl_vtable->display_roundtrip_queue(ctx->native_dpy, wl_output->queue);
221     if (!wl_output->wl_drm)
222         return false;
223     return true;
224 }
225
226 /* Create planar/prime YUV buffer
227  * Create a prime buffer if fd is not -1, otherwise a
228  * planar buffer
229  */
230 static struct wl_buffer *
231 create_prime_or_planar_buffer(
232     struct va_wl_output *wl_output,
233     uint32_t             name,
234     int                  fd,
235     int32_t              width,
236     int32_t              height,
237     uint32_t             format,
238     int32_t              offsets[3],
239     int32_t              pitches[3]
240 )
241 {
242     struct wl_vtable * const wl_vtable = &wl_output->vtable;
243     struct wl_proxy *id;
244
245     id = wl_vtable->proxy_create(
246              (struct wl_proxy *)wl_output->wl_drm,
247              wl_vtable->buffer_interface
248          );
249     if (!id)
250         return NULL;
251
252     wl_vtable->proxy_marshal(
253         (struct wl_proxy *)wl_output->wl_drm,
254         (fd != -1) ? WL_DRM_CREATE_PRIME_BUFFER : WL_DRM_CREATE_PLANAR_BUFFER,
255         id,
256         (fd != -1) ? fd : name,
257         width, height, format,
258         offsets[0], pitches[0],
259         offsets[1], pitches[1],
260         offsets[2], pitches[2]
261     );
262     return (struct wl_buffer *)id;
263 }
264
265 /* Hook to return Wayland buffer associated with the VA surface */
266 static VAStatus
267 va_GetSurfaceBufferWl(
268     struct VADriverContext *ctx,
269     VASurfaceID             surface,
270     unsigned int            flags,
271     struct wl_buffer      **out_buffer
272 )
273 {
274     struct VADriverVTableWayland * const vtable = ctx->vtable_wayland;
275     struct i965_driver_data * const i965 = i965_driver_data(ctx);
276     struct object_surface *obj_surface;
277     struct wl_buffer *buffer;
278     uint32_t name, drm_format;
279     int offsets[3], pitches[3];
280     int fd = -1;
281
282     obj_surface = SURFACE(surface);
283     if (!obj_surface)
284         return VA_STATUS_ERROR_INVALID_SURFACE;
285
286     if (flags != VA_FRAME_PICTURE)
287         return VA_STATUS_ERROR_FLAG_NOT_SUPPORTED;
288
289     if (!out_buffer)
290         return VA_STATUS_ERROR_INVALID_PARAMETER;
291
292     if (!ensure_wl_output(ctx))
293         return VA_STATUS_ERROR_INVALID_DISPLAY;
294
295     if (!vtable->has_prime_sharing || (drm_intel_bo_gem_export_to_prime(obj_surface->bo, &fd) != 0)) {
296         fd = -1;
297
298         if (drm_intel_bo_flink(obj_surface->bo, &name) != 0)
299             return VA_STATUS_ERROR_INVALID_SURFACE;
300     }
301
302     switch (obj_surface->fourcc) {
303     case VA_FOURCC_NV12:
304         drm_format = WL_DRM_FORMAT_NV12;
305         offsets[0] = 0;
306         pitches[0] = obj_surface->width;
307         offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
308         pitches[1] = obj_surface->cb_cr_pitch;
309         offsets[2] = 0;
310         pitches[2] = 0;
311         break;
312     case VA_FOURCC_YV12:
313     case VA_FOURCC_I420:
314     case VA_FOURCC_IMC1:
315     case VA_FOURCC_IMC3:
316     case VA_FOURCC_422H:
317     case VA_FOURCC_422V:
318     case VA_FOURCC_411P:
319     case VA_FOURCC_444P:
320         switch (obj_surface->subsampling) {
321         case SUBSAMPLE_YUV411:
322             drm_format = WL_DRM_FORMAT_YUV411;
323             break;
324         case SUBSAMPLE_YUV420:
325             drm_format = WL_DRM_FORMAT_YUV420;
326             break;
327         case SUBSAMPLE_YUV422H:
328         case SUBSAMPLE_YUV422V:
329             drm_format = WL_DRM_FORMAT_YUV422;
330             break;
331         case SUBSAMPLE_YUV444:
332             drm_format = WL_DRM_FORMAT_YUV444;
333             break;
334         default:
335             return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
336         }
337         offsets[0] = 0;
338         pitches[0] = obj_surface->width;
339         offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
340         pitches[1] = obj_surface->cb_cr_pitch;
341         offsets[2] = obj_surface->width * obj_surface->y_cr_offset;
342         pitches[2] = obj_surface->cb_cr_pitch;
343         break;
344     default:
345         return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
346     }
347
348     buffer = create_prime_or_planar_buffer(
349                  i965->wl_output,
350                  name,
351                  fd,
352                  obj_surface->orig_width,
353                  obj_surface->orig_height,
354                  drm_format,
355                  offsets,
356                  pitches
357              );
358
359     if (fd != -1)
360         close(fd);
361
362     if (!buffer)
363         return VA_STATUS_ERROR_ALLOCATION_FAILED;
364
365     *out_buffer = buffer;
366     return VA_STATUS_SUCCESS;
367 }
368
369 /* Hook to return Wayland buffer associated with the VA image */
370 static VAStatus
371 va_GetImageBufferWl(
372     struct VADriverContext *ctx,
373     VAImageID               image,
374     unsigned int            flags,
375     struct wl_buffer      **out_buffer
376 )
377 {
378     return VA_STATUS_ERROR_UNIMPLEMENTED;
379 }
380
381 bool
382 ensure_driver_vtable(VADriverContextP ctx)
383 {
384     struct VADriverVTableWayland * const vtable = ctx->vtable_wayland;
385
386     if (!vtable)
387         return false;
388
389     vtable->vaGetSurfaceBufferWl = va_GetSurfaceBufferWl;
390     vtable->vaGetImageBufferWl   = va_GetImageBufferWl;
391     return true;
392 }
393
394 bool
395 i965_output_wayland_init(VADriverContextP ctx)
396 {
397     struct i965_driver_data * const i965 = i965_driver_data(ctx);
398     struct dso_handle *dso_handle;
399     struct wl_vtable *wl_vtable;
400
401     static const struct dso_symbol libegl_symbols[] = {
402         {
403             "wl_drm_interface",
404             offsetof(struct wl_vtable, drm_interface)
405         },
406         { NULL, }
407     };
408
409     static const struct dso_symbol libwl_client_symbols[] = {
410         {
411             "wl_buffer_interface",
412             offsetof(struct wl_vtable, buffer_interface)
413         },
414         {
415             "wl_registry_interface",
416             offsetof(struct wl_vtable, registry_interface)
417         },
418         {
419             "wl_display_create_queue",
420             offsetof(struct wl_vtable, display_create_queue)
421         },
422         {
423             "wl_display_roundtrip_queue",
424             offsetof(struct wl_vtable, display_roundtrip_queue)
425         },
426         {
427             "wl_event_queue_destroy",
428             offsetof(struct wl_vtable, event_queue_destroy)
429         },
430         {
431             "wl_proxy_create_wrapper",
432             offsetof(struct wl_vtable, proxy_create_wrapper)
433         },
434         {
435             "wl_proxy_wrapper_destroy",
436             offsetof(struct wl_vtable, proxy_wrapper_destroy)
437         },
438         {
439             "wl_proxy_create",
440             offsetof(struct wl_vtable, proxy_create)
441         },
442         {
443             "wl_proxy_destroy",
444             offsetof(struct wl_vtable, proxy_destroy)
445         },
446         {
447             "wl_proxy_marshal",
448             offsetof(struct wl_vtable, proxy_marshal)
449         },
450         {
451             "wl_proxy_add_listener",
452             offsetof(struct wl_vtable, proxy_add_listener)
453         },
454         {
455             "wl_proxy_set_queue",
456             offsetof(struct wl_vtable, proxy_set_queue)
457         },
458         { NULL, }
459     };
460
461     if (ctx->display_type != VA_DISPLAY_WAYLAND)
462         return false;
463
464     i965->wl_output = calloc(1, sizeof(struct va_wl_output));
465     if (!i965->wl_output)
466         goto error;
467
468     i965->wl_output->libegl_handle = dso_open(LIBEGL_NAME);
469     if (!i965->wl_output->libegl_handle) {
470         i965->wl_output->libegl_handle = dso_open(LIBEGL_NAME_FALLBACK);
471         if (!i965->wl_output->libegl_handle)
472             goto error;
473     }
474
475     dso_handle = i965->wl_output->libegl_handle;
476     wl_vtable  = &i965->wl_output->vtable;
477     if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
478                          libegl_symbols))
479         goto error;
480
481     i965->wl_output->libwl_client_handle = dso_open(LIBWAYLAND_CLIENT_NAME);
482     if (!i965->wl_output->libwl_client_handle)
483         goto error;
484
485     dso_handle = i965->wl_output->libwl_client_handle;
486     wl_vtable  = &i965->wl_output->vtable;
487     if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
488                          libwl_client_symbols))
489         goto error;
490
491     if (!ensure_driver_vtable(ctx))
492         goto error;
493     return true;
494
495 error:
496     i965_output_wayland_terminate(ctx);
497     return false;
498 }
499
500 void
501 i965_output_wayland_terminate(VADriverContextP ctx)
502 {
503     struct i965_driver_data * const i965 = i965_driver_data(ctx);
504     struct va_wl_output *wl_output;
505
506     if (ctx->display_type != VA_DISPLAY_WAYLAND)
507         return;
508
509     wl_output = i965->wl_output;
510     if (!wl_output)
511         return;
512
513     if (wl_output->wl_drm) {
514         wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_drm);
515         wl_output->wl_drm = NULL;
516     }
517
518     if (wl_output->wl_registry) {
519         wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_registry);
520         wl_output->wl_registry = NULL;
521     }
522
523     if (wl_output->queue) {
524         wl_output->vtable.event_queue_destroy(wl_output->queue);
525         wl_output->queue = NULL;
526     }
527
528     if (wl_output->libegl_handle) {
529         dso_close(wl_output->libegl_handle);
530         wl_output->libegl_handle = NULL;
531     }
532
533     if (wl_output->libwl_client_handle) {
534         dso_close(wl_output->libwl_client_handle);
535         wl_output->libwl_client_handle = NULL;
536     }
537     free(wl_output);
538     i965->wl_output = NULL;
539 }