vulkan/device: expose extension/layer choices

Extensions and layers can be enabled before calling
gst_vulkan_device_open().  The available extensions are stored in
GstVulkanPhysicalDevice.

Defaults are still the same.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1341>
This commit is contained in:
Matthew Waters 2020-06-15 01:26:08 +10:00 committed by GStreamer Merge Bot
parent ceb5ac0e4f
commit 09613696a6
5 changed files with 418 additions and 52 deletions

View file

@ -54,6 +54,9 @@ static void gst_vulkan_device_finalize (GObject * object);
struct _GstVulkanDevicePrivate
{
GPtrArray *enabled_layers;
GPtrArray *enabled_extensions;
gboolean opened;
guint queue_family_id;
guint n_queues;
@ -163,6 +166,10 @@ gst_vulkan_device_get_property (GObject * object, guint prop_id,
static void
gst_vulkan_device_init (GstVulkanDevice * device)
{
GstVulkanDevicePrivate *priv = GET_PRIV (device);
priv->enabled_layers = g_ptr_array_new_with_free_func (g_free);
priv->enabled_extensions = g_ptr_array_new_with_free_func (g_free);
}
static void
@ -172,6 +179,10 @@ gst_vulkan_device_constructed (GObject * object)
g_object_get (device->physical_device, "instance", &device->instance, NULL);
/* by default allow vkswapper to work for rendering to an output window.
* Ignore the failure if the extension does not exist. */
gst_vulkan_device_enable_extension (device, VK_KHR_SWAPCHAIN_EXTENSION_NAME);
G_OBJECT_CLASS (parent_class)->constructed (object);
}
@ -219,6 +230,7 @@ static void
gst_vulkan_device_finalize (GObject * object)
{
GstVulkanDevice *device = GST_VULKAN_DEVICE (object);
GstVulkanDevicePrivate *priv = GET_PRIV (device);
if (device->device) {
vkDeviceWaitIdle (device->device);
@ -229,6 +241,12 @@ gst_vulkan_device_finalize (GObject * object)
gst_clear_object (&device->physical_device);
gst_clear_object (&device->instance);
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);
}
@ -247,9 +265,6 @@ gboolean
gst_vulkan_device_open (GstVulkanDevice * device, GError ** error)
{
GstVulkanDevicePrivate *priv = GET_PRIV (device);
const char *extension_names[64];
uint32_t enabled_extension_count = 0;
gboolean have_swapchain_ext;
VkPhysicalDevice gpu;
VkResult err;
guint i;
@ -265,29 +280,6 @@ gst_vulkan_device_open (GstVulkanDevice * device, GError ** error)
gpu = gst_vulkan_device_get_physical_device (device);
have_swapchain_ext = 0;
enabled_extension_count = 0;
memset (extension_names, 0, sizeof (extension_names));
for (i = 0; i < device->physical_device->n_device_extensions; i++) {
GST_TRACE_OBJECT (device, "checking device extension %s",
device->physical_device->device_extensions[i].extensionName);
if (!strcmp (VK_KHR_SWAPCHAIN_EXTENSION_NAME,
device->physical_device->device_extensions[i].extensionName)) {
have_swapchain_ext = TRUE;
extension_names[enabled_extension_count++] =
(gchar *) VK_KHR_SWAPCHAIN_EXTENSION_NAME;
}
g_assert (enabled_extension_count < 64);
}
if (!have_swapchain_ext) {
g_set_error_literal (error, GST_VULKAN_ERROR,
VK_ERROR_EXTENSION_NOT_PRESENT,
"Failed to find required extension, \"" VK_KHR_SWAPCHAIN_EXTENSION_NAME
"\"");
goto error;
}
/* FIXME: allow overriding/selecting */
for (i = 0; i < device->physical_device->n_queue_families; i++) {
if (device->physical_device->
@ -317,10 +309,12 @@ gst_vulkan_device_open (GstVulkanDevice * device, GError ** error)
device_info.pNext = NULL;
device_info.queueCreateInfoCount = 1;
device_info.pQueueCreateInfos = &queue_info;
device_info.enabledLayerCount = 0;
device_info.ppEnabledLayerNames = NULL;
device_info.enabledExtensionCount = enabled_extension_count;
device_info.ppEnabledExtensionNames = (const char *const *) extension_names;
device_info.enabledLayerCount = priv->enabled_layers->len;
device_info.ppEnabledLayerNames =
(const char *const *) priv->enabled_layers->pdata;
device_info.enabledExtensionCount = priv->enabled_extensions->len;
device_info.ppEnabledExtensionNames =
(const char *const *) priv->enabled_extensions->pdata;
device_info.pEnabledFeatures = NULL;
err = vkCreateDevice (gpu, &device_info, NULL, &device->device);
@ -629,3 +623,221 @@ gst_vulkan_device_create_fence (GstVulkanDevice * device, GError ** error)
return gst_vulkan_fence_cache_acquire (priv->fence_cache, error);
}
/* 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_device_is_extension_enabled_unlocked (GstVulkanDevice * device,
const gchar * name, guint * index)
{
GstVulkanDevicePrivate *priv = GET_PRIV (device);
return ptr_array_find_string (priv->enabled_extensions, name, index);
}
/**
* gst_vulkan_device_is_extension_enabled:
* @device: a # GstVulkanDevice
* @name: extension name
*
* Returns: whether extension @name is enabled
*/
gboolean
gst_vulkan_device_is_extension_enabled (GstVulkanDevice * device,
const gchar * name)
{
gboolean ret;
g_return_val_if_fail (GST_IS_VULKAN_DEVICE (device), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
GST_OBJECT_LOCK (device);
ret = gst_vulkan_device_is_extension_enabled_unlocked (device, name, NULL);
GST_OBJECT_UNLOCK (device);
return ret;
}
static gboolean
gst_vulkan_device_enable_extension_unlocked (GstVulkanDevice * device,
const gchar * name)
{
GstVulkanDevicePrivate *priv = GET_PRIV (device);
if (gst_vulkan_device_is_extension_enabled_unlocked (device, name, NULL))
/* extension is already enabled */
return TRUE;
if (!gst_vulkan_physical_device_get_extension_info (device->physical_device,
name, NULL))
return FALSE;
g_ptr_array_add (priv->enabled_extensions, g_strdup (name));
return TRUE;
}
/**
* gst_vulkan_device_enable_extension:
* @device: a #GstVulkanDevice
* @name: extension name to enable
*
* Enable an Vulkan extension by @name. Enabling an extension will
* only have an effect before the call to gst_vulkan_device_open().
*
* Returns: whether the Vulkan extension could be enabled.
*/
gboolean
gst_vulkan_device_enable_extension (GstVulkanDevice * device,
const gchar * name)
{
gboolean ret;
g_return_val_if_fail (GST_IS_VULKAN_DEVICE (device), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
GST_OBJECT_LOCK (device);
ret = gst_vulkan_device_enable_extension_unlocked (device, name);
GST_OBJECT_UNLOCK (device);
return ret;
}
static gboolean
gst_vulkan_device_disable_extension_unlocked (GstVulkanDevice * device,
const gchar * name)
{
GstVulkanDevicePrivate *priv = GET_PRIV (device);
guint i;
if (!gst_vulkan_physical_device_get_extension_info (device->physical_device,
name, NULL))
return FALSE;
if (!gst_vulkan_device_is_extension_enabled_unlocked (device, name, &i))
/* extension is already disabled */
return TRUE;
g_ptr_array_remove_index_fast (priv->enabled_extensions, i);
return TRUE;
}
/**
* gst_vulkan_device_disable_extension:
* @device: a #GstVulkanDevice
* @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_device_open().
*
* Returns: whether the Vulkan extension could be disabled.
*/
gboolean
gst_vulkan_device_disable_extension (GstVulkanDevice * device,
const gchar * name)
{
gboolean ret;
g_return_val_if_fail (GST_IS_VULKAN_DEVICE (device), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
GST_OBJECT_LOCK (device);
ret = gst_vulkan_device_disable_extension_unlocked (device, name);
GST_OBJECT_UNLOCK (device);
return ret;
}
static gboolean
gst_vulkan_device_is_layer_enabled_unlocked (GstVulkanDevice * device,
const gchar * name)
{
GstVulkanDevicePrivate *priv = GET_PRIV (device);
return ptr_array_find_string (priv->enabled_layers, name, NULL);
}
/**
* gst_vulkan_device_is_layer_enabled:
* @device: a # GstVulkanDevice
* @name: layer name
*
* Returns: whether layer @name is enabled
*/
gboolean
gst_vulkan_device_is_layer_enabled (GstVulkanDevice * device,
const gchar * name)
{
gboolean ret;
g_return_val_if_fail (GST_IS_VULKAN_DEVICE (device), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
GST_OBJECT_LOCK (device);
ret = gst_vulkan_device_is_layer_enabled_unlocked (device, name);
GST_OBJECT_UNLOCK (device);
return ret;
}
static gboolean
gst_vulkan_device_enable_layer_unlocked (GstVulkanDevice * device,
const gchar * name)
{
GstVulkanDevicePrivate *priv = GET_PRIV (device);
if (gst_vulkan_device_is_layer_enabled_unlocked (device, name))
/* layer is already enabled */
return TRUE;
if (!gst_vulkan_physical_device_get_layer_info (device->physical_device,
name, NULL, NULL, NULL))
return FALSE;
g_ptr_array_add (priv->enabled_layers, g_strdup (name));
return TRUE;
}
/**
* gst_vulkan_device_enable_layer:
* @device: a #GstVulkanDevice
* @name: layer name to enable
*
* Enable an Vulkan layer by @name. Enabling a layer will
* only have an effect before the call to gst_vulkan_device_open().
*
* Returns: whether the Vulkan layer could be enabled.
*/
gboolean
gst_vulkan_device_enable_layer (GstVulkanDevice * device, const gchar * name)
{
gboolean ret;
g_return_val_if_fail (GST_IS_VULKAN_DEVICE (device), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
GST_OBJECT_LOCK (device);
ret = gst_vulkan_device_enable_layer_unlocked (device, name);
GST_OBJECT_UNLOCK (device);
return ret;
}

View file

@ -63,6 +63,22 @@ GST_VULKAN_API
gboolean gst_vulkan_device_open (GstVulkanDevice * device,
GError ** error);
GST_VULKAN_API
gboolean gst_vulkan_device_enable_extension (GstVulkanDevice * device,
const gchar * name);
GST_VULKAN_API
gboolean gst_vulkan_device_disable_extension (GstVulkanDevice * device,
const gchar * name);
GST_VULKAN_API
gboolean gst_vulkan_device_is_extension_enabled (GstVulkanDevice * device,
const gchar * name);
GST_VULKAN_API
gboolean gst_vulkan_device_enable_layer (GstVulkanDevice * device,
const gchar * name);
GST_VULKAN_API
gboolean gst_vulkan_device_is_layer_enabled (GstVulkanDevice * device,
const gchar * name);
GST_VULKAN_API
gpointer gst_vulkan_device_get_proc_address (GstVulkanDevice * device,
const gchar * name);

View file

@ -52,7 +52,12 @@ static void gst_vulkan_physical_device_finalize (GObject * object);
struct _GstVulkanPhysicalDevicePrivate
{
guint dummy;
guint32 n_available_layers;
VkLayerProperties *available_layers;
guint32 n_available_extensions;
VkExtensionProperties *available_extensions;
#if defined (VK_API_VERSION_1_2)
VkPhysicalDeviceFeatures2 features10;
VkPhysicalDeviceProperties2 properties10;
@ -162,6 +167,9 @@ gst_vulkan_physical_device_init (GstVulkanPhysicalDevice * device)
{
GstVulkanPhysicalDevicePrivate *priv = GET_PRIV (device);
priv->n_available_layers = 0;
priv->n_available_extensions = 0;
#if defined (VK_API_VERSION_1_2)
priv->properties10.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
priv->properties11.sType =
@ -231,12 +239,13 @@ static void
gst_vulkan_physical_device_finalize (GObject * object)
{
GstVulkanPhysicalDevice *device = GST_VULKAN_PHYSICAL_DEVICE (object);
GstVulkanPhysicalDevicePrivate *priv = GET_PRIV (device);
g_free (device->device_layers);
device->device_layers = NULL;
g_free (priv->available_layers);
priv->available_layers = NULL;
g_free (device->device_extensions);
device->device_extensions = NULL;
g_free (priv->available_extensions);
priv->available_extensions = NULL;
g_free (device->queue_family_props);
device->queue_family_props = NULL;
@ -803,15 +812,15 @@ gst_vulkan_physical_device_fill_info (GstVulkanPhysicalDevice * device,
err =
vkEnumerateDeviceLayerProperties (device->device,
&device->n_device_layers, NULL);
&priv->n_available_layers, NULL);
if (gst_vulkan_error_to_g_error (err, error,
"vkEnumerateDeviceLayerProperties") < 0)
goto error;
device->device_layers = g_new0 (VkLayerProperties, device->n_device_layers);
priv->available_layers = g_new0 (VkLayerProperties, priv->n_available_layers);
err =
vkEnumerateDeviceLayerProperties (device->device,
&device->n_device_layers, device->device_layers);
&priv->n_available_layers, priv->available_layers);
if (gst_vulkan_error_to_g_error (err, error,
"vkEnumerateDeviceLayerProperties") < 0) {
goto error;
@ -819,18 +828,19 @@ gst_vulkan_physical_device_fill_info (GstVulkanPhysicalDevice * device,
err =
vkEnumerateDeviceExtensionProperties (device->device, NULL,
&device->n_device_extensions, NULL);
&priv->n_available_extensions, NULL);
if (gst_vulkan_error_to_g_error (err, error,
"vkEnumerateDeviceExtensionProperties") < 0) {
goto error;
}
GST_DEBUG_OBJECT (device, "Found %u extensions", device->n_device_extensions);
GST_DEBUG_OBJECT (device, "Found %u extensions",
priv->n_available_extensions);
device->device_extensions =
g_new0 (VkExtensionProperties, device->n_device_extensions);
priv->available_extensions =
g_new0 (VkExtensionProperties, priv->n_available_extensions);
err =
vkEnumerateDeviceExtensionProperties (device->device, NULL,
&device->n_device_extensions, device->device_extensions);
&priv->n_available_extensions, priv->available_extensions);
if (gst_vulkan_error_to_g_error (err, error,
"vkEnumerateDeviceExtensionProperties") < 0) {
goto error;
@ -951,3 +961,117 @@ gst_vulkan_physical_device_get_instance (GstVulkanPhysicalDevice * device)
return device->instance ? gst_object_ref (device->instance) : NULL;
}
static gboolean
gst_vulkan_physical_device_get_layer_info_unlocked (GstVulkanPhysicalDevice *
device, const gchar * name, gchar ** description, guint32 * spec_version,
guint32 * implementation_version)
{
GstVulkanPhysicalDevicePrivate *priv;
int i;
priv = GET_PRIV (device);
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_physical_device_get_layer_info:
* @device: a #GstVulkanPhysicalDevice
* @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_physical_device_get_layer_info (GstVulkanPhysicalDevice * device,
const gchar * name, gchar ** description, guint32 * spec_version,
guint32 * implementation_version)
{
gboolean ret;
g_return_val_if_fail (GST_IS_VULKAN_PHYSICAL_DEVICE (device), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
GST_OBJECT_LOCK (device);
ret =
gst_vulkan_physical_device_get_layer_info_unlocked (device, name,
description, spec_version, implementation_version);
GST_OBJECT_UNLOCK (device);
return ret;
}
static gboolean
gst_vulkan_physical_device_get_extension_info_unlocked (GstVulkanPhysicalDevice
* device, const gchar * name, guint32 * spec_version)
{
GstVulkanPhysicalDevicePrivate *priv;
int i;
priv = GET_PRIV (device);
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_physical_device_get_extension_info:
* @device: a #GstVulkanPhysicalDevice
* @name: the extension name to look for
* @spec_version: (out) (nullable): return value for the exteion specification version
*
* Retrieves information about a device 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_physical_device_get_extension_info (GstVulkanPhysicalDevice * device,
const gchar * name, guint32 * spec_version)
{
gboolean ret;
g_return_val_if_fail (GST_IS_VULKAN_PHYSICAL_DEVICE (device), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
GST_OBJECT_LOCK (device);
ret =
gst_vulkan_physical_device_get_extension_info_unlocked (device, name,
spec_version);
GST_OBJECT_UNLOCK (device);
return ret;
}

View file

@ -44,12 +44,6 @@ struct _GstVulkanPhysicalDevice
guint device_index;
VkPhysicalDevice device; /* hides a pointer */
VkLayerProperties *device_layers;
guint32 n_device_layers;
VkExtensionProperties *device_extensions;
guint32 n_device_extensions;
VkPhysicalDeviceProperties properties;
VkPhysicalDeviceFeatures features;
VkPhysicalDeviceMemoryProperties memory_properties;
@ -64,12 +58,25 @@ struct _GstVulkanPhysicalDeviceClass
};
GST_VULKAN_API
GstVulkanPhysicalDevice * gst_vulkan_physical_device_new (GstVulkanInstance * instance, guint device_index);
GstVulkanPhysicalDevice * gst_vulkan_physical_device_new (GstVulkanInstance * instance,
guint device_index);
GST_VULKAN_API
GstVulkanInstance * gst_vulkan_physical_device_get_instance (GstVulkanPhysicalDevice * device);
GstVulkanInstance * gst_vulkan_physical_device_get_instance (GstVulkanPhysicalDevice * device);
GST_VULKAN_API
VkPhysicalDevice gst_vulkan_physical_device_get_handle (GstVulkanPhysicalDevice * device);
VkPhysicalDevice gst_vulkan_physical_device_get_handle (GstVulkanPhysicalDevice * device);
GST_VULKAN_API
gboolean gst_vulkan_physical_device_get_extension_info (GstVulkanPhysicalDevice * device,
const gchar * name,
guint32 * spec_version);
GST_VULKAN_API
gboolean gst_vulkan_physical_device_get_layer_info (GstVulkanPhysicalDevice * device,
const gchar * name,
gchar ** description,
guint32 * spec_version,
guint32 * implementation_version);
G_END_DECLS

View file

@ -132,6 +132,13 @@ _get_function_table (GstVulkanSwapper * swapper)
GST_ERROR_OBJECT (swapper, "Failed to get instance from the device");
return FALSE;
}
if (!gst_vulkan_device_is_extension_enabled (device,
VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
GST_ERROR_OBJECT (swapper, "Required extension \'%s\' is not enabled on "
"device %" GST_PTR_FORMAT, VK_KHR_SWAPCHAIN_EXTENSION_NAME, device);
return FALSE;
}
#define GET_PROC_ADDRESS_REQUIRED(type, name) \
G_STMT_START { \
priv->G_PASTE (, name) = G_PASTE(G_PASTE(gst_vulkan_, type), _get_proc_address) (type, "vk" G_STRINGIFY(name)); \