2 * gstvaapidisplay_wayland.c - VA/Wayland display abstraction
4 * Copyright (C) 2012 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
23 * SECTION:gstvaapidisplay_wayland
24 * @short_description: VA/Wayland display abstraction
29 #include "gstvaapidisplay_priv.h"
30 #include "gstvaapidisplay_wayland.h"
31 #include "gstvaapidisplay_wayland_priv.h"
34 #include "gstvaapidebug.h"
36 G_DEFINE_TYPE(GstVaapiDisplayWayland,
37 gst_vaapi_display_wayland,
38 GST_VAAPI_TYPE_DISPLAY);
47 #define NAME_PREFIX "WLD:"
48 #define NAME_PREFIX_LENGTH 4
50 static inline gboolean
51 is_display_name(const gchar *display_name)
53 return strncmp(display_name, NAME_PREFIX, NAME_PREFIX_LENGTH) == 0;
56 static inline const gchar *
57 get_default_display_name(void)
59 static const gchar *g_display_name;
62 g_display_name = getenv("WAYLAND_DISPLAY");
63 return g_display_name;
67 get_display_name_length(const gchar *display_name)
71 str = strchr(display_name, '-');
73 return str - display_name;
74 return strlen(display_name);
78 compare_display_name(gconstpointer a, gconstpointer b, gpointer user_data)
80 const gchar *cached_name = a;
81 const gchar *tested_name = b;
82 guint cached_name_length, tested_name_length;
84 if (!cached_name || !is_display_name(cached_name))
86 cached_name += NAME_PREFIX_LENGTH;
87 cached_name_length = get_display_name_length(cached_name);
89 g_return_val_if_fail(tested_name && is_display_name(tested_name), FALSE);
90 tested_name += NAME_PREFIX_LENGTH;
91 tested_name_length = get_display_name_length(tested_name);
93 /* XXX: handle screen number and default WAYLAND_DISPLAY name */
94 if (cached_name_length != tested_name_length)
96 if (strncmp(cached_name, tested_name, cached_name_length) != 0)
102 gst_vaapi_display_wayland_finalize(GObject *object)
104 G_OBJECT_CLASS(gst_vaapi_display_wayland_parent_class)->finalize(object);
107 /* Reconstruct a display name without our prefix */
109 get_display_name(gpointer ptr)
111 GstVaapiDisplayWayland * const display = GST_VAAPI_DISPLAY_WAYLAND(ptr);
112 const gchar *display_name = display->priv->display_name;
117 if (is_display_name(display_name)) {
118 display_name += NAME_PREFIX_LENGTH;
119 if (*display_name == '\0')
124 /* XXX: this should not happen */
125 g_assert(0 && "display name without prefix");
129 /* Mangle display name with our prefix */
131 set_display_name(GstVaapiDisplayWayland *display, const gchar *display_name)
133 GstVaapiDisplayWaylandPrivate * const priv = display->priv;
135 g_free(priv->display_name);
138 display_name = get_default_display_name();
142 priv->display_name = g_strdup_printf("%s%s", NAME_PREFIX, display_name);
146 gst_vaapi_display_wayland_set_property(
153 GstVaapiDisplayWayland * const display = GST_VAAPI_DISPLAY_WAYLAND(object);
156 case PROP_DISPLAY_NAME:
157 set_display_name(display, g_value_get_string(value));
159 case PROP_WL_DISPLAY:
160 display->priv->wl_display = g_value_get_pointer(value);
163 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
168 gst_vaapi_display_wayland_get_property(
175 GstVaapiDisplayWayland * const display = GST_VAAPI_DISPLAY_WAYLAND(object);
178 case PROP_DISPLAY_NAME:
179 g_value_set_string(value, get_display_name(display));
181 case PROP_WL_DISPLAY:
182 g_value_set_pointer(value, gst_vaapi_display_wayland_get_display(display));
185 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
191 gst_vaapi_display_wayland_constructed(GObject *object)
193 GstVaapiDisplayWayland * const display = GST_VAAPI_DISPLAY_WAYLAND(object);
194 GstVaapiDisplayWaylandPrivate * const priv = display->priv;
195 GstVaapiDisplayCache * const cache = gst_vaapi_display_get_cache();
196 const GstVaapiDisplayInfo *info;
197 GObjectClass *parent_class;
199 priv->create_display = priv->wl_display == NULL;
201 /* Don't create Wayland display if there is one in the cache already */
202 if (priv->create_display) {
203 info = gst_vaapi_display_cache_lookup_by_name(
206 compare_display_name, NULL
209 priv->wl_display = info->native_display;
210 priv->create_display = FALSE;
214 /* Reset display-name if the user provided his own Wayland display */
215 if (!priv->create_display) {
216 /* XXX: how to get socket/display name? */
217 GST_WARNING("wayland: get display name");
218 set_display_name(display, NULL);
221 parent_class = G_OBJECT_CLASS(gst_vaapi_display_wayland_parent_class);
222 if (parent_class->constructed)
223 parent_class->constructed(object);
227 output_handle_geometry(void *data, struct wl_output *output,
228 int x, int y, int physical_width, int physical_height,
229 int subpixel, const char *make, const char *model,
232 GstVaapiDisplayWaylandPrivate * const priv = data;
234 priv->phys_width = physical_width;
235 priv->phys_height = physical_height;
239 output_handle_mode(void *data, struct wl_output *wl_output,
240 uint32_t flags, int width, int height, int refresh)
242 GstVaapiDisplayWaylandPrivate * const priv = data;
244 if (flags & WL_OUTPUT_MODE_CURRENT) {
246 priv->height = height;
250 static const struct wl_output_listener output_listener = {
251 output_handle_geometry,
256 display_handle_global(
257 struct wl_display *display,
259 const char *interface,
264 GstVaapiDisplayWaylandPrivate * const priv = data;
266 if (strcmp(interface, "wl_compositor") == 0)
267 priv->compositor = wl_display_bind(display, id, &wl_compositor_interface);
268 else if (strcmp(interface, "wl_shell") == 0)
269 priv->shell = wl_display_bind(display, id, &wl_shell_interface);
270 else if (strcmp(interface, "wl_output") == 0) {
271 priv->output = wl_display_bind(display, id, &wl_output_interface);
272 wl_output_add_listener(priv->output, &output_listener, priv);
277 event_mask_update(uint32_t mask, void *data)
279 GstVaapiDisplayWaylandPrivate * const priv = data;
281 priv->event_mask = mask;
286 gst_vaapi_display_wayland_open_display(GstVaapiDisplay * display)
288 GstVaapiDisplayWaylandPrivate * const priv =
289 GST_VAAPI_DISPLAY_WAYLAND(display)->priv;
291 if (!priv->create_display)
292 return priv->wl_display != NULL;
294 priv->wl_display = wl_display_connect(get_display_name(display));
295 if (!priv->wl_display)
298 wl_display_set_user_data(priv->wl_display, priv);
299 wl_display_add_global_listener(priv->wl_display, display_handle_global, priv);
300 priv->event_fd = wl_display_get_fd(priv->wl_display, event_mask_update, priv);
301 wl_display_iterate(priv->wl_display, priv->event_mask);
302 wl_display_roundtrip(priv->wl_display);
304 if (!priv->compositor) {
305 GST_ERROR("failed to bind compositor interface");
310 GST_ERROR("failed to bind shell interface");
317 gst_vaapi_display_wayland_close_display(GstVaapiDisplay * display)
319 GstVaapiDisplayWaylandPrivate * const priv =
320 GST_VAAPI_DISPLAY_WAYLAND(display)->priv;
322 if (priv->compositor) {
323 wl_compositor_destroy(priv->compositor);
324 priv->compositor = NULL;
327 if (priv->wl_display) {
328 if (priv->create_display)
329 wl_display_disconnect(priv->wl_display);
330 priv->wl_display = NULL;
333 if (priv->display_name) {
334 g_free(priv->display_name);
335 priv->display_name = NULL;
340 gst_vaapi_display_wayland_get_display_info(
341 GstVaapiDisplay *display,
342 GstVaapiDisplayInfo *info
345 GstVaapiDisplayWaylandPrivate * const priv =
346 GST_VAAPI_DISPLAY_WAYLAND(display)->priv;
347 GstVaapiDisplayCache *cache;
348 const GstVaapiDisplayInfo *cached_info;
350 /* Return any cached info even if child has its own VA display */
351 cache = gst_vaapi_display_get_cache();
355 gst_vaapi_display_cache_lookup_by_native_display(cache, priv->wl_display);
357 *info = *cached_info;
361 /* Otherwise, create VA display if there is none already */
362 info->native_display = priv->wl_display;
363 info->display_name = priv->display_name;
364 if (!info->va_display) {
365 info->va_display = vaGetDisplayWl(priv->wl_display);
366 if (!info->va_display)
368 info->display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
374 gst_vaapi_display_wayland_get_size(
375 GstVaapiDisplay *display,
380 GstVaapiDisplayWaylandPrivate * const priv =
381 GST_VAAPI_DISPLAY_WAYLAND(display)->priv;
387 *pwidth = priv->width;
390 *pheight = priv->height;
394 gst_vaapi_display_wayland_get_size_mm(
395 GstVaapiDisplay *display,
400 GstVaapiDisplayWaylandPrivate * const priv =
401 GST_VAAPI_DISPLAY_WAYLAND(display)->priv;
407 *pwidth = priv->phys_width;
410 *pheight = priv->phys_height;
414 gst_vaapi_display_wayland_class_init(GstVaapiDisplayWaylandClass * klass)
416 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
417 GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
419 g_type_class_add_private(klass, sizeof(GstVaapiDisplayWaylandPrivate));
421 object_class->finalize = gst_vaapi_display_wayland_finalize;
422 object_class->set_property = gst_vaapi_display_wayland_set_property;
423 object_class->get_property = gst_vaapi_display_wayland_get_property;
424 object_class->constructed = gst_vaapi_display_wayland_constructed;
426 dpy_class->open_display = gst_vaapi_display_wayland_open_display;
427 dpy_class->close_display = gst_vaapi_display_wayland_close_display;
428 dpy_class->get_display = gst_vaapi_display_wayland_get_display_info;
429 dpy_class->get_size = gst_vaapi_display_wayland_get_size;
430 dpy_class->get_size_mm = gst_vaapi_display_wayland_get_size_mm;
433 * GstVaapiDisplayWayland:wayland-display:
435 * The Wayland #wl_display that was created by
436 * gst_vaapi_display_wayland_new() or that was bound from
437 * gst_vaapi_display_wayland_new_with_display().
439 g_object_class_install_property
442 g_param_spec_pointer("wl-display",
445 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
448 * GstVaapiDisplayWayland:display-name:
450 * The Wayland display name.
452 g_object_class_install_property
455 g_param_spec_string("display-name",
456 "Wayland display name",
457 "Wayland display name",
459 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
463 gst_vaapi_display_wayland_init(GstVaapiDisplayWayland *display)
465 GstVaapiDisplayWaylandPrivate * const priv =
466 GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE(display);
468 display->priv = priv;
469 priv->create_display = TRUE;
470 priv->display_name = NULL;
471 priv->wl_display = NULL;
472 priv->compositor = NULL;
477 priv->phys_width = 0;
478 priv->phys_height = 0;
480 priv->event_mask = 0;
484 * gst_vaapi_display_wayland_new:
485 * @display_name: the Wayland display name
487 * Opens an Wayland #wl_display using @display_name and returns a
488 * newly allocated #GstVaapiDisplay object. The Wayland display will
489 * be cloed when the reference count of the object reaches zero.
491 * Return value: a newly allocated #GstVaapiDisplay object
494 gst_vaapi_display_wayland_new(const gchar *display_name)
496 return g_object_new(GST_VAAPI_TYPE_DISPLAY_WAYLAND,
497 "display-name", display_name,
502 * gst_vaapi_display_wayland_new_with_display:
503 * @wl_display: an Wayland #wl_display
505 * Creates a #GstVaapiDisplay based on the Wayland @wl_display
506 * display. The caller still owns the display and must call
507 * wl_display_disconnect() when all #GstVaapiDisplay references are
508 * released. Doing so too early can yield undefined behaviour.
510 * Return value: a newly allocated #GstVaapiDisplay object
513 gst_vaapi_display_wayland_new_with_display(struct wl_display *wl_display)
515 g_return_val_if_fail(wl_display, NULL);
517 return g_object_new(GST_VAAPI_TYPE_DISPLAY_WAYLAND,
518 "wl-display", wl_display,
523 * gst_vaapi_display_wayland_get_display:
524 * @display: a #GstVaapiDisplayWayland
526 * Returns the underlying Wayland #wl_display that was created by
527 * gst_vaapi_display_wayland_new() or that was bound from
528 * gst_vaapi_display_wayland_new_with_display().
530 * Return value: the Wayland #wl_display attached to @display
533 gst_vaapi_display_wayland_get_display(GstVaapiDisplayWayland *display)
535 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_WAYLAND(display), NULL);
537 return display->priv->wl_display;