OSDN Git Service

Fix the quality range regression issue
[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         { "wl_drm_interface",
353           offsetof(struct wl_vtable, drm_interface) },
354         { NULL, }
355     };
356
357     static const struct dso_symbol libwl_client_symbols[] = {
358         { "wl_buffer_interface",
359           offsetof(struct wl_vtable, buffer_interface) },
360         { "wl_registry_interface",
361           offsetof(struct wl_vtable, registry_interface) },
362         { "wl_display_roundtrip",
363           offsetof(struct wl_vtable, display_roundtrip) },
364         { "wl_proxy_create",
365           offsetof(struct wl_vtable, proxy_create) },
366         { "wl_proxy_destroy",
367           offsetof(struct wl_vtable, proxy_destroy) },
368         { "wl_proxy_marshal",
369           offsetof(struct wl_vtable, proxy_marshal) },
370         { "wl_proxy_add_listener",
371           offsetof(struct wl_vtable, proxy_add_listener) },
372         { NULL, }
373     };
374
375     if (ctx->display_type != VA_DISPLAY_WAYLAND)
376         return false;
377
378     i965->wl_output = calloc(1, sizeof(struct va_wl_output));
379     if (!i965->wl_output)
380         goto error;
381
382     i965->wl_output->libegl_handle = dso_open(LIBEGL_NAME);
383     if (!i965->wl_output->libegl_handle) {
384         i965->wl_output->libegl_handle = dso_open(LIBEGL_NAME_FALLBACK);
385         if (!i965->wl_output->libegl_handle)
386             goto error;
387     }
388
389     dso_handle = i965->wl_output->libegl_handle;
390     wl_vtable  = &i965->wl_output->vtable;
391     if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
392                          libegl_symbols))
393         goto error;
394
395     i965->wl_output->libwl_client_handle = dso_open(LIBWAYLAND_CLIENT_NAME);
396     if (!i965->wl_output->libwl_client_handle)
397         goto error;
398
399     dso_handle = i965->wl_output->libwl_client_handle;
400     wl_vtable  = &i965->wl_output->vtable;
401     if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
402                          libwl_client_symbols))
403         goto error;
404
405     if (!ensure_driver_vtable(ctx))
406         goto error;
407     return true;
408
409 error:
410     i965_output_wayland_terminate(ctx);
411     return false;
412 }
413
414 void
415 i965_output_wayland_terminate(VADriverContextP ctx)
416 {
417     struct i965_driver_data * const i965 = i965_driver_data(ctx);
418     struct va_wl_output *wl_output;
419
420     if (ctx->display_type != VA_DISPLAY_WAYLAND)
421         return;
422
423     wl_output = i965->wl_output;
424     if (!wl_output)
425         return;
426
427     if (wl_output->wl_drm) {
428         wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_drm);
429         wl_output->wl_drm = NULL;
430     }
431
432     if (wl_output->libegl_handle) {
433         dso_close(wl_output->libegl_handle);
434         wl_output->libegl_handle = NULL;
435     }
436
437     if (wl_output->libwl_client_handle) {
438         dso_close(wl_output->libwl_client_handle);
439         wl_output->libwl_client_handle = NULL;
440     }
441     free(wl_output);
442     i965->wl_output = NULL;
443 }