0dbf26f9cd3882cbb0b6e617fbaa73404ce5e991
[platform/upstream/gstreamer.git] / gst-libs / gst / vulkan / gstvkinstance.c
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
97 _init_debug (void)
98 {
99   static volatile 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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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   g_assert (instance->n_physical_devices > 0);
979   instance->physical_devices =
980       g_new0 (VkPhysicalDevice, instance->n_physical_devices);
981   err =
982       vkEnumeratePhysicalDevices (instance->instance,
983       &instance->n_physical_devices, instance->physical_devices);
984   if (gst_vulkan_error_to_g_error (err, error,
985           "vkEnumeratePhysicalDevices") < 0)
986     goto error;
987
988 #if !defined (GST_DISABLE_DEBUG)
989   vulkan_debug_level = gst_debug_category_get_threshold (GST_VULKAN_DEBUG_CAT);
990
991   if (vulkan_debug_level >= GST_LEVEL_ERROR
992       && gst_vulkan_instance_is_extension_enabled_unlocked (instance,
993           VK_EXT_DEBUG_REPORT_EXTENSION_NAME, NULL)) {
994     VkDebugReportCallbackCreateInfoEXT info = { 0, };
995
996     priv->dbgCreateDebugReportCallback = (PFN_vkCreateDebugReportCallbackEXT)
997         gst_vulkan_instance_get_proc_address (instance,
998         "vkCreateDebugReportCallbackEXT");
999     if (!priv->dbgCreateDebugReportCallback) {
1000       g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED,
1001           "Failed to retrieve vkCreateDebugReportCallback");
1002       goto error;
1003     }
1004     priv->dbgDestroyDebugReportCallback = (PFN_vkDestroyDebugReportCallbackEXT)
1005         gst_vulkan_instance_get_proc_address (instance,
1006         "vkDestroyDebugReportCallbackEXT");
1007     if (!priv->dbgDestroyDebugReportCallback) {
1008       g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED,
1009           "Failed to retrieve vkDestroyDebugReportCallback");
1010       goto error;
1011     }
1012     priv->dbgReportMessage = (PFN_vkDebugReportMessageEXT)
1013         gst_vulkan_instance_get_proc_address (instance,
1014         "vkDebugReportMessageEXT");
1015     if (!priv->dbgReportMessage) {
1016       g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED,
1017           "Failed to retrieve vkDebugReportMessage");
1018       goto error;
1019     }
1020
1021     info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
1022     info.pNext = NULL;
1023     info.flags = 0;
1024     info.pfnCallback = (PFN_vkDebugReportCallbackEXT) _gst_vk_debug_callback;
1025     info.pUserData = NULL;
1026     /* matches the conditions in _gst_vk_debug_callback() */
1027     if (vulkan_debug_level >= GST_LEVEL_ERROR)
1028       info.flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
1029     if (vulkan_debug_level >= GST_LEVEL_WARNING)
1030       info.flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
1031     if (vulkan_debug_level >= GST_LEVEL_FIXME)
1032       info.flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
1033     if (vulkan_debug_level >= GST_LEVEL_LOG)
1034       info.flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
1035     if (vulkan_debug_level >= GST_LEVEL_TRACE)
1036       info.flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
1037
1038     err =
1039         priv->dbgCreateDebugReportCallback (instance->instance, &info, NULL,
1040         &priv->msg_callback);
1041     if (gst_vulkan_error_to_g_error (err, error,
1042             "vkCreateDebugReportCallback") < 0)
1043       goto error;
1044   }
1045 #endif
1046
1047   priv->opened = TRUE;
1048   GST_OBJECT_UNLOCK (instance);
1049
1050   return TRUE;
1051
1052 error:
1053   {
1054     GST_OBJECT_UNLOCK (instance);
1055     return FALSE;
1056   }
1057 }
1058
1059 /**
1060  * gst_vulkan_instance_get_proc_address:
1061  * @instance: a #GstVulkanInstance
1062  * @name: name of the function to retrieve
1063  *
1064  * Performs `vkGetInstanceProcAddr()` with @instance and @name
1065  *
1066  * Returns: the function pointer for @name or %NULL
1067  *
1068  * Since: 1.18
1069  */
1070 gpointer
1071 gst_vulkan_instance_get_proc_address (GstVulkanInstance * instance,
1072     const gchar * name)
1073 {
1074   gpointer ret;
1075
1076   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), NULL);
1077   g_return_val_if_fail (instance->instance != NULL, NULL);
1078   g_return_val_if_fail (name != NULL, NULL);
1079
1080   ret = vkGetInstanceProcAddr (instance->instance, name);
1081
1082   GST_TRACE_OBJECT (instance, "%s = %p", name, ret);
1083
1084   return ret;
1085 }
1086
1087 /**
1088  * gst_vulkan_instance_create_device:
1089  * @instance: a #GstVulkanInstance
1090  *
1091  * Returns: (transfer full): a new #GstVulkanDevice
1092  *
1093  * Since: 1.18
1094  */
1095 GstVulkanDevice *
1096 gst_vulkan_instance_create_device (GstVulkanInstance * instance,
1097     GError ** error)
1098 {
1099   GstVulkanDevice *device;
1100
1101   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), NULL);
1102
1103   g_signal_emit (instance, gst_vulkan_instance_signals[SIGNAL_CREATE_DEVICE], 0,
1104       &device);
1105
1106   if (!device) {
1107     device = gst_vulkan_device_new_with_index (instance, 0);
1108   }
1109
1110   if (!gst_vulkan_device_open (device, error)) {
1111     gst_object_unref (device);
1112     device = NULL;
1113   }
1114
1115   return device;
1116 }
1117
1118 /**
1119  * gst_context_set_vulkan_instance:
1120  * @context: a #GstContext
1121  * @instance: a #GstVulkanInstance
1122  *
1123  * Sets @instance on @context
1124  *
1125  * Since: 1.18
1126  */
1127 void
1128 gst_context_set_vulkan_instance (GstContext * context,
1129     GstVulkanInstance * instance)
1130 {
1131   GstStructure *s;
1132
1133   g_return_if_fail (context != NULL);
1134   g_return_if_fail (gst_context_is_writable (context));
1135
1136   if (instance)
1137     GST_CAT_LOG (GST_CAT_CONTEXT,
1138         "setting GstVulkanInstance(%" GST_PTR_FORMAT ") on context(%"
1139         GST_PTR_FORMAT ")", instance, context);
1140
1141   s = gst_context_writable_structure (context);
1142   gst_structure_set (s, GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR,
1143       GST_TYPE_VULKAN_INSTANCE, instance, NULL);
1144 }
1145
1146 /**
1147  * gst_context_get_vulkan_instance:
1148  * @context: a #GstContext
1149  * @instance: resulting #GstVulkanInstance
1150  *
1151  * Returns: Whether @instance was in @context
1152  *
1153  * Since: 1.18
1154  */
1155 gboolean
1156 gst_context_get_vulkan_instance (GstContext * context,
1157     GstVulkanInstance ** instance)
1158 {
1159   const GstStructure *s;
1160   gboolean ret;
1161
1162   g_return_val_if_fail (instance != NULL, FALSE);
1163   g_return_val_if_fail (context != NULL, FALSE);
1164
1165   s = gst_context_get_structure (context);
1166   ret = gst_structure_get (s, GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR,
1167       GST_TYPE_VULKAN_INSTANCE, instance, NULL);
1168
1169   GST_CAT_LOG (GST_CAT_CONTEXT, "got GstVulkanInstance(%" GST_PTR_FORMAT
1170       ") from context(%" GST_PTR_FORMAT ")", *instance, context);
1171
1172   return ret;
1173 }
1174
1175 /**
1176  * gst_vulkan_instance_handle_context_query:
1177  * @element: a #GstElement
1178  * @query: a #GstQuery of type #GST_QUERY_CONTEXT
1179  * @instance: (nullable): the #GstVulkanInstance
1180  *
1181  * If a #GstVulkanInstance is requested in @query, sets @instance as the reply.
1182  *
1183  * Intended for use with element query handlers to respond to #GST_QUERY_CONTEXT
1184  * for a #GstVulkanInstance.
1185  *
1186  * Returns: whether @query was responded to with @instance
1187  *
1188  * Since: 1.18
1189  */
1190 gboolean
1191 gst_vulkan_instance_handle_context_query (GstElement * element,
1192     GstQuery * query, GstVulkanInstance * instance)
1193 {
1194   gboolean res = FALSE;
1195   const gchar *context_type;
1196   GstContext *context, *old_context;
1197
1198   g_return_val_if_fail (element != NULL, FALSE);
1199   g_return_val_if_fail (query != NULL, FALSE);
1200   g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT, FALSE);
1201
1202   if (!instance)
1203     return FALSE;
1204
1205   gst_query_parse_context_type (query, &context_type);
1206
1207   if (g_strcmp0 (context_type, GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR) == 0) {
1208     gst_query_parse_context (query, &old_context);
1209
1210     if (old_context)
1211       context = gst_context_copy (old_context);
1212     else
1213       context = gst_context_new (GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR, TRUE);
1214
1215     gst_context_set_vulkan_instance (context, instance);
1216     gst_query_set_context (query, context);
1217     gst_context_unref (context);
1218
1219     res = instance != NULL;
1220   }
1221
1222   return res;
1223 }
1224
1225 /**
1226  * gst_vulkan_instance_run_context_query:
1227  * @element: a #GstElement
1228  * @instance: (inout): a #GstVulkanInstance
1229  *
1230  * Attempt to retrieve a #GstVulkanInstance using #GST_QUERY_CONTEXT from the
1231  * surrounding elements of @element.
1232  *
1233  * Returns: whether @instance contains a valid #GstVulkanInstance
1234  *
1235  * Since: 1.18
1236  */
1237 gboolean
1238 gst_vulkan_instance_run_context_query (GstElement * element,
1239     GstVulkanInstance ** instance)
1240 {
1241   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1242   g_return_val_if_fail (instance != NULL, FALSE);
1243
1244   _init_debug ();
1245
1246   if (*instance && GST_IS_VULKAN_INSTANCE (*instance))
1247     return TRUE;
1248
1249   gst_vulkan_global_context_query (element,
1250       GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR);
1251
1252   GST_DEBUG_OBJECT (element, "found instance %p", *instance);
1253
1254   if (*instance)
1255     return TRUE;
1256
1257   return FALSE;
1258 }
1259
1260 /**
1261  * gst_vulkan_instance_check_version:
1262  * @instance: a #GstVulkanInstance
1263  * @major: major version
1264  * @minor: minor version
1265  * @patch: patch version
1266  *
1267  * Check if the configured vulkan instance supports the specified version.
1268  * Will not work prior to opening the instance with gst_vulkan_instance_open().
1269  * If a specific version is requested, the @patch level is ignored.
1270  *
1271  * Returns: whether @instance is at least the requested version.
1272  *
1273  * Since: 1.18
1274  */
1275 gboolean
1276 gst_vulkan_instance_check_version (GstVulkanInstance * instance,
1277     guint major, guint minor, guint patch)
1278 {
1279   GstVulkanInstancePrivate *priv;
1280
1281   g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE);
1282
1283   priv = GET_PRIV (instance);
1284
1285   return (priv->requested_api_major == 0
1286       && VK_MAKE_VERSION (major, minor, patch) <= priv->supported_instance_api)
1287       || (priv->requested_api_major >= 0 && (major < priv->requested_api_major
1288           || (major == priv->requested_api_major
1289               && minor <= priv->requested_api_minor)));
1290 }
1291
1292 /**
1293  * gst_vulkan_instance_get_version:
1294  * @instance: a #GstVulkanInstance
1295  * @major: major version
1296  * @minor: minor version
1297  * @patch: patch version
1298  *
1299  * Retrieve the vulkan instance configured version.  Only returns the supported
1300  * API version by the instance without taking into account the requested API
1301  * version.  This means gst_vulkan_instance_check_version() will return
1302  * different values if a specific version has been requested (which is the
1303  * default) than a version check that is performed manually by retrieving the
1304  * version with this function.
1305  *
1306  * Since: 1.18
1307  */
1308 void
1309 gst_vulkan_instance_get_version (GstVulkanInstance * instance,
1310     guint * major, guint * minor, guint * patch)
1311 {
1312   GstVulkanInstancePrivate *priv;
1313
1314   g_return_if_fail (GST_IS_VULKAN_INSTANCE (instance));
1315
1316   priv = GET_PRIV (instance);
1317
1318   GST_OBJECT_LOCK (instance);
1319   if (!priv->supported_instance_api)
1320     gst_vulkan_get_supported_api_version_unlocked (instance);
1321
1322   if (major)
1323     *major = VK_VERSION_MAJOR (priv->supported_instance_api);
1324   if (minor)
1325     *minor = VK_VERSION_MINOR (priv->supported_instance_api);
1326   if (patch)
1327     *patch = VK_VERSION_PATCH (priv->supported_instance_api);
1328   GST_OBJECT_UNLOCK (instance);
1329 }