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.
25 #include "gstvkutils.h"
29 * @title: Vulkan Utils
30 * @short_description: Vulkan utilities
31 * @see_also: #GstVulkanInstance, #GstVulkanDevice
33 * GstVulkanQueue encapsulates the vulkan command queue.
36 GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
39 _init_context_debug (void)
41 #ifndef GST_DISABLE_GST_DEBUG
42 static volatile gsize _init = 0;
44 if (g_once_init_enter (&_init)) {
45 GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
46 g_once_init_leave (&_init, 1);
52 _vk_pad_query (const GValue * item, GValue * value, gpointer user_data)
54 GstPad *pad = g_value_get_object (item);
55 GstQuery *query = user_data;
58 _init_context_debug ();
60 res = gst_pad_peer_query (pad, query);
63 g_value_set_boolean (value, TRUE);
67 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "pad peer query failed");
72 * gst_vulkan_run_query:
73 * @element: a #GstElement
74 * @query: the #GstQuery to perform
75 * @direction: the #GstPadDirection to perform query on
77 * Returns: whether @query was answered successfully
82 gst_vulkan_run_query (GstElement * element, GstQuery * query,
83 GstPadDirection direction)
86 GstIteratorFoldFunction func = _vk_pad_query;
89 g_value_init (&res, G_TYPE_BOOLEAN);
90 g_value_set_boolean (&res, FALSE);
93 if (direction == GST_PAD_SRC)
94 it = gst_element_iterate_src_pads (element);
96 it = gst_element_iterate_sink_pads (element);
98 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
99 gst_iterator_resync (it);
101 gst_iterator_free (it);
103 return g_value_get_boolean (&res);
107 _vulkan_local_context_query (GstElement * element,
108 const gchar * context_type, gboolean set_context)
113 _init_context_debug ();
115 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
116 * check if downstream already has a context of the specific type
117 * 2b) Query upstream as above.
119 query = gst_query_new_context (context_type);
120 if (gst_vulkan_run_query (element, query, GST_PAD_SRC)) {
121 gst_query_parse_context (query, &ctxt);
122 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
123 "found context (%p) in downstream query", ctxt);
125 gst_element_set_context (element, ctxt);
126 } else if (gst_vulkan_run_query (element, query, GST_PAD_SINK)) {
127 gst_query_parse_context (query, &ctxt);
128 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
129 "found context (%p) in upstream query", ctxt);
131 gst_element_set_context (element, ctxt);
133 gst_query_unref (query);
141 * gst_vulkan_global_context_query:
142 * @element: a #GstElement
143 * @context_type: the context type to query for
145 * Performs the steps necessary for executing a context query including
146 * posting a message for the application to respond.
151 gst_vulkan_global_context_query (GstElement * element,
152 const gchar * context_type)
157 if ((query = _vulkan_local_context_query (element, context_type, TRUE))) {
158 gst_query_unref (query);
162 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
163 * the required context type and afterwards check if a
164 * usable context was set now as in 1). The message could
165 * be handled by the parent bins of the element and the
168 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
169 "posting need context message");
170 msg = gst_message_new_need_context (GST_OBJECT_CAST (element), context_type);
171 gst_element_post_message (element, msg);
174 * Whomever responds to the need-context message performs a
175 * GstElement::set_context() with the required context in which the element
176 * is required to update the display_ptr or call gst_vulkan_handle_set_context().
181 * gst_vulkan_local_context_query:
182 * @element: a #GstElement
183 * @context_type: the context type to query for
185 * Performs the steps necessary for executing a context query between only
186 * other elements in the pipeline
191 gst_vulkan_local_context_query (GstElement * element,
192 const gchar * context_type)
194 return _vulkan_local_context_query (element, context_type, FALSE);
198 _vk_display_context_query (GstElement * element,
199 GstVulkanDisplay ** display_ptr)
201 gst_vulkan_global_context_query (element,
202 GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR);
205 /* 4) Create a context by itself and post a GST_MESSAGE_HAVE_CONTEXT
209 * @element: (transfer none):
210 * @context: (transfer full):
213 _vk_context_propagate (GstElement * element, GstContext * context)
217 _init_context_debug ();
219 gst_element_set_context (element, context);
221 GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
222 "posting have context (%" GST_PTR_FORMAT ") message", context);
223 msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context);
224 gst_element_post_message (GST_ELEMENT_CAST (element), msg);
228 * gst_vulkan_ensure_element_data:
229 * @element: a #GstElement
230 * @display_ptr: (inout) (optional): the resulting #GstVulkanDisplay
231 * @instance_ptr: (inout): the resulting #GstVulkanInstance
233 * Perform the steps necessary for retrieving a #GstVulkanInstance and
234 * (optionally) an #GstVulkanDisplay from the surrounding elements or from
235 * the application using the #GstContext mechanism.
237 * If the contents of @display_ptr or @instance_ptr are not %NULL, then no
238 * #GstContext query is necessary and no #GstVulkanInstance or #GstVulkanDisplay
239 * retrieval is performed.
241 * Returns: whether a #GstVulkanInstance exists in @instance_ptr and if
242 * @display_ptr is not %NULL, whether a #GstVulkanDisplay exists in
248 gst_vulkan_ensure_element_data (GstElement * element,
249 GstVulkanDisplay ** display_ptr, GstVulkanInstance ** instance_ptr)
251 g_return_val_if_fail (element != NULL, FALSE);
252 g_return_val_if_fail (instance_ptr != NULL, FALSE);
254 /* 1) Check if the element already has a context of the specific
257 if (!*instance_ptr) {
258 GError *error = NULL;
259 GstContext *context = NULL;
261 gst_vulkan_global_context_query (element,
262 GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR);
264 /* Neighbour found and it updated the display */
265 if (!*instance_ptr) {
266 /* If no neighboor, or application not interested, use system default */
267 *instance_ptr = gst_vulkan_instance_new ();
269 context = gst_context_new (GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR, TRUE);
270 gst_context_set_vulkan_instance (context, *instance_ptr);
273 if (!gst_vulkan_instance_open (*instance_ptr, &error)) {
274 GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND,
275 ("Failed to create vulkan instance"), ("%s", error->message));
276 gst_object_unref (*instance_ptr);
277 *instance_ptr = NULL;
278 g_clear_error (&error);
283 _vk_context_propagate (element, context);
286 /* we don't care about a display */
288 return *instance_ptr != NULL;
291 _vk_display_context_query (element, display_ptr);
293 /* Neighbour found and it updated the display */
297 /* instance is required before the display */
298 g_return_val_if_fail (*instance_ptr != NULL, FALSE);
300 /* If no neighboor, or application not interested, use system default */
301 *display_ptr = gst_vulkan_display_new (*instance_ptr);
303 context = gst_context_new (GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR, TRUE);
304 gst_context_set_vulkan_display (context, *display_ptr);
306 _vk_context_propagate (element, context);
310 return *display_ptr != NULL && *instance_ptr != NULL;
314 * gst_vulkan_handle_set_context:
315 * @element: a #GstElement
316 * @context: a #GstContext
317 * @display: (inout) (transfer full) (optional): location of a #GstVulkanDisplay
318 * @instance: (inout) (transfer full): location of a #GstVulkanInstance
320 * Helper function for implementing #GstElementClass.set_context() in
321 * Vulkan capable elements.
323 * Retrieve's the #GstVulkanDisplay or #GstVulkanInstance in @context and places
324 * the result in @display or @instance respectively.
326 * Returns: whether the @display or @instance could be set successfully
331 gst_vulkan_handle_set_context (GstElement * element, GstContext * context,
332 GstVulkanDisplay ** display, GstVulkanInstance ** instance)
334 GstVulkanDisplay *display_replacement = NULL;
335 GstVulkanInstance *instance_replacement = NULL;
336 const gchar *context_type;
338 g_return_val_if_fail (instance != NULL, FALSE);
343 context_type = gst_context_get_context_type (context);
346 && g_strcmp0 (context_type, GST_VULKAN_DISPLAY_CONTEXT_TYPE_STR) == 0) {
347 if (!gst_context_get_vulkan_display (context, &display_replacement)) {
348 GST_WARNING_OBJECT (element, "Failed to get display from context");
351 } else if (g_strcmp0 (context_type,
352 GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR) == 0) {
353 if (!gst_context_get_vulkan_instance (context, &instance_replacement)) {
354 GST_WARNING_OBJECT (element, "Failed to get instance from context");
359 if (display_replacement) {
360 GstVulkanDisplay *old = *display;
361 *display = display_replacement;
364 gst_object_unref (old);
367 if (instance_replacement) {
368 GstVulkanInstance *old = *instance;
369 *instance = instance_replacement;
372 gst_object_unref (old);
379 * gst_vulkan_handle_context_query:
380 * @element: a #GstElement
381 * @query: a #GstQuery of type %GST_QUERY_CONTEXT
382 * @display: (transfer none) (nullable): a #GstVulkanDisplay
383 * @instance: (transfer none) (nullable): a #GstVulkanInstance
384 * @device: (transfer none) (nullable): a #GstVulkanInstance
386 * Returns: Whether the @query was successfully responded to from the passed
387 * @display, @instance, and @device.
392 gst_vulkan_handle_context_query (GstElement * element, GstQuery * query,
393 GstVulkanDisplay * display, GstVulkanInstance * instance,
394 GstVulkanDevice * device)
396 if (gst_vulkan_display_handle_context_query (element, query, display))
398 if (gst_vulkan_instance_handle_context_query (element, query, instance))
400 if (gst_vulkan_device_handle_context_query (element, query, device))