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 void (*wl_display_roundtrip_func)(struct wl_display *display);
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);
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;
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;
74 /* These function are copied and adapted from the version inside
75 * wayland-client-protocol.h
79 struct wl_vtable *wl_vtable,
80 struct wl_registry *wl_registry,
82 const struct wl_interface *interface,
88 id = wl_vtable->proxy_create((struct wl_proxy *) wl_registry,
93 wl_vtable->proxy_marshal((struct wl_proxy *) wl_registry,
94 WL_REGISTRY_BIND, name, interface->name,
100 static struct wl_registry *
101 display_get_registry(
102 struct wl_vtable *wl_vtable,
103 struct wl_display *wl_display
106 struct wl_proxy *callback;
108 callback = wl_vtable->proxy_create((struct wl_proxy *) wl_display,
109 wl_vtable->registry_interface);
113 wl_vtable->proxy_marshal((struct wl_proxy *) wl_display,
114 WL_DISPLAY_GET_REGISTRY, callback);
116 return (struct wl_registry *) callback;
120 registry_add_listener(
121 struct wl_vtable *wl_vtable,
122 struct wl_registry *wl_registry,
123 const struct wl_registry_listener *listener,
127 return wl_vtable->proxy_add_listener((struct wl_proxy *) wl_registry,
128 (void (**)(void)) listener, data);
132 registry_handle_global(
134 struct wl_registry *registry,
136 const char *interface,
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;
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);
151 static const struct wl_registry_listener registry_listener = {
152 registry_handle_global,
156 /* Ensure wl_drm instance is created */
158 ensure_wl_output(VADriverContextP ctx)
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;
164 if (wl_output->wl_drm)
167 wl_output->wl_registry = display_get_registry(wl_vtable, ctx->native_dpy);
168 registry_add_listener(wl_vtable, wl_output->wl_registry,
169 ®istry_listener, ctx);
170 wl_vtable->display_roundtrip(ctx->native_dpy);
171 if (!wl_output->wl_drm)
176 /* Create planar/prime YUV buffer
177 * Create a prime buffer if fd is not -1, otherwise a
180 static struct wl_buffer *
181 create_prime_or_planar_buffer(
182 struct va_wl_output *wl_output,
192 struct wl_vtable * const wl_vtable = &wl_output->vtable;
195 id = wl_vtable->proxy_create(
196 (struct wl_proxy *)wl_output->wl_drm,
197 wl_vtable->buffer_interface
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,
206 (fd != -1) ? fd : name,
207 width, height, format,
208 offsets[0], pitches[0],
209 offsets[1], pitches[1],
210 offsets[2], pitches[2]
212 return (struct wl_buffer *)id;
215 /* Hook to return Wayland buffer associated with the VA surface */
217 va_GetSurfaceBufferWl(
218 struct VADriverContext *ctx,
221 struct wl_buffer **out_buffer
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];
232 obj_surface = SURFACE(surface);
234 return VA_STATUS_ERROR_INVALID_SURFACE;
236 if (flags != VA_FRAME_PICTURE)
237 return VA_STATUS_ERROR_FLAG_NOT_SUPPORTED;
240 return VA_STATUS_ERROR_INVALID_PARAMETER;
242 if (!ensure_wl_output(ctx))
243 return VA_STATUS_ERROR_INVALID_DISPLAY;
245 if (!vtable->has_prime_sharing || (drm_intel_bo_gem_export_to_prime(obj_surface->bo, &fd) != 0)) {
248 if (drm_intel_bo_flink(obj_surface->bo, &name) != 0)
249 return VA_STATUS_ERROR_INVALID_SURFACE;
252 switch (obj_surface->fourcc) {
254 drm_format = WL_DRM_FORMAT_NV12;
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;
270 switch (obj_surface->subsampling) {
271 case SUBSAMPLE_YUV411:
272 drm_format = WL_DRM_FORMAT_YUV411;
274 case SUBSAMPLE_YUV420:
275 drm_format = WL_DRM_FORMAT_YUV420;
277 case SUBSAMPLE_YUV422H:
278 case SUBSAMPLE_YUV422V:
279 drm_format = WL_DRM_FORMAT_YUV422;
281 case SUBSAMPLE_YUV444:
282 drm_format = WL_DRM_FORMAT_YUV444;
285 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
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;
295 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
298 buffer = create_prime_or_planar_buffer(
302 obj_surface->orig_width,
303 obj_surface->orig_height,
313 return VA_STATUS_ERROR_ALLOCATION_FAILED;
315 *out_buffer = buffer;
316 return VA_STATUS_SUCCESS;
319 /* Hook to return Wayland buffer associated with the VA image */
322 struct VADriverContext *ctx,
325 struct wl_buffer **out_buffer
328 return VA_STATUS_ERROR_UNIMPLEMENTED;
332 ensure_driver_vtable(VADriverContextP ctx)
334 struct VADriverVTableWayland * const vtable = ctx->vtable_wayland;
339 vtable->vaGetSurfaceBufferWl = va_GetSurfaceBufferWl;
340 vtable->vaGetImageBufferWl = va_GetImageBufferWl;
345 i965_output_wayland_init(VADriverContextP ctx)
347 struct i965_driver_data * const i965 = i965_driver_data(ctx);
348 struct dso_handle *dso_handle;
349 struct wl_vtable *wl_vtable;
351 static const struct dso_symbol libegl_symbols[] = {
352 { "wl_drm_interface",
353 offsetof(struct wl_vtable, drm_interface) },
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) },
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) },
375 if (ctx->display_type != VA_DISPLAY_WAYLAND)
378 i965->wl_output = calloc(1, sizeof(struct va_wl_output));
379 if (!i965->wl_output)
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)
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),
395 i965->wl_output->libwl_client_handle = dso_open(LIBWAYLAND_CLIENT_NAME);
396 if (!i965->wl_output->libwl_client_handle)
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))
405 if (!ensure_driver_vtable(ctx))
410 i965_output_wayland_terminate(ctx);
415 i965_output_wayland_terminate(VADriverContextP ctx)
417 struct i965_driver_data * const i965 = i965_driver_data(ctx);
418 struct va_wl_output *wl_output;
420 if (ctx->display_type != VA_DISPLAY_WAYLAND)
423 wl_output = i965->wl_output;
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;
432 if (wl_output->libegl_handle) {
433 dso_close(wl_output->libegl_handle);
434 wl_output->libegl_handle = NULL;
437 if (wl_output->libwl_client_handle) {
438 dso_close(wl_output->libwl_client_handle);
439 wl_output->libwl_client_handle = NULL;
442 i965->wl_output = NULL;