• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2015 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 "gstvkinstance.h"
26 
27 #include <string.h>
28 
29 /**
30  * SECTION:vkinstance
31  * @title: GstVulkanInstance
32  * @short_description: GStreamer Vulkan instance
33  * @see_also: #GstVulkanPhysicalDevice, #GstVulkanDevice, #GstVulkanDisplay
34  *
35  * #GstVulkanInstance encapsulates the necessary information for the toplevel
36  * Vulkan instance object.
37  *
38  * If GStreamer is built with debugging support, the default Vulkan API chosen
39  * can be selected with the environment variable
40  * `GST_VULKAN_INSTANCE_API_VERSION=1.0`.  Any subsequent setting of the
41  * requested Vulkan API version through the available properties will override
42  * the environment variable.
43  */
44 
45 #define APP_SHORT_NAME "GStreamer"
46 
47 #define GST_CAT_DEFAULT gst_vulkan_instance_debug
48 GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
49 GST_DEBUG_CATEGORY (GST_VULKAN_DEBUG_CAT);
50 GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
51 
52 enum
53 {
54   SIGNAL_0,
55   SIGNAL_CREATE_DEVICE,
56   LAST_SIGNAL
57 };
58 
59 enum
60 {
61   PROP_0,
62   PROP_REQUESTED_API_MAJOR_VERSION,
63   PROP_REQUESTED_API_MINOR_VERSION,
64 };
65 
66 #define DEFAULT_REQUESTED_API_VERSION_MAJOR 0
67 #define DEFAULT_REQUESTED_API_VERSION_MINOR 0
68 
69 static guint gst_vulkan_instance_signals[LAST_SIGNAL] = { 0 };
70 
71 static void gst_vulkan_instance_finalize (GObject * object);
72 
73 struct _GstVulkanInstancePrivate
74 {
75   gboolean info_collected;
76   gboolean opened;
77   guint requested_api_major;
78   guint requested_api_minor;
79   uint32_t supported_instance_api;
80 
81   guint n_available_layers;
82   VkLayerProperties *available_layers;
83   guint n_available_extensions;
84   VkExtensionProperties *available_extensions;
85   GPtrArray *enabled_layers;
86   GPtrArray *enabled_extensions;
87 
88 #if !defined (GST_DISABLE_DEBUG)
89   VkDebugReportCallbackEXT msg_callback;
90   PFN_vkCreateDebugReportCallbackEXT dbgCreateDebugReportCallback;
91   PFN_vkDestroyDebugReportCallbackEXT dbgDestroyDebugReportCallback;
92   PFN_vkDebugReportMessageEXT dbgReportMessage;
93 #endif
94 };
95 
96 static void
_init_debug(void)97 _init_debug (void)
98 {
99   static gsize _init = 0;
100 
101   if (g_once_init_enter (&_init)) {
102     GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "vulkaninstance", 0,
103         "Vulkan Instance");
104     GST_DEBUG_CATEGORY_INIT (GST_VULKAN_DEBUG_CAT, "vulkandebug", 0,
105         "Vulkan Debug");
106     GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
107     g_once_init_leave (&_init, 1);
108   }
109 }
110 
111 #define GET_PRIV(instance) gst_vulkan_instance_get_instance_private (instance)
112 
113 #define gst_vulkan_instance_parent_class parent_class
114 G_DEFINE_TYPE_WITH_CODE (GstVulkanInstance, gst_vulkan_instance,
115     GST_TYPE_OBJECT, G_ADD_PRIVATE (GstVulkanInstance)
116     _init_debug ());
117 
118 /**
119  * gst_vulkan_instance_new:
120  *
121  * Returns: (transfer full): a new uninitialized #GstVulkanInstance
122  *
123  * Since: 1.18
124  */
125 GstVulkanInstance *
gst_vulkan_instance_new(void)126 gst_vulkan_instance_new (void)
127 {
128   GstVulkanInstance *instance;
129 
130   instance = g_object_new (GST_TYPE_VULKAN_INSTANCE, NULL);
131   gst_object_ref_sink (instance);
132 
133   return instance;
134 }
135 
136 static void
gst_vulkan_instance_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)137 gst_vulkan_instance_set_property (GObject * object, guint prop_id,
138     const GValue * value, GParamSpec * pspec)
139 {
140   GstVulkanInstance *instance = GST_VULKAN_INSTANCE (object);
141   GstVulkanInstancePrivate *priv = GET_PRIV (instance);
142 
143   GST_OBJECT_LOCK (instance);
144   switch (prop_id) {
145     case PROP_REQUESTED_API_MAJOR_VERSION:
146       if (priv->opened)
147         g_warning ("Attempt to set the requested API version after the "
148             "instance has been opened");
149       priv->requested_api_major = g_value_get_uint (value);
150       break;
151     case PROP_REQUESTED_API_MINOR_VERSION:
152       if (priv->opened)
153         g_warning ("Attempt to set the requested API version after the "
154             "instance has been opened");
155       priv->requested_api_minor = g_value_get_uint (value);
156       break;
157     default:
158       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
159       break;
160   }
161   GST_OBJECT_UNLOCK (instance);
162 }
163 
164 static void
gst_vulkan_instance_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)165 gst_vulkan_instance_get_property (GObject * object,
166     guint prop_id, GValue * value, GParamSpec * pspec)
167 {
168   GstVulkanInstance *instance = GST_VULKAN_INSTANCE (object);
169   GstVulkanInstancePrivate *priv = GET_PRIV (instance);
170 
171   GST_OBJECT_LOCK (instance);
172   switch (prop_id) {
173     case PROP_REQUESTED_API_MAJOR_VERSION:
174       g_value_set_uint (value, priv->requested_api_major);
175       break;
176     case PROP_REQUESTED_API_MINOR_VERSION:
177       g_value_set_uint (value, priv->requested_api_minor);
178       break;
179     default:
180       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
181       break;
182   }
183   GST_OBJECT_UNLOCK (instance);
184 }
185 
186 static void
gst_vulkan_instance_init(GstVulkanInstance * instance)187 gst_vulkan_instance_init (GstVulkanInstance * instance)
188 {
189   GstVulkanInstancePrivate *priv = GET_PRIV (instance);
190 
191   priv->requested_api_major = DEFAULT_REQUESTED_API_VERSION_MAJOR;
192   priv->requested_api_minor = DEFAULT_REQUESTED_API_VERSION_MINOR;
193 
194   priv->enabled_layers = g_ptr_array_new_with_free_func (g_free);
195   priv->enabled_extensions = g_ptr_array_new_with_free_func (g_free);
196 
197 #if !defined (GST_DISABLE_DEBUG)
198   {
199     const gchar *api_override = g_getenv ("GST_VULKAN_INSTANCE_API_VERSION");
200     if (api_override) {
201       gchar *end;
202       gint64 major, minor;
203 
204       major = g_ascii_strtoll (api_override, &end, 10);
205       if (end && end[0] == '.') {
206         minor = g_ascii_strtoll (&end[1], NULL, 10);
207         if (major > 0 && major < G_MAXINT64 && minor >= 0 && minor < G_MAXINT64) {
208           priv->requested_api_major = major;
209           priv->requested_api_minor = minor;
210         }
211       }
212     }
213   }
214 #endif
215 }
216 
217 static void
gst_vulkan_instance_class_init(GstVulkanInstanceClass * klass)218 gst_vulkan_instance_class_init (GstVulkanInstanceClass * klass)
219 {
220   GObjectClass *gobject_class = (GObjectClass *) klass;
221 
222   gst_vulkan_memory_init_once ();
223   gst_vulkan_image_memory_init_once ();
224   gst_vulkan_buffer_memory_init_once ();
225 
226   gobject_class->get_property = gst_vulkan_instance_get_property;
227   gobject_class->set_property = gst_vulkan_instance_set_property;
228   gobject_class->finalize = gst_vulkan_instance_finalize;
229 
230   /**
231    * GstVulkanInstance:requested-api-major:
232    *
233    * Since: 1.18
234    */
235   g_object_class_install_property (gobject_class,
236       PROP_REQUESTED_API_MAJOR_VERSION,
237       g_param_spec_uint ("requested-api-major", "Requested API Major",
238           "Major version of the requested Vulkan API (0 = maximum supported)",
239           0, G_MAXUINT, DEFAULT_REQUESTED_API_VERSION_MAJOR,
240           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
241 
242   /**
243    * GstVulkanInstance:requested-api-minor:
244    *
245    * Since: 1.18
246    */
247   g_object_class_install_property (gobject_class,
248       PROP_REQUESTED_API_MINOR_VERSION,
249       g_param_spec_uint ("requested-api-minor", "Requested API Minor",
250           "Minor version of the requested Vulkan API",
251           0, G_MAXUINT, DEFAULT_REQUESTED_API_VERSION_MINOR,
252           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
253 
254   /**
255    * GstVulkanInstance::create-device:
256    * @object: the #GstVulkanDisplay
257    *
258    * Overrides the #GstVulkanDevice creation mechanism.
259    * It can be called from any thread.
260    *
261    * Returns: (transfer full): the newly created #GstVulkanDevice.
262    *
263    * Since: 1.18
264    */
265   gst_vulkan_instance_signals[SIGNAL_CREATE_DEVICE] =
266       g_signal_new ("create-device", G_TYPE_FROM_CLASS (klass),
267       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, GST_TYPE_VULKAN_DEVICE, 0);
268 }
269 
270 static void
gst_vulkan_instance_finalize(GObject * object)271 gst_vulkan_instance_finalize (GObject * object)
272 {
273   GstVulkanInstance *instance = GST_VULKAN_INSTANCE (object);
274   GstVulkanInstancePrivate *priv = GET_PRIV (instance);
275 
276   if (priv->opened) {
277     if (priv->dbgDestroyDebugReportCallback)
278       priv->dbgDestroyDebugReportCallback (instance->instance,
279           priv->msg_callback, NULL);
280 
281     g_free (instance->physical_devices);
282   }
283   priv->opened = FALSE;
284 
285   if (instance->instance)
286     vkDestroyInstance (instance->instance, NULL);
287   instance->instance = NULL;
288 
289   g_free (priv->available_layers);
290   priv->available_layers = NULL;
291 
292   g_free (priv->available_extensions);
293   priv->available_extensions = NULL;
294 
295   g_ptr_array_unref (priv->enabled_layers);
296   priv->enabled_layers = NULL;
297 
298   g_ptr_array_unref (priv->enabled_extensions);
299   priv->enabled_extensions = NULL;
300 
301   G_OBJECT_CLASS (parent_class)->finalize (object);
302 }
303 
304 VKAPI_ATTR static VkBool32
_gst_vk_debug_callback(VkDebugReportFlagsEXT msgFlags,VkDebugReportObjectTypeEXT objType,uint64_t srcObject,size_t location,int32_t msgCode,const char * pLayerPrefix,const char * pMsg,void * pUserData)305 _gst_vk_debug_callback (VkDebugReportFlagsEXT msgFlags,
306     VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location,
307     int32_t msgCode, const char *pLayerPrefix, const char *pMsg,
308     void *pUserData)
309 {
310   if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
311     GST_CAT_ERROR (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix,
312         msgCode, pMsg);
313     g_critical ("[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
314   } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
315     GST_CAT_WARNING (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix,
316         msgCode, pMsg);
317     g_warning ("[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
318   } else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
319     GST_CAT_LOG (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix,
320         msgCode, pMsg);
321   } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
322     GST_CAT_FIXME (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix,
323         msgCode, pMsg);
324   } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
325     GST_CAT_TRACE (GST_VULKAN_DEBUG_CAT, "[%s] Code %d : %s", pLayerPrefix,
326         msgCode, pMsg);
327   } else {
328     return FALSE;
329   }
330 
331   /*
332    * false indicates that layer should not bail-out of an
333    * API call that had validation failures. This may mean that the
334    * app dies inside the driver due to invalid parameter(s).
335    * That's what would happen without validation layers, so we'll
336    * keep that behavior here.
337    */
338   return FALSE;
339 }
340 
341 static gboolean
gst_vulkan_instance_get_layer_info_unlocked(GstVulkanInstance * instance,const gchar * name,gchar ** description,guint32 * spec_version,guint32 * implementation_version)342 gst_vulkan_instance_get_layer_info_unlocked (GstVulkanInstance * instance,
343     const gchar * name, gchar ** description, guint32 * spec_version,
344     guint32 * implementation_version)
345 {
346   GstVulkanInstancePrivate *priv;
347   int i;
348 
349   priv = GET_PRIV (instance);
350 
351   for (i = 0; i < priv->n_available_layers; i++) {
352     if (g_strcmp0 (name, priv->available_layers[i].layerName) == 0) {
353       if (description)
354         *description = g_strdup (priv->available_layers[i].description);
355       if (spec_version)
356         *spec_version = priv->available_layers[i].specVersion;
357       if (implementation_version)
358         *spec_version = priv->available_layers[i].implementationVersion;
359       return TRUE;
360     }
361   }
362 
363   return FALSE;
364 }
365 
366 /**
367  * gst_vulkan_instance_get_layer_info:
368  * @instance: a #GstVulkanInstance
369  * @name: the layer name to look for
370  * @description: (out) (nullable): return value for the layer description or %NULL
371  * @spec_version: (out) (nullable): return value for the layer specification version
372  * @implementation_version: (out) (nullable): return value for the layer implementation version
373  *
374  * Retrieves information about a layer.
375  *
376  * Will not find any layers before gst_vulkan_instance_fill_info() has been
377  * called.
378  *
379  * Returns: whether layer @name is available
380  *
381  * Since: 1.18
382  */
383 gboolean
gst_vulkan_instance_get_layer_info(GstVulkanInstance * instance,const gchar * name,gchar ** description,guint32 * spec_version,guint32 * implementation_version)384 gst_vulkan_instance_get_layer_info (GstVulkanInstance * instance,
385     const gchar * name, gchar ** description, guint32 * spec_version,
386     guint32 * implementation_version)
387 {
388   gboolean ret;
389 
390   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE);
391   g_return_val_if_fail (name != NULL, FALSE);
392 
393   GST_OBJECT_LOCK (instance);
394   ret =
395       gst_vulkan_instance_get_layer_info_unlocked (instance, name, description,
396       spec_version, implementation_version);
397   GST_OBJECT_UNLOCK (instance);
398 
399   return ret;
400 }
401 
402 G_GNUC_INTERNAL gboolean
403 gst_vulkan_instance_get_extension_info_unlocked (GstVulkanInstance * instance,
404     const gchar * name, guint32 * spec_version);
405 
406 G_GNUC_INTERNAL gboolean
gst_vulkan_instance_get_extension_info_unlocked(GstVulkanInstance * instance,const gchar * name,guint32 * spec_version)407 gst_vulkan_instance_get_extension_info_unlocked (GstVulkanInstance * instance,
408     const gchar * name, guint32 * spec_version)
409 {
410   GstVulkanInstancePrivate *priv;
411   int i;
412 
413   priv = GET_PRIV (instance);
414 
415   for (i = 0; i < priv->n_available_extensions; i++) {
416     if (g_strcmp0 (name, priv->available_extensions[i].extensionName) == 0) {
417       if (spec_version)
418         *spec_version = priv->available_extensions[i].specVersion;
419       return TRUE;
420     }
421   }
422 
423   return FALSE;
424 }
425 
426 /**
427  * gst_vulkan_instance_get_extension_info:
428  * @instance: a #GstVulkanInstance
429  * @name: the layer name to look for
430  * @spec_version: (out) (nullable): return value for the layer specification version
431  *
432  * Retrieves information about an extension.
433  *
434  * Will not find any extensions before gst_vulkan_instance_fill_info() has been
435  * called.
436  *
437  * Returns: whether extension @name is available
438  *
439  * Since: 1.18
440  */
441 gboolean
gst_vulkan_instance_get_extension_info(GstVulkanInstance * instance,const gchar * name,guint32 * spec_version)442 gst_vulkan_instance_get_extension_info (GstVulkanInstance * instance,
443     const gchar * name, guint32 * spec_version)
444 {
445   gboolean ret;
446 
447   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE);
448   g_return_val_if_fail (name != NULL, FALSE);
449 
450   GST_OBJECT_LOCK (instance);
451   ret =
452       gst_vulkan_instance_get_extension_info_unlocked (instance, name,
453       spec_version);
454   GST_OBJECT_UNLOCK (instance);
455 
456   return ret;
457 }
458 
459 /* reimplement a specfic case of g_ptr_array_find_with_equal_func as that
460  * requires Glib 2.54 */
461 static gboolean
ptr_array_find_string(GPtrArray * array,const gchar * str,guint * index)462 ptr_array_find_string (GPtrArray * array, const gchar * str, guint * index)
463 {
464   guint i;
465 
466   for (i = 0; i < array->len; i++) {
467     gchar *val = (gchar *) g_ptr_array_index (array, i);
468     if (g_strcmp0 (val, str) == 0) {
469       if (index)
470         *index = i;
471       return TRUE;
472     }
473   }
474 
475   return FALSE;
476 }
477 
478 static gboolean
gst_vulkan_instance_is_extension_enabled_unlocked(GstVulkanInstance * instance,const gchar * name,guint * index)479 gst_vulkan_instance_is_extension_enabled_unlocked (GstVulkanInstance * instance,
480     const gchar * name, guint * index)
481 {
482   GstVulkanInstancePrivate *priv = GET_PRIV (instance);
483 
484   return ptr_array_find_string (priv->enabled_extensions, name, index);
485 }
486 
487 /**
488  * gst_vulkan_instance_is_extension_enabled:
489  * @instance: a # GstVulkanInstance
490  * @name: extension name
491  *
492  * Returns: whether extension @name is enabled
493  *
494  * Since: 1.18
495  */
496 gboolean
gst_vulkan_instance_is_extension_enabled(GstVulkanInstance * instance,const gchar * name)497 gst_vulkan_instance_is_extension_enabled (GstVulkanInstance * instance,
498     const gchar * name)
499 {
500   gboolean ret;
501 
502   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE);
503   g_return_val_if_fail (name != NULL, FALSE);
504 
505   GST_OBJECT_LOCK (instance);
506   ret =
507       gst_vulkan_instance_is_extension_enabled_unlocked (instance, name, NULL);
508   GST_OBJECT_UNLOCK (instance);
509 
510   return ret;
511 }
512 
513 static gboolean
gst_vulkan_instance_enable_extension_unlocked(GstVulkanInstance * instance,const gchar * name)514 gst_vulkan_instance_enable_extension_unlocked (GstVulkanInstance * instance,
515     const gchar * name)
516 {
517   GstVulkanInstancePrivate *priv = GET_PRIV (instance);
518   gboolean extension_is_available = FALSE;
519   guint i;
520 
521   if (gst_vulkan_instance_is_extension_enabled_unlocked (instance, name, NULL))
522     /* extension is already enabled */
523     return TRUE;
524 
525   for (i = 0; i < priv->n_available_extensions; i++) {
526     if (g_strcmp0 (name, priv->available_extensions[i].extensionName) == 0) {
527       extension_is_available = TRUE;
528       break;
529     }
530   }
531 
532   if (!extension_is_available)
533     return FALSE;
534 
535   g_ptr_array_add (priv->enabled_extensions, g_strdup (name));
536 
537   return TRUE;
538 }
539 
540 /**
541  * gst_vulkan_instance_enable_extension:
542  * @instance: a #GstVulkanInstance
543  * @name: extension name to enable
544  *
545  * Enable an Vulkan extension by @name.  Extensions cannot be enabled until
546  * gst_vulkan_instance_fill_info() has been called.  Enabling an extension will
547  * only have an effect before the call to gst_vulkan_instance_open().
548  *
549  * Returns: whether the Vulkan extension could be enabled.
550  *
551  * Since: 1.18
552  */
553 gboolean
gst_vulkan_instance_enable_extension(GstVulkanInstance * instance,const gchar * name)554 gst_vulkan_instance_enable_extension (GstVulkanInstance * instance,
555     const gchar * name)
556 {
557   gboolean ret;
558 
559   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE);
560   g_return_val_if_fail (name != NULL, FALSE);
561 
562   GST_OBJECT_LOCK (instance);
563   ret = gst_vulkan_instance_enable_extension_unlocked (instance, name);
564   GST_OBJECT_UNLOCK (instance);
565 
566   return ret;
567 }
568 
569 static gboolean
gst_vulkan_instance_disable_extension_unlocked(GstVulkanInstance * instance,const gchar * name)570 gst_vulkan_instance_disable_extension_unlocked (GstVulkanInstance * instance,
571     const gchar * name)
572 {
573   GstVulkanInstancePrivate *priv = GET_PRIV (instance);
574   gboolean extension_is_available = FALSE;
575   guint i;
576 
577   for (i = 0; i < priv->n_available_extensions; i++) {
578     if (g_strcmp0 (name, priv->available_extensions[i].extensionName) == 0) {
579       extension_is_available = TRUE;
580       break;
581     }
582   }
583 
584   if (!extension_is_available)
585     return FALSE;
586 
587   if (!gst_vulkan_instance_is_extension_enabled_unlocked (instance, name, &i))
588     /* extension is already enabled */
589     return TRUE;
590 
591   g_ptr_array_remove_index_fast (priv->enabled_extensions, i);
592 
593   return TRUE;
594 }
595 
596 /**
597  * gst_vulkan_instance_disable_extension:
598  * @instance: a #GstVulkanInstance
599  * @name: extension name to enable
600  *
601  * Disable an Vulkan extension by @name.  Disabling an extension will only have
602  * an effect before the call to gst_vulkan_instance_open().
603  *
604  * Returns: whether the Vulkan extension could be disabled.
605  *
606  * Since: 1.18
607  */
608 gboolean
gst_vulkan_instance_disable_extension(GstVulkanInstance * instance,const gchar * name)609 gst_vulkan_instance_disable_extension (GstVulkanInstance * instance,
610     const gchar * name)
611 {
612   gboolean ret;
613 
614   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE);
615   g_return_val_if_fail (name != NULL, FALSE);
616 
617   GST_OBJECT_LOCK (instance);
618   ret = gst_vulkan_instance_disable_extension_unlocked (instance, name);
619   GST_OBJECT_UNLOCK (instance);
620 
621   return ret;
622 }
623 
624 static gboolean
gst_vulkan_instance_is_layer_enabled_unlocked(GstVulkanInstance * instance,const gchar * name)625 gst_vulkan_instance_is_layer_enabled_unlocked (GstVulkanInstance * instance,
626     const gchar * name)
627 {
628   GstVulkanInstancePrivate *priv = GET_PRIV (instance);
629 
630   return ptr_array_find_string (priv->enabled_layers, name, NULL);
631 }
632 
633 /**
634  * gst_vulkan_instance_is_layer_enabled:
635  * @instance: a # GstVulkanInstance
636  * @name: layer name
637  *
638  * Returns: whether layer @name is enabled
639  *
640  * Since: 1.18
641  */
642 gboolean
gst_vulkan_instance_is_layer_enabled(GstVulkanInstance * instance,const gchar * name)643 gst_vulkan_instance_is_layer_enabled (GstVulkanInstance * instance,
644     const gchar * name)
645 {
646   gboolean ret;
647 
648   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE);
649   g_return_val_if_fail (name != NULL, FALSE);
650 
651   GST_OBJECT_LOCK (instance);
652   ret = gst_vulkan_instance_is_layer_enabled_unlocked (instance, name);
653   GST_OBJECT_UNLOCK (instance);
654 
655   return ret;
656 }
657 
658 static gboolean
gst_vulkan_instance_enable_layer_unlocked(GstVulkanInstance * instance,const gchar * name)659 gst_vulkan_instance_enable_layer_unlocked (GstVulkanInstance * instance,
660     const gchar * name)
661 {
662   GstVulkanInstancePrivate *priv = GET_PRIV (instance);
663   gboolean layer_is_available = FALSE;
664   guint i;
665 
666   if (gst_vulkan_instance_is_layer_enabled_unlocked (instance, name))
667     /* layer is already enabled */
668     return TRUE;
669 
670   for (i = 0; i < priv->n_available_layers; i++) {
671     if (g_strcmp0 (name, priv->available_layers[i].layerName) == 0) {
672       layer_is_available = TRUE;
673       break;
674     }
675   }
676 
677   if (!layer_is_available)
678     return FALSE;
679 
680   g_ptr_array_add (priv->enabled_layers, g_strdup (name));
681 
682   return TRUE;
683 }
684 
685 /**
686  * gst_vulkan_instance_enable_layer:
687  * @instance: a #GstVulkanInstance
688  * @name: layer name to enable
689  *
690  * Enable an Vulkan layer by @name.  Layer cannot be enabled until
691  * gst_vulkan_instance_fill_info() has been called.  Enabling a layer will
692  * only have an effect before the call to gst_vulkan_instance_open().
693  *
694  * Returns: whether the Vulkan layer could be enabled.
695  *
696  * Since: 1.18
697  */
698 gboolean
gst_vulkan_instance_enable_layer(GstVulkanInstance * instance,const gchar * name)699 gst_vulkan_instance_enable_layer (GstVulkanInstance * instance,
700     const gchar * name)
701 {
702   gboolean ret;
703 
704   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE);
705   g_return_val_if_fail (name != NULL, FALSE);
706 
707   GST_OBJECT_LOCK (instance);
708   ret = gst_vulkan_instance_enable_layer_unlocked (instance, name);
709   GST_OBJECT_UNLOCK (instance);
710 
711   return ret;
712 }
713 
714 static void
gst_vulkan_get_supported_api_version_unlocked(GstVulkanInstance * instance)715 gst_vulkan_get_supported_api_version_unlocked (GstVulkanInstance * instance)
716 {
717   GstVulkanInstancePrivate *priv = GET_PRIV (instance);
718   PFN_vkEnumerateInstanceVersion gst_vkEnumerateInstanceVersion;
719 
720   if (priv->supported_instance_api)
721     return;
722 
723   gst_vkEnumerateInstanceVersion =
724       (PFN_vkEnumerateInstanceVersion) vkGetInstanceProcAddr (NULL,
725       "vkEnumerateInstanceVersion");
726 
727   if (!gst_vkEnumerateInstanceVersion
728       || VK_SUCCESS !=
729       gst_vkEnumerateInstanceVersion (&priv->supported_instance_api)) {
730     priv->supported_instance_api = VK_MAKE_VERSION (1, 0, 0);
731   }
732 }
733 
734 G_GNUC_INTERNAL GstVulkanDisplayType
735 gst_vulkan_display_choose_type_unlocked (GstVulkanInstance * instance);
736 
737 static gboolean
gst_vulkan_instance_fill_info_unlocked(GstVulkanInstance * instance,GError ** error)738 gst_vulkan_instance_fill_info_unlocked (GstVulkanInstance * instance,
739     GError ** error)
740 {
741   GstVulkanInstancePrivate *priv;
742   VkResult err;
743   guint i;
744 
745   priv = GET_PRIV (instance);
746 
747   if (priv->info_collected)
748     return TRUE;
749   priv->info_collected = TRUE;
750 
751   gst_vulkan_get_supported_api_version_unlocked (instance);
752 
753   /* Look for validation layers */
754   err = vkEnumerateInstanceLayerProperties (&priv->n_available_layers, NULL);
755   if (gst_vulkan_error_to_g_error (err, error,
756           "vKEnumerateInstanceLayerProperties") < 0) {
757     return FALSE;
758   }
759 
760   priv->available_layers = g_new0 (VkLayerProperties, priv->n_available_layers);
761   err =
762       vkEnumerateInstanceLayerProperties (&priv->n_available_layers,
763       priv->available_layers);
764   if (gst_vulkan_error_to_g_error (err, error,
765           "vKEnumerateInstanceLayerProperties") < 0) {
766     return FALSE;
767   }
768 
769   err =
770       vkEnumerateInstanceExtensionProperties (NULL,
771       &priv->n_available_extensions, NULL);
772   if (gst_vulkan_error_to_g_error (err, error,
773           "vkEnumerateInstanceExtensionProperties") < 0) {
774     return FALSE;
775   }
776 
777   priv->available_extensions =
778       g_new0 (VkExtensionProperties, priv->n_available_extensions);
779   err =
780       vkEnumerateInstanceExtensionProperties (NULL,
781       &priv->n_available_extensions, priv->available_extensions);
782   if (gst_vulkan_error_to_g_error (err, error,
783           "vkEnumerateInstanceExtensionProperties") < 0) {
784     return FALSE;
785   }
786 
787   GST_INFO_OBJECT (instance, "found %u layers and %u extensions",
788       priv->n_available_layers, priv->n_available_extensions);
789 
790   for (i = 0; i < priv->n_available_layers; i++)
791     GST_DEBUG_OBJECT (instance, "available layer %u: %s", i,
792         priv->available_layers[i].layerName);
793   for (i = 0; i < priv->n_available_extensions; i++)
794     GST_DEBUG_OBJECT (instance, "available extension %u: %s", i,
795         priv->available_extensions[i].extensionName);
796 
797   /* configure default extensions */
798   {
799     GstVulkanDisplayType display_type;
800     const gchar *winsys_ext_name;
801     GstDebugLevel vulkan_debug_level;
802 
803     display_type = gst_vulkan_display_choose_type_unlocked (instance);
804 
805     winsys_ext_name =
806         gst_vulkan_display_type_to_extension_string (display_type);
807     if (!winsys_ext_name) {
808       GST_WARNING_OBJECT (instance, "No window system extension enabled");
809     } else if (gst_vulkan_instance_get_extension_info_unlocked (instance,
810             VK_KHR_SURFACE_EXTENSION_NAME, NULL)
811         && gst_vulkan_instance_get_extension_info_unlocked (instance,
812             winsys_ext_name, NULL)) {
813       gst_vulkan_instance_enable_extension_unlocked (instance,
814           VK_KHR_SURFACE_EXTENSION_NAME);
815       gst_vulkan_instance_enable_extension_unlocked (instance, winsys_ext_name);
816     }
817 #if !defined (GST_DISABLE_DEBUG)
818     vulkan_debug_level =
819         gst_debug_category_get_threshold (GST_VULKAN_DEBUG_CAT);
820 
821     if (vulkan_debug_level >= GST_LEVEL_ERROR) {
822       if (gst_vulkan_instance_get_extension_info_unlocked (instance,
823               VK_EXT_DEBUG_REPORT_EXTENSION_NAME, NULL)) {
824         gst_vulkan_instance_enable_extension_unlocked (instance,
825             VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
826       }
827     }
828 #endif
829   }
830 
831   return TRUE;
832 }
833 
834 /**
835  * gst_vulkan_instance_fill_info:
836  * @instance: a #GstVulkanInstance
837  * @error: #GError
838  *
839  * Retrieve as much information about the available Vulkan instance without
840  * actually creating an Vulkan instance.  Will not do anything while @instance
841  * is open.
842  *
843  * Returns: whether the instance information could be retrieved
844  *
845  * Since: 1.18
846  */
847 gboolean
gst_vulkan_instance_fill_info(GstVulkanInstance * instance,GError ** error)848 gst_vulkan_instance_fill_info (GstVulkanInstance * instance, GError ** error)
849 {
850   gboolean ret;
851 
852   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE);
853 
854   GST_OBJECT_LOCK (instance);
855   ret = gst_vulkan_instance_fill_info_unlocked (instance, error);
856   GST_OBJECT_UNLOCK (instance);
857 
858   return ret;
859 }
860 
861 /**
862  * gst_vulkan_instance_open:
863  * @instance: a #GstVulkanInstance
864  * @error: #GError
865  *
866  * Returns: whether the instance could be created
867  *
868  * Since: 1.18
869  */
870 gboolean
gst_vulkan_instance_open(GstVulkanInstance * instance,GError ** error)871 gst_vulkan_instance_open (GstVulkanInstance * instance, GError ** error)
872 {
873   GstVulkanInstancePrivate *priv;
874   uint32_t requested_instance_api;
875   GstDebugLevel vulkan_debug_level;
876   VkResult err;
877 
878   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE);
879 
880   priv = GET_PRIV (instance);
881 
882   GST_OBJECT_LOCK (instance);
883   if (priv->opened) {
884     GST_OBJECT_UNLOCK (instance);
885     return TRUE;
886   }
887 
888   if (!gst_vulkan_instance_fill_info_unlocked (instance, error))
889     goto error;
890 
891   if (priv->requested_api_major) {
892     requested_instance_api =
893         VK_MAKE_VERSION (priv->requested_api_major, priv->requested_api_minor,
894         0);
895   } else {
896     requested_instance_api = priv->supported_instance_api;
897   }
898 
899   if (requested_instance_api > priv->supported_instance_api) {
900     g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED,
901         "Requested API version (%u.%u) is larger than the maximum supported "
902         "version (%u.%u)", VK_VERSION_MAJOR (requested_instance_api),
903         VK_VERSION_MINOR (requested_instance_api),
904         VK_VERSION_MAJOR (priv->supported_instance_api),
905         VK_VERSION_MINOR (priv->supported_instance_api));
906     goto error;
907   }
908 
909   /* list of known vulkan loader environment variables taken from:
910    * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/blob/master/loader/LoaderAndLayerInterface.md#table-of-debug-environment-variables */
911   GST_DEBUG_OBJECT (instance, "VK_ICD_FILENAMES: %s",
912       g_getenv ("VK_ICD_FILENAMES"));
913   GST_DEBUG_OBJECT (instance, "VK_INSTANCE_LAYERS: %s",
914       g_getenv ("VK_INSTANCE_LAYERS"));
915   GST_DEBUG_OBJECT (instance, "VK_LAYER_PATH: %s", g_getenv ("VK_LAYER_PATH"));
916   GST_DEBUG_OBJECT (instance, "VK_LOADER_DISABLE_INST_EXT_FILTER: %s",
917       g_getenv ("VK_LOADER_DISABLE_INST_EXT_FILTER"));
918   GST_DEBUG_OBJECT (instance, "VK_LOADER_DEBUG: %s",
919       g_getenv ("VK_LOADER_DEBUG"));
920 
921   {
922     guint i;
923 
924     GST_INFO_OBJECT (instance, "attempting to create instance for Vulkan API "
925         "%u.%u, max supported %u.%u with %u layers and %u extensions",
926         VK_VERSION_MAJOR (requested_instance_api),
927         VK_VERSION_MINOR (requested_instance_api),
928         VK_VERSION_MAJOR (priv->supported_instance_api),
929         VK_VERSION_MINOR (priv->supported_instance_api),
930         priv->enabled_layers->len, priv->enabled_extensions->len);
931 
932     for (i = 0; i < priv->enabled_layers->len; i++)
933       GST_DEBUG_OBJECT (instance, "layer %u: %s", i,
934           (gchar *) g_ptr_array_index (priv->enabled_layers, i));
935     for (i = 0; i < priv->enabled_extensions->len; i++)
936       GST_DEBUG_OBJECT (instance, "extension %u: %s", i,
937           (gchar *) g_ptr_array_index (priv->enabled_extensions, i));
938   }
939 
940   {
941     VkApplicationInfo app = { 0, };
942     VkInstanceCreateInfo inst_info = { 0, };
943 
944     /* *INDENT-OFF* */
945     app = (VkApplicationInfo) {
946         .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
947         .pNext = NULL,
948         .pApplicationName = APP_SHORT_NAME,
949         .applicationVersion = 0,
950         .pEngineName = APP_SHORT_NAME,
951         .engineVersion = 0,
952         .apiVersion = requested_instance_api,
953     };
954 
955     inst_info = (VkInstanceCreateInfo) {
956         .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
957         .pNext = NULL,
958         .pApplicationInfo = &app,
959         .enabledLayerCount = priv->enabled_layers->len,
960         .ppEnabledLayerNames = (const char *const *) priv->enabled_layers->pdata,
961         .enabledExtensionCount = priv->enabled_extensions->len,
962         .ppEnabledExtensionNames = (const char *const *) priv->enabled_extensions->pdata,
963     };
964     /* *INDENT-ON* */
965 
966     err = vkCreateInstance (&inst_info, NULL, &instance->instance);
967     if (gst_vulkan_error_to_g_error (err, error, "vkCreateInstance") < 0) {
968       goto error;
969     }
970   }
971 
972   err =
973       vkEnumeratePhysicalDevices (instance->instance,
974       &instance->n_physical_devices, NULL);
975   if (gst_vulkan_error_to_g_error (err, error,
976           "vkEnumeratePhysicalDevices") < 0)
977     goto error;
978 
979   if (instance->n_physical_devices == 0) {
980     GST_WARNING_OBJECT (instance, "No available physical device");
981     g_set_error_literal (error,
982         GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND,
983         "No available physical device");
984     goto error;
985   }
986 
987   instance->physical_devices =
988       g_new0 (VkPhysicalDevice, instance->n_physical_devices);
989   err =
990       vkEnumeratePhysicalDevices (instance->instance,
991       &instance->n_physical_devices, instance->physical_devices);
992   if (gst_vulkan_error_to_g_error (err, error,
993           "vkEnumeratePhysicalDevices") < 0)
994     goto error;
995 
996 #if !defined (GST_DISABLE_DEBUG)
997   vulkan_debug_level = gst_debug_category_get_threshold (GST_VULKAN_DEBUG_CAT);
998 
999   if (vulkan_debug_level >= GST_LEVEL_ERROR
1000       && gst_vulkan_instance_is_extension_enabled_unlocked (instance,
1001           VK_EXT_DEBUG_REPORT_EXTENSION_NAME, NULL)) {
1002     VkDebugReportCallbackCreateInfoEXT info = { 0, };
1003 
1004     priv->dbgCreateDebugReportCallback = (PFN_vkCreateDebugReportCallbackEXT)
1005         gst_vulkan_instance_get_proc_address (instance,
1006         "vkCreateDebugReportCallbackEXT");
1007     if (!priv->dbgCreateDebugReportCallback) {
1008       g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED,
1009           "Failed to retrieve vkCreateDebugReportCallback");
1010       goto error;
1011     }
1012     priv->dbgDestroyDebugReportCallback = (PFN_vkDestroyDebugReportCallbackEXT)
1013         gst_vulkan_instance_get_proc_address (instance,
1014         "vkDestroyDebugReportCallbackEXT");
1015     if (!priv->dbgDestroyDebugReportCallback) {
1016       g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED,
1017           "Failed to retrieve vkDestroyDebugReportCallback");
1018       goto error;
1019     }
1020     priv->dbgReportMessage = (PFN_vkDebugReportMessageEXT)
1021         gst_vulkan_instance_get_proc_address (instance,
1022         "vkDebugReportMessageEXT");
1023     if (!priv->dbgReportMessage) {
1024       g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED,
1025           "Failed to retrieve vkDebugReportMessage");
1026       goto error;
1027     }
1028 
1029     info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
1030     info.pNext = NULL;
1031     info.flags = 0;
1032     info.pfnCallback = (PFN_vkDebugReportCallbackEXT) _gst_vk_debug_callback;
1033     info.pUserData = NULL;
1034     /* matches the conditions in _gst_vk_debug_callback() */
1035     if (vulkan_debug_level >= GST_LEVEL_ERROR)
1036       info.flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
1037     if (vulkan_debug_level >= GST_LEVEL_WARNING)
1038       info.flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
1039     if (vulkan_debug_level >= GST_LEVEL_FIXME)
1040       info.flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
1041     if (vulkan_debug_level >= GST_LEVEL_LOG)
1042       info.flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
1043     if (vulkan_debug_level >= GST_LEVEL_TRACE)
1044       info.flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
1045 
1046     err =
1047         priv->dbgCreateDebugReportCallback (instance->instance, &info, NULL,
1048         &priv->msg_callback);
1049     if (gst_vulkan_error_to_g_error (err, error,
1050             "vkCreateDebugReportCallback") < 0)
1051       goto error;
1052   }
1053 #endif
1054 
1055   priv->opened = TRUE;
1056   GST_OBJECT_UNLOCK (instance);
1057 
1058   return TRUE;
1059 
1060 error:
1061   {
1062     GST_OBJECT_UNLOCK (instance);
1063     return FALSE;
1064   }
1065 }
1066 
1067 /**
1068  * gst_vulkan_instance_get_proc_address:
1069  * @instance: a #GstVulkanInstance
1070  * @name: name of the function to retrieve
1071  *
1072  * Performs `vkGetInstanceProcAddr()` with @instance and @name
1073  *
1074  * Returns: the function pointer for @name or %NULL
1075  *
1076  * Since: 1.18
1077  */
1078 gpointer
gst_vulkan_instance_get_proc_address(GstVulkanInstance * instance,const gchar * name)1079 gst_vulkan_instance_get_proc_address (GstVulkanInstance * instance,
1080     const gchar * name)
1081 {
1082   gpointer ret;
1083 
1084   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), NULL);
1085   g_return_val_if_fail (instance->instance != NULL, NULL);
1086   g_return_val_if_fail (name != NULL, NULL);
1087 
1088   ret = vkGetInstanceProcAddr (instance->instance, name);
1089 
1090   GST_TRACE_OBJECT (instance, "%s = %p", name, ret);
1091 
1092   return ret;
1093 }
1094 
1095 /**
1096  * gst_vulkan_instance_create_device:
1097  * @instance: a #GstVulkanInstance
1098  *
1099  * Returns: (transfer full): a new #GstVulkanDevice
1100  *
1101  * Since: 1.18
1102  */
1103 GstVulkanDevice *
gst_vulkan_instance_create_device(GstVulkanInstance * instance,GError ** error)1104 gst_vulkan_instance_create_device (GstVulkanInstance * instance,
1105     GError ** error)
1106 {
1107   GstVulkanDevice *device;
1108 
1109   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), NULL);
1110 
1111   g_signal_emit (instance, gst_vulkan_instance_signals[SIGNAL_CREATE_DEVICE], 0,
1112       &device);
1113 
1114   if (!device) {
1115     device = gst_vulkan_device_new_with_index (instance, 0);
1116   }
1117 
1118   if (!gst_vulkan_device_open (device, error)) {
1119     gst_object_unref (device);
1120     device = NULL;
1121   }
1122 
1123   return device;
1124 }
1125 
1126 /**
1127  * gst_context_set_vulkan_instance:
1128  * @context: a #GstContext
1129  * @instance: a #GstVulkanInstance
1130  *
1131  * Sets @instance on @context
1132  *
1133  * Since: 1.18
1134  */
1135 void
gst_context_set_vulkan_instance(GstContext * context,GstVulkanInstance * instance)1136 gst_context_set_vulkan_instance (GstContext * context,
1137     GstVulkanInstance * instance)
1138 {
1139   GstStructure *s;
1140 
1141   g_return_if_fail (context != NULL);
1142   g_return_if_fail (gst_context_is_writable (context));
1143 
1144   if (instance)
1145     GST_CAT_LOG (GST_CAT_CONTEXT,
1146         "setting GstVulkanInstance(%" GST_PTR_FORMAT ") on context(%"
1147         GST_PTR_FORMAT ")", instance, context);
1148 
1149   s = gst_context_writable_structure (context);
1150   gst_structure_set (s, GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR,
1151       GST_TYPE_VULKAN_INSTANCE, instance, NULL);
1152 }
1153 
1154 /**
1155  * gst_context_get_vulkan_instance:
1156  * @context: a #GstContext
1157  * @instance: resulting #GstVulkanInstance
1158  *
1159  * Returns: Whether @instance was in @context
1160  *
1161  * Since: 1.18
1162  */
1163 gboolean
gst_context_get_vulkan_instance(GstContext * context,GstVulkanInstance ** instance)1164 gst_context_get_vulkan_instance (GstContext * context,
1165     GstVulkanInstance ** instance)
1166 {
1167   const GstStructure *s;
1168   gboolean ret;
1169 
1170   g_return_val_if_fail (instance != NULL, FALSE);
1171   g_return_val_if_fail (context != NULL, FALSE);
1172 
1173   s = gst_context_get_structure (context);
1174   ret = gst_structure_get (s, GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR,
1175       GST_TYPE_VULKAN_INSTANCE, instance, NULL);
1176 
1177   GST_CAT_LOG (GST_CAT_CONTEXT, "got GstVulkanInstance(%" GST_PTR_FORMAT
1178       ") from context(%" GST_PTR_FORMAT ")", *instance, context);
1179 
1180   return ret;
1181 }
1182 
1183 /**
1184  * gst_vulkan_instance_handle_context_query:
1185  * @element: a #GstElement
1186  * @query: a #GstQuery of type #GST_QUERY_CONTEXT
1187  * @instance: (nullable): the #GstVulkanInstance
1188  *
1189  * If a #GstVulkanInstance is requested in @query, sets @instance as the reply.
1190  *
1191  * Intended for use with element query handlers to respond to #GST_QUERY_CONTEXT
1192  * for a #GstVulkanInstance.
1193  *
1194  * Returns: whether @query was responded to with @instance
1195  *
1196  * Since: 1.18
1197  */
1198 gboolean
gst_vulkan_instance_handle_context_query(GstElement * element,GstQuery * query,GstVulkanInstance * instance)1199 gst_vulkan_instance_handle_context_query (GstElement * element,
1200     GstQuery * query, GstVulkanInstance * instance)
1201 {
1202   gboolean res = FALSE;
1203   const gchar *context_type;
1204   GstContext *context, *old_context;
1205 
1206   g_return_val_if_fail (element != NULL, FALSE);
1207   g_return_val_if_fail (query != NULL, FALSE);
1208   g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT, FALSE);
1209 
1210   if (!instance)
1211     return FALSE;
1212 
1213   gst_query_parse_context_type (query, &context_type);
1214 
1215   if (g_strcmp0 (context_type, GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR) == 0) {
1216     gst_query_parse_context (query, &old_context);
1217 
1218     if (old_context)
1219       context = gst_context_copy (old_context);
1220     else
1221       context = gst_context_new (GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR, TRUE);
1222 
1223     gst_context_set_vulkan_instance (context, instance);
1224     gst_query_set_context (query, context);
1225     gst_context_unref (context);
1226 
1227     res = instance != NULL;
1228   }
1229 
1230   return res;
1231 }
1232 
1233 /**
1234  * gst_vulkan_instance_run_context_query:
1235  * @element: a #GstElement
1236  * @instance: (inout): a #GstVulkanInstance
1237  *
1238  * Attempt to retrieve a #GstVulkanInstance using #GST_QUERY_CONTEXT from the
1239  * surrounding elements of @element.
1240  *
1241  * Returns: whether @instance contains a valid #GstVulkanInstance
1242  *
1243  * Since: 1.18
1244  */
1245 gboolean
gst_vulkan_instance_run_context_query(GstElement * element,GstVulkanInstance ** instance)1246 gst_vulkan_instance_run_context_query (GstElement * element,
1247     GstVulkanInstance ** instance)
1248 {
1249   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1250   g_return_val_if_fail (instance != NULL, FALSE);
1251 
1252   _init_debug ();
1253 
1254   if (*instance && GST_IS_VULKAN_INSTANCE (*instance))
1255     return TRUE;
1256 
1257   gst_vulkan_global_context_query (element,
1258       GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR);
1259 
1260   GST_DEBUG_OBJECT (element, "found instance %p", *instance);
1261 
1262   if (*instance)
1263     return TRUE;
1264 
1265   return FALSE;
1266 }
1267 
1268 /**
1269  * gst_vulkan_instance_check_version:
1270  * @instance: a #GstVulkanInstance
1271  * @major: major version
1272  * @minor: minor version
1273  * @patch: patch version
1274  *
1275  * Check if the configured vulkan instance supports the specified version.
1276  * Will not work prior to opening the instance with gst_vulkan_instance_open().
1277  * If a specific version is requested, the @patch level is ignored.
1278  *
1279  * Returns: whether @instance is at least the requested version.
1280  *
1281  * Since: 1.18
1282  */
1283 gboolean
gst_vulkan_instance_check_version(GstVulkanInstance * instance,guint major,guint minor,guint patch)1284 gst_vulkan_instance_check_version (GstVulkanInstance * instance,
1285     guint major, guint minor, guint patch)
1286 {
1287   GstVulkanInstancePrivate *priv;
1288 
1289   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE);
1290 
1291   priv = GET_PRIV (instance);
1292 
1293   return (priv->requested_api_major == 0
1294       && VK_MAKE_VERSION (major, minor, patch) <= priv->supported_instance_api)
1295       || (priv->requested_api_major >= 0 && (major < priv->requested_api_major
1296           || (major == priv->requested_api_major
1297               && minor <= priv->requested_api_minor)));
1298 }
1299 
1300 /**
1301  * gst_vulkan_instance_get_version:
1302  * @instance: a #GstVulkanInstance
1303  * @major: major version
1304  * @minor: minor version
1305  * @patch: patch version
1306  *
1307  * Retrieve the vulkan instance configured version.  Only returns the supported
1308  * API version by the instance without taking into account the requested API
1309  * version.  This means gst_vulkan_instance_check_version() will return
1310  * different values if a specific version has been requested (which is the
1311  * default) than a version check that is performed manually by retrieving the
1312  * version with this function.
1313  *
1314  * Since: 1.18
1315  */
1316 void
gst_vulkan_instance_get_version(GstVulkanInstance * instance,guint * major,guint * minor,guint * patch)1317 gst_vulkan_instance_get_version (GstVulkanInstance * instance,
1318     guint * major, guint * minor, guint * patch)
1319 {
1320   GstVulkanInstancePrivate *priv;
1321 
1322   g_return_if_fail (GST_IS_VULKAN_INSTANCE (instance));
1323 
1324   priv = GET_PRIV (instance);
1325 
1326   GST_OBJECT_LOCK (instance);
1327   if (!priv->supported_instance_api)
1328     gst_vulkan_get_supported_api_version_unlocked (instance);
1329 
1330   if (major)
1331     *major = VK_VERSION_MAJOR (priv->supported_instance_api);
1332   if (minor)
1333     *minor = VK_VERSION_MINOR (priv->supported_instance_api);
1334   if (patch)
1335     *patch = VK_VERSION_PATCH (priv->supported_instance_api);
1336   GST_OBJECT_UNLOCK (instance);
1337 }
1338