1 /*
2 * GStreamer
3 * Copyright (C) 2019 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/gst.h>
26
27 #include <gst/vulkan/vulkan.h>
28
29 #include "gstvkwindow_android.h"
30 #include "gstvkdisplay_android.h"
31
32 #define GET_PRIV(o) gst_vulkan_window_android_get_instance_private (o)
33
34 #define GST_CAT_DEFAULT gst_vulkan_window_android_debug
35 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
36
37 static void
_init_debug(void)38 _init_debug (void)
39 {
40 static gsize _init = 0;
41
42 if (g_once_init_enter (&_init)) {
43 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "vulkanwindowandroid", 0,
44 "Vulkan Android Window");
45 g_once_init_leave (&_init, 1);
46 }
47 }
48
49 enum
50 {
51 PROP_0,
52 };
53
54 struct _GstVulkanWindowAndroidPrivate
55 {
56 struct ANativeWindow *internal_window;
57 gint window_width, window_height;
58
59 gint preferred_width;
60 gint preferred_height;
61 };
62
63 #define gst_vulkan_window_android_parent_class parent_class
64 G_DEFINE_TYPE_WITH_CODE (GstVulkanWindowAndroid, gst_vulkan_window_android,
65 GST_TYPE_VULKAN_WINDOW,
66 G_ADD_PRIVATE (GstVulkanWindowAndroid) _init_debug ());
67
68 static VkSurfaceKHR gst_vulkan_window_android_get_surface (GstVulkanWindow *
69 window, GError ** error);
70 static gboolean
71 gst_vulkan_window_android_get_presentation_support (GstVulkanWindow * window,
72 GstVulkanDevice * device, guint32 queue_family_idx);
73 static gboolean gst_vulkan_window_android_open (GstVulkanWindow * window,
74 GError ** error);
75 static void gst_vulkan_window_android_close (GstVulkanWindow * window);
76 static void gst_vulkan_window_android_set_window_handle (GstVulkanWindow *
77 window, guintptr window_handle);
78
79 static void
gst_vulkan_window_android_class_init(GstVulkanWindowAndroidClass * klass)80 gst_vulkan_window_android_class_init (GstVulkanWindowAndroidClass * klass)
81 {
82 GstVulkanWindowClass *window_class = (GstVulkanWindowClass *) klass;
83
84 window_class->open = GST_DEBUG_FUNCPTR (gst_vulkan_window_android_open);
85 window_class->close = GST_DEBUG_FUNCPTR (gst_vulkan_window_android_close);
86 window_class->get_surface = gst_vulkan_window_android_get_surface;
87 window_class->get_presentation_support =
88 gst_vulkan_window_android_get_presentation_support;
89 window_class->set_window_handle = gst_vulkan_window_android_set_window_handle;
90 }
91
92 static void
gst_vulkan_window_android_init(GstVulkanWindowAndroid * window)93 gst_vulkan_window_android_init (GstVulkanWindowAndroid * window)
94 {
95 GstVulkanWindowAndroidPrivate *priv = GET_PRIV (window);
96
97 priv->preferred_width = 320;
98 priv->preferred_height = 240;
99 }
100
101 /* Must be called in the gl thread */
102 GstVulkanWindowAndroid *
gst_vulkan_window_android_new(GstVulkanDisplay * display)103 gst_vulkan_window_android_new (GstVulkanDisplay * display)
104 {
105 GstVulkanWindowAndroid *window;
106
107 _init_debug ();
108
109 if ((gst_vulkan_display_get_handle_type (display) &
110 GST_VULKAN_DISPLAY_TYPE_ANDROID)
111 == GST_VULKAN_DISPLAY_TYPE_NONE) {
112 GST_INFO ("Wrong display type %u for this window type %u", display->type,
113 GST_VULKAN_DISPLAY_TYPE_ANDROID);
114 return NULL;
115 }
116
117 window = g_object_new (GST_TYPE_VULKAN_WINDOW_ANDROID, NULL);
118 gst_object_ref_sink (window);
119
120 return window;
121 }
122
123 gboolean
gst_vulkan_window_android_create_window(GstVulkanWindowAndroid * window_android)124 gst_vulkan_window_android_create_window (GstVulkanWindowAndroid *
125 window_android)
126 {
127 GstVulkanWindowAndroidPrivate *priv = GET_PRIV (window_android);
128
129 if (!priv->internal_window) {
130 GST_WARNING_OBJECT (window_android, "No ANativeWindow provided");
131 return FALSE;
132 }
133
134 return TRUE;
135 }
136
137 static VkSurfaceKHR
gst_vulkan_window_android_get_surface(GstVulkanWindow * window,GError ** error)138 gst_vulkan_window_android_get_surface (GstVulkanWindow * window,
139 GError ** error)
140 {
141 GstVulkanWindowAndroid *window_android = GST_VULKAN_WINDOW_ANDROID (window);
142 GstVulkanWindowAndroidPrivate *priv = GET_PRIV (window_android);
143 VkAndroidSurfaceCreateInfoKHR info = { 0, };
144 VkSurfaceKHR ret;
145 VkResult err;
146
147 if (!priv->internal_window) {
148 g_set_error_literal (error, GST_VULKAN_ERROR,
149 VK_ERROR_INITIALIZATION_FAILED,
150 "No layer to retrieve surface for. Has create_window() been called?");
151 return 0;
152 }
153
154 info.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
155 info.pNext = NULL;
156 info.flags = 0;
157 info.window = priv->internal_window;
158
159 if (!window_android->CreateAndroidSurface)
160 window_android->CreateAndroidSurface =
161 gst_vulkan_instance_get_proc_address (window->display->instance,
162 "vkCreateAndroidSurfaceKHR");
163 if (!window_android->CreateAndroidSurface) {
164 g_set_error_literal (error, GST_VULKAN_ERROR, VK_ERROR_FEATURE_NOT_PRESENT,
165 "Could not retrieve \"vkCreateAndroidSurfaceKHR\" function pointer");
166 return VK_NULL_HANDLE;
167 }
168
169 err =
170 window_android->CreateAndroidSurface (window->display->instance->instance,
171 &info, NULL, &ret);
172 if (gst_vulkan_error_to_g_error (err, error, "vkCreateAndroidSurfaceKHR") < 0)
173 return VK_NULL_HANDLE;
174
175 return ret;
176 }
177
178 static gboolean
gst_vulkan_window_android_get_presentation_support(GstVulkanWindow * window,GstVulkanDevice * device,guint32 queue_family_idx)179 gst_vulkan_window_android_get_presentation_support (GstVulkanWindow * window,
180 GstVulkanDevice * device, guint32 queue_family_idx)
181 {
182 return TRUE;
183 }
184
185 static gboolean
gst_vulkan_window_android_open(GstVulkanWindow * window,GError ** error)186 gst_vulkan_window_android_open (GstVulkanWindow * window, GError ** error)
187 {
188 GstVulkanWindowAndroid *window_android = GST_VULKAN_WINDOW_ANDROID (window);
189
190 if (!GST_VULKAN_WINDOW_CLASS (parent_class)->open (window, error))
191 return FALSE;
192
193 return gst_vulkan_window_android_create_window (window_android);
194 }
195
196 static void
gst_vulkan_window_android_close(GstVulkanWindow * window)197 gst_vulkan_window_android_close (GstVulkanWindow * window)
198 {
199 GST_VULKAN_WINDOW_CLASS (parent_class)->close (window);
200 }
201
202 static void
gst_vulkan_window_android_set_window_handle(GstVulkanWindow * window,guintptr window_handle)203 gst_vulkan_window_android_set_window_handle (GstVulkanWindow * window,
204 guintptr window_handle)
205 {
206 GstVulkanWindowAndroid *window_android = GST_VULKAN_WINDOW_ANDROID (window);
207 GstVulkanWindowAndroidPrivate *priv = GET_PRIV (window_android);
208 struct ANativeWindow *native_window = (struct ANativeWindow *) window_handle;
209
210 g_return_if_fail (native_window != NULL);
211
212 if (priv->internal_window && priv->internal_window != native_window) {
213 GST_FIXME_OBJECT (window_android, "View changes are not implemented");
214 return;
215 }
216
217 priv->internal_window = native_window;
218 }
219