1 /*
2 * GStreamer
3 * Copyright (C) 2016 Matthew Waters <matthew@centricular.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <gst/vulkan/wayland/gstvkdisplay_wayland.h>
26
27 #include "wayland_event_source.h"
28
29 GST_DEBUG_CATEGORY_STATIC (gst_vulkan_display_wayland_debug);
30 #define GST_CAT_DEFAULT gst_vulkan_display_wayland_debug
31
32 G_DEFINE_TYPE_WITH_CODE (GstVulkanDisplayWayland, gst_vulkan_display_wayland,
33 GST_TYPE_VULKAN_DISPLAY, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT,
34 "vulkandisplaywayland", 0, "Vulkan Wayland Display");
35 );
36
37 static void gst_vulkan_display_wayland_finalize (GObject * object);
38 static gpointer gst_vulkan_display_wayland_get_handle (GstVulkanDisplay *
39 display);
40
41 static void
registry_handle_global(void * data,struct wl_registry * registry,uint32_t name,const char * interface,uint32_t version)42 registry_handle_global (void *data, struct wl_registry *registry,
43 uint32_t name, const char *interface, uint32_t version)
44 {
45 GstVulkanDisplayWayland *display = data;
46
47 GST_TRACE_OBJECT (display, "registry_handle_global with registry %p, "
48 "interface %s, version %u", registry, interface, version);
49
50 if (g_strcmp0 (interface, "wl_compositor") == 0) {
51 display->compositor =
52 wl_registry_bind (registry, name, &wl_compositor_interface, 1);
53 } else if (g_strcmp0 (interface, "wl_subcompositor") == 0) {
54 display->subcompositor =
55 wl_registry_bind (registry, name, &wl_subcompositor_interface, 1);
56 } else if (g_strcmp0 (interface, "wl_shell") == 0) {
57 display->shell = wl_registry_bind (registry, name, &wl_shell_interface, 1);
58 }
59 }
60
61 static const struct wl_registry_listener registry_listener = {
62 registry_handle_global
63 };
64
65 static void
_connect_listeners(GstVulkanDisplayWayland * display)66 _connect_listeners (GstVulkanDisplayWayland * display)
67 {
68 display->registry = wl_display_get_registry (display->display);
69 wl_registry_add_listener (display->registry, ®istry_listener, display);
70
71 wl_display_roundtrip (display->display);
72 }
73
74 static void
gst_vulkan_display_wayland_class_init(GstVulkanDisplayWaylandClass * klass)75 gst_vulkan_display_wayland_class_init (GstVulkanDisplayWaylandClass * klass)
76 {
77 GST_VULKAN_DISPLAY_CLASS (klass)->get_handle =
78 GST_DEBUG_FUNCPTR (gst_vulkan_display_wayland_get_handle);
79
80 G_OBJECT_CLASS (klass)->finalize = gst_vulkan_display_wayland_finalize;
81 }
82
83 static void
gst_vulkan_display_wayland_init(GstVulkanDisplayWayland * display_wayland)84 gst_vulkan_display_wayland_init (GstVulkanDisplayWayland * display_wayland)
85 {
86 GstVulkanDisplay *display = (GstVulkanDisplay *) display_wayland;
87
88 display->type = GST_VULKAN_DISPLAY_TYPE_WAYLAND;
89 display_wayland->foreign_display = FALSE;
90 }
91
92 static void
gst_vulkan_display_wayland_finalize(GObject * object)93 gst_vulkan_display_wayland_finalize (GObject * object)
94 {
95 GstVulkanDisplayWayland *display_wayland =
96 GST_VULKAN_DISPLAY_WAYLAND (object);
97
98 if (!display_wayland->foreign_display && display_wayland->display) {
99 wl_display_flush (display_wayland->display);
100 wl_display_disconnect (display_wayland->display);
101 }
102
103 G_OBJECT_CLASS (gst_vulkan_display_wayland_parent_class)->finalize (object);
104 }
105
106 /**
107 * gst_vulkan_display_wayland_new:
108 * @name: (allow-none): a display name
109 *
110 * Create a new #GstVulkanDisplayWayland from the wayland display name. See `wl_display_connect`()
111 * for details on what is a valid name.
112 *
113 * Returns: (transfer full): a new #GstVulkanDisplayWayland or %NULL
114 *
115 * Since: 1.18
116 */
117 GstVulkanDisplayWayland *
gst_vulkan_display_wayland_new(const gchar * name)118 gst_vulkan_display_wayland_new (const gchar * name)
119 {
120 GstVulkanDisplayWayland *ret;
121
122 ret = g_object_new (GST_TYPE_VULKAN_DISPLAY_WAYLAND, NULL);
123 gst_object_ref_sink (ret);
124 ret->display = wl_display_connect (name);
125
126 if (!ret->display) {
127 GST_ERROR ("Failed to open Wayland display connection with name, \'%s\'",
128 name);
129 return NULL;
130 }
131
132 /* connecting the listeners after attaching the event source will race with
133 * the source and the source may eat an event that we're waiting for and
134 * deadlock */
135 _connect_listeners (ret);
136
137 GST_VULKAN_DISPLAY (ret)->event_source =
138 wayland_event_source_new (ret->display, NULL);
139 g_source_attach (GST_VULKAN_DISPLAY (ret)->event_source,
140 GST_VULKAN_DISPLAY (ret)->main_context);
141
142 return ret;
143 }
144
145 /**
146 * gst_vulkan_display_wayland_new_with_display:
147 * @display: an existing, wayland display
148 *
149 * Creates a new display connection from a wl_display Display.
150 *
151 * Returns: (transfer full): a new #GstVulkanDisplayWayland
152 *
153 * Since: 1.18
154 */
155 GstVulkanDisplayWayland *
gst_vulkan_display_wayland_new_with_display(struct wl_display * display)156 gst_vulkan_display_wayland_new_with_display (struct wl_display * display)
157 {
158 GstVulkanDisplayWayland *ret;
159
160 g_return_val_if_fail (display != NULL, NULL);
161
162 ret = g_object_new (GST_TYPE_VULKAN_DISPLAY_WAYLAND, NULL);
163 gst_object_ref_sink (ret);
164
165 ret->display = display;
166 ret->foreign_display = TRUE;
167
168 _connect_listeners (ret);
169
170 return ret;
171 }
172
173 static gpointer
gst_vulkan_display_wayland_get_handle(GstVulkanDisplay * display)174 gst_vulkan_display_wayland_get_handle (GstVulkanDisplay * display)
175 {
176 return GST_VULKAN_DISPLAY_WAYLAND (display)->display;
177 }
178
179 static gboolean
_roundtrip_async(gpointer data)180 _roundtrip_async (gpointer data)
181 {
182 GstVulkanDisplayWayland *display = data;
183
184 wl_display_roundtrip (display->display);
185
186 return G_SOURCE_REMOVE;
187 }
188
189 void
gst_vulkan_display_wayland_roundtrip_async(GstVulkanDisplayWayland * display)190 gst_vulkan_display_wayland_roundtrip_async (GstVulkanDisplayWayland * display)
191 {
192 g_return_if_fail (GST_IS_VULKAN_DISPLAY_WAYLAND (display));
193
194 g_main_context_invoke (GST_VULKAN_DISPLAY (display)->main_context,
195 (GSourceFunc) _roundtrip_async, display);
196 }
197