BDW doesn't support H.264 Baseline profile
[platform/upstream/libva-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     case VA_FOURCC('I','M','C','3'):
253     case VA_FOURCC('4','2','2','H'):
254     case VA_FOURCC('4','2','2','V'):
255     case VA_FOURCC('4','1','1','P'):
256     case VA_FOURCC('4','4','4','P'):
257         switch (obj_surface->subsampling) {
258         case SUBSAMPLE_YUV411:
259             drm_format = WL_DRM_FORMAT_YUV411;
260             break;
261         case SUBSAMPLE_YUV420:
262             drm_format = WL_DRM_FORMAT_YUV420;
263             break;
264         case SUBSAMPLE_YUV422H:
265         case SUBSAMPLE_YUV422V:
266             drm_format = WL_DRM_FORMAT_YUV422;
267             break;
268         case SUBSAMPLE_YUV444:
269             drm_format = WL_DRM_FORMAT_YUV444;
270             break;
271         default:
272             assert(0 && "unsupported subsampling");
273             return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
274         }
275         offsets[0] = 0;
276         pitches[0] = obj_surface->width;
277         offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
278         pitches[1] = obj_surface->cb_cr_pitch;
279         offsets[2] = obj_surface->width * obj_surface->y_cr_offset;
280         pitches[2] = obj_surface->cb_cr_pitch;
281         break;
282     default:
283         assert(0 && "unsupported format");
284         return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
285     }
286
287     buffer = create_planar_buffer(
288         i965->wl_output,
289         name,
290         obj_surface->orig_width,
291         obj_surface->orig_height,
292         drm_format,
293         offsets,
294         pitches
295     );
296     if (!buffer)
297         return VA_STATUS_ERROR_ALLOCATION_FAILED;
298
299     *out_buffer = buffer;
300     return VA_STATUS_SUCCESS;
301 }
302
303 /* Hook to return Wayland buffer associated with the VA image */
304 static VAStatus
305 va_GetImageBufferWl(
306     struct VADriverContext *ctx,
307     VAImageID               image,
308     unsigned int            flags,
309     struct wl_buffer      **out_buffer
310 )
311 {
312     return VA_STATUS_ERROR_UNIMPLEMENTED;
313 }
314
315 bool
316 ensure_driver_vtable(VADriverContextP ctx)
317 {
318     struct VADriverVTableWayland * const vtable = ctx->vtable_wayland;
319
320     if (!vtable)
321         return false;
322
323     vtable->vaGetSurfaceBufferWl = va_GetSurfaceBufferWl;
324     vtable->vaGetImageBufferWl   = va_GetImageBufferWl;
325     return true;
326 }
327
328 bool
329 i965_output_wayland_init(VADriverContextP ctx)
330 {
331     struct i965_driver_data * const i965 = i965_driver_data(ctx);
332     struct dso_handle *dso_handle;
333     struct wl_vtable *wl_vtable;
334
335     static const struct dso_symbol libegl_symbols[] = {
336         { "wl_drm_interface",
337           offsetof(struct wl_vtable, drm_interface) },
338         { NULL, }
339     };
340
341     static const struct dso_symbol libwl_client_symbols[] = {
342         { "wl_buffer_interface",
343           offsetof(struct wl_vtable, buffer_interface) },
344         { "wl_registry_interface",
345           offsetof(struct wl_vtable, registry_interface) },
346         { "wl_display_roundtrip",
347           offsetof(struct wl_vtable, display_roundtrip) },
348         { "wl_proxy_create",
349           offsetof(struct wl_vtable, proxy_create) },
350         { "wl_proxy_destroy",
351           offsetof(struct wl_vtable, proxy_destroy) },
352         { "wl_proxy_marshal",
353           offsetof(struct wl_vtable, proxy_marshal) },
354         { "wl_proxy_add_listener",
355           offsetof(struct wl_vtable, proxy_add_listener) },
356         { NULL, }
357     };
358
359     if (ctx->display_type != VA_DISPLAY_WAYLAND)
360         return false;
361
362     i965->wl_output = calloc(1, sizeof(struct va_wl_output));
363     if (!i965->wl_output)
364         goto error;
365
366     i965->wl_output->libegl_handle = dso_open(LIBEGL_NAME);
367     if (!i965->wl_output->libegl_handle)
368         goto error;
369
370     dso_handle = i965->wl_output->libegl_handle;
371     wl_vtable  = &i965->wl_output->vtable;
372     if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
373                          libegl_symbols))
374         goto error;
375
376     i965->wl_output->libwl_client_handle = dso_open(LIBWAYLAND_CLIENT_NAME);
377     if (!i965->wl_output->libwl_client_handle)
378         goto error;
379
380     dso_handle = i965->wl_output->libwl_client_handle;
381     wl_vtable  = &i965->wl_output->vtable;
382     if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
383                          libwl_client_symbols))
384         goto error;
385
386     if (!ensure_driver_vtable(ctx))
387         goto error;
388     return true;
389
390 error:
391     i965_output_wayland_terminate(ctx);
392     return false;
393 }
394
395 void
396 i965_output_wayland_terminate(VADriverContextP ctx)
397 {
398     struct i965_driver_data * const i965 = i965_driver_data(ctx);
399     struct va_wl_output *wl_output;
400
401     if (ctx->display_type != VA_DISPLAY_WAYLAND)
402         return;
403
404     wl_output = i965->wl_output;
405     if (!wl_output)
406         return;
407
408     if (wl_output->wl_drm) {
409         wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_drm);
410         wl_output->wl_drm = NULL;
411     }
412
413     if (wl_output->libegl_handle) {
414         dso_close(wl_output->libegl_handle);
415         wl_output->libegl_handle = NULL;
416     }
417
418     if (wl_output->libwl_client_handle) {
419         dso_close(wl_output->libwl_client_handle);
420         wl_output->libwl_client_handle = NULL;
421     }
422     free(wl_output);
423     i965->wl_output = NULL;
424 }