OSDN Git Service

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