From 2af2402880bf75977a2e7313483d68d1d1a76dcc Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 16 Sep 2019 15:29:26 +1000 Subject: [PATCH] vulkan: add device provider implementation --- ext/vulkan/gstvulkan.c | 5 + ext/vulkan/meson.build | 1 + ext/vulkan/vkdeviceprovider.c | 519 ++++++++++++++++++++++++++++++ ext/vulkan/vkdeviceprovider.h | 90 ++++++ gst-libs/gst/vulkan/gstvkphysicaldevice.c | 3 +- tests/check/elements/vkdeviceprovider.c | 120 +++++++ tests/check/meson.build | 1 + 7 files changed, 738 insertions(+), 1 deletion(-) create mode 100644 ext/vulkan/vkdeviceprovider.c create mode 100644 ext/vulkan/vkdeviceprovider.h create mode 100644 tests/check/elements/vkdeviceprovider.c diff --git a/ext/vulkan/gstvulkan.c b/ext/vulkan/gstvulkan.c index c7441e2..d989d9f 100644 --- a/ext/vulkan/gstvulkan.c +++ b/ext/vulkan/gstvulkan.c @@ -35,6 +35,7 @@ #include "vkcolorconvert.h" #include "vkdownload.h" #include "vkviewconvert.h" +#include "vkdeviceprovider.h" #define GST_CAT_DEFAULT gst_vulkan_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); @@ -74,6 +75,10 @@ plugin_init (GstPlugin * plugin) return FALSE; } + if (!gst_device_provider_register (plugin, "vulkandeviceprovider", + GST_RANK_MARGINAL, GST_TYPE_VULKAN_DEVICE_PROVIDER)) + return FALSE; + return TRUE; } diff --git a/ext/vulkan/meson.build b/ext/vulkan/meson.build index 34276a3..8659cc2 100644 --- a/ext/vulkan/meson.build +++ b/ext/vulkan/meson.build @@ -12,6 +12,7 @@ vulkan_sources = [ 'gstvulkan.c', 'vkcolorconvert.c', 'vkdownload.c', + 'vkdeviceprovider.c', 'vkfullscreenrender.c', 'vkimageidentity.c', 'vksink.c', diff --git a/ext/vulkan/vkdeviceprovider.c b/ext/vulkan/vkdeviceprovider.c new file mode 100644 index 0000000..7432e08 --- /dev/null +++ b/ext/vulkan/vkdeviceprovider.c @@ -0,0 +1,519 @@ +/* GStreamer + * Copyright (C) 2019 Matthew Waters + * + * vkdeviceprovider.c: vulkan device probing and monitoring + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "vkdeviceprovider.h" + +#include + +#include + +GST_DEBUG_CATEGORY_STATIC (vulkan_device_debug); +#define GST_CAT_DEFAULT vulkan_device_debug + + +static GstDevice *gst_vulkan_device_object_new (GstVulkanPhysicalDevice * + device, GstCaps * caps, GstVulkanDeviceType type, GstStructure * properties, + gboolean is_default); + +G_DEFINE_TYPE_WITH_CODE (GstVulkanDeviceProvider, gst_vulkan_device_provider, + GST_TYPE_DEVICE_PROVIDER, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, + "vulkandevice", 0, "Vulkan Device");); + +static void gst_vulkan_device_provider_finalize (GObject * object); +static void gst_vulkan_device_provider_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_vulkan_device_provider_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); + +static GList *gst_vulkan_device_provider_probe (GstDeviceProvider * provider); + +enum +{ + PROP_PROVIDER_0, + PROP_PROVIDER_LAST, +}; + +static void +gst_vulkan_device_provider_class_init (GstVulkanDeviceProviderClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass); + + gobject_class->set_property = gst_vulkan_device_provider_set_property; + gobject_class->get_property = gst_vulkan_device_provider_get_property; + gobject_class->finalize = gst_vulkan_device_provider_finalize; + + dm_class->probe = gst_vulkan_device_provider_probe; + + gst_device_provider_class_set_static_metadata (dm_class, + "Vulkan Device Provider", "Sink/Video", + "List and provider Vulkan sink devices", + "Matthew Waters "); +} + +static void +gst_vulkan_device_provider_init (GstVulkanDeviceProvider * self) +{ +} + +static void +gst_vulkan_device_provider_finalize (GObject * object) +{ + G_OBJECT_CLASS (gst_vulkan_device_provider_parent_class)->finalize (object); +} + +static void +gst_vulkan_device_provider_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vulkan_device_provider_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +fill_properties (GstVulkanPhysicalDevice * device, GstStructure * s) +{ + gst_structure_set (s, "vulkan.name", G_TYPE_STRING, + device->properties.deviceName, NULL); + gst_structure_set (s, "vulkan.type", G_TYPE_STRING, + gst_vulkan_physical_device_type_to_string (device->properties.deviceType), + NULL); + + { + int maj = VK_VERSION_MAJOR (device->properties.apiVersion); + int min = VK_VERSION_MINOR (device->properties.apiVersion); + int patch = VK_VERSION_PATCH (device->properties.apiVersion); + gchar *api_str = g_strdup_printf ("%i.%i.%i", maj, min, patch); + gst_structure_set (s, "vulkan.api.version", G_TYPE_STRING, api_str, + "vulkan.api.version.major", G_TYPE_UINT, maj, + "vulkan.api.version.minor", G_TYPE_UINT, min, + "vulkan.api.version.patch", G_TYPE_UINT, patch, NULL); + g_free (api_str); + } + + { + int maj = VK_VERSION_MAJOR (device->properties.driverVersion); + int min = VK_VERSION_MINOR (device->properties.driverVersion); + int patch = VK_VERSION_PATCH (device->properties.driverVersion); + gchar *api_str = g_strdup_printf ("%i.%i.%i", maj, min, patch); + gst_structure_set (s, "vulkan.driver.version", G_TYPE_STRING, api_str, + "vulkan.driver.version.major", G_TYPE_UINT, maj, + "vulkan.driver.version.minor", G_TYPE_UINT, min, + "vulkan.driver.version.patch", G_TYPE_UINT, patch, NULL); + g_free (api_str); + } + + gst_structure_set (s, "vulkan.vendor.id", G_TYPE_UINT, + device->properties.vendorID, NULL); + gst_structure_set (s, "vulkan.device.id", G_TYPE_UINT, + device->properties.deviceID, NULL); + + /* memory properties */ + { + int i; + + gst_structure_set (s, "vulkan.memory.n_heaps", G_TYPE_UINT, + (guint) device->memory_properties.memoryHeapCount, NULL); + for (i = 0; i < device->memory_properties.memoryHeapCount; i++) { + gchar *prop_flags_str = + gst_vulkan_memory_heap_flags_to_string (device-> + memory_properties.memoryHeaps[i].flags); + gchar *prop_id; + + prop_id = g_strdup_printf ("vulkan.memory.heaps.%i.size", i); + gst_structure_set (s, prop_id, G_TYPE_UINT64, + (guint64) device->memory_properties.memoryHeaps[i].size, NULL); + g_free (prop_id); + + prop_id = g_strdup_printf ("vulkan.memory.heaps.%i.flags", i); + gst_structure_set (s, prop_id, G_TYPE_UINT, + (guint) device->memory_properties.memoryHeaps[i].flags, NULL); + g_free (prop_id); + + prop_id = g_strdup_printf ("vulkan.memory.heaps.%i.flags.str", i); + gst_structure_set (s, prop_id, G_TYPE_STRING, prop_flags_str, NULL); + g_free (prop_id); + + g_free (prop_flags_str); + } + + gst_structure_set (s, "vulkan.memory.n_types", G_TYPE_UINT, + (guint) device->memory_properties.memoryTypeCount, NULL); + for (i = 0; i < device->memory_properties.memoryTypeCount; i++) { + gchar *prop_flags_str = + gst_vulkan_memory_property_flags_to_string (device->memory_properties. + memoryTypes[i].propertyFlags); + gchar *prop_id; + + prop_id = g_strdup_printf ("vulkan.memory.types.%i.heap", i); + gst_structure_set (s, prop_id, G_TYPE_UINT, + (guint) device->memory_properties.memoryTypes[i].heapIndex, NULL); + g_free (prop_id); + + prop_id = g_strdup_printf ("vulkan.memory.types.%i.flags", i); + gst_structure_set (s, prop_id, G_TYPE_UINT, + (guint) device->memory_properties.memoryTypes[i].propertyFlags, NULL); + g_free (prop_id); + + prop_id = g_strdup_printf ("vulkan.memory.types.%i.flags.str", i); + gst_structure_set (s, prop_id, G_TYPE_STRING, prop_flags_str, NULL); + g_free (prop_id); + + g_free (prop_flags_str); + } + + gst_structure_set (s, "vulkan.n_queue_families", G_TYPE_UINT, + device->n_queue_families, NULL); + for (i = 0; i < device->n_queue_families; i++) { + gchar *queue_flags_str = + gst_vulkan_queue_flags_to_string (device-> + queue_family_props[i].queueFlags); + gchar *prop_id; + + prop_id = g_strdup_printf ("vulkan.queue_family.%i.n_queues", i); + gst_structure_set (s, prop_id, G_TYPE_UINT, + (guint) device->queue_family_props[i].queueCount, NULL); + g_free (prop_id); + + prop_id = g_strdup_printf ("vulkan.queue_family.%i.flags", i); + gst_structure_set (s, prop_id, G_TYPE_UINT, + (guint) device->queue_family_props[i].queueFlags, NULL); + g_free (prop_id); + + prop_id = g_strdup_printf ("vulkan.queue_family.%i.flags.str", i); + gst_structure_set (s, prop_id, G_TYPE_STRING, queue_flags_str, NULL); + g_free (prop_id); + + prop_id = + g_strdup_printf ("vulkan.queue_family.%i.timestamp_resolution", i); + gst_structure_set (s, prop_id, G_TYPE_UINT, + (guint) device->queue_family_props[i].timestampValidBits, NULL); + g_free (prop_id); + + prop_id = + g_strdup_printf + ("vulkan.queue_family.%i.min_image_transfer_granuality.width", i); + gst_structure_set (s, prop_id, G_TYPE_UINT, + (guint) device->queue_family_props[i]. + minImageTransferGranularity.width, NULL); + g_free (prop_id); + + prop_id = + g_strdup_printf + ("vulkan.queue_family.%i.min_image_transfer_granuality.height", i); + gst_structure_set (s, prop_id, G_TYPE_UINT, + (guint) device->queue_family_props[i]. + minImageTransferGranularity.height, NULL); + g_free (prop_id); + + prop_id = + g_strdup_printf + ("vulkan.queue_family.%i.min_image_transfer_granuality.depth", i); + gst_structure_set (s, prop_id, G_TYPE_UINT, + (guint) device->queue_family_props[i]. + minImageTransferGranularity.depth, NULL); + g_free (prop_id); + + g_free (queue_flags_str); + } + } +} + +static GList * +gst_vulkan_device_provider_probe (GstDeviceProvider * provider) +{ + GstVulkanInstance *instance; + GError *error = NULL; + GList *ret = NULL; + guint i; + + instance = gst_vulkan_instance_new (); + if (!gst_vulkan_instance_open (instance, &error)) + goto failed; + + for (i = 0; i < instance->n_physical_devices; i++) { + GstVulkanPhysicalDevice *device; + gboolean is_default = i == 0; + GstStructure *props; + GstCaps *caps; + + device = gst_vulkan_physical_device_new (instance, i); + + props = gst_structure_new_empty ("properties"); + fill_properties (device, props); + caps = gst_caps_from_string ("video/x-raw(memory:VulkanImage)"); + ret = g_list_prepend (ret, gst_vulkan_device_object_new (device, caps, + GST_VULKAN_DEVICE_TYPE_SINK, props, is_default)); + gst_caps_unref (caps); + gst_structure_free (props); + } + + /* TODO: device groups? */ + + gst_object_unref (instance); + return ret; + +failed: + if (error) { + GST_WARNING_OBJECT (provider, "%s", error->message); + g_clear_error (&error); + } + if (instance) + gst_object_unref (instance); + + return NULL; +} + +enum +{ + PROP_0, + PROP_PHYSICAL_DEVICE, +}; + +G_DEFINE_TYPE (GstVulkanDeviceObject, gst_vulkan_device_object, + GST_TYPE_DEVICE); + +static void gst_vulkan_device_object_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); +static void gst_vulkan_device_object_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_vulkan_device_object_finalize (GObject * object); +static GstElement *gst_vulkan_device_object_create_element (GstDevice * device, + const gchar * name); +static gboolean gst_vulkan_device_object_reconfigure_element (GstDevice * + device, GstElement * element); + +static void +gst_vulkan_device_object_class_init (GstVulkanDeviceObjectClass * klass) +{ + GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + dev_class->create_element = gst_vulkan_device_object_create_element; + dev_class->reconfigure_element = gst_vulkan_device_object_reconfigure_element; + + object_class->get_property = gst_vulkan_device_object_get_property; + object_class->set_property = gst_vulkan_device_object_set_property; + object_class->finalize = gst_vulkan_device_object_finalize; + + g_object_class_install_property (object_class, PROP_PHYSICAL_DEVICE, + g_param_spec_object ("physical-device", "Physical Device", + "Associated Vulkan Physical Device", GST_TYPE_VULKAN_PHYSICAL_DEVICE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); +} + +static void +gst_vulkan_device_object_init (GstVulkanDeviceObject * device) +{ +} + +static void +gst_vulkan_device_object_finalize (GObject * object) +{ + GstVulkanDeviceObject *device = GST_VULKAN_DEVICE_OBJECT (object); + + gst_clear_object (&device->physical_device); + + G_OBJECT_CLASS (gst_vulkan_device_object_parent_class)->finalize (object); +} + +static gpointer +_ref_if_set (gpointer data, gpointer user_data) +{ + if (data) { + return g_weak_ref_get (data); + } + return NULL; +} + +static void +_ref_free (GWeakRef * ref) +{ + g_weak_ref_clear (ref); + g_free (ref); +} + +static GstPadProbeReturn +device_context_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) +{ + GstVulkanPhysicalDevice *physical = GST_VULKAN_PHYSICAL_DEVICE (user_data); + GstElement *element = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (pad))); + GstPadProbeReturn ret = GST_PAD_PROBE_OK; + + if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_QUERY_BOTH) { + GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info); + + if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT) { + const char *context_type = NULL; + + gst_query_parse_context_type (query, &context_type); + + if (gst_vulkan_instance_handle_context_query (element, query, + physical->instance)) { + ret = GST_PAD_PROBE_HANDLED; + goto out; + } + + if (g_strcmp0 (context_type, GST_VULKAN_DEVICE_CONTEXT_TYPE_STR) == 0) { + GstVulkanDevice *device = NULL; + + GST_OBJECT_LOCK (physical); + device = g_object_dup_data (G_OBJECT (physical), + "vkdeviceprovider.physical.device", (GDuplicateFunc) _ref_if_set, + NULL); + if (!device || !GST_IS_VULKAN_DEVICE (device)) { + GWeakRef *ref = g_new0 (GWeakRef, 1); + if (device) + gst_object_unref (device); + device = gst_vulkan_device_new (physical); + g_weak_ref_init (ref, device); + g_object_set_data_full (G_OBJECT (physical), + "vkdeviceprovider.physical.device", ref, + (GDestroyNotify) _ref_free); + } + GST_OBJECT_UNLOCK (physical); + + if (gst_vulkan_device_handle_context_query (element, query, device)) { + ret = GST_PAD_PROBE_HANDLED; + gst_object_unref (device); + goto out; + } + gst_object_unref (device); + } + } + } + +out: + gst_object_unref (element); + return ret; +} + +static GstElement * +gst_vulkan_device_object_create_element (GstDevice * device, const gchar * name) +{ + GstVulkanDeviceObject *vulkan_device = GST_VULKAN_DEVICE_OBJECT (device); + GstElement *elem; + GstPad *pad; + + elem = gst_element_factory_make (vulkan_device->element, name); + pad = gst_element_get_static_pad (elem, "sink"); + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_QUERY_BOTH, + (GstPadProbeCallback) device_context_probe, + gst_object_ref (vulkan_device->physical_device), + (GDestroyNotify) gst_object_unref); + gst_object_unref (pad); + + return elem; +} + +static gboolean +gst_vulkan_device_object_reconfigure_element (GstDevice * device, + GstElement * element) +{ + return FALSE; +} + +/* Takes ownership of @caps and @props */ +static GstDevice * +gst_vulkan_device_object_new (GstVulkanPhysicalDevice * device, GstCaps * caps, + GstVulkanDeviceType type, GstStructure * props, gboolean is_default) +{ + GstVulkanDeviceObject *gstdev; + const gchar *element = NULL; + const gchar *klass = NULL; + gchar *device_name = NULL; + + g_return_val_if_fail (GST_IS_VULKAN_PHYSICAL_DEVICE (device), NULL); + g_return_val_if_fail (caps, NULL); + g_return_val_if_fail (props, NULL); + + switch (type) { + case GST_VULKAN_DEVICE_TYPE_SINK: + element = "vulkansink"; + klass = "Video/Sink"; + break; + default: + g_assert_not_reached (); + break; + } + + g_object_get (device, "name", &device_name, NULL); + + gst_structure_set (props, "is-default", G_TYPE_BOOLEAN, is_default, NULL); + gstdev = + g_object_new (GST_TYPE_VULKAN_DEVICE_OBJECT, "display-name", device_name, + "caps", caps, "device-class", klass, "properties", props, NULL); + + gstdev->physical_device = device; + gstdev->type = type; + g_object_get (device, "device-index", &gstdev->device_index, NULL); + gstdev->element = element; + gstdev->is_default = is_default; + + g_free (device_name); + + return GST_DEVICE (gstdev); +} + +static void +gst_vulkan_device_object_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVulkanDeviceObject *vulkan_device = GST_VULKAN_DEVICE_OBJECT (object); + + switch (prop_id) { + case PROP_PHYSICAL_DEVICE: + g_value_set_object (value, vulkan_device->physical_device); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_vulkan_device_object_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/ext/vulkan/vkdeviceprovider.h b/ext/vulkan/vkdeviceprovider.h new file mode 100644 index 0000000..5ee4007 --- /dev/null +++ b/ext/vulkan/vkdeviceprovider.h @@ -0,0 +1,90 @@ +/* GStreamer + * Copyright (C) 2019 Matthew Waters + * + * vkdeviceprovider.h: Device probing and monitoring + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_VULKAN_DEVICE_PROVIDER_H__ +#define __GST_VULKAN_DEVICE_PROVIDER_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include + +G_BEGIN_DECLS + +typedef struct _GstVulkanDeviceProvider GstVulkanDeviceProvider; +typedef struct _GstVulkanDeviceProviderClass GstVulkanDeviceProviderClass; + +#define GST_TYPE_VULKAN_DEVICE_PROVIDER (gst_vulkan_device_provider_get_type()) +#define GST_IS_VULKAN_DEVICE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VULKAN_DEVICE_PROVIDER)) +#define GST_IS_VULKAN_DEVICE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VULKAN_DEVICE_PROVIDER)) +#define GST_VULKAN_DEVICE_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VULKAN_DEVICE_PROVIDER, GstVulkanDeviceProviderClass)) +#define GST_VULKAN_DEVICE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VULKAN_DEVICE_PROVIDER, GstVulkanDeviceProvider)) +#define GST_VULKAN_DEVICE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE_PROVIDER, GstVulkanDeviceProviderClass)) +#define GST_VULKAN_DEVICE_PROVIDER_CAST(obj) ((GstVulkanDeviceProvider *)(obj)) + +struct _GstVulkanDeviceProvider { + GstDeviceProvider parent; +}; + +typedef enum { + GST_VULKAN_DEVICE_TYPE_SINK +} GstVulkanDeviceType; + +struct _GstVulkanDeviceProviderClass { + GstDeviceProviderClass parent_class; +}; + +GType gst_vulkan_device_provider_get_type (void); + +typedef struct _GstVulkanDeviceObject GstVulkanDeviceObject; +typedef struct _GstVulkanDeviceObjectClass GstVulkanDeviceObjectClass; + +#define GST_TYPE_VULKAN_DEVICE_OBJECT (gst_vulkan_device_object_get_type()) +#define GST_IS_VULKAN_DEVICE_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VULKAN_DEVICE_OBJECT)) +#define GST_IS_VULKAN_DEVICE_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VULKAN_DEVICE_OBJECT)) +#define GST_VULKAN_DEVICE_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VULKAN_DEVICE_OBJECT, GstVulkanDeviceObjectClass)) +#define GST_VULKAN_DEVICE_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VULKAN_DEVICE_OBJECT, GstVulkanDeviceObject)) +#define GST_VULKAN_DEVICE_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VULKAN_DEVICE_OBJECT, GstVulkanDeviceObjectClass)) +#define GST_VULKAN_DEVICE_OBJECT_CAST(obj) ((GstVulkanDevice *)(obj)) + +struct _GstVulkanDeviceObject { + GstDevice parent; + + GstVulkanDeviceType type; + guint device_index; + gboolean is_default; + const gchar *element; + GstVulkanPhysicalDevice *physical_device; +}; + +struct _GstVulkanDeviceObjectClass { + GstDeviceClass parent_class; +}; + +GType gst_vulkan_device_object_get_type (void); + +G_END_DECLS + +#endif /* __GST_VULKAN_DEVICE_PROVIDER_H__ */ diff --git a/gst-libs/gst/vulkan/gstvkphysicaldevice.c b/gst-libs/gst/vulkan/gstvkphysicaldevice.c index f14e37b..70f50f5 100644 --- a/gst-libs/gst/vulkan/gstvkphysicaldevice.c +++ b/gst-libs/gst/vulkan/gstvkphysicaldevice.c @@ -184,7 +184,8 @@ gst_vulkan_physical_device_class_init (GstVulkanPhysicalDeviceClass * g_object_class_install_property (gobject_class, PROP_DEVICE_ID, g_param_spec_uint ("device-index", "Device Index", "Device Index", 0, - G_MAXUINT32, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_MAXUINT32, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_NAME, g_param_spec_string ("name", "Name", "Device Name", NULL, diff --git a/tests/check/elements/vkdeviceprovider.c b/tests/check/elements/vkdeviceprovider.c new file mode 100644 index 0000000..bf69346 --- /dev/null +++ b/tests/check/elements/vkdeviceprovider.c @@ -0,0 +1,120 @@ +/* GStreamer Vulkan device provider unit test + * + * Copyright (C) 2019 Matthew Wayers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +static GstDeviceMonitor * +vulkan_sink_device_provider (void) +{ + GstDeviceMonitor *monitor = gst_device_monitor_new (); + GstCaps *caps; + + caps = gst_caps_from_string ("video/x-raw(memory:VulkanImage)"); + gst_device_monitor_add_filter (monitor, "Video/Sink", caps); + gst_caps_unref (caps); + + gst_device_monitor_start (monitor); + + return monitor; +} + +GST_START_TEST (vulkan_provider_creation) +{ + GstDeviceMonitor *monitor; + GList *devices, *l; + gboolean found_vulkan_device = FALSE; + + monitor = vulkan_sink_device_provider (); + devices = gst_device_monitor_get_devices (monitor); + + for (l = devices; l; l = g_list_next (l)) { + GstDevice *device = GST_DEVICE (l->data); + GstVulkanPhysicalDevice *vk_phys_device; + GstVulkanDevice *elem_device; + GstElement *pipeline, *sink, *upload, *src; + GParamSpec *pspec; + + if (!(pspec = + g_object_class_find_property (G_OBJECT_GET_CLASS (device), + "physical-device"))) + continue; + if (G_PARAM_SPEC_VALUE_TYPE (pspec) != GST_TYPE_VULKAN_PHYSICAL_DEVICE) + continue; + + found_vulkan_device = TRUE; + g_object_get (device, "physical-device", &vk_phys_device, NULL); + fail_unless (GST_IS_VULKAN_PHYSICAL_DEVICE (vk_phys_device)); + + pipeline = gst_pipeline_new ("vkdeviceprovider"); + src = gst_element_factory_make ("videotestsrc", NULL); + upload = gst_element_factory_make ("vulkanupload", NULL); + sink = gst_device_create_element (device, NULL); + + fail_unless (gst_bin_add (GST_BIN (pipeline), src)); + fail_unless (gst_bin_add (GST_BIN (pipeline), upload)); + fail_unless (gst_bin_add (GST_BIN (pipeline), sink)); + fail_unless (gst_element_link_many (src, upload, sink, NULL)); + gst_element_set_state (pipeline, GST_STATE_READY); + + g_object_get (sink, "device", &elem_device, NULL); + fail_unless (GST_IS_VULKAN_DEVICE (elem_device)); + + GST_DEBUG ("%p =? %p", vk_phys_device, elem_device->physical_device); + fail_unless (vk_phys_device == elem_device->physical_device); + + gst_object_unref (vk_phys_device); + gst_object_unref (elem_device); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + } + g_list_free_full (devices, gst_object_unref); + gst_device_monitor_stop (monitor); + gst_object_unref (monitor); + + if (!found_vulkan_device) + GST_WARNING ("No vulkan devices found"); +} + +GST_END_TEST; + +static Suite * +vkdeviceprovider_suite (void) +{ + Suite *s = suite_create ("vkdeviceprovider"); + TCase *tc_basic = tcase_create ("general"); + GstVulkanInstance *instance; + gboolean have_instance; + + suite_add_tcase (s, tc_basic); + + /* FIXME: CI doesn't have a software vulkan renderer (and none exists currently) */ + instance = gst_vulkan_instance_new (); + have_instance = gst_vulkan_instance_open (instance, NULL); + gst_object_unref (instance); + if (have_instance) { + tcase_add_test (tc_basic, vulkan_provider_creation); + } + + return s; +} + +GST_CHECK_MAIN (vkdeviceprovider); diff --git a/tests/check/meson.build b/tests/check/meson.build index 9ad6439..ce9a179 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -58,6 +58,7 @@ base_tests = [ [['elements/vkcolorconvert.c'], not gstvulkan_dep.found(), [gstvulkan_dep]], [['libs/vkwindow.c'], not gstvulkan_dep.found(), [gstvulkan_dep]], [['libs/vkdevice.c'], not gstvulkan_dep.found(), [gstvulkan_dep]], + [['elements/vkdeviceprovider.c'], not gstvulkan_dep.found(), [gstvulkan_dep]], ] # FIXME: unistd dependency, unstable or not tested yet on windows -- 2.7.4