[PATCH i-g-t v3 12/29] lib/unigraf: Initial Unigraf support
Louis Chauvet
louis.chauvet at bootlin.com
Sat Aug 23 02:11:32 UTC 2025
This introduce the basic boilerplate to connect to a unigraf device.
This integration currently only supports one device openned to simplify
its usage and cleanup.
The functions unigraf_open_device and unigraf_require_device will register
a handler to do proper cleanup on IGT exit.
Signed-off-by: Louis Chauvet <louis.chauvet at bootlin.com>
---
lib/meson.build | 10 +++++
lib/unigraf/TSI.h | 8 ----
lib/unigraf/unigraf.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++
lib/unigraf/unigraf.h | 50 +++++++++++++++++++++++
meson.build | 14 +++++++
5 files changed, 183 insertions(+), 8 deletions(-)
diff --git a/lib/meson.build b/lib/meson.build
index f078dad4e5b17159849716f6698d6b4f1fd74475..f21e36ab5319bbdfb93533ee72e22d6b6e4197cb 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -143,6 +143,13 @@ lib_deps = [
zlib
]
+if libtsi.found()
+ lib_deps += libtsi
+ lib_sources += [
+ 'unigraf/unigraf.c'
+ ]
+endif
+
if libdrm_nouveau.found()
lib_deps += libdrm_nouveau
lib_sources += [
@@ -212,6 +219,9 @@ endif
if chamelium.found()
lib_deps += chamelium
lib_sources += [ 'igt_chamelium.c', 'igt_chamelium_stream.c' ]
+endif
+
+if chamelium.found() or libtsi.found()
lib_sources += 'monitor_edids/monitor_edids_helper.c'
endif
diff --git a/lib/unigraf/TSI.h b/lib/unigraf/TSI.h
index 62daaab6300e3ad0057217af869749cd9dc287ee..669748c91aace505921e53ac872d453acb6ff7c3 100644
--- a/lib/unigraf/TSI.h
+++ b/lib/unigraf/TSI.h
@@ -210,14 +210,6 @@ TSI_RESULT TSIX_DEV_GetDeviceRoleCount(TSI_HANDLE Device);
TSI_RESULT TSIX_DEV_GetDeviceRoleName(TSI_HANDLE Device, int RoleIndex,
char *RoleNameString, unsigned int RoleStringMaxLength);
-/**
- * TSIX_VIN_GetInputCount() - Get the number of video inputs available on a device
- * @Device: Device handle to query
- *
- * Returns: >=0 in case of success, the number of video inputs available on the device
- */
-TSI_RESULT TSIX_VIN_GetInputCount(TSI_HANDLE Device);
-
/**
* TSIX_VIN_GetInputName() - Get the name of a specific video input on a device
* @Device: Device handle to query
diff --git a/lib/unigraf/unigraf.c b/lib/unigraf/unigraf.c
new file mode 100644
index 0000000000000000000000000000000000000000..55c3c445fa5efae9559c10f4f56052442027346f
--- /dev/null
+++ b/lib/unigraf/unigraf.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: MIT
+
+#include "drmtest.h"
+#include "glib.h"
+#include "igt_core.h"
+#include "igt_edid.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "unigraf.h"
+#include "TSI.h"
+#include "TSI_types.h"
+#include "igt_kms.h"
+#include "igt_pipe_crc.h"
+#include "igt_rc.h"
+#include "monitor_edids/monitor_edids_helper.h"
+
+#define unigraf_debug(fmt, ...) igt_debug("TSI:%p: " fmt, unigraf_device, ##__VA_ARGS__)
+
+static int unigraf_open_count;
+static TSI_HANDLE unigraf_device;
+static char *unigraf_default_edid;
+static char *unigraf_connector_name;
+
+static void unigraf_close_device(void)
+{
+ unigraf_debug("Closing...\n");
+ unigraf_assert(TSIX_DEV_CloseDevice(unigraf_device));
+ TSI_Clean();
+ unigraf_device = NULL;
+ free(unigraf_default_edid);
+ free(unigraf_connector_name);
+}
+
+/**
+ * unigraf_exit_handler - Handle the exit signal and clean up unigraf resources.
+ * @sig: The signal number received.
+ *
+ * This function is called when the program receives an exit signal. It ensures
+ * that all unigraf resources are properly cleaned up by calling unigraf_deinit
+ * for each open instance.
+ */
+static void unigraf_exit_handler(int sig)
+{
+ if (unigraf_open_count)
+ unigraf_close_device();
+}
+
+static void unigraf_init(void)
+{
+ int ret;
+
+ unigraf_debug("Initialize unigraf...\n");
+ ret = TSI_Init(TSI_CURRENT_VERSION);
+ unigraf_assert(ret);
+ igt_install_exit_handler(unigraf_exit_handler);
+}
+
+/**
+ * unigraf_device_count() - Return the number of scanned devices
+ *
+ * Must be called after a unigraf_rescan_devices().
+ */
+static unsigned int unigraf_device_count(void)
+{
+ return unigraf_assert(TSIX_DEV_GetDeviceCount());
+}
+
+bool unigraf_open_device(int drm_fd)
+{
+ TSI_RESULT r;
+ int device_count;
+ int chosen_device = 0;
+ int chosen_role = 0;
+ int chosen_input = 0;
+
+ assert(igt_can_fail());
+
+ if (unigraf_device)
+ return true;
+
+ unigraf_init();
+
+ unigraf_assert(TSIX_DEV_RescanDevices(0, TSI_DEVCAP_VIDEO_CAPTURE, 0));
+
+ device_count = unigraf_device_count();
+ if (device_count < 1) {
+ unigraf_debug("No device found.\n");
+ return false;
+ }
+
+ unigraf_device = TSIX_DEV_OpenDevice(chosen_device, &r);
+ unigraf_assert(r);
+ igt_assert(unigraf_device);
+ unigraf_debug("Successfully opened the unigraf device %d.\n", chosen_device);
+
+ unigraf_assert(TSIX_DEV_SelectRole(unigraf_device, chosen_role));
+ unigraf_assert(TSIX_VIN_Select(unigraf_device, chosen_input));
+ unigraf_assert(TSIX_VIN_Enable(unigraf_device, chosen_input));
+
+ return true;
+}
+
+void unigraf_require_device(int drm_fd)
+{
+ igt_require(unigraf_open_device(drm_fd));
+}
diff --git a/lib/unigraf/unigraf.h b/lib/unigraf/unigraf.h
new file mode 100644
index 0000000000000000000000000000000000000000..8cdbf00201b2a0467ec15259cf4bc0a2d8f9b61e
--- /dev/null
+++ b/lib/unigraf/unigraf.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef UNIGRAF_H
+#define UNIGRAF_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/**
+ * unigraf_assert: Helper macro to assert a TSI return value and retrieve a detailed error message.
+ * @result: libTSI return value to check
+ *
+ * This macro checks the return value of a libTSI function call. If the return value indicates an
+ * error, it retrieves a detailed error message and asserts with that message.
+ * If retrieving the error description fails, it asserts with a generic error message.
+ */
+#define unigraf_assert(result) \
+({ \
+ char msg[256]; \
+ TSI_RESULT __r = (result); \
+ if (__r < TSI_SUCCESS) { \
+ TSI_RESULT __r2 = TSI_MISC_GetErrorDescription(__r, msg, sizeof(msg)); \
+ if (__r2 < TSI_SUCCESS) \
+ igt_assert_f(false, "unigraf error: %d (get error description failed: %d)\n", \
+ __r, __r2); \
+ else \
+ igt_assert_f(false, "unigraf error: %d (%s)\n", __r, msg); \
+ } \
+ (__r); \
+})
+
+/**
+ * unigraf_open_device() - Search and open a device.
+ * @drm_fd: File descriptor of the currently used drm device
+ *
+ * Returns: true if a device was found and initialized, otherwise false.
+ *
+ * This function searches for a compatible device and opens it.
+ */
+bool unigraf_open_device(int drm_fd);
+
+/**
+ * unigraf_require_device() - Search and open a device.
+ * @drm_fd: File descriptor of the currently used drm device
+ *
+ * This is a shorthand to reduce test boilerplate when a unigraf device must be present.
+ */
+void unigraf_require_device(int drm_fd);
+
+#endif // UNIGRAF_H
diff --git a/meson.build b/meson.build
index aeed3b1d2240c4f224933600a531482791e612d1..f6d60243658148ead523bd0ad5c52d3ae997bdbc 100644
--- a/meson.build
+++ b/meson.build
@@ -165,6 +165,12 @@ cairo = dependency('cairo', version : '>1.12.0', required : true)
libudev = dependency('libudev', required : true)
glib = dependency('glib-2.0', required : true)
+libtsi = cc.find_library('TSI', required : false)
+
+if libtsi.found()
+ config.set('HAVE_UNIGRAF', 1)
+endif
+
xmlrpc = dependency('xmlrpc', required : false)
xmlrpc_util = dependency('xmlrpc_util', required : false)
xmlrpc_client = dependency('xmlrpc_client', required : false)
@@ -288,6 +294,7 @@ libexecdir = join_paths(get_option('libexecdir'), 'igt-gpu-tools')
amdgpudir = join_paths(libexecdir, 'amdgpu')
msmdir = join_paths(libexecdir, 'msm')
panfrostdir = join_paths(libexecdir, 'panfrost')
+unigrafdir = join_paths(libexecdir, 'unigraf')
v3ddir = join_paths(libexecdir, 'v3d')
vc4dir = join_paths(libexecdir, 'vc4')
vmwgfxdir = join_paths(libexecdir, 'vmwgfx')
@@ -357,6 +364,12 @@ if get_option('use_rpath')
vmwgfx_rpathdir = join_paths(vmwgfx_rpathdir, '..')
endforeach
vmwgfx_rpathdir = join_paths(vmwgfx_rpathdir, libdir)
+
+ unigraf_rpathdir = '$ORIGIN'
+ foreach p : unigrafdir.split('/')
+ unigraf_rpathdir = join_paths(unigraf_rpathdir, '..')
+ endforeach
+ unigraf_rpathdir = join_paths(unigraf_rpathdir, libdir)
else
bindir_rpathdir = ''
libexecdir_rpathdir = ''
@@ -366,6 +379,7 @@ else
v3d_rpathdir = ''
vc4_rpathdir = ''
vmwgfx_rpathdir = ''
+ unigraf_rpathdir = ''
endif
build_testplan = get_option('testplan')
--
2.50.1
More information about the igt-dev
mailing list