MPEG-2 encoding path
[profile/ivi/vaapi-intel-driver.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 <assert.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 #define LIBEGL_NAME             "libEGL.so.1"
39 #define LIBWAYLAND_CLIENT_NAME  "libwayland-client.so.0"
40
41 typedef uint32_t (*wl_display_get_global_func)(struct wl_display *display,
42     const char *interface, uint32_t version);
43 typedef void (*wl_display_roundtrip_func)(struct wl_display *display);
44
45 typedef struct wl_proxy *(*wl_proxy_create_func)(struct wl_proxy *factory,
46     const struct wl_interface *interface);
47 typedef void (*wl_proxy_destroy_func)(struct wl_proxy *proxy);
48 typedef void (*wl_proxy_marshal_func)(struct wl_proxy *p, uint32_t opcode, ...);
49 typedef int (*wl_proxy_add_listener_func) (struct wl_proxy *proxy,
50     void (**implementation)(void), void *data);
51
52 struct wl_vtable {
53     const struct wl_interface  *buffer_interface;
54     const struct wl_interface  *drm_interface;
55     const struct wl_interface  *registry_interface;
56     wl_display_roundtrip_func   display_roundtrip;
57     wl_proxy_create_func        proxy_create;
58     wl_proxy_destroy_func       proxy_destroy;
59     wl_proxy_marshal_func       proxy_marshal;
60     wl_proxy_add_listener_func  proxy_add_listener;
61 };
62
63 struct va_wl_output {
64     struct dso_handle  *libegl_handle;
65     struct dso_handle  *libwl_client_handle;
66     struct wl_vtable    vtable;
67     struct wl_drm      *wl_drm;
68     struct wl_registry *wl_registry;
69 };
70
71 /* These function are copied and adapted from the version inside
72  * wayland-client-protocol.h
73  */
74 static void *
75 registry_bind(
76     struct wl_vtable          *wl_vtable,
77     struct wl_registry        *wl_registry,
78     uint32_t                   name,
79     const struct wl_interface *interface,
80     uint32_t                   version
81 )
82 {
83     struct wl_proxy *id;
84
85     id = wl_vtable->proxy_create((struct wl_proxy *) wl_registry,
86                                  interface);
87     if (!id)
88       return NULL;
89
90     wl_vtable->proxy_marshal((struct wl_proxy *) wl_registry,
91                              WL_REGISTRY_BIND, name, interface->name,
92                              version, id);
93
94     return (void *) id;
95 }
96
97 static struct wl_registry *
98 display_get_registry(
99     struct wl_vtable  *wl_vtable,
100     struct wl_display *wl_display
101 )
102 {
103     struct wl_proxy *callback;
104
105     callback = wl_vtable->proxy_create((struct wl_proxy *) wl_display,
106                                        wl_vtable->registry_interface);
107     if (!callback)
108       return NULL;
109
110     wl_vtable->proxy_marshal((struct wl_proxy *) wl_display,
111                              WL_DISPLAY_GET_REGISTRY, callback);
112
113     return (struct wl_registry *) callback;
114 }
115
116 static int
117 registry_add_listener(
118     struct wl_vtable                  *wl_vtable,
119     struct wl_registry                *wl_registry,
120     const struct wl_registry_listener *listener,
121     void                              *data
122 )
123 {
124     return wl_vtable->proxy_add_listener((struct wl_proxy *) wl_registry,
125                                          (void (**)(void)) listener, data);
126 }
127
128 static void
129 registry_handle_global(
130     void               *data,
131     struct wl_registry *registry,
132     uint32_t            id,
133     const char         *interface,
134     uint32_t            version
135 )
136 {
137     VADriverContextP ctx = data;
138     struct i965_driver_data * const i965 = i965_driver_data(ctx);
139     struct va_wl_output * const wl_output = i965->wl_output;
140     struct wl_vtable * const wl_vtable = &wl_output->vtable;
141
142     if (strcmp(interface, "wl_drm") == 0) {
143         wl_output->wl_drm = registry_bind(wl_vtable, wl_output->wl_registry,
144                                           id, wl_vtable->drm_interface, 1);
145     }
146 }
147
148 static const struct wl_registry_listener registry_listener = {
149     registry_handle_global,
150     NULL
151 };
152
153 /* Ensure wl_drm instance is created */
154 static bool
155 ensure_wl_output(VADriverContextP ctx)
156 {
157     struct i965_driver_data * const i965 = i965_driver_data(ctx);
158     struct va_wl_output * const wl_output = i965->wl_output;
159     struct wl_vtable * const wl_vtable = &wl_output->vtable;
160
161     if (wl_output->wl_drm)
162         return true;
163
164     wl_output->wl_registry = display_get_registry(wl_vtable, ctx->native_dpy);
165     registry_add_listener(wl_vtable, wl_output->wl_registry,
166                           &registry_listener, ctx);
167     wl_vtable->display_roundtrip(ctx->native_dpy);
168     if (!wl_output->wl_drm)
169         return false;
170     return true;
171 }
172
173 /* Create planar YUV buffer */
174 static struct wl_buffer *
175 create_planar_buffer(
176     struct va_wl_output *wl_output,
177     uint32_t             name,
178     int32_t              width,
179     int32_t              height,
180     uint32_t             format,
181     int32_t              offsets[3],
182     int32_t              pitches[3]
183 )
184 {
185     struct wl_vtable * const wl_vtable = &wl_output->vtable;
186     struct wl_proxy *id;
187
188     id = wl_vtable->proxy_create(
189         (struct wl_proxy *)wl_output->wl_drm,
190         wl_vtable->buffer_interface
191     );
192     if (!id)
193         return NULL;
194
195     wl_vtable->proxy_marshal(
196         (struct wl_proxy *)wl_output->wl_drm,
197         WL_DRM_CREATE_PLANAR_BUFFER,
198         id,
199         name,
200         width, height, format,
201         offsets[0], pitches[0],
202         offsets[1], pitches[1],
203         offsets[2], pitches[2]
204     );
205     return (struct wl_buffer *)id;
206 }
207
208 /* Hook to return Wayland buffer associated with the VA surface */
209 static VAStatus
210 va_GetSurfaceBufferWl(
211     struct VADriverContext *ctx,
212     VASurfaceID             surface,
213     unsigned int            flags,
214     struct wl_buffer      **out_buffer
215 )
216 {
217     struct i965_driver_data * const i965 = i965_driver_data(ctx);
218     struct object_surface *obj_surface;
219     struct wl_buffer *buffer;
220     uint32_t name, drm_format;
221     int offsets[3], pitches[3];
222
223     obj_surface = SURFACE(surface);
224     if (!obj_surface)
225         return VA_STATUS_ERROR_INVALID_SURFACE;
226
227     if (flags != VA_FRAME_PICTURE)
228         return VA_STATUS_ERROR_FLAG_NOT_SUPPORTED;
229
230     if (!out_buffer)
231         return VA_STATUS_ERROR_INVALID_PARAMETER;
232
233     if (!ensure_wl_output(ctx))
234         return VA_STATUS_ERROR_INVALID_DISPLAY;
235
236     if (drm_intel_bo_flink(obj_surface->bo, &name) != 0)
237         return VA_STATUS_ERROR_INVALID_SURFACE;
238
239     switch (obj_surface->fourcc) {
240     case VA_FOURCC('N','V','1','2'):
241         drm_format = WL_DRM_FORMAT_NV12;
242         offsets[0] = 0;
243         pitches[0] = obj_surface->width;
244         offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
245         pitches[1] = obj_surface->cb_cr_pitch;
246         offsets[2] = 0;
247         pitches[2] = 0;
248         break;
249     case VA_FOURCC('Y','V','1','2'):
250     case VA_FOURCC('I','4','2','0'):
251     case VA_FOURCC('I','M','C','1'):
252         switch (obj_surface->subsampling) {
253         case SUBSAMPLE_YUV411:
254             drm_format = WL_DRM_FORMAT_YUV411;
255             break;
256         case SUBSAMPLE_YUV420:
257             drm_format = WL_DRM_FORMAT_YUV420;
258             break;
259         case SUBSAMPLE_YUV422H:
260         case SUBSAMPLE_YUV422V:
261             drm_format = WL_DRM_FORMAT_YUV422;
262             break;
263         case SUBSAMPLE_YUV444:
264             drm_format = WL_DRM_FORMAT_YUV444;
265             break;
266         default:
267             assert(0 && "unsupported subsampling");
268             return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
269         }
270         offsets[0] = 0;
271         pitches[0] = obj_surface->width;
272         offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
273         pitches[1] = obj_surface->cb_cr_pitch;
274         offsets[2] = obj_surface->width * obj_surface->y_cr_offset;
275         pitches[2] = obj_surface->cb_cr_pitch;
276         break;
277     default:
278         assert(0 && "unsupported format");
279         return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
280     }
281
282     buffer = create_planar_buffer(
283         i965->wl_output,
284         name,
285         obj_surface->orig_width,
286         obj_surface->orig_height,
287         drm_format,
288         offsets,
289         pitches
290     );
291     if (!buffer)
292         return VA_STATUS_ERROR_ALLOCATION_FAILED;
293
294     *out_buffer = buffer;
295     return VA_STATUS_SUCCESS;
296 }
297
298 /* Hook to return Wayland buffer associated with the VA image */
299 static VAStatus
300 va_GetImageBufferWl(
301     struct VADriverContext *ctx,
302     VAImageID               image,
303     unsigned int            flags,
304     struct wl_buffer      **out_buffer
305 )
306 {
307     return VA_STATUS_ERROR_UNIMPLEMENTED;
308 }
309
310 bool
311 ensure_driver_vtable(VADriverContextP ctx)
312 {
313     struct VADriverVTableWayland * const vtable = ctx->vtable_wayland;
314
315     if (!vtable)
316         return false;
317
318     vtable->vaGetSurfaceBufferWl = va_GetSurfaceBufferWl;
319     vtable->vaGetImageBufferWl   = va_GetImageBufferWl;
320     return true;
321 }
322
323 bool
324 i965_output_wayland_init(VADriverContextP ctx)
325 {
326     struct i965_driver_data * const i965 = i965_driver_data(ctx);
327     struct dso_handle *dso_handle;
328     struct wl_vtable *wl_vtable;
329
330     static const struct dso_symbol libegl_symbols[] = {
331         { "wl_drm_interface",
332           offsetof(struct wl_vtable, drm_interface) },
333         { NULL, }
334     };
335
336     static const struct dso_symbol libwl_client_symbols[] = {
337         { "wl_buffer_interface",
338           offsetof(struct wl_vtable, buffer_interface) },
339         { "wl_registry_interface",
340           offsetof(struct wl_vtable, registry_interface) },
341         { "wl_display_roundtrip",
342           offsetof(struct wl_vtable, display_roundtrip) },
343         { "wl_proxy_create",
344           offsetof(struct wl_vtable, proxy_create) },
345         { "wl_proxy_destroy",
346           offsetof(struct wl_vtable, proxy_destroy) },
347         { "wl_proxy_marshal",
348           offsetof(struct wl_vtable, proxy_marshal) },
349         { "wl_proxy_add_listener",
350           offsetof(struct wl_vtable, proxy_add_listener) },
351         { NULL, }
352     };
353
354     if (ctx->display_type != VA_DISPLAY_WAYLAND)
355         return false;
356
357     i965->wl_output = calloc(1, sizeof(struct va_wl_output));
358     if (!i965->wl_output)
359         goto error;
360
361     i965->wl_output->libegl_handle = dso_open(LIBEGL_NAME);
362     if (!i965->wl_output->libegl_handle)
363         goto error;
364
365     dso_handle = i965->wl_output->libegl_handle;
366     wl_vtable  = &i965->wl_output->vtable;
367     if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
368                          libegl_symbols))
369         goto error;
370
371     i965->wl_output->libwl_client_handle = dso_open(LIBWAYLAND_CLIENT_NAME);
372     if (!i965->wl_output->libwl_client_handle)
373         goto error;
374
375     dso_handle = i965->wl_output->libwl_client_handle;
376     wl_vtable  = &i965->wl_output->vtable;
377     if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
378                          libwl_client_symbols))
379         goto error;
380
381     if (!ensure_driver_vtable(ctx))
382         goto error;
383     return true;
384
385 error:
386     i965_output_wayland_terminate(ctx);
387     return false;
388 }
389
390 void
391 i965_output_wayland_terminate(VADriverContextP ctx)
392 {
393     struct i965_driver_data * const i965 = i965_driver_data(ctx);
394     struct va_wl_output *wl_output;
395
396     if (ctx->display_type != VA_DISPLAY_WAYLAND)
397         return;
398
399     wl_output = i965->wl_output;
400     if (!wl_output)
401         return;
402
403     if (wl_output->wl_drm) {
404         wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_drm);
405         wl_output->wl_drm = NULL;
406     }
407
408     if (wl_output->libegl_handle) {
409         dso_close(wl_output->libegl_handle);
410         wl_output->libegl_handle = NULL;
411     }
412
413     if (wl_output->libwl_client_handle) {
414         dso_close(wl_output->libwl_client_handle);
415         wl_output->libwl_client_handle = NULL;
416     }
417     free(wl_output);
418     i965->wl_output = NULL;
419 }