[igt-dev] [PATCH v2] tests/syncobj_sync_file: new test
Erik Kurzinger
ekurzinger at nvidia.com
Wed Jul 26 17:56:58 UTC 2023
This test suite exercises the new DRM_IOCTL_IMPORT/EXPORT_SYNC_FILE
ioctl introduced in [1].
[1] https://lore.kernel.org/dri-devel/5e687ad8-78ad-0350-6052-a698b278cc8c@nvidia.com/
V1 -> V2:
* added "v2" to new libigt functions to differentiate them from existing ones
* added convenience functions to wrap the raw import/export ioctls
* fixed error codes in invalid handle tests, ENOENT instead of EINVAL
* used 0 instead of 0xffffffff as invalid handle in requirement check
Signed-off-by: Erik Kurzinger <ekurzinger at nvidia.com>
---
include/drm-uapi/drm.h | 11 ++
lib/igt_syncobj.c | 64 ++++++++++
lib/igt_syncobj.h | 5 +
tests/meson.build | 1 +
tests/syncobj_sync_file.c | 242 ++++++++++++++++++++++++++++++++++++++
5 files changed, 323 insertions(+)
create mode 100644 tests/syncobj_sync_file.c
diff --git a/include/drm-uapi/drm.h b/include/drm-uapi/drm.h
index 5e54c3aa4..389dc138a 100644
--- a/include/drm-uapi/drm.h
+++ b/include/drm-uapi/drm.h
@@ -878,6 +878,12 @@ struct drm_syncobj_transfer {
__u32 pad;
};
+struct drm_syncobj_sync_file {
+ __u32 handle;
+ __u32 fd;
+ __u64 point;
+};
+
#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2) /* wait for time point to become available */
@@ -1090,8 +1096,13 @@ extern "C" {
#define DRM_IOCTL_SYNCOBJ_TRANSFER DRM_IOWR(0xCC, struct drm_syncobj_transfer)
#define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL DRM_IOWR(0xCD, struct drm_syncobj_timeline_array)
+
+
#define DRM_IOCTL_MODE_GETFB2 DRM_IOWR(0xCE, struct drm_mode_fb_cmd2)
+#define DRM_IOCTL_SYNCOBJ_IMPORT_SYNC_FILE DRM_IOWR(0xD0, struct drm_syncobj_sync_file)
+#define DRM_IOCTL_SYNCOBJ_EXPORT_SYNC_FILE DRM_IOWR(0xD1, struct drm_syncobj_sync_file)
+
/*
* Device specific ioctls should only be in their respective headers
* The device specific ioctl range is from 0x40 to 0x9f.
diff --git a/lib/igt_syncobj.c b/lib/igt_syncobj.c
index a24ed10b7..ee7d01ad0 100644
--- a/lib/igt_syncobj.c
+++ b/lib/igt_syncobj.c
@@ -181,6 +181,70 @@ syncobj_import_sync_file(int fd, uint32_t handle, int sync_file)
igt_assert_eq(__syncobj_fd_to_handle(fd, &args), 0);
}
+int
+__syncobj_import_sync_file_v2(int fd, struct drm_syncobj_sync_file *args)
+{
+ int err = 0;
+ if (igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_IMPORT_SYNC_FILE, args)) {
+ err = -errno;
+ igt_assume(err);
+ errno = 0;
+ }
+ return err;
+}
+
+/**
+ * syncobj_import_sync_file_v2:
+ * @fd: The DRM file descriptor
+ * @handle: The handle of the syncobj to import into
+ * @sync_file: The sync_file FD to import
+ * @point: The timeline point to import into
+ *
+ * Import a sync_file fd into a syncobj at a given timeline point
+ */
+void
+syncobj_import_sync_file_v2(int fd, uint32_t handle,
+ int sync_file, uint64_t point)
+{
+ struct drm_syncobj_sync_file args = { 0 };
+ args.handle = handle;
+ args.point = point;
+ args.fd = sync_file;
+ igt_assert_eq(__syncobj_import_sync_file_v2(fd, &args), 0);
+}
+
+int
+__syncobj_export_sync_file_v2(int fd, struct drm_syncobj_sync_file *args)
+{
+ int err = 0;
+ if (igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_EXPORT_SYNC_FILE, args)) {
+ err = -errno;
+ igt_assume(err);
+ errno = 0;
+ }
+ return err;
+}
+
+/**
+ * syncobj_export_sync_file_v2:
+ * @fd: The DRM file descriptor
+ * @handle: The handle to the syncobj to export from
+ * @point: The timeline point to export from
+ *
+ * Export a sync_file FD from a syncobj at a given timeline point
+ * Returns: The exported sync_file FD
+ */
+int
+syncobj_export_sync_file_v2(int fd, uint32_t handle, uint64_t point)
+{
+ struct drm_syncobj_sync_file args = { 0 };
+ args.handle = handle;
+ args.point = point;
+ args.fd = -1;
+ igt_assert_eq(__syncobj_export_sync_file_v2(fd, &args), 0);
+ return args.fd;
+}
+
int
__syncobj_wait(int fd, struct drm_syncobj_wait *args)
{
diff --git a/lib/igt_syncobj.h b/lib/igt_syncobj.h
index e6725671d..207fd2142 100644
--- a/lib/igt_syncobj.h
+++ b/lib/igt_syncobj.h
@@ -35,6 +35,11 @@ int __syncobj_fd_to_handle(int fd, struct drm_syncobj_handle *args);
int syncobj_handle_to_fd(int fd, uint32_t handle, uint32_t flags);
uint32_t syncobj_fd_to_handle(int fd, int syncobj_fd, uint32_t flags);
void syncobj_import_sync_file(int fd, uint32_t handle, int sync_file);
+int __syncobj_import_sync_file_v2(int fd, struct drm_syncobj_sync_file *args);
+void syncobj_import_sync_file_v2(int fd, uint32_t handle,
+ int sync_file, uint64_t point);
+int __syncobj_export_sync_file_v2(int fd, struct drm_syncobj_sync_file *args);
+int syncobj_export_sync_file_v2(int fd, uint32_t handle, uint64_t point);
int __syncobj_wait(int fd, struct drm_syncobj_wait *args);
int syncobj_wait_err(int fd, uint32_t *handles, uint32_t count,
uint64_t abs_timeout_nsec, uint32_t flags);
diff --git a/tests/meson.build b/tests/meson.build
index 944a0941f..1712c31ca 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -80,6 +80,7 @@ test_progs = [
'syncobj_basic',
'syncobj_wait',
'syncobj_timeline',
+ 'syncobj_sync_file',
'sw_sync',
'template',
'testdisplay',
diff --git a/tests/syncobj_sync_file.c b/tests/syncobj_sync_file.c
new file mode 100644
index 000000000..3a6a8f8a1
--- /dev/null
+++ b/tests/syncobj_sync_file.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright © 2023 NVIDIA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "igt.h"
+#include "igt_syncobj.h"
+#include "sw_sync.h"
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include "drm.h"
+
+/**
+ * TEST: syncobj sync file
+ * Category: Infrastructure
+ * Description: Tests for DRM syncobj sync file import and export
+ * Feature: synchronization
+ * Functionality: semaphore
+ * Run type: FULL
+ * Sub-category: DRM
+ * Test category: GEM_Legacy
+ *
+ * SUBTEST: binary-import-export
+ * Description: Verifies importing and exporting sync files with a binary syncobj.
+ *
+ * SUBTEST: timeline-import-export
+ * Description: Verifies importing and exporting sync files with a timeline syncobj.
+ *
+ * SUBTEST: invalid-handle-import
+ * Description: Verifies that importing a sync file to an invalid syncobj fails.
+ *
+ * SUBTEST: invalid-handle-export
+ * Description: Verifies that exporting a sync file from an invalid syncobj fails.
+ *
+ * SUBTEST: invalid-fd-import
+ * Description: Verifies that importing an invalid sync file fails.
+ *
+ * SUBTEST: unsubmitted-export
+ * Description: Verifies that exporting a sync file for an unsubmitted point fails.
+ *
+ */
+
+IGT_TEST_DESCRIPTION("Tests for DRM syncobj sync file import and export");
+
+const char *test_binary_import_export_desc =
+ "Verifies importing and exporting a sync file with a binary syncobj.";
+static void
+test_binary_import_export(int fd)
+{
+ uint32_t syncobj = syncobj_create(fd, 0);
+ int timeline = sw_sync_timeline_create();
+ int sync_file = sw_sync_timeline_create_fence(timeline, 1);
+ int exported_sync_file;
+
+ syncobj_import_sync_file_v2(fd, syncobj, sync_file, 0);
+ close(sync_file);
+ exported_sync_file = syncobj_export_sync_file_v2(fd, syncobj, 0);
+
+ igt_assert(!syncobj_wait(fd, &syncobj, 1, 0, 0, NULL));
+ igt_assert_eq(sync_fence_status(exported_sync_file), 0);
+
+ sw_sync_timeline_inc(timeline, 1);
+ igt_assert(syncobj_wait(fd, &syncobj, 1, 0, 0, NULL));
+ igt_assert_eq(sync_fence_status(exported_sync_file), 1);
+
+ close(exported_sync_file);
+ close(timeline);
+ syncobj_destroy(fd, syncobj);
+}
+
+const char *test_timeline_import_export_desc =
+ "Verifies importing and exporting sync files with a timeline syncobj.";
+static void
+test_timeline_import_export(int fd)
+{
+ uint32_t syncobj = syncobj_create(fd, 0);
+ int timeline = sw_sync_timeline_create();
+ int sync_file1 = sw_sync_timeline_create_fence(timeline, 1);
+ int sync_file2 = sw_sync_timeline_create_fence(timeline, 2);
+ int exported_sync_file1, exported_sync_file2;
+ uint64_t point1 = 1, point2 = 2;
+
+ syncobj_import_sync_file_v2(fd, syncobj, sync_file1, point1);
+ close(sync_file1);
+ exported_sync_file1 = syncobj_export_sync_file_v2(fd, syncobj, point1);
+
+ syncobj_import_sync_file_v2(fd, syncobj, sync_file2, point2);
+ close(sync_file2);
+ exported_sync_file2 = syncobj_export_sync_file_v2(fd, syncobj, point2);
+
+ igt_assert(!syncobj_timeline_wait(fd, &syncobj, &point1, 1, 0, 0, NULL));
+ igt_assert_eq(sync_fence_status(exported_sync_file1), 0);
+ igt_assert(!syncobj_timeline_wait(fd, &syncobj, &point2, 1, 0, 0, NULL));
+ igt_assert_eq(sync_fence_status(exported_sync_file2), 0);
+
+ sw_sync_timeline_inc(timeline, 1);
+ igt_assert(syncobj_timeline_wait(fd, &syncobj, &point1, 1, 0, 0, NULL));
+ igt_assert_eq(sync_fence_status(exported_sync_file1), 1);
+ igt_assert(!syncobj_timeline_wait(fd, &syncobj, &point2, 1, 0, 0, NULL));
+ igt_assert_eq(sync_fence_status(exported_sync_file2), 0);
+
+ sw_sync_timeline_inc(timeline, 1);
+ igt_assert(syncobj_timeline_wait(fd, &syncobj, &point1, 1, 0, 0, NULL));
+ igt_assert_eq(sync_fence_status(exported_sync_file1), 1);
+ igt_assert(syncobj_timeline_wait(fd, &syncobj, &point2, 1, 0, 0, NULL));
+ igt_assert_eq(sync_fence_status(exported_sync_file2), 1);
+
+ close(exported_sync_file1);
+ close(exported_sync_file2);
+ close(timeline);
+ syncobj_destroy(fd, syncobj);
+}
+
+const char *test_invalid_handle_import_desc =
+ "Verifies that importing a sync file to an invalid syncobj fails.";
+static void
+test_invalid_handle_import(int fd)
+{
+ struct drm_syncobj_sync_file args = { 0 };
+ int timeline = sw_sync_timeline_create();
+
+ args.fd = sw_sync_timeline_create_fence(timeline, 1);
+ igt_assert_eq(__syncobj_import_sync_file_v2(fd, &args), -ENOENT);
+
+ close(args.fd);
+ close(timeline);
+}
+
+const char *test_invalid_handle_export_desc =
+ "Verifies that exporting a sync file from an invalid syncobj fails.";
+static void
+test_invalid_handle_export(int fd)
+{
+ struct drm_syncobj_sync_file args = { 0 };
+
+ args.fd = -1;
+ igt_assert_eq(__syncobj_export_sync_file_v2(fd, &args), -ENOENT);
+}
+
+const char *test_invalid_fd_import_desc =
+ "Verifies that importing an invalid sync file fails.";
+static void
+test_invalid_fd_import(int fd)
+{
+ struct drm_syncobj_sync_file args = { 0 };
+
+ args.handle = syncobj_create(fd, 0);
+ args.point = 0;
+ args.fd = -1;
+ igt_assert_eq(__syncobj_import_sync_file_v2(fd, &args), -EINVAL);
+
+ syncobj_destroy(fd, args.handle);
+}
+
+const char *test_unsubmitted_export_desc =
+ "Verifies that exporting a sync file for an unsubmitted point fails.";
+static void
+test_unsubmitted_export(int fd)
+{
+ struct drm_syncobj_sync_file args = { 0 };
+
+ args.handle = syncobj_create(fd, 0);
+ args.point = 0;
+ args.fd = -1;
+ igt_assert_eq(__syncobj_export_sync_file_v2(fd, &args), -EINVAL);
+
+ syncobj_destroy(fd, args.handle);
+}
+
+static bool has_syncobj_timeline(int fd)
+{
+ uint64_t value;
+ return drmGetCap(fd, DRM_CAP_SYNCOBJ_TIMELINE,
+ &value) == 0 && value;
+}
+
+static bool has_syncobj_sync_file_import_export(int fd)
+{
+ struct drm_syncobj_sync_file args = { 0 };
+ /* if sync file import/export is supported this will fail with ENOENT,
+ * otherwise it will fail with EINVAL */
+ return __syncobj_export_sync_file_v2(fd, &args) == -ENOENT;
+}
+
+igt_main
+{
+ int fd = -1;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_ANY);
+ igt_require(has_syncobj_timeline(fd));
+ igt_require(has_syncobj_sync_file_import_export(fd));
+ igt_require_sw_sync();
+ }
+
+ igt_describe(test_binary_import_export_desc);
+ igt_subtest("binary-import-export")
+ test_binary_import_export(fd);
+
+ igt_describe(test_timeline_import_export_desc);
+ igt_subtest("timeline-import-export")
+ test_timeline_import_export(fd);
+
+ igt_describe(test_invalid_handle_import_desc);
+ igt_subtest("invalid-handle-import")
+ test_invalid_handle_import(fd);
+
+ igt_describe(test_invalid_handle_export_desc);
+ igt_subtest("invalid-handle-export")
+ test_invalid_handle_export(fd);
+
+ igt_describe(test_invalid_fd_import_desc);
+ igt_subtest("invalid-fd-import")
+ test_invalid_fd_import(fd);
+
+ igt_describe(test_unsubmitted_export_desc);
+ igt_subtest("unsubmitted-export")
+ test_unsubmitted_export(fd);
+
+ igt_fixture {
+ drm_close_driver(fd);
+ }
+
+}
--
2.41.0
More information about the igt-dev
mailing list