OSDN Git Service

svct: Usa an array to store QP rounding accumulator
[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 <assert.h>
29 #include <va/va_backend.h>
30 #include <va/va_backend_wayland.h>
31 #include <wayland-client.h>
32 #include <wayland-drm-client-protocol.h>
33 #include "intel_driver.h"
34 #include "i965_output_wayland.h"
35 #include "i965_drv_video.h"
36 #include "i965_defines.h"
37 #include "dso_utils.h"
38
39 #define LIBEGL_NAME             "libEGL.so.1"
40 #define LIBWAYLAND_CLIENT_NAME  "libwayland-client.so.0"
41
42 typedef uint32_t (*wl_display_get_global_func)(struct wl_display *display,
43     const char *interface, uint32_t version);
44 typedef void (*wl_display_roundtrip_func)(struct wl_display *display);
45
46 typedef struct wl_proxy *(*wl_proxy_create_func)(struct wl_proxy *factory,
47     const struct wl_interface *interface);
48 typedef void (*wl_proxy_destroy_func)(struct wl_proxy *proxy);
49 typedef void (*wl_proxy_marshal_func)(struct wl_proxy *p, uint32_t opcode, ...);
50 typedef int (*wl_proxy_add_listener_func) (struct wl_proxy *proxy,
51     void (**implementation)(void), void *data);
52
53 struct wl_vtable {
54     const struct wl_interface  *buffer_interface;
55     const struct wl_interface  *drm_interface;
56     const struct wl_interface  *registry_interface;
57     wl_display_roundtrip_func   display_roundtrip;
58     wl_proxy_create_func        proxy_create;
59     wl_proxy_destroy_func       proxy_destroy;
60     wl_proxy_marshal_func       proxy_marshal;
61     wl_proxy_add_listener_func  proxy_add_listener;
62 };
63
64 struct va_wl_output {
65     struct dso_handle  *libegl_handle;
66     struct dso_handle  *libwl_client_handle;
67     struct wl_vtable    vtable;
68     struct wl_drm      *wl_drm;
69     struct wl_registry *wl_registry;
70 };
71
72 /* These function are copied and adapted from the version inside
73  * wayland-client-protocol.h
74  */
75 static void *
76 registry_bind(
77     struct wl_vtable          *wl_vtable,
78     struct wl_registry        *wl_registry,
79     uint32_t                   name,
80     const struct wl_interface *interface,
81     uint32_t                   version
82 )
83 {
84     struct wl_proxy *id;
85
86     id = wl_vtable->proxy_create((struct wl_proxy *) wl_registry,
87                                  interface);
88     if (!id)
89       return NULL;
90
91     wl_vtable->proxy_marshal((struct wl_proxy *) wl_registry,
92                              WL_REGISTRY_BIND, name, interface->name,
93                              version, id);
94
95     return (void *) id;
96 }
97
98 static struct wl_registry *
99 display_get_registry(
100     struct wl_vtable  *wl_vtable,
101     struct wl_display *wl_display
102 )
103 {
104     struct wl_proxy *callback;
105
106     callback = wl_vtable->proxy_create((struct wl_proxy *) wl_display,
107                                        wl_vtable->registry_interface);
108     if (!callback)
109       return NULL;
110
111     wl_vtable->proxy_marshal((struct wl_proxy *) wl_display,
112                              WL_DISPLAY_GET_REGISTRY, callback);
113
114     return (struct wl_registry *) callback;
115 }
116
117 static int
118 registry_add_listener(
119     struct wl_vtable                  *wl_vtable,
120     struct wl_registry                *wl_registry,
121     const struct wl_registry_listener *listener,
122     void                              *data
123 )
124 {
125     return wl_vtable->proxy_add_listener((struct wl_proxy *) wl_registry,
126                                          (void (**)(void)) listener, data);
127 }
128
129 static void
130 registry_handle_global(
131     void               *data,
132     struct wl_registry *registry,
133     uint32_t            id,
134     const char         *interface,
135     uint32_t            version
136 )
137 {
138     VADriverContextP ctx = data;
139     struct i965_driver_data * const i965 = i965_driver_data(ctx);
140     struct va_wl_output * const wl_output = i965->wl_output;
141     struct wl_vtable * const wl_vtable = &wl_output->vtable;
142
143     if (strcmp(interface, "wl_drm") == 0) {
144         wl_output->wl_drm = registry_bind(wl_vtable, wl_output->wl_registry,
145                                           id, wl_vtable->drm_interface, 2);
146     }
147 }
148
149 static const struct wl_registry_listener registry_listener = {
150     registry_handle_global,
151     NULL
152 };
153
154 /* Ensure wl_drm instance is created */
155 static bool
156 ensure_wl_output(VADriverContextP ctx)
157 {
158     struct i965_driver_data * const i965 = i965_driver_data(ctx);
159     struct va_wl_output * const wl_output = i965->wl_output;
160     struct wl_vtable * const wl_vtable = &wl_output->vtable;
161
162     if (wl_output->wl_drm)
163         return true;
164
165     wl_output->wl_registry = display_get_registry(wl_vtable, ctx->native_dpy);
166     registry_add_listener(wl_vtable, wl_output->wl_registry,
167                           &registry_listener, ctx);
168     wl_vtable->display_roundtrip(ctx->native_dpy);
169     if (!wl_output->wl_drm)
170         return false;
171     return true;
172 }
173
174 /* Create planar/prime YUV buffer
175  * Create a prime buffer if fd is not -1, otherwise a
176  * planar buffer
177  */
178 static struct wl_buffer *
179 create_prime_or_planar_buffer(
180     struct va_wl_output *wl_output,
181     uint32_t             name,
182     int                  fd,
183     int32_t              width,
184     int32_t              height,
185     uint32_t             format,
186     int32_t              offsets[3],
187     int32_t              pitches[3]
188 )
189 {
190     struct wl_vtable * const wl_vtable = &wl_output->vtable;
191     struct wl_proxy *id;
192
193     id = wl_vtable->proxy_create(
194         (struct wl_proxy *)wl_output->wl_drm,
195         wl_vtable->buffer_interface
196     );
197     if (!id)
198         return NULL;
199
200     wl_vtable->proxy_marshal(
201         (struct wl_proxy *)wl_output->wl_drm,
202         (fd != -1) ? WL_DRM_CREATE_PRIME_BUFFER : WL_DRM_CREATE_PLANAR_BUFFER,
203         id,
204         (fd != -1) ? fd : name,
205         width, height, format,
206         offsets[0], pitches[0],
207         offsets[1], pitches[1],
208         offsets[2], pitches[2]
209     );
210     return (struct wl_buffer *)id;
211 }
212
213 /* Hook to return Wayland buffer associated with the VA surface */
214 static VAStatus
215 va_GetSurfaceBufferWl(
216     struct VADriverContext *ctx,
217     VASurfaceID             surface,
218     unsigned int            flags,
219     struct wl_buffer      **out_buffer
220 )
221 {
222     struct VADriverVTableWayland * const vtable = ctx->vtable_wayland;
223     struct i965_driver_data * const i965 = i965_driver_data(ctx);
224     struct object_surface *obj_surface;
225     struct wl_buffer *buffer;
226     uint32_t name, drm_format;
227     int offsets[3], pitches[3];
228     int fd = -1;
229
230     obj_surface = SURFACE(surface);
231     if (!obj_surface)
232         return VA_STATUS_ERROR_INVALID_SURFACE;
233
234     if (flags != VA_FRAME_PICTURE)
235         return VA_STATUS_ERROR_FLAG_NOT_SUPPORTED;
236
237     if (!out_buffer)
238         return VA_STATUS_ERROR_INVALID_PARAMETER;
239
240     if (!ensure_wl_output(ctx))
241         return VA_STATUS_ERROR_INVALID_DISPLAY;
242
243     if (!vtable->has_prime_sharing || (drm_intel_bo_gem_export_to_prime(obj_surface->bo, &fd) != 0)) {
244         fd = -1;
245
246         if (drm_intel_bo_flink(obj_surface->bo, &name) != 0)
247             return VA_STATUS_ERROR_INVALID_SURFACE;
248     }
249
250     switch (obj_surface->fourcc) {
251     case VA_FOURCC_NV12:
252         drm_format = WL_DRM_FORMAT_NV12;
253         offsets[0] = 0;
254         pitches[0] = obj_surface->width;
255         offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
256         pitches[1] = obj_surface->cb_cr_pitch;
257         offsets[2] = 0;
258         pitches[2] = 0;
259         break;
260     case VA_FOURCC_YV12:
261     case VA_FOURCC_I420:
262     case VA_FOURCC_IMC1:
263     case VA_FOURCC_IMC3:
264     case VA_FOURCC_422H:
265     case VA_FOURCC_422V:
266     case VA_FOURCC_411P:
267     case VA_FOURCC_444P:
268         switch (obj_surface->subsampling) {
269         case SUBSAMPLE_YUV411:
270             drm_format = WL_DRM_FORMAT_YUV411;
271             break;
272         case SUBSAMPLE_YUV420:
273             drm_format = WL_DRM_FORMAT_YUV420;
274             break;
275         case SUBSAMPLE_YUV422H:
276         case SUBSAMPLE_YUV422V:
277             drm_format = WL_DRM_FORMAT_YUV422;
278             break;
279         case SUBSAMPLE_YUV444:
280             drm_format = WL_DRM_FORMAT_YUV444;
281             break;
282         default:
283             assert(0 && "unsupported subsampling");
284             return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
285         }
286         offsets[0] = 0;
287         pitches[0] = obj_surface->width;
288         offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
289         pitches[1] = obj_surface->cb_cr_pitch;
290         offsets[2] = obj_surface->width * obj_surface->y_cr_offset;
291         pitches[2] = obj_surface->cb_cr_pitch;
292         break;
293     default:
294         assert(0 && "unsupported format");
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         goto error;
385
386     dso_handle = i965->wl_output->libegl_handle;
387     wl_vtable  = &i965->wl_output->vtable;
388     if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
389                          libegl_symbols))
390         goto error;
391
392     i965->wl_output->libwl_client_handle = dso_open(LIBWAYLAND_CLIENT_NAME);
393     if (!i965->wl_output->libwl_client_handle)
394         goto error;
395
396     dso_handle = i965->wl_output->libwl_client_handle;
397     wl_vtable  = &i965->wl_output->vtable;
398     if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
399                          libwl_client_symbols))
400         goto error;
401
402     if (!ensure_driver_vtable(ctx))
403         goto error;
404     return true;
405
406 error:
407     i965_output_wayland_terminate(ctx);
408     return false;
409 }
410
411 void
412 i965_output_wayland_terminate(VADriverContextP ctx)
413 {
414     struct i965_driver_data * const i965 = i965_driver_data(ctx);
415     struct va_wl_output *wl_output;
416
417     if (ctx->display_type != VA_DISPLAY_WAYLAND)
418         return;
419
420     wl_output = i965->wl_output;
421     if (!wl_output)
422         return;
423
424     if (wl_output->wl_drm) {
425         wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_drm);
426         wl_output->wl_drm = NULL;
427     }
428
429     if (wl_output->libegl_handle) {
430         dso_close(wl_output->libegl_handle);
431         wl_output->libegl_handle = NULL;
432     }
433
434     if (wl_output->libwl_client_handle) {
435         dso_close(wl_output->libwl_client_handle);
436         wl_output->libwl_client_handle = NULL;
437     }
438     free(wl_output);
439     i965->wl_output = NULL;
440 }