2 * Copyright (C) 2012 Intel Corporation. All Rights Reserved.
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:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
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.
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"
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"
44 typedef uint32_t (*wl_display_get_global_func)(struct wl_display *display,
45 const char *interface, uint32_t version);
46 typedef struct wl_event_queue *(*wl_display_create_queue_func)(struct wl_display *display);
47 typedef void (*wl_display_roundtrip_queue_func)(struct wl_display *display,
48 struct wl_event_queue *queue);
49 typedef void (*wl_event_queue_destroy_func)(struct wl_event_queue *queue);
50 typedef void *(*wl_proxy_create_wrapper_func)(struct wl_proxy *proxy);
51 typedef void(*wl_proxy_wrapper_destroy_func)(void *proxy);
52 typedef struct wl_proxy *(*wl_proxy_create_func)(struct wl_proxy *factory,
53 const struct wl_interface *interface);
54 typedef void (*wl_proxy_destroy_func)(struct wl_proxy *proxy);
55 typedef void (*wl_proxy_marshal_func)(struct wl_proxy *p, uint32_t opcode, ...);
56 typedef int (*wl_proxy_add_listener_func)(struct wl_proxy *proxy,
57 void (**implementation)(void), void *data);
58 typedef void (*wl_proxy_set_queue_func)(struct wl_proxy *proxy, struct wl_event_queue *queue);
61 const struct wl_interface *buffer_interface;
62 const struct wl_interface *drm_interface;
63 const struct wl_interface *registry_interface;
64 wl_display_create_queue_func display_create_queue;
65 wl_display_roundtrip_queue_func display_roundtrip_queue;
66 wl_event_queue_destroy_func event_queue_destroy;
67 wl_proxy_create_wrapper_func proxy_create_wrapper;
68 wl_proxy_wrapper_destroy_func proxy_wrapper_destroy;
69 wl_proxy_create_func proxy_create;
70 wl_proxy_destroy_func proxy_destroy;
71 wl_proxy_marshal_func proxy_marshal;
72 wl_proxy_add_listener_func proxy_add_listener;
73 wl_proxy_set_queue_func proxy_set_queue;
77 struct dso_handle *libegl_handle;
78 struct dso_handle *libwl_client_handle;
79 struct wl_vtable vtable;
80 struct wl_event_queue *queue;
81 struct wl_drm *wl_drm;
83 struct wl_registry *wl_registry;
86 /* These function are copied and adapted from the version inside
87 * wayland-client-protocol.h
91 struct wl_vtable *wl_vtable,
92 struct wl_registry *wl_registry,
94 const struct wl_interface *interface,
100 id = wl_vtable->proxy_create((struct wl_proxy *) wl_registry,
105 wl_vtable->proxy_marshal((struct wl_proxy *) wl_registry,
106 WL_REGISTRY_BIND, name, interface->name,
112 static struct wl_registry *
113 display_get_registry(
114 struct wl_vtable *wl_vtable,
115 struct wl_display *wl_display
118 struct wl_proxy *callback;
120 callback = wl_vtable->proxy_create((struct wl_proxy *) wl_display,
121 wl_vtable->registry_interface);
125 wl_vtable->proxy_marshal((struct wl_proxy *) wl_display,
126 WL_DISPLAY_GET_REGISTRY, callback);
128 return (struct wl_registry *) callback;
132 registry_add_listener(
133 struct wl_vtable *wl_vtable,
134 struct wl_registry *wl_registry,
135 const struct wl_registry_listener *listener,
139 return wl_vtable->proxy_add_listener((struct wl_proxy *) wl_registry,
140 (void (**)(void)) listener, data);
144 registry_handle_global(
146 struct wl_registry *registry,
148 const char *interface,
152 VADriverContextP ctx = data;
153 struct i965_driver_data * const i965 = i965_driver_data(ctx);
154 struct va_wl_output * const wl_output = i965->wl_output;
155 struct wl_vtable * const wl_vtable = &wl_output->vtable;
157 if (strcmp(interface, "wl_drm") == 0) {
158 wl_output->wl_drm_name = name;
159 wl_output->wl_drm = registry_bind(wl_vtable, wl_output->wl_registry,
160 name, wl_vtable->drm_interface,
161 (version < 2) ? version : 2);
166 registry_handle_global_remove(
168 struct wl_registry *registry,
172 VADriverContextP ctx = data;
173 struct i965_driver_data * const i965 = i965_driver_data(ctx);
174 struct va_wl_output * const wl_output = i965->wl_output;
176 if (wl_output->wl_drm && name == wl_output->wl_drm_name) {
177 wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_drm);
178 wl_output->wl_drm = NULL;
182 static const struct wl_registry_listener registry_listener = {
183 registry_handle_global,
184 registry_handle_global_remove
187 /* Ensure wl_drm instance is created */
189 ensure_wl_output(VADriverContextP ctx)
191 struct i965_driver_data * const i965 = i965_driver_data(ctx);
192 struct va_wl_output * const wl_output = i965->wl_output;
193 struct wl_vtable * const wl_vtable = &wl_output->vtable;
194 struct wl_display *display_wrapper;
196 if (wl_output->wl_drm)
199 if (wl_output->queue) {
200 wl_output->vtable.event_queue_destroy(wl_output->queue);
201 wl_output->queue = NULL;
203 wl_output->queue = wl_vtable->display_create_queue(ctx->native_dpy);
204 if (!wl_output->queue)
207 display_wrapper = wl_vtable->proxy_create_wrapper(ctx->native_dpy);
208 if (!display_wrapper)
210 wl_vtable->proxy_set_queue((struct wl_proxy *) display_wrapper, wl_output->queue);
212 if (wl_output->wl_registry) {
213 wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_registry);
214 wl_output->wl_registry = NULL;
216 wl_output->wl_registry = display_get_registry(wl_vtable, display_wrapper);
217 wl_vtable->proxy_wrapper_destroy(display_wrapper);
218 registry_add_listener(wl_vtable, wl_output->wl_registry,
219 ®istry_listener, ctx);
220 wl_vtable->display_roundtrip_queue(ctx->native_dpy, wl_output->queue);
221 if (!wl_output->wl_drm)
226 /* Create planar/prime YUV buffer
227 * Create a prime buffer if fd is not -1, otherwise a
230 static struct wl_buffer *
231 create_prime_or_planar_buffer(
232 struct va_wl_output *wl_output,
242 struct wl_vtable * const wl_vtable = &wl_output->vtable;
245 id = wl_vtable->proxy_create(
246 (struct wl_proxy *)wl_output->wl_drm,
247 wl_vtable->buffer_interface
252 wl_vtable->proxy_marshal(
253 (struct wl_proxy *)wl_output->wl_drm,
254 (fd != -1) ? WL_DRM_CREATE_PRIME_BUFFER : WL_DRM_CREATE_PLANAR_BUFFER,
256 (fd != -1) ? fd : name,
257 width, height, format,
258 offsets[0], pitches[0],
259 offsets[1], pitches[1],
260 offsets[2], pitches[2]
262 return (struct wl_buffer *)id;
265 /* Hook to return Wayland buffer associated with the VA surface */
267 va_GetSurfaceBufferWl(
268 struct VADriverContext *ctx,
271 struct wl_buffer **out_buffer
274 struct VADriverVTableWayland * const vtable = ctx->vtable_wayland;
275 struct i965_driver_data * const i965 = i965_driver_data(ctx);
276 struct object_surface *obj_surface;
277 struct wl_buffer *buffer;
278 uint32_t name, drm_format;
279 int offsets[3], pitches[3];
282 obj_surface = SURFACE(surface);
284 return VA_STATUS_ERROR_INVALID_SURFACE;
286 if (flags != VA_FRAME_PICTURE)
287 return VA_STATUS_ERROR_FLAG_NOT_SUPPORTED;
290 return VA_STATUS_ERROR_INVALID_PARAMETER;
292 if (!ensure_wl_output(ctx))
293 return VA_STATUS_ERROR_INVALID_DISPLAY;
295 if (!vtable->has_prime_sharing || (drm_intel_bo_gem_export_to_prime(obj_surface->bo, &fd) != 0)) {
298 if (drm_intel_bo_flink(obj_surface->bo, &name) != 0)
299 return VA_STATUS_ERROR_INVALID_SURFACE;
302 switch (obj_surface->fourcc) {
304 drm_format = WL_DRM_FORMAT_NV12;
306 pitches[0] = obj_surface->width;
307 offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
308 pitches[1] = obj_surface->cb_cr_pitch;
320 switch (obj_surface->subsampling) {
321 case SUBSAMPLE_YUV411:
322 drm_format = WL_DRM_FORMAT_YUV411;
324 case SUBSAMPLE_YUV420:
325 drm_format = WL_DRM_FORMAT_YUV420;
327 case SUBSAMPLE_YUV422H:
328 case SUBSAMPLE_YUV422V:
329 drm_format = WL_DRM_FORMAT_YUV422;
331 case SUBSAMPLE_YUV444:
332 drm_format = WL_DRM_FORMAT_YUV444;
335 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
338 pitches[0] = obj_surface->width;
339 offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
340 pitches[1] = obj_surface->cb_cr_pitch;
341 offsets[2] = obj_surface->width * obj_surface->y_cr_offset;
342 pitches[2] = obj_surface->cb_cr_pitch;
345 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
348 buffer = create_prime_or_planar_buffer(
352 obj_surface->orig_width,
353 obj_surface->orig_height,
363 return VA_STATUS_ERROR_ALLOCATION_FAILED;
365 *out_buffer = buffer;
366 return VA_STATUS_SUCCESS;
369 /* Hook to return Wayland buffer associated with the VA image */
372 struct VADriverContext *ctx,
375 struct wl_buffer **out_buffer
378 return VA_STATUS_ERROR_UNIMPLEMENTED;
382 ensure_driver_vtable(VADriverContextP ctx)
384 struct VADriverVTableWayland * const vtable = ctx->vtable_wayland;
389 vtable->vaGetSurfaceBufferWl = va_GetSurfaceBufferWl;
390 vtable->vaGetImageBufferWl = va_GetImageBufferWl;
395 i965_output_wayland_init(VADriverContextP ctx)
397 struct i965_driver_data * const i965 = i965_driver_data(ctx);
398 struct dso_handle *dso_handle;
399 struct wl_vtable *wl_vtable;
401 static const struct dso_symbol libegl_symbols[] = {
404 offsetof(struct wl_vtable, drm_interface)
409 static const struct dso_symbol libwl_client_symbols[] = {
411 "wl_buffer_interface",
412 offsetof(struct wl_vtable, buffer_interface)
415 "wl_registry_interface",
416 offsetof(struct wl_vtable, registry_interface)
419 "wl_display_create_queue",
420 offsetof(struct wl_vtable, display_create_queue)
423 "wl_display_roundtrip_queue",
424 offsetof(struct wl_vtable, display_roundtrip_queue)
427 "wl_event_queue_destroy",
428 offsetof(struct wl_vtable, event_queue_destroy)
431 "wl_proxy_create_wrapper",
432 offsetof(struct wl_vtable, proxy_create_wrapper)
435 "wl_proxy_wrapper_destroy",
436 offsetof(struct wl_vtable, proxy_wrapper_destroy)
440 offsetof(struct wl_vtable, proxy_create)
444 offsetof(struct wl_vtable, proxy_destroy)
448 offsetof(struct wl_vtable, proxy_marshal)
451 "wl_proxy_add_listener",
452 offsetof(struct wl_vtable, proxy_add_listener)
455 "wl_proxy_set_queue",
456 offsetof(struct wl_vtable, proxy_set_queue)
461 if (ctx->display_type != VA_DISPLAY_WAYLAND)
464 i965->wl_output = calloc(1, sizeof(struct va_wl_output));
465 if (!i965->wl_output)
468 i965->wl_output->libegl_handle = dso_open(LIBEGL_NAME);
469 if (!i965->wl_output->libegl_handle) {
470 i965->wl_output->libegl_handle = dso_open(LIBEGL_NAME_FALLBACK);
471 if (!i965->wl_output->libegl_handle)
475 dso_handle = i965->wl_output->libegl_handle;
476 wl_vtable = &i965->wl_output->vtable;
477 if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
481 i965->wl_output->libwl_client_handle = dso_open(LIBWAYLAND_CLIENT_NAME);
482 if (!i965->wl_output->libwl_client_handle)
485 dso_handle = i965->wl_output->libwl_client_handle;
486 wl_vtable = &i965->wl_output->vtable;
487 if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
488 libwl_client_symbols))
491 if (!ensure_driver_vtable(ctx))
496 i965_output_wayland_terminate(ctx);
501 i965_output_wayland_terminate(VADriverContextP ctx)
503 struct i965_driver_data * const i965 = i965_driver_data(ctx);
504 struct va_wl_output *wl_output;
506 if (ctx->display_type != VA_DISPLAY_WAYLAND)
509 wl_output = i965->wl_output;
513 if (wl_output->wl_drm) {
514 wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_drm);
515 wl_output->wl_drm = NULL;
518 if (wl_output->wl_registry) {
519 wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_registry);
520 wl_output->wl_registry = NULL;
523 if (wl_output->queue) {
524 wl_output->vtable.event_queue_destroy(wl_output->queue);
525 wl_output->queue = NULL;
528 if (wl_output->libegl_handle) {
529 dso_close(wl_output->libegl_handle);
530 wl_output->libegl_handle = NULL;
533 if (wl_output->libwl_client_handle) {
534 dso_close(wl_output->libwl_client_handle);
535 wl_output->libwl_client_handle = NULL;
538 i965->wl_output = NULL;