3 * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
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.
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.
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.
26 #include "vkutils_private.h"
28 GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
31 _check_for_all_layers (uint32_t check_count, const char **check_names,
32 uint32_t layer_count, VkLayerProperties * layers,
33 guint32 * supported_layers_count, gchar *** supported_layers)
37 if (check_count <= 0 || layer_count <= 0) {
38 GST_WARNING ("no layers requested or supported");
39 *supported_layers = NULL;
43 *supported_layers = g_new0 (gchar *, check_count + 1);
46 for (i = 0; i < check_count; i++) {
47 gboolean found = FALSE;
48 for (j = 0; j < layer_count; j++) {
49 if (g_strcmp0 (check_names[i], layers[j].layerName) == 0) {
50 GST_TRACE ("found layer: %s", check_names[i]);
52 (*supported_layers)[k++] = g_strdup (check_names[i]);
56 GST_WARNING ("Cannot find layer: %s", check_names[i]);
59 (*supported_layers)[k] = NULL;
60 *supported_layers_count = g_strv_length (*supported_layers);
66 _init_context_debug (void)
68 #ifndef GST_DISABLE_GST_DEBUG
69 static volatile gsize _init = 0;
71 if (g_once_init_enter (&_init)) {
72 GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
73 g_once_init_leave (&_init, 1);
79 _vk_pad_query (const GValue * item, GValue * value, gpointer user_data)
81 GstPad *pad = g_value_get_object (item);
82 GstQuery *query = user_data;
85 _init_context_debug ();
87 res = gst_pad_peer_query (pad, query);
90 g_value_set_boolean (value, TRUE);
94 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "pad peer query failed");
99 gst_vulkan_run_query (GstElement * element, GstQuery * query,
100 GstPadDirection direction)
103 GstIteratorFoldFunction func = _vk_pad_query;
106 g_value_init (&res, G_TYPE_BOOLEAN);
107 g_value_set_boolean (&res, FALSE);
110 if (direction == GST_PAD_SRC)
111 it = gst_element_iterate_src_pads (element);
113 it = gst_element_iterate_sink_pads (element);
115 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
116 gst_iterator_resync (it);
118 gst_iterator_free (it);
120 return g_value_get_boolean (&res);
124 gst_vulkan_global_context_query (GstElement * element,
125 const gchar * context_type)
130 if ((query = gst_vulkan_local_context_query (element, context_type, TRUE))) {
131 gst_query_unref (query);
135 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
136 * the required context type and afterwards check if a
137 * usable context was set now as in 1). The message could
138 * be handled by the parent bins of the element and the
141 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
142 "posting need context message");
143 msg = gst_message_new_need_context (GST_OBJECT_CAST (element), context_type);
144 gst_element_post_message (element, msg);
147 * Whomever responds to the need-context message performs a
148 * GstElement::set_context() with the required context in which the element
149 * is required to update the display_ptr or call gst_vulkan_handle_set_context().
154 gst_vulkan_local_context_query (GstElement * element,
155 const gchar * context_type, gboolean set_context)
160 _init_context_debug ();
162 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
163 * check if downstream already has a context of the specific type
164 * 2b) Query upstream as above.
166 query = gst_query_new_context (context_type);
167 if (gst_vulkan_run_query (element, query, GST_PAD_SRC)) {
168 gst_query_parse_context (query, &ctxt);
169 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
170 "found context (%p) in downstream query", ctxt);
172 gst_element_set_context (element, ctxt);
173 } else if (gst_vulkan_run_query (element, query, GST_PAD_SINK)) {
174 gst_query_parse_context (query, &ctxt);
175 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
176 "found context (%p) in upstream query", ctxt);
178 gst_element_set_context (element, ctxt);
180 gst_query_unref (query);
188 _vk_display_context_query (GstElement * element,
189 GstVulkanDisplay ** display_ptr)
191 gst_vulkan_global_context_query (element,
192 GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR);
195 /* 4) Create a context by itself and post a GST_MESSAGE_HAVE_CONTEXT
199 * @element: (transfer none):
200 * @context: (transfer full):
203 _vk_context_propagate (GstElement * element, GstContext * context)
207 _init_context_debug ();
209 gst_element_set_context (element, context);
211 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
212 "posting have context (%" GST_PTR_FORMAT ") message", context);
213 msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context);
214 gst_element_post_message (GST_ELEMENT_CAST (element), msg);
218 gst_vulkan_ensure_element_data (gpointer element,
219 GstVulkanDisplay ** display_ptr, GstVulkanInstance ** instance_ptr)
221 g_return_val_if_fail (element != NULL, FALSE);
222 g_return_val_if_fail (display_ptr != NULL, FALSE);
223 g_return_val_if_fail (instance_ptr != NULL, FALSE);
225 /* 1) Check if the element already has a context of the specific
228 if (!*instance_ptr) {
229 GError *error = NULL;
231 gst_vulkan_global_context_query (element,
232 GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR);
234 /* Neighbour found and it updated the display */
235 if (!*instance_ptr) {
238 /* If no neighboor, or application not interested, use system default */
239 *instance_ptr = gst_vulkan_instance_new ();
241 context = gst_context_new (GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR, TRUE);
242 gst_context_set_vulkan_instance (context, *instance_ptr);
244 _vk_context_propagate (element, context);
247 if (!gst_vulkan_instance_open (*instance_ptr, &error)) {
248 GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND,
249 ("Failed to create vulkan instance"), ("%s", error->message));
250 gst_object_unref (*instance_ptr);
251 *instance_ptr = NULL;
252 g_clear_error (&error);
258 _vk_display_context_query (element, display_ptr);
260 /* Neighbour found and it updated the display */
264 /* instance is required before the display */
265 g_return_val_if_fail (*instance_ptr != NULL, FALSE);
267 /* If no neighboor, or application not interested, use system default */
268 *display_ptr = gst_vulkan_display_new (*instance_ptr);
270 context = gst_context_new (GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR, TRUE);
271 gst_context_set_vulkan_display (context, *display_ptr);
273 _vk_context_propagate (element, context);
277 return *display_ptr != NULL && *instance_ptr != NULL;
281 gst_vulkan_handle_set_context (GstElement * element, GstContext * context,
282 GstVulkanDisplay ** display, GstVulkanInstance ** instance)
284 GstVulkanDisplay *display_replacement = NULL;
285 GstVulkanInstance *instance_replacement = NULL;
286 const gchar *context_type;
288 g_return_val_if_fail (display != NULL, FALSE);
289 g_return_val_if_fail (instance != NULL, FALSE);
294 context_type = gst_context_get_context_type (context);
296 if (g_strcmp0 (context_type, GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR) == 0) {
297 if (!gst_context_get_vulkan_display (context, &display_replacement)) {
298 GST_WARNING_OBJECT (element, "Failed to get display from context");
301 } else if (g_strcmp0 (context_type,
302 GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR) == 0) {
303 if (!gst_context_get_vulkan_instance (context, &instance_replacement)) {
304 GST_WARNING_OBJECT (element, "Failed to get instance from context");
309 if (display_replacement) {
310 GstVulkanDisplay *old = *display;
311 *display = display_replacement;
314 gst_object_unref (old);
317 if (instance_replacement) {
318 GstVulkanInstance *old = *instance;
319 *instance = instance_replacement;
322 gst_object_unref (old);
329 gst_vulkan_handle_context_query (GstElement * element, GstQuery * query,
330 GstVulkanDisplay ** display, GstVulkanInstance ** instance,
331 GstVulkanDevice ** device)
333 if (gst_vulkan_display_handle_context_query (element, query, display))
335 if (gst_vulkan_instance_handle_context_query (element, query, instance))
337 if (gst_vulkan_device_handle_context_query (element, query, device))