From 51dda24a88e6ecb89460b251afbed75e1fdbc183 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 25 Feb 2025 20:09:48 +1100 Subject: [PATCH] vulkan: fix device related API version checks The API version exposed by a particular device can be completely different from what is exported by the parent instance. Since Vulkan 1.1 it is also possible to use newer device API than supported by the instance API version (with the appropriate version checks). Part-of: --- .../gst/vulkan/gstvkdecoder-private.c | 3 +- .../gst-libs/gst/vulkan/gstvkinstance.c | 67 ++++++++++++++++++- .../gst-libs/gst/vulkan/gstvkinstance.h | 10 +++ .../gst-libs/gst/vulkan/gstvkphysicaldevice.c | 17 +++-- .../tests/check/libs/vkdevice.c | 5 +- 5 files changed, 89 insertions(+), 13 deletions(-) diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkdecoder-private.c b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkdecoder-private.c index 8374840f9a..5df4c77d44 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkdecoder-private.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkdecoder-private.c @@ -1015,7 +1015,8 @@ gst_vulkan_decoder_update_ycbcr_sampler (GstVulkanDecoder * self, device = self->queue->device; - if (!gst_vulkan_instance_check_version (device->instance, 1, 2, 0)) { + if (!gst_vulkan_physical_device_check_api_version (device->physical_device, 1, + 2, 0)) { g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED, "Sampler Ycbcr conversion not available in API"); return FALSE; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkinstance.c b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkinstance.c index 96583ae6ba..2b5d948452 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkinstance.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkinstance.c @@ -77,6 +77,7 @@ struct _GstVulkanInstancePrivate guint requested_api_major; guint requested_api_minor; uint32_t supported_instance_api; + uint32_t configured_instance_api; guint n_available_layers; VkLayerProperties *available_layers; @@ -983,6 +984,8 @@ gst_vulkan_instance_open (GstVulkanInstance * instance, GError ** error) } } + priv->configured_instance_api = requested_instance_api; + err = vkEnumeratePhysicalDevices (instance->instance, &instance->n_physical_devices, NULL); @@ -1334,7 +1337,7 @@ gst_vulkan_instance_check_version (GstVulkanInstance * instance, * @minor: (out): minor version * @patch: (out): patch version * - * Retrieve the vulkan instance configured version. Only returns the supported + * Retrieve the vulkan instance supported version. Only returns the supported * API version by the instance without taking into account the requested API * version. This means gst_vulkan_instance_check_version() will return * different values if a specific version has been requested (which is the @@ -1365,3 +1368,65 @@ gst_vulkan_instance_get_version (GstVulkanInstance * instance, *patch = VK_VERSION_PATCH (priv->supported_instance_api); GST_OBJECT_UNLOCK (instance); } + +/** + * gst_vulkan_instance_get_api_version: + * @instance: a #GstVulkanInstance + * @major: (out): major version + * @minor: (out): minor version + * @patch: (out): patch version + * + * Returns the vulkan API version configured when constructing the + * #GstVulkanInstance. This value can be any valid Vulkan API version and may + * not match gst_vulkan_instance_get_version() in any way. This version is the + * maximum allowed vulkan API to be used in any capacity. + * + * This will not return valid values until gst_vulkan_instance_open() has been + * called. + * + * Since: 1.26 + */ +void +gst_vulkan_instance_get_api_version (GstVulkanInstance * instance, + guint * major, guint * minor, guint * patch) +{ + GstVulkanInstancePrivate *priv; + + g_return_if_fail (GST_IS_VULKAN_INSTANCE (instance)); + + priv = GET_PRIV (instance); + + GST_OBJECT_LOCK (instance); + if (major) + *major = VK_VERSION_MAJOR (priv->configured_instance_api); + if (minor) + *minor = VK_VERSION_MINOR (priv->configured_instance_api); + if (patch) + *patch = VK_VERSION_PATCH (priv->configured_instance_api); + GST_OBJECT_UNLOCK (instance); +} + +/** + * gst_vulkan_instance_check_api_version: + * @instance: a #GstVulkanInstance + * @major: the API major version to check + * @minor: the API minor version to check + * @patch: the API patch version to check + * + * Returns: whether the #GstVulkanInstance supports the version specified + * by @major, @minor and @patch. + * + * Since: 1.26 + */ +gboolean +gst_vulkan_instance_check_api_version (GstVulkanInstance * instance, + guint major, guint minor, guint patch) +{ + GstVulkanInstancePrivate *priv; + + g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE); + + priv = GET_PRIV (instance); + + return VK_MAKE_VERSION (major, minor, patch) <= priv->configured_instance_api; +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkinstance.h b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkinstance.h index 99cd8f2ef9..2cbfdc93e9 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkinstance.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkinstance.h @@ -148,6 +148,16 @@ gboolean gst_vulkan_instance_enable_layer (GstVulkanInstan GST_VULKAN_API gboolean gst_vulkan_instance_is_layer_enabled (GstVulkanInstance * instance, const gchar * name); +GST_VULKAN_API +void gst_vulkan_instance_get_api_version (GstVulkanInstance * instance, + guint * major, + guint * minor, + guint * patch); +GST_VULKAN_API +gboolean gst_vulkan_instance_check_api_version (GstVulkanInstance * instance, + guint major, + guint minor, + guint patch); G_END_DECLS diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkphysicaldevice.c b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkphysicaldevice.c index 184253e264..4c3d73388c 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkphysicaldevice.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/vulkan/gstvkphysicaldevice.c @@ -504,7 +504,7 @@ dump_features (GstVulkanPhysicalDevice * device, GError ** error) GstVulkanPhysicalDevicePrivate *priv = GET_PRIV (device); VkBaseOutStructure *iter; - if (gst_vulkan_instance_check_version (device->instance, 1, 2, 0)) { + if (gst_vulkan_physical_device_check_api_version (device, 1, 2, 0)) { for (iter = (VkBaseOutStructure *) & priv->features10; iter; iter = iter->pNext) { if (iter->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2) @@ -517,12 +517,12 @@ dump_features (GstVulkanPhysicalDevice * device, GError ** error) VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES) dump_features12 (device, (VkPhysicalDeviceVulkan12Features *) iter); #if defined (VK_API_VERSION_1_3) - else if (gst_vulkan_instance_check_version (device->instance, 1, 3, 0) + else if (gst_vulkan_physical_device_check_api_version (device, 1, 3, 0) && iter->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES) dump_features13 (device, (VkPhysicalDeviceVulkan13Features *) iter); #if defined(VK_KHR_video_maintenance1) - else if (gst_vulkan_instance_check_version (device->instance, 1, 3, 283) + else if (gst_vulkan_physical_device_check_api_version (device, 1, 3, 283) && iter->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_1_FEATURES_KHR) dump_videomaintenance1 (device, @@ -909,7 +909,7 @@ physical_device_info (GstVulkanPhysicalDevice * device, GError ** error) return FALSE; #if defined (VK_API_VERSION_1_2) - if (gst_vulkan_instance_check_version (device->instance, 1, 2, 0)) { + if (gst_vulkan_physical_device_check_api_version (device, 1, 2, 0)) { for (iter = (VkBaseOutStructure *) & priv->properties10; iter; iter = iter->pNext) { if (iter->sType == @@ -919,7 +919,7 @@ physical_device_info (GstVulkanPhysicalDevice * device, GError ** error) VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES) dump_properties12 (device, (VkPhysicalDeviceVulkan12Properties *) iter); #if defined (VK_API_VERSION_1_3) - else if (gst_vulkan_instance_check_version (device->instance, 1, 3, 0) + else if (gst_vulkan_physical_device_check_api_version (device, 1, 3, 0) && iter->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES) dump_properties13 (device, (VkPhysicalDeviceVulkan13Properties *) iter); @@ -992,7 +992,7 @@ gst_vulkan_physical_device_fill_info (GstVulkanPhysicalDevice * device, vkGetPhysicalDeviceProperties (device->device, &device->properties); #if defined (VK_API_VERSION_1_2) - if (gst_vulkan_instance_check_version (device->instance, 1, 2, 0)) { + if (gst_vulkan_physical_device_check_api_version (device, 1, 2, 0)) { PFN_vkGetPhysicalDeviceProperties2 get_props2; PFN_vkGetPhysicalDeviceMemoryProperties2 get_mem_props2; PFN_vkGetPhysicalDeviceFeatures2 get_features2; @@ -1313,8 +1313,7 @@ gboolean gst_vulkan_physical_device_check_api_version (GstVulkanPhysicalDevice * device, guint major, guint minor, guint patch) { - /* Since Vulkan 1.1 it is possible to have different supported API versions - * between an instance and a device */ return VK_MAKE_VERSION (major, minor, patch) <= device->properties.apiVersion - && (gst_vulkan_instance_check_version (device->instance, 1, 1, 0) || (major == 1 && minor == 0)); + && gst_vulkan_instance_check_api_version (device->instance, major, minor, + patch); } diff --git a/subprojects/gst-plugins-bad/tests/check/libs/vkdevice.c b/subprojects/gst-plugins-bad/tests/check/libs/vkdevice.c index 7ec55302c0..567125ae54 100644 --- a/subprojects/gst-plugins-bad/tests/check/libs/vkdevice.c +++ b/subprojects/gst-plugins-bad/tests/check/libs/vkdevice.c @@ -62,8 +62,9 @@ GST_START_TEST (test_physical_device_version) gst_vulkan_physical_device_get_api_version (phys, &major, &minor, NULL); - if (major > 1 || minor >= 0) - fail_unless (gst_vulkan_physical_device_check_api_version (phys, major, minor, 0)); + if (major > 0) + fail_unless (gst_vulkan_physical_device_check_api_version (phys, major, + minor, 0)); if (minor > 0) fail_unless (gst_vulkan_physical_device_check_api_version (phys, major,