• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &registry_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