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 #define GLIB_DISABLE_DEPRECATION_WARNINGS
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <linux/input.h>
28
29 #include "wayland_event_source.h"
30
31 #include "vkdisplay_wayland.h"
32 #include "vkwindow_wayland.h"
33
34 #define GST_CAT_DEFAULT gst_vulkan_window_wayland_debug
35 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
36
37 #define gst_vulkan_window_wayland_parent_class parent_class
38 G_DEFINE_TYPE (GstVulkanWindowWayland, gst_vulkan_window_wayland,
39 GST_TYPE_VULKAN_WINDOW)
40
41 static void gst_vulkan_window_wayland_close (GstVulkanWindow * window);
42 static gboolean gst_vulkan_window_wayland_open (GstVulkanWindow * window,
43 GError ** error);
44 static VkSurfaceKHR gst_vulkan_window_wayland_get_surface (GstVulkanWindow
45 * window, GError ** error);
46 static gboolean
47 gst_vulkan_window_wayland_get_presentation_support (GstVulkanWindow *
48 window, GstVulkanDevice * device, guint32 queue_family_idx);
49
50 static void
handle_ping(void * data,struct wl_shell_surface * shell_surface,uint32_t serial)51 handle_ping (void *data, struct wl_shell_surface *shell_surface,
52 uint32_t serial)
53 {
54 GstVulkanWindowWayland *window_wl = data;
55
56 GST_TRACE_OBJECT (window_wl, "ping received serial %u", serial);
57
58 wl_shell_surface_pong (shell_surface, serial);
59 }
60
61 /*
62 static void window_resize (GstVulkanWindowWayland * window_wl, guint width,
63 guint height);*/
64
65 static void
handle_configure(void * data,struct wl_shell_surface * shell_surface,uint32_t edges,int32_t width,int32_t height)66 handle_configure (void *data, struct wl_shell_surface *shell_surface,
67 uint32_t edges, int32_t width, int32_t height)
68 {
69 GstVulkanWindowWayland *window_wl = data;
70
71 GST_DEBUG_OBJECT (window_wl, "configure event on surface %p, %ix%i",
72 shell_surface, width, height);
73
74 /*window_resize (window_wl, width, height); */
75 }
76
77 static void
handle_popup_done(void * data,struct wl_shell_surface * shell_surface)78 handle_popup_done (void *data, struct wl_shell_surface *shell_surface)
79 {
80 }
81
82 static const struct wl_shell_surface_listener shell_surface_listener = {
83 handle_ping,
84 handle_configure,
85 handle_popup_done
86 };
87
88 static void
destroy_surfaces(GstVulkanWindowWayland * window_wl)89 destroy_surfaces (GstVulkanWindowWayland * window_wl)
90 {
91 GST_DEBUG_OBJECT (window_wl, "destroying created surfaces");
92
93 if (window_wl->shell_surface) {
94 wl_shell_surface_destroy (window_wl->shell_surface);
95 window_wl->shell_surface = NULL;
96 }
97 if (window_wl->surface) {
98 wl_surface_destroy (window_wl->surface);
99 window_wl->surface = NULL;
100 }
101 }
102
103 static void
create_surfaces(GstVulkanWindowWayland * window_wl)104 create_surfaces (GstVulkanWindowWayland * window_wl)
105 {
106 GstVulkanDisplayWayland *display =
107 GST_VULKAN_DISPLAY_WAYLAND (GST_VULKAN_WINDOW (window_wl)->display);
108 gint width, height;
109
110 if (!window_wl->surface) {
111 window_wl->surface = wl_compositor_create_surface (display->compositor);
112 if (window_wl->queue)
113 wl_proxy_set_queue ((struct wl_proxy *) window_wl->surface,
114 window_wl->queue);
115 }
116
117 if (!window_wl->shell_surface) {
118 window_wl->shell_surface =
119 wl_shell_get_shell_surface (display->shell, window_wl->surface);
120 if (window_wl->queue)
121 wl_proxy_set_queue ((struct wl_proxy *) window_wl->shell_surface,
122 window_wl->queue);
123
124 wl_shell_surface_add_listener (window_wl->shell_surface,
125 &shell_surface_listener, window_wl);
126
127 wl_shell_surface_set_title (window_wl->shell_surface, "Vulkan Renderer");
128 wl_shell_surface_set_toplevel (window_wl->shell_surface);
129 GST_DEBUG_OBJECT (window_wl, "Successfully created shell surface %p",
130 window_wl->shell_surface);
131 }
132
133 if (window_wl->window_width > 0)
134 width = window_wl->window_width;
135 else
136 width = 320;
137 window_wl->window_width = width;
138
139 if (window_wl->window_height > 0)
140 height = window_wl->window_height;
141 else
142 height = 240;
143 window_wl->window_height = height;
144 }
145
146 static void
gst_vulkan_window_wayland_class_init(GstVulkanWindowWaylandClass * klass)147 gst_vulkan_window_wayland_class_init (GstVulkanWindowWaylandClass * klass)
148 {
149 GstVulkanWindowClass *window_class = (GstVulkanWindowClass *) klass;
150
151 window_class->close = GST_DEBUG_FUNCPTR (gst_vulkan_window_wayland_close);
152 window_class->open = GST_DEBUG_FUNCPTR (gst_vulkan_window_wayland_open);
153 window_class->get_surface =
154 GST_DEBUG_FUNCPTR (gst_vulkan_window_wayland_get_surface);
155 window_class->get_presentation_support =
156 GST_DEBUG_FUNCPTR (gst_vulkan_window_wayland_get_presentation_support);
157 }
158
159 static void
gst_vulkan_window_wayland_init(GstVulkanWindowWayland * window)160 gst_vulkan_window_wayland_init (GstVulkanWindowWayland * window)
161 {
162 }
163
164 GstVulkanWindowWayland *
gst_vulkan_window_wayland_new(GstVulkanDisplay * display)165 gst_vulkan_window_wayland_new (GstVulkanDisplay * display)
166 {
167 GstVulkanWindowWayland *window;
168
169 if ((gst_vulkan_display_get_handle_type (display) &
170 GST_VULKAN_DISPLAY_TYPE_WAYLAND)
171 == 0)
172 /* we require a wayland display to create wayland surfaces */
173 return NULL;
174
175 GST_DEBUG ("creating Wayland window");
176
177 window = g_object_new (GST_TYPE_VULKAN_WINDOW_WAYLAND, NULL);
178 gst_object_ref_sink (window);
179
180 return window;
181 }
182
183 static void
gst_vulkan_window_wayland_close(GstVulkanWindow * window)184 gst_vulkan_window_wayland_close (GstVulkanWindow * window)
185 {
186 GstVulkanWindowWayland *window_wl;
187
188 window_wl = GST_VULKAN_WINDOW_WAYLAND (window);
189
190 destroy_surfaces (window_wl);
191
192 g_source_destroy (window_wl->wl_source);
193 g_source_unref (window_wl->wl_source);
194 window_wl->wl_source = NULL;
195
196 GST_VULKAN_WINDOW_CLASS (parent_class)->close (window);
197 }
198
199 static gboolean
gst_vulkan_window_wayland_open(GstVulkanWindow * window,GError ** error)200 gst_vulkan_window_wayland_open (GstVulkanWindow * window, GError ** error)
201 {
202 GstVulkanDisplayWayland *display;
203 GstVulkanWindowWayland *window_wl = GST_VULKAN_WINDOW_WAYLAND (window);
204
205 if (!GST_IS_VULKAN_DISPLAY_WAYLAND (window->display)) {
206 g_set_error (error, GST_VULKAN_WINDOW_ERROR,
207 GST_VULKAN_WINDOW_ERROR_RESOURCE_UNAVAILABLE,
208 "Failed to retrieve Wayland display (wrong type?)");
209 return FALSE;
210 }
211 display = GST_VULKAN_DISPLAY_WAYLAND (window->display);
212
213 if (!display->display) {
214 g_set_error (error, GST_VULKAN_WINDOW_ERROR,
215 GST_VULKAN_WINDOW_ERROR_RESOURCE_UNAVAILABLE,
216 "Failed to retrieve Wayland display");
217 return FALSE;
218 }
219
220 window_wl->queue = NULL;
221
222 if (!GST_VULKAN_WINDOW_CLASS (parent_class)->open (window, error))
223 return FALSE;
224
225 create_surfaces (window_wl);
226
227 gst_vulkan_display_wayland_roundtrip_async (display);
228
229 return TRUE;
230 }
231
232 static VkSurfaceKHR
gst_vulkan_window_wayland_get_surface(GstVulkanWindow * window,GError ** error)233 gst_vulkan_window_wayland_get_surface (GstVulkanWindow * window,
234 GError ** error)
235 {
236 GstVulkanWindowWayland *window_wl = GST_VULKAN_WINDOW_WAYLAND (window);
237 VkWaylandSurfaceCreateInfoKHR info = { 0, };
238 VkSurfaceKHR ret;
239 VkResult err;
240
241 info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
242 info.pNext = NULL;
243 info.flags = 0;
244 info.display = GST_VULKAN_DISPLAY_WAYLAND_DISPLAY (window->display);
245 info.surface = window_wl->surface;
246
247 if (!window_wl->CreateWaylandSurface)
248 window_wl->CreateWaylandSurface =
249 gst_vulkan_instance_get_proc_address (window->display->instance,
250 "vkCreateWaylandSurfaceKHR");
251 if (!window_wl->CreateWaylandSurface) {
252 g_set_error_literal (error, GST_VULKAN_ERROR, VK_ERROR_FEATURE_NOT_PRESENT,
253 "Could not retrieve \"vkCreateWaylandSurfaceKHR\" function pointer");
254 return NULL;
255 }
256
257 err =
258 window_wl->CreateWaylandSurface (window->display->instance->instance,
259 &info, NULL, &ret);
260 if (gst_vulkan_error_to_g_error (err, error, "vkCreateWaylandSurfaceKHR") < 0)
261 return NULL;
262
263 return ret;
264 }
265
266 static gboolean
gst_vulkan_window_wayland_get_presentation_support(GstVulkanWindow * window,GstVulkanDevice * device,guint32 queue_family_idx)267 gst_vulkan_window_wayland_get_presentation_support (GstVulkanWindow * window,
268 GstVulkanDevice * device, guint32 queue_family_idx)
269 {
270 GstVulkanWindowWayland *window_wl = GST_VULKAN_WINDOW_WAYLAND (window);
271 VkPhysicalDevice gpu;
272
273 if (!window_wl->GetPhysicalDeviceWaylandPresentationSupport)
274 window_wl->GetPhysicalDeviceWaylandPresentationSupport =
275 gst_vulkan_instance_get_proc_address (window->display->instance,
276 "vkGetPhysicalDeviceWaylandPresentationSupportKHR");
277 if (!window_wl->GetPhysicalDeviceWaylandPresentationSupport) {
278 GST_WARNING_OBJECT (window, "Could not retrieve "
279 "\"vkGetPhysicalDeviceWaylandPresentationSupportKHR\" "
280 "function pointer");
281 return FALSE;
282 }
283
284 gpu = gst_vulkan_device_get_physical_device (device);
285 if (window_wl->GetPhysicalDeviceWaylandPresentationSupport (gpu,
286 queue_family_idx,
287 GST_VULKAN_DISPLAY_WAYLAND_DISPLAY (window->display)))
288 return TRUE;
289 return FALSE;
290 }
291