/* GStreamer * Copyright (C) 2025 Seungha Yang * * 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gsthip.h" #include "gsthiploader.h" #include #ifndef GST_DISABLE_GST_DEBUG #define GST_CAT_DEFAULT ensure_debug_category() static GstDebugCategory * ensure_debug_category (void) { static GstDebugCategory *cat = nullptr; static std::once_flag once; std::call_once (once,[&] { cat = _gst_debug_category_new ("hipdevice", 0, "hipdevice"); }); return cat; } #endif enum { PROP_0, PROP_DEVICE_ID, PROP_VENDOR, PROP_TEXTURE2D_SUPPORT, }; struct _GstHipDevicePrivate { ~_GstHipDevicePrivate () { gst_clear_hip_stream (&stream); } guint device_id; GstHipVendor vendor; gboolean texture_support; GstHipStream *stream = nullptr; }; #define gst_hip_device_parent_class parent_class G_DEFINE_TYPE (GstHipDevice, gst_hip_device, GST_TYPE_OBJECT); static void gst_hip_device_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void gst_hip_device_finalize (GObject * object); static void gst_hip_device_class_init (GstHipDeviceClass * klass) { auto object_class = G_OBJECT_CLASS (klass); object_class->get_property = gst_hip_device_get_property; object_class->finalize = gst_hip_device_finalize; g_object_class_install_property (object_class, PROP_DEVICE_ID, g_param_spec_uint ("device-id", "Device ID", "Device ID", 0, G_MAXUINT, 0, (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); g_object_class_install_property (object_class, PROP_VENDOR, g_param_spec_enum ("vendor", "Vendor", "Vendor", GST_TYPE_HIP_VENDOR, GST_HIP_VENDOR_UNKNOWN, (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); g_object_class_install_property (object_class, PROP_TEXTURE2D_SUPPORT, g_param_spec_boolean ("texture2d-support", "Texture2D support", "Texture2D support", FALSE, (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); gst_hip_memory_init_once (); } static void gst_hip_device_init (GstHipDevice * self) { self->priv = new GstHipDevicePrivate (); } static void gst_hip_device_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { auto self = GST_HIP_DEVICE (object); auto priv = self->priv; switch (prop_id) { case PROP_DEVICE_ID: g_value_set_uint (value, priv->device_id); break; case PROP_VENDOR: g_value_set_enum (value, priv->vendor); break; case PROP_TEXTURE2D_SUPPORT: g_value_set_boolean (value, priv->texture_support); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gst_hip_device_finalize (GObject * object) { auto self = GST_HIP_DEVICE (object); delete self->priv; G_OBJECT_CLASS (parent_class)->finalize (object); } GstHipDevice * gst_hip_device_new (GstHipVendor vendor, guint device_id) { if (vendor == GST_HIP_VENDOR_UNKNOWN) { if (gst_hip_load_library (GST_HIP_VENDOR_AMD)) vendor = GST_HIP_VENDOR_AMD; else if (gst_hip_load_library (GST_HIP_VENDOR_NVIDIA)) vendor = GST_HIP_VENDOR_NVIDIA; else return nullptr; } if (!gst_hip_load_library (vendor)) { GST_INFO ("Couldn't load HIP library"); return nullptr; } int num_dev = 0; auto hip_ret = HipGetDeviceCount (vendor, &num_dev); if (hip_ret != hipSuccess || num_dev <= 0) { GST_DEBUG ("No supported HIP device, error: %d", hip_ret); return nullptr; } if ((guint) num_dev <= device_id) { GST_DEBUG ("Num device %d <= requested device id %d", num_dev, device_id); return nullptr; } gboolean texture_support = FALSE; int val = 0; hip_ret = HipDeviceGetAttribute (vendor, &val, hipDeviceAttributeMaxTexture2DWidth, device_id); if (hip_ret == hipSuccess && val > 0) { hip_ret = HipDeviceGetAttribute (vendor, &val, hipDeviceAttributeMaxTexture2DHeight, device_id); if (hip_ret == hipSuccess && val > 0) { hip_ret = HipDeviceGetAttribute (vendor, &val, hipDeviceAttributeTextureAlignment, device_id); if (hip_ret == hipSuccess && val > 0) { texture_support = TRUE; } } } auto stream = gst_hip_stream_new (vendor, device_id); if (!stream) { GST_ERROR ("Couldn't create stream"); return nullptr; } auto self = (GstHipDevice *) g_object_new (GST_TYPE_HIP_DEVICE, nullptr); gst_object_ref_sink (self); self->priv->device_id = device_id; self->priv->vendor = vendor; self->priv->texture_support = texture_support; self->priv->stream = stream; return self; } gboolean gst_hip_device_set_current (GstHipDevice * device) { g_return_val_if_fail (GST_IS_HIP_DEVICE (device), FALSE); auto priv = device->priv; auto hip_ret = HipSetDevice (priv->vendor, priv->device_id); if (!gst_hip_result (hip_ret, priv->vendor)) { GST_ERROR_OBJECT (device, "hipSetDevice result %d", hip_ret); return FALSE; } return TRUE; } hipError_t gst_hip_device_get_attribute (GstHipDevice * device, hipDeviceAttribute_t attr, gint * value) { g_return_val_if_fail (GST_IS_HIP_DEVICE (device), hipErrorInvalidDevice); auto priv = device->priv; return HipDeviceGetAttribute (priv->vendor, value, attr, priv->device_id); } gboolean gst_hip_device_is_equal (GstHipDevice * device1, GstHipDevice * device2) { if (!device1 || !device2) return FALSE; g_return_val_if_fail (GST_IS_HIP_DEVICE (device1), FALSE); g_return_val_if_fail (GST_IS_HIP_DEVICE (device2), FALSE); if (device1 == device2) return TRUE; if (device1->priv->device_id == device2->priv->device_id && device1->priv->vendor == device2->priv->vendor) { return TRUE; } return FALSE; } GstHipVendor gst_hip_device_get_vendor (GstHipDevice * device) { g_return_val_if_fail (GST_IS_HIP_DEVICE (device), GST_HIP_VENDOR_UNKNOWN); return device->priv->vendor; } guint gst_hip_device_get_device_id (GstHipDevice * device) { g_return_val_if_fail (GST_IS_HIP_DEVICE (device), (guint) - 1); return device->priv->device_id; } GstHipStream * gst_hip_device_get_stream (GstHipDevice * device) { g_return_val_if_fail (GST_IS_HIP_DEVICE (device), nullptr); return device->priv->stream; }