diff --git a/gst-libs/gst/vulkan/gstvkdisplay.c b/gst-libs/gst/vulkan/gstvkdisplay.c index 530554a9a8..814cd7fe90 100644 --- a/gst-libs/gst/vulkan/gstvkdisplay.c +++ b/gst-libs/gst/vulkan/gstvkdisplay.c @@ -514,20 +514,12 @@ gst_context_get_vulkan_display (GstContext * context, return ret; } -/** - * gst_vulkan_display_choose_type: - * @instance: a #GstVulkanInstance - * - * This function will read the %GST_VULKAN_WINDOW environment variable for - * a user choice or choose the first supported implementation. - * - * Returns: the default #GstVulkanDisplayType #GstVulkanInstance will choose - * on creation - * - * Since: 1.18 - */ -GstVulkanDisplayType -gst_vulkan_display_choose_type (GstVulkanInstance * instance) +typedef gboolean (*InstanceGetExtensionInfo) (GstVulkanInstance * instance, + const gchar * name, guint32 * spec_version); + +static GstVulkanDisplayType +gst_vulkan_display_choose_type_full (GstVulkanInstance * instance, + InstanceGetExtensionInfo get_ext_info) { const gchar *window_str; GstVulkanDisplayType type = GST_VULKAN_DISPLAY_TYPE_NONE; @@ -535,14 +527,17 @@ gst_vulkan_display_choose_type (GstVulkanInstance * instance) window_str = g_getenv ("GST_VULKAN_WINDOW"); - /* FIXME: enumerate instance extensions for the supported winsys' */ + if (!get_ext_info (instance, VK_KHR_SURFACE_EXTENSION_NAME, NULL)) + /* Vulkan doesn't have support for surfaces */ + return GST_VULKAN_DISPLAY_TYPE_NONE; #define CHOOSE_WINSYS(lname,uname) \ G_STMT_START { \ if (!type && g_strcmp0 (window_str, G_STRINGIFY (lname)) == 0) { \ type = G_PASTE(GST_VULKAN_DISPLAY_TYPE_,uname); \ } \ - if (!first_supported) \ + if (!first_supported && get_ext_info (instance, \ + gst_vulkan_display_type_to_extension_string (G_PASTE(GST_VULKAN_DISPLAY_TYPE_,uname)), NULL)) \ first_supported = G_PASTE(GST_VULKAN_DISPLAY_TYPE_,uname); \ } G_STMT_END @@ -567,7 +562,9 @@ gst_vulkan_display_choose_type (GstVulkanInstance * instance) type = GST_VULKAN_DISPLAY_TYPE_WIN32; } - if (!first_supported) + if (!first_supported && get_ext_info (instance, + gst_vulkan_display_type_to_extension_string + (GST_VULKAN_DISPLAY_TYPE_WIN32), NULL)) first_supported = GST_VULKAN_DISPLAY_TYPE_WIN32; #endif @@ -577,7 +574,9 @@ gst_vulkan_display_choose_type (GstVulkanInstance * instance) type = GST_VULKAN_DISPLAY_TYPE_ANDROID; } - if (!first_supported) + if (!first_supported && get_ext_info (instance, + gst_vulkan_display_type_to_extension_string + (GST_VULKAN_DISPLAY_TYPE_ANDROID), NULL)) first_supported = GST_VULKAN_DISPLAY_TYPE_ANDROID; #endif @@ -594,6 +593,42 @@ gst_vulkan_display_choose_type (GstVulkanInstance * instance) return GST_VULKAN_DISPLAY_TYPE_NONE; } +G_GNUC_INTERNAL GstVulkanDisplayType +gst_vulkan_display_choose_type_unlocked (GstVulkanInstance * instance); + +G_GNUC_INTERNAL gboolean +gst_vulkan_instance_get_extension_info_unlocked (GstVulkanInstance * instance, + const gchar * name, guint32 * spec_version); + +G_GNUC_INTERNAL GstVulkanDisplayType +gst_vulkan_display_choose_type_unlocked (GstVulkanInstance * instance) +{ + return gst_vulkan_display_choose_type_full (instance, + (InstanceGetExtensionInfo) + gst_vulkan_instance_get_extension_info_unlocked); +} + +/** + * gst_vulkan_display_choose_type: + * @instance: a #GstVulkanInstance + * + * This function will read the %GST_VULKAN_WINDOW environment variable for + * a user choice or choose the first supported implementation. + * + * gst_vulkan_instance_fill_info() must have been called prior to this function. + * + * Returns: the default #GstVulkanDisplayType #GstVulkanInstance will choose + * on creation + * + * Since: 1.18 + */ +GstVulkanDisplayType +gst_vulkan_display_choose_type (GstVulkanInstance * instance) +{ + return gst_vulkan_display_choose_type_full (instance, + (InstanceGetExtensionInfo) gst_vulkan_instance_get_extension_info); +} + /** * gst_vulkan_display_type_to_extension_string: * @type: a #GstVulkanDisplayType @@ -613,7 +648,6 @@ gst_vulkan_display_type_to_extension_string (GstVulkanDisplayType type) if (type & GST_VULKAN_DISPLAY_TYPE_XCB) return VK_KHR_XCB_SURFACE_EXTENSION_NAME; #endif - #if GST_VULKAN_HAVE_WINDOW_WAYLAND if (type & GST_VULKAN_DISPLAY_TYPE_WAYLAND) return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME; diff --git a/gst-libs/gst/vulkan/gstvkinstance.c b/gst-libs/gst/vulkan/gstvkinstance.c index ddd619b6a0..404a20ddd2 100644 --- a/gst-libs/gst/vulkan/gstvkinstance.c +++ b/gst-libs/gst/vulkan/gstvkinstance.c @@ -72,10 +72,18 @@ static void gst_vulkan_instance_finalize (GObject * object); struct _GstVulkanInstancePrivate { + gboolean info_collected; gboolean opened; guint requested_api_major; guint requested_api_minor; uint32_t supported_instance_api; + + guint n_available_layers; + VkLayerProperties *available_layers; + guint n_available_extensions; + VkExtensionProperties *available_extensions; + GPtrArray *enabled_layers; + GPtrArray *enabled_extensions; }; static void @@ -169,6 +177,9 @@ gst_vulkan_instance_init (GstVulkanInstance * instance) priv->requested_api_major = DEFAULT_REQUESTED_API_VERSION_MAJOR; priv->requested_api_minor = DEFAULT_REQUESTED_API_VERSION_MINOR; + priv->enabled_layers = g_ptr_array_new_with_free_func (g_free); + priv->enabled_extensions = g_ptr_array_new_with_free_func (g_free); + #if !defined (GST_DISABLE_DEBUG) { const gchar *api_override = g_getenv ("GST_VULKAN_INSTANCE_API_VERSION"); @@ -251,6 +262,18 @@ gst_vulkan_instance_finalize (GObject * object) vkDestroyInstance (instance->instance, NULL); instance->instance = NULL; + g_free (priv->available_layers); + priv->available_layers = NULL; + + g_free (priv->available_extensions); + priv->available_extensions = NULL; + + g_ptr_array_unref (priv->enabled_layers); + priv->enabled_layers = NULL; + + g_ptr_array_unref (priv->enabled_extensions); + priv->enabled_extensions = NULL; + G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -291,6 +314,369 @@ _gst_vk_debug_callback (VkDebugReportFlagsEXT msgFlags, return FALSE; } +static gboolean +gst_vulkan_instance_get_layer_info_unlocked (GstVulkanInstance * instance, + const gchar * name, gchar ** description, guint32 * spec_version, + guint32 * implementation_version) +{ + GstVulkanInstancePrivate *priv; + int i; + + priv = GET_PRIV (instance); + + for (i = 0; i < priv->n_available_layers; i++) { + if (g_strcmp0 (name, priv->available_layers[i].layerName) == 0) { + if (description) + *description = g_strdup (priv->available_layers[i].description); + if (spec_version) + *spec_version = priv->available_layers[i].specVersion; + if (implementation_version) + *spec_version = priv->available_layers[i].implementationVersion; + return TRUE; + } + } + + return FALSE; +} + +/** + * gst_vulkan_instance_get_layer_info: + * @instance: a #GstVulkanInstance + * @name: the layer name to look for + * @description: (out) (nullable): return value for the layer description or %NULL + * @spec_version: (out) (nullable): return value for the layer specification version + * @implementation_version: (out) (nullable): return value for the layer implementation version + * + * Retrieves information about a layer. + * + * Will not find any layers before gst_vulkan_instance_fill_info() has been + * called. + * + * Returns: whether layer @name is available + * + * Since: 1.18 + */ +gboolean +gst_vulkan_instance_get_layer_info (GstVulkanInstance * instance, + const gchar * name, gchar ** description, guint32 * spec_version, + guint32 * implementation_version) +{ + gboolean ret; + + g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + GST_OBJECT_LOCK (instance); + ret = + gst_vulkan_instance_get_layer_info_unlocked (instance, name, description, + spec_version, implementation_version); + GST_OBJECT_UNLOCK (instance); + + return ret; +} + +G_GNUC_INTERNAL gboolean +gst_vulkan_instance_get_extension_info_unlocked (GstVulkanInstance * instance, + const gchar * name, guint32 * spec_version); + +G_GNUC_INTERNAL gboolean +gst_vulkan_instance_get_extension_info_unlocked (GstVulkanInstance * instance, + const gchar * name, guint32 * spec_version) +{ + GstVulkanInstancePrivate *priv; + int i; + + priv = GET_PRIV (instance); + + for (i = 0; i < priv->n_available_extensions; i++) { + if (g_strcmp0 (name, priv->available_extensions[i].extensionName) == 0) { + if (spec_version) + *spec_version = priv->available_extensions[i].specVersion; + return TRUE; + } + } + + return FALSE; +} + +/** + * gst_vulkan_instance_get_extension_info: + * @instance: a #GstVulkanInstance + * @name: the layer name to look for + * @spec_version: (out) (nullable): return value for the layer specification version + * + * Retrieves information about an extension. + * + * Will not find any extensions before gst_vulkan_instance_fill_info() has been + * called. + * + * Returns: whether extension @name is available + * + * Since: 1.18 + */ +gboolean +gst_vulkan_instance_get_extension_info (GstVulkanInstance * instance, + const gchar * name, guint32 * spec_version) +{ + gboolean ret; + + g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + GST_OBJECT_LOCK (instance); + ret = + gst_vulkan_instance_get_extension_info_unlocked (instance, name, + spec_version); + GST_OBJECT_UNLOCK (instance); + + return ret; +} + +/* reimplement a specfic case of g_ptr_array_find_with_equal_func as that + * requires Glib 2.54 */ +static gboolean +ptr_array_find_string (GPtrArray * array, const gchar * str, guint * index) +{ + guint i; + + for (i = 0; i < array->len; i++) { + gchar *val = (gchar *) g_ptr_array_index (array, i); + if (g_strcmp0 (val, str) == 0) { + if (index) + *index = i; + return TRUE; + } + } + + return FALSE; +} + +static gboolean +gst_vulkan_instance_is_extension_enabled_unlocked (GstVulkanInstance * instance, + const gchar * name, guint * index) +{ + GstVulkanInstancePrivate *priv = GET_PRIV (instance); + + return ptr_array_find_string (priv->enabled_extensions, name, index); +} + +/** + * gst_vulkan_instance_is_extension_enabled: + * @instance: a # GstVulkanInstance + * @name: extension name + * + * Returns: whether extension @name is enabled + */ +gboolean +gst_vulkan_instance_is_extension_enabled (GstVulkanInstance * instance, + const gchar * name) +{ + gboolean ret; + + g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + GST_OBJECT_LOCK (instance); + ret = + gst_vulkan_instance_is_extension_enabled_unlocked (instance, name, NULL); + GST_OBJECT_UNLOCK (instance); + + return ret; +} + +static gboolean +gst_vulkan_instance_enable_extension_unlocked (GstVulkanInstance * instance, + const gchar * name) +{ + GstVulkanInstancePrivate *priv = GET_PRIV (instance); + gboolean extension_is_available = FALSE; + guint i; + + if (gst_vulkan_instance_is_extension_enabled_unlocked (instance, name, NULL)) + /* extension is already enabled */ + return TRUE; + + for (i = 0; i < priv->n_available_extensions; i++) { + if (g_strcmp0 (name, priv->available_extensions[i].extensionName) == 0) { + extension_is_available = TRUE; + break; + } + } + + if (!extension_is_available) + return FALSE; + + g_ptr_array_add (priv->enabled_extensions, g_strdup (name)); + + return TRUE; +} + +/** + * gst_vulkan_instance_enable_extension: + * @instance: a #GstVulkanInstance + * @name: extension name to enable + * + * Enable an Vulkan extension by @name. Extensions cannot be enabled until + * gst_vulkan_instance_fill_info() has been called. Enabling an extension will + * only have an effect before the call to gst_vulkan_instance_open(). + * + * Returns: whether the Vulkan extension could be enabled. + */ +gboolean +gst_vulkan_instance_enable_extension (GstVulkanInstance * instance, + const gchar * name) +{ + gboolean ret; + + g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + GST_OBJECT_LOCK (instance); + ret = gst_vulkan_instance_enable_extension_unlocked (instance, name); + GST_OBJECT_UNLOCK (instance); + + return ret; +} + +static gboolean +gst_vulkan_instance_disable_extension_unlocked (GstVulkanInstance * instance, + const gchar * name) +{ + GstVulkanInstancePrivate *priv = GET_PRIV (instance); + gboolean extension_is_available = FALSE; + guint i; + + for (i = 0; i < priv->n_available_extensions; i++) { + if (g_strcmp0 (name, priv->available_extensions[i].extensionName) == 0) { + extension_is_available = TRUE; + break; + } + } + + if (!extension_is_available) + return FALSE; + + if (!gst_vulkan_instance_is_extension_enabled_unlocked (instance, name, &i)) + /* extension is already enabled */ + return TRUE; + + g_ptr_array_remove_index_fast (priv->enabled_extensions, i); + + return TRUE; +} + +/** + * gst_vulkan_instance_disable_extension: + * @instance: a #GstVulkanInstance + * @name: extension name to enable + * + * Disable an Vulkan extension by @name. Disabling an extension will only have + * an effect before the call to gst_vulkan_instance_open(). + * + * Returns: whether the Vulkan extension could be disabled. + */ +gboolean +gst_vulkan_instance_disable_extension (GstVulkanInstance * instance, + const gchar * name) +{ + gboolean ret; + + g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + GST_OBJECT_LOCK (instance); + ret = gst_vulkan_instance_disable_extension_unlocked (instance, name); + GST_OBJECT_UNLOCK (instance); + + return ret; +} + +static gboolean +gst_vulkan_instance_is_layer_enabled_unlocked (GstVulkanInstance * instance, + const gchar * name) +{ + GstVulkanInstancePrivate *priv = GET_PRIV (instance); + + return ptr_array_find_string (priv->enabled_layers, name, NULL); +} + +/** + * gst_vulkan_instance_is_layer_enabled: + * @instance: a # GstVulkanInstance + * @name: layer name + * + * Returns: whether layer @name is enabled + */ +gboolean +gst_vulkan_instance_is_layer_enabled (GstVulkanInstance * instance, + const gchar * name) +{ + gboolean ret; + + g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + GST_OBJECT_LOCK (instance); + ret = gst_vulkan_instance_is_layer_enabled_unlocked (instance, name); + GST_OBJECT_UNLOCK (instance); + + return ret; +} + +static gboolean +gst_vulkan_instance_enable_layer_unlocked (GstVulkanInstance * instance, + const gchar * name) +{ + GstVulkanInstancePrivate *priv = GET_PRIV (instance); + gboolean layer_is_available = FALSE; + guint i; + + if (gst_vulkan_instance_is_layer_enabled_unlocked (instance, name)) + /* layer is already enabled */ + return TRUE; + + for (i = 0; i < priv->n_available_layers; i++) { + if (g_strcmp0 (name, priv->available_layers[i].layerName) == 0) { + layer_is_available = TRUE; + break; + } + } + + if (!layer_is_available) + return FALSE; + + g_ptr_array_add (priv->enabled_layers, g_strdup (name)); + + return TRUE; +} + +/** + * gst_vulkan_instance_enable_layer: + * @instance: a #GstVulkanInstance + * @name: layer name to enable + * + * Enable an Vulkan layer by @name. Layer cannot be enabled until + * gst_vulkan_instance_fill_info() has been called. Enabling a layer will + * only have an effect before the call to gst_vulkan_instance_open(). + * + * Returns: whether the Vulkan layer could be enabled. + */ +gboolean +gst_vulkan_instance_enable_layer (GstVulkanInstance * instance, + const gchar * name) +{ + gboolean ret; + + g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + GST_OBJECT_LOCK (instance); + ret = gst_vulkan_instance_enable_layer_unlocked (instance, name); + GST_OBJECT_UNLOCK (instance); + + return ret; +} + static void gst_vulkan_get_supported_api_version_unlocked (GstVulkanInstance * instance) { @@ -311,6 +697,122 @@ gst_vulkan_get_supported_api_version_unlocked (GstVulkanInstance * instance) } } +G_GNUC_INTERNAL GstVulkanDisplayType +gst_vulkan_display_choose_type_unlocked (GstVulkanInstance * instance); + +static gboolean +gst_vulkan_instance_fill_info_unlocked (GstVulkanInstance * instance, + GError ** error) +{ + GstVulkanInstancePrivate *priv; + VkResult err; + + priv = GET_PRIV (instance); + + if (priv->info_collected) + return TRUE; + priv->info_collected = TRUE; + + gst_vulkan_get_supported_api_version_unlocked (instance); + + /* Look for validation layers */ + err = vkEnumerateInstanceLayerProperties (&priv->n_available_layers, NULL); + if (gst_vulkan_error_to_g_error (err, error, + "vKEnumerateInstanceLayerProperties") < 0) { + return FALSE; + } + + priv->available_layers = g_new0 (VkLayerProperties, priv->n_available_layers); + err = + vkEnumerateInstanceLayerProperties (&priv->n_available_layers, + priv->available_layers); + if (gst_vulkan_error_to_g_error (err, error, + "vKEnumerateInstanceLayerProperties") < 0) { + return FALSE; + } + + err = + vkEnumerateInstanceExtensionProperties (NULL, + &priv->n_available_extensions, NULL); + if (gst_vulkan_error_to_g_error (err, error, + "vkEnumerateInstanceExtensionProperties") < 0) { + return FALSE; + } + + priv->available_extensions = + g_new0 (VkExtensionProperties, priv->n_available_extensions); + err = + vkEnumerateInstanceExtensionProperties (NULL, + &priv->n_available_extensions, priv->available_extensions); + if (gst_vulkan_error_to_g_error (err, error, + "vkEnumerateInstanceExtensionProperties") < 0) { + return FALSE; + } + + /* configure default extensions */ + { + GstVulkanDisplayType display_type; + const gchar *winsys_ext_name; + GstDebugLevel vulkan_debug_level; + + display_type = gst_vulkan_display_choose_type_unlocked (instance); + + winsys_ext_name = + gst_vulkan_display_type_to_extension_string (display_type); + if (!winsys_ext_name) { + GST_WARNING_OBJECT (instance, "No window system extension enabled"); + } else if (gst_vulkan_instance_get_extension_info_unlocked (instance, + VK_KHR_SURFACE_EXTENSION_NAME, NULL) + && gst_vulkan_instance_get_extension_info_unlocked (instance, + winsys_ext_name, NULL)) { + gst_vulkan_instance_enable_extension_unlocked (instance, + VK_KHR_SURFACE_EXTENSION_NAME); + gst_vulkan_instance_enable_extension_unlocked (instance, winsys_ext_name); + } +#if !defined (GST_DISABLE_DEBUG) + vulkan_debug_level = + gst_debug_category_get_threshold (GST_VULKAN_DEBUG_CAT); + + if (vulkan_debug_level >= GST_LEVEL_ERROR) { + if (gst_vulkan_instance_get_extension_info_unlocked (instance, + VK_EXT_DEBUG_REPORT_EXTENSION_NAME, NULL)) { + gst_vulkan_instance_enable_extension_unlocked (instance, + VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + } + } +#endif + } + + return TRUE; +} + +/** + * gst_vulkan_instance_fill_info: + * @instance: a #GstVulkanInstance + * @error: #GError + * + * Retrieve as much information about the available Vulkan instance without + * actually creating an Vulkan instance. Will not do anything while @instance + * is open. + * + * Returns: whether the instance information could be retrieved + * + * Since: 1.18 + */ +gboolean +gst_vulkan_instance_fill_info (GstVulkanInstance * instance, GError ** error) +{ + gboolean ret; + + g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE); + + GST_OBJECT_LOCK (instance); + ret = gst_vulkan_instance_fill_info_unlocked (instance, error); + GST_OBJECT_UNLOCK (instance); + + return ret; +} + /** * gst_vulkan_instance_open: * @instance: a #GstVulkanInstance @@ -324,14 +826,8 @@ gboolean gst_vulkan_instance_open (GstVulkanInstance * instance, GError ** error) { GstVulkanInstancePrivate *priv; - VkExtensionProperties *instance_extensions; - char *extension_names[64]; /* FIXME: make dynamic */ - VkLayerProperties *instance_layers; - uint32_t instance_extension_count = 0; - uint32_t enabled_extension_count = 0; - uint32_t instance_layer_count = 0; uint32_t requested_instance_api; - gboolean have_debug_extension = FALSE; + GstDebugLevel vulkan_debug_level; VkResult err; g_return_val_if_fail (GST_IS_VULKAN_INSTANCE (instance), FALSE); @@ -344,7 +840,9 @@ gst_vulkan_instance_open (GstVulkanInstance * instance, GError ** error) return TRUE; } - gst_vulkan_get_supported_api_version_unlocked (instance); + if (!gst_vulkan_instance_fill_info_unlocked (instance, error)) + goto error; + if (priv->requested_api_major) { requested_instance_api = VK_MAKE_VERSION (priv->requested_api_major, priv->requested_api_minor, @@ -370,100 +868,6 @@ gst_vulkan_instance_open (GstVulkanInstance * instance, GError ** error) goto error; } - /* Look for validation layers */ - err = vkEnumerateInstanceLayerProperties (&instance_layer_count, NULL); - if (gst_vulkan_error_to_g_error (err, error, - "vKEnumerateInstanceLayerProperties") < 0) - goto error; - - instance_layers = g_new0 (VkLayerProperties, instance_layer_count); - err = - vkEnumerateInstanceLayerProperties (&instance_layer_count, - instance_layers); - if (gst_vulkan_error_to_g_error (err, error, - "vKEnumerateInstanceLayerProperties") < 0) { - g_free (instance_layers); - goto error; - } - - g_free (instance_layers); - - err = - vkEnumerateInstanceExtensionProperties (NULL, &instance_extension_count, - NULL); - if (gst_vulkan_error_to_g_error (err, error, - "vkEnumerateInstanceExtensionProperties") < 0) { - goto error; - } - GST_DEBUG_OBJECT (instance, "Found %u extensions", instance_extension_count); - - memset (extension_names, 0, sizeof (extension_names)); - instance_extensions = - g_new0 (VkExtensionProperties, instance_extension_count); - err = - vkEnumerateInstanceExtensionProperties (NULL, &instance_extension_count, - instance_extensions); - if (gst_vulkan_error_to_g_error (err, error, - "vkEnumerateInstanceExtensionProperties") < 0) { - g_free (instance_extensions); - goto error; - } - - { - GstVulkanDisplayType display_type; - gboolean swapchain_ext_found = FALSE; - gboolean winsys_ext_found = FALSE; - const gchar *winsys_ext_name; - uint32_t i; - - display_type = gst_vulkan_display_choose_type (instance); - - winsys_ext_name = - gst_vulkan_display_type_to_extension_string (display_type); - if (!winsys_ext_name) { - GST_WARNING_OBJECT (instance, "No window system extension enabled"); - winsys_ext_found = TRUE; /* Don't error out completely */ - } - - /* TODO: allow outside selection */ - for (i = 0; i < instance_extension_count; i++) { - GST_TRACE_OBJECT (instance, "checking instance extension %s", - instance_extensions[i].extensionName); - - if (!g_strcmp0 (VK_KHR_SURFACE_EXTENSION_NAME, - instance_extensions[i].extensionName)) { - swapchain_ext_found = TRUE; - extension_names[enabled_extension_count++] = - (gchar *) VK_KHR_SURFACE_EXTENSION_NAME; - } - if (!g_strcmp0 (VK_EXT_DEBUG_REPORT_EXTENSION_NAME, - instance_extensions[i].extensionName)) { - extension_names[enabled_extension_count++] = - (gchar *) VK_EXT_DEBUG_REPORT_EXTENSION_NAME; - have_debug_extension = TRUE; - } - if (!g_strcmp0 (winsys_ext_name, instance_extensions[i].extensionName)) { - winsys_ext_found = TRUE; - extension_names[enabled_extension_count++] = (gchar *) winsys_ext_name; - } - g_assert (enabled_extension_count < 64); - } - if (!swapchain_ext_found) { - g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED, - "vkEnumerateInstanceExtensionProperties failed to find the required " - "\"" VK_KHR_SURFACE_EXTENSION_NAME "\" extension"); - g_free (instance_extensions); - goto error; - } - if (!winsys_ext_found) { - g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED, - "vkEnumerateInstanceExtensionProperties failed to find the required " - "\"%s\" window system extension", winsys_ext_name); - g_free (instance_extensions); - goto error; - } - } - { VkApplicationInfo app = { 0, }; VkInstanceCreateInfo inst_info = { 0, }; @@ -483,22 +887,19 @@ gst_vulkan_instance_open (GstVulkanInstance * instance, GError ** error) .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pNext = NULL, .pApplicationInfo = &app, - .enabledLayerCount = 0, - .ppEnabledLayerNames = NULL, - .enabledExtensionCount = enabled_extension_count, - .ppEnabledExtensionNames = (const char *const *) extension_names + .enabledLayerCount = priv->enabled_layers->len, + .ppEnabledLayerNames = (const char *const *) priv->enabled_layers->pdata, + .enabledExtensionCount = priv->enabled_extensions->len, + .ppEnabledExtensionNames = (const char *const *) priv->enabled_extensions->pdata, }; /* *INDENT-ON* */ err = vkCreateInstance (&inst_info, NULL, &instance->instance); if (gst_vulkan_error_to_g_error (err, error, "vkCreateInstance") < 0) { - g_free (instance_extensions); goto error; } } - g_free (instance_extensions); - err = vkEnumeratePhysicalDevices (instance->instance, &instance->n_physical_devices, NULL); @@ -515,7 +916,12 @@ gst_vulkan_instance_open (GstVulkanInstance * instance, GError ** error) "vkEnumeratePhysicalDevices") < 0) goto error; - if (have_debug_extension) { +#if !defined (GST_DISABLE_DEBUG) + vulkan_debug_level = gst_debug_category_get_threshold (GST_VULKAN_DEBUG_CAT); + + if (vulkan_debug_level >= GST_LEVEL_ERROR + && gst_vulkan_instance_is_extension_enabled_unlocked (instance, + VK_EXT_DEBUG_REPORT_EXTENSION_NAME, NULL)) { VkDebugReportCallbackCreateInfoEXT info = { 0, }; instance->dbgCreateDebugReportCallback = @@ -561,6 +967,7 @@ gst_vulkan_instance_open (GstVulkanInstance * instance, GError ** error) "vkCreateDebugReportCallback") < 0) goto error; } +#endif priv->opened = TRUE; GST_OBJECT_UNLOCK (instance); diff --git a/gst-libs/gst/vulkan/gstvkinstance.h b/gst-libs/gst/vulkan/gstvkinstance.h index 81c3806c7b..d5d224fed9 100644 --- a/gst-libs/gst/vulkan/gstvkinstance.h +++ b/gst-libs/gst/vulkan/gstvkinstance.h @@ -58,6 +58,9 @@ struct _GstVulkanInstanceClass GST_VULKAN_API GstVulkanInstance * gst_vulkan_instance_new (void); GST_VULKAN_API +gboolean gst_vulkan_instance_fill_info (GstVulkanInstance * instance, + GError ** error); +GST_VULKAN_API gboolean gst_vulkan_instance_open (GstVulkanInstance * instance, GError ** error); @@ -93,6 +96,32 @@ void gst_vulkan_instance_get_version (GstVulkanInstan guint * minor, guint * patch); +GST_VULKAN_API +gboolean gst_vulkan_instance_get_extension_info (GstVulkanInstance * instance, + const gchar * name, + guint32 * spec_version); +GST_VULKAN_API +gboolean gst_vulkan_instance_enable_extension (GstVulkanInstance * instance, + const gchar * name); +GST_VULKAN_API +gboolean gst_vulkan_instance_disable_extension (GstVulkanInstance * instance, + const gchar * name); +GST_VULKAN_API +gboolean gst_vulkan_instance_is_extension_enabled (GstVulkanInstance * instance, + const gchar * name); +GST_VULKAN_API +gboolean gst_vulkan_instance_get_layer_info (GstVulkanInstance * instance, + const gchar * name, + gchar ** description, + guint32 * spec_version, + guint32 * implementation_version); +GST_VULKAN_API +gboolean gst_vulkan_instance_enable_layer (GstVulkanInstance * instance, + const gchar * name); +GST_VULKAN_API +gboolean gst_vulkan_instance_is_layer_enabled (GstVulkanInstance * instance, + const gchar * name); + G_END_DECLS #endif /* __GST_VULKAN_INSTANCE_H__ */ diff --git a/tests/check/libs/vkinstance.c b/tests/check/libs/vkinstance.c index 2d989dc650..b07efc5dc3 100644 --- a/tests/check/libs/vkinstance.c +++ b/tests/check/libs/vkinstance.c @@ -107,6 +107,43 @@ GST_START_TEST (test_instance_request_version) GST_END_TEST; +GST_START_TEST (test_instance_enable_extension) +{ + GstVulkanInstance *instance; + /* test with a very common extension */ + const gchar *test_ext_name = VK_KHR_SURFACE_EXTENSION_NAME; + + instance = gst_vulkan_instance_new (); + fail_unless (instance != NULL); + fail_unless (gst_vulkan_instance_fill_info (instance, NULL)); + + /* only run the test if the extension is available. otherwise, skip. */ + if (gst_vulkan_instance_get_extension_info (instance, test_ext_name, NULL)) { + /* ensure it has been disabled */ + if (gst_vulkan_instance_is_extension_enabled (instance, test_ext_name)) + gst_vulkan_instance_disable_extension (instance, test_ext_name); + + fail_unless (gst_vulkan_instance_enable_extension (instance, + test_ext_name)); + fail_unless (gst_vulkan_instance_is_extension_enabled (instance, + test_ext_name)); + fail_unless (gst_vulkan_instance_disable_extension (instance, + test_ext_name)); + fail_unless (!gst_vulkan_instance_is_extension_enabled (instance, + test_ext_name)); + + fail_unless (gst_vulkan_instance_enable_extension (instance, + test_ext_name)); + fail_unless (gst_vulkan_instance_open (instance, NULL)); + fail_unless (gst_vulkan_instance_is_extension_enabled (instance, + test_ext_name)); + } + + gst_object_unref (instance); +} + +GST_END_TEST; + static Suite * vkinstance_suite (void) { @@ -128,10 +165,10 @@ vkinstance_suite (void) tcase_add_test (tc_basic, test_instance_open); tcase_add_test (tc_basic, test_instance_default_max_version); tcase_add_test (tc_basic, test_instance_request_version); + tcase_add_test (tc_basic, test_instance_enable_extension); } return s; } - GST_CHECK_MAIN (vkinstance);