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 #define LIBEGL_NAME "libEGL.so.1"
39 #define LIBWAYLAND_CLIENT_NAME "libwayland-client.so.0"
41 typedef uint32_t (*wl_display_get_global_func)(struct wl_display *display,
42 const char *interface, uint32_t version);
43 typedef void (*wl_display_roundtrip_func)(struct wl_display *display);
45 typedef struct wl_proxy *(*wl_proxy_create_func)(struct wl_proxy *factory,
46 const struct wl_interface *interface);
47 typedef void (*wl_proxy_destroy_func)(struct wl_proxy *proxy);
48 typedef void (*wl_proxy_marshal_func)(struct wl_proxy *p, uint32_t opcode, ...);
49 typedef int (*wl_proxy_add_listener_func) (struct wl_proxy *proxy,
50 void (**implementation)(void), void *data);
53 const struct wl_interface *buffer_interface;
54 const struct wl_interface *drm_interface;
55 const struct wl_interface *registry_interface;
56 wl_display_roundtrip_func display_roundtrip;
57 wl_proxy_create_func proxy_create;
58 wl_proxy_destroy_func proxy_destroy;
59 wl_proxy_marshal_func proxy_marshal;
60 wl_proxy_add_listener_func proxy_add_listener;
64 struct dso_handle *libegl_handle;
65 struct dso_handle *libwl_client_handle;
66 struct wl_vtable vtable;
67 struct wl_drm *wl_drm;
68 struct wl_registry *wl_registry;
71 /* These function are copied and adapted from the version inside
72 * wayland-client-protocol.h
76 struct wl_vtable *wl_vtable,
77 struct wl_registry *wl_registry,
79 const struct wl_interface *interface,
85 id = wl_vtable->proxy_create((struct wl_proxy *) wl_registry,
90 wl_vtable->proxy_marshal((struct wl_proxy *) wl_registry,
91 WL_REGISTRY_BIND, name, interface->name,
97 static struct wl_registry *
99 struct wl_vtable *wl_vtable,
100 struct wl_display *wl_display
103 struct wl_proxy *callback;
105 callback = wl_vtable->proxy_create((struct wl_proxy *) wl_display,
106 wl_vtable->registry_interface);
110 wl_vtable->proxy_marshal((struct wl_proxy *) wl_display,
111 WL_DISPLAY_GET_REGISTRY, callback);
113 return (struct wl_registry *) callback;
117 registry_add_listener(
118 struct wl_vtable *wl_vtable,
119 struct wl_registry *wl_registry,
120 const struct wl_registry_listener *listener,
124 return wl_vtable->proxy_add_listener((struct wl_proxy *) wl_registry,
125 (void (**)(void)) listener, data);
129 registry_handle_global(
131 struct wl_registry *registry,
133 const char *interface,
137 VADriverContextP ctx = data;
138 struct i965_driver_data * const i965 = i965_driver_data(ctx);
139 struct va_wl_output * const wl_output = i965->wl_output;
140 struct wl_vtable * const wl_vtable = &wl_output->vtable;
142 if (strcmp(interface, "wl_drm") == 0) {
143 wl_output->wl_drm = registry_bind(wl_vtable, wl_output->wl_registry,
144 id, wl_vtable->drm_interface, 1);
148 static const struct wl_registry_listener registry_listener = {
149 registry_handle_global,
153 /* Ensure wl_drm instance is created */
155 ensure_wl_output(VADriverContextP ctx)
157 struct i965_driver_data * const i965 = i965_driver_data(ctx);
158 struct va_wl_output * const wl_output = i965->wl_output;
159 struct wl_vtable * const wl_vtable = &wl_output->vtable;
161 if (wl_output->wl_drm)
164 wl_output->wl_registry = display_get_registry(wl_vtable, ctx->native_dpy);
165 registry_add_listener(wl_vtable, wl_output->wl_registry,
166 ®istry_listener, ctx);
167 wl_vtable->display_roundtrip(ctx->native_dpy);
168 if (!wl_output->wl_drm)
173 /* Create planar YUV buffer */
174 static struct wl_buffer *
175 create_planar_buffer(
176 struct va_wl_output *wl_output,
185 struct wl_vtable * const wl_vtable = &wl_output->vtable;
188 id = wl_vtable->proxy_create(
189 (struct wl_proxy *)wl_output->wl_drm,
190 wl_vtable->buffer_interface
195 wl_vtable->proxy_marshal(
196 (struct wl_proxy *)wl_output->wl_drm,
197 WL_DRM_CREATE_PLANAR_BUFFER,
200 width, height, format,
201 offsets[0], pitches[0],
202 offsets[1], pitches[1],
203 offsets[2], pitches[2]
205 return (struct wl_buffer *)id;
208 /* Hook to return Wayland buffer associated with the VA surface */
210 va_GetSurfaceBufferWl(
211 struct VADriverContext *ctx,
214 struct wl_buffer **out_buffer
217 struct i965_driver_data * const i965 = i965_driver_data(ctx);
218 struct object_surface *obj_surface;
219 struct wl_buffer *buffer;
220 uint32_t name, drm_format;
221 int offsets[3], pitches[3];
223 obj_surface = SURFACE(surface);
225 return VA_STATUS_ERROR_INVALID_SURFACE;
227 if (flags != VA_FRAME_PICTURE)
228 return VA_STATUS_ERROR_FLAG_NOT_SUPPORTED;
231 return VA_STATUS_ERROR_INVALID_PARAMETER;
233 if (!ensure_wl_output(ctx))
234 return VA_STATUS_ERROR_INVALID_DISPLAY;
236 if (drm_intel_bo_flink(obj_surface->bo, &name) != 0)
237 return VA_STATUS_ERROR_INVALID_SURFACE;
239 switch (obj_surface->fourcc) {
241 drm_format = WL_DRM_FORMAT_NV12;
243 pitches[0] = obj_surface->width;
244 offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
245 pitches[1] = obj_surface->cb_cr_pitch;
257 switch (obj_surface->subsampling) {
258 case SUBSAMPLE_YUV411:
259 drm_format = WL_DRM_FORMAT_YUV411;
261 case SUBSAMPLE_YUV420:
262 drm_format = WL_DRM_FORMAT_YUV420;
264 case SUBSAMPLE_YUV422H:
265 case SUBSAMPLE_YUV422V:
266 drm_format = WL_DRM_FORMAT_YUV422;
268 case SUBSAMPLE_YUV444:
269 drm_format = WL_DRM_FORMAT_YUV444;
272 assert(0 && "unsupported subsampling");
273 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
276 pitches[0] = obj_surface->width;
277 offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
278 pitches[1] = obj_surface->cb_cr_pitch;
279 offsets[2] = obj_surface->width * obj_surface->y_cr_offset;
280 pitches[2] = obj_surface->cb_cr_pitch;
283 assert(0 && "unsupported format");
284 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
287 buffer = create_planar_buffer(
290 obj_surface->orig_width,
291 obj_surface->orig_height,
297 return VA_STATUS_ERROR_ALLOCATION_FAILED;
299 *out_buffer = buffer;
300 return VA_STATUS_SUCCESS;
303 /* Hook to return Wayland buffer associated with the VA image */
306 struct VADriverContext *ctx,
309 struct wl_buffer **out_buffer
312 return VA_STATUS_ERROR_UNIMPLEMENTED;
316 ensure_driver_vtable(VADriverContextP ctx)
318 struct VADriverVTableWayland * const vtable = ctx->vtable_wayland;
323 vtable->vaGetSurfaceBufferWl = va_GetSurfaceBufferWl;
324 vtable->vaGetImageBufferWl = va_GetImageBufferWl;
329 i965_output_wayland_init(VADriverContextP ctx)
331 struct i965_driver_data * const i965 = i965_driver_data(ctx);
332 struct dso_handle *dso_handle;
333 struct wl_vtable *wl_vtable;
335 static const struct dso_symbol libegl_symbols[] = {
336 { "wl_drm_interface",
337 offsetof(struct wl_vtable, drm_interface) },
341 static const struct dso_symbol libwl_client_symbols[] = {
342 { "wl_buffer_interface",
343 offsetof(struct wl_vtable, buffer_interface) },
344 { "wl_registry_interface",
345 offsetof(struct wl_vtable, registry_interface) },
346 { "wl_display_roundtrip",
347 offsetof(struct wl_vtable, display_roundtrip) },
349 offsetof(struct wl_vtable, proxy_create) },
350 { "wl_proxy_destroy",
351 offsetof(struct wl_vtable, proxy_destroy) },
352 { "wl_proxy_marshal",
353 offsetof(struct wl_vtable, proxy_marshal) },
354 { "wl_proxy_add_listener",
355 offsetof(struct wl_vtable, proxy_add_listener) },
359 if (ctx->display_type != VA_DISPLAY_WAYLAND)
362 i965->wl_output = calloc(1, sizeof(struct va_wl_output));
363 if (!i965->wl_output)
366 i965->wl_output->libegl_handle = dso_open(LIBEGL_NAME);
367 if (!i965->wl_output->libegl_handle)
370 dso_handle = i965->wl_output->libegl_handle;
371 wl_vtable = &i965->wl_output->vtable;
372 if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
376 i965->wl_output->libwl_client_handle = dso_open(LIBWAYLAND_CLIENT_NAME);
377 if (!i965->wl_output->libwl_client_handle)
380 dso_handle = i965->wl_output->libwl_client_handle;
381 wl_vtable = &i965->wl_output->vtable;
382 if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
383 libwl_client_symbols))
386 if (!ensure_driver_vtable(ctx))
391 i965_output_wayland_terminate(ctx);
396 i965_output_wayland_terminate(VADriverContextP ctx)
398 struct i965_driver_data * const i965 = i965_driver_data(ctx);
399 struct va_wl_output *wl_output;
401 if (ctx->display_type != VA_DISPLAY_WAYLAND)
404 wl_output = i965->wl_output;
408 if (wl_output->wl_drm) {
409 wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_drm);
410 wl_output->wl_drm = NULL;
413 if (wl_output->libegl_handle) {
414 dso_close(wl_output->libegl_handle);
415 wl_output->libegl_handle = NULL;
418 if (wl_output->libwl_client_handle) {
419 dso_close(wl_output->libwl_client_handle);
420 wl_output->libwl_client_handle = NULL;
423 i965->wl_output = NULL;