* [PATCH i-g-t v2 0/2] RFC: Add modifier helper and temporary test
@ 2026-04-01 15:25 Jeevan B
2026-04-01 15:25 ` [PATCH i-g-t v2 1/2] lib: Add modifier helper for querying driver-supported modifiers Jeevan B
2026-04-01 15:25 ` [PATCH i-g-t v2 2/2] DONT_MERGE: Add kms_modifier_list test to verify new modifier helper Jeevan B
0 siblings, 2 replies; 5+ messages in thread
From: Jeevan B @ 2026-04-01 15:25 UTC (permalink / raw)
To: igt-dev; +Cc: uma.shankar, jani.nikula, Jeevan B
This series adds a new helper for querying driver-supported format
modifiers and a temporary test to verify that the helper outputs the
expected modifier list.
Jeevan B (2):
lib: Add modifier helper for querying driver-supported modifiers
DONT_MERGE: Add kms_modifier_list test to verify new modifier helper
lib/igt_modifier.c | 242 ++++++++++++++++++++++++++++++++++++++
lib/igt_modifier.h | 18 +++
lib/meson.build | 1 +
tests/kms_modifier_list.c | 127 ++++++++++++++++++++
tests/meson.build | 1 +
5 files changed, 389 insertions(+)
create mode 100644 lib/igt_modifier.c
create mode 100644 lib/igt_modifier.h
create mode 100644 tests/kms_modifier_list.c
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH i-g-t v2 1/2] lib: Add modifier helper for querying driver-supported modifiers
2026-04-01 15:25 [PATCH i-g-t v2 0/2] RFC: Add modifier helper and temporary test Jeevan B
@ 2026-04-01 15:25 ` Jeevan B
2026-04-01 16:00 ` Ville Syrjälä
2026-04-01 15:25 ` [PATCH i-g-t v2 2/2] DONT_MERGE: Add kms_modifier_list test to verify new modifier helper Jeevan B
1 sibling, 1 reply; 5+ messages in thread
From: Jeevan B @ 2026-04-01 15:25 UTC (permalink / raw)
To: igt-dev; +Cc: uma.shankar, jani.nikula, Jeevan B
Introduce a new helper library that collects DRM format modifiers
reported by KMS planes via the IN_FORMATS property. Two functions are
added:
- igt_get_all_supported_modifiers()
- igt_get_basic_tiling_modifiers()
These helpers return unique modifier lists for a given format and will
be used by modifier-related tests.
v2: Update license headers, removes unnecessary inline usage,
standardizes loops to use int, drops unused casts, introduces
a small struct to manage modifier lists more cleanly, improves
allocation handling, simplifies the basic modifier selection
logic, and update coding‑style improvements.
Signed-off-by: Jeevan B <jeevan.b@intel.com>
---
lib/igt_modifier.c | 242 +++++++++++++++++++++++++++++++++++++++++++++
lib/igt_modifier.h | 18 ++++
lib/meson.build | 1 +
3 files changed, 261 insertions(+)
create mode 100644 lib/igt_modifier.c
create mode 100644 lib/igt_modifier.h
diff --git a/lib/igt_modifier.c b/lib/igt_modifier.c
new file mode 100644
index 000000000..ffcf09bc9
--- /dev/null
+++ b/lib/igt_modifier.c
@@ -0,0 +1,242 @@
+/* SPDX-License-Identifier: MIT */
+
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <drm_fourcc.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "igt_modifier.h"
+#include "igt_core.h"
+#include "drmtest.h"
+
+/*
+ * Modifier array with dynamic allocation.
+ */
+struct modifiers {
+ uint64_t *array;
+ int nelems;
+ int alloc;
+};
+
+static void modifiers_init(struct modifiers *m)
+{
+ m->array = NULL;
+ m->nelems = 0;
+ m->alloc = 0;
+}
+
+static bool modifiers_contains(const struct modifiers *m, uint64_t val)
+{
+ for (int i = 0; i < m->nelems; i++)
+ if (m->array[i] == val)
+ return true;
+ return false;
+}
+
+static void modifiers_append_unique(struct modifiers *m, uint64_t val)
+{
+ if (modifiers_contains(m, val))
+ return;
+
+ if (m->nelems == m->alloc) {
+ int new_alloc = m->alloc ? m->alloc * 2 : 8;
+ m->array = realloc(m->array, new_alloc * sizeof(uint64_t));
+ igt_assert(m->array);
+
+ m->alloc = new_alloc;
+ }
+
+ m->array[m->nelems++] = val;
+}
+
+static void modifiers_finalize(struct modifiers *m, uint64_t **out, int *count)
+{
+ *out = m->array;
+ *count = m->nelems;
+}
+
+
+static const uint32_t *
+blob_formats_ptr(const struct drm_format_modifier_blob *blob)
+{
+ return (const uint32_t *)((const char *)blob + blob->formats_offset);
+}
+
+static const struct drm_format_modifier *
+blob_modifiers_ptr(const struct drm_format_modifier_blob *blob)
+{
+ return (const struct drm_format_modifier *)
+ ((const char *)blob + blob->modifiers_offset);
+}
+
+static void collect_modifiers_from_blob(struct modifiers *m,
+ const struct drm_format_modifier_blob *blob,
+ uint32_t format)
+{
+ const uint32_t *formats = blob_formats_ptr(blob);
+ const struct drm_format_modifier *mods = blob_modifiers_ptr(blob);
+
+ int fmt_idx = -1;
+
+ for (int i = 0; i < (int)blob->count_formats; i++) {
+ if (formats[i] == format) {
+ fmt_idx = i;
+ break;
+ }
+ }
+
+ if (fmt_idx < 0)
+ return;
+
+ for (int i = 0; i < (int)blob->count_modifiers; i++) {
+ const struct drm_format_modifier *entry = &mods[i];
+ int rel = fmt_idx - entry->offset;
+
+ if (rel < 0 || rel >= 64)
+ continue;
+
+ if (entry->formats & (1ULL << rel))
+ modifiers_append_unique(m, entry->modifier);
+ }
+}
+
+static int query_plane_modifiers(int drm_fd, uint32_t format,
+ uint64_t **out)
+{
+ struct modifiers mods;
+ drmModePlaneResPtr pres;
+
+ modifiers_init(&mods);
+
+ drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+
+ pres = drmModeGetPlaneResources(drm_fd);
+ if (!pres)
+ goto fallback;
+
+ for (int i = 0; i < (int)pres->count_planes; i++) {
+ drmModePlanePtr p;
+ drmModeObjectPropertiesPtr props;
+ drmModePropertyBlobPtr blob;
+ bool supported;
+ int f, j;
+
+ p = drmModeGetPlane(drm_fd, pres->planes[i]);
+ if (!p)
+ continue;
+
+ supported = false;
+
+ for (f = 0; f < (int)p->count_formats; f++) {
+ if (p->formats[f] == format) {
+ supported = true;
+ break;
+ }
+ }
+
+ if (!supported) {
+ drmModeFreePlane(p);
+ continue;
+ }
+
+ props = drmModeObjectGetProperties(drm_fd, p->plane_id,
+ DRM_MODE_OBJECT_PLANE);
+
+ blob = NULL;
+
+ if (props) {
+ for ( j = 0; j < props->count_props; j++) {
+ drmModePropertyPtr prop =
+ drmModeGetProperty(drm_fd, props->props[j]);
+ if (!prop)
+ continue;
+
+ if (!strcmp(prop->name, "IN_FORMATS") &&
+ drm_property_type_is(prop, DRM_MODE_PROP_BLOB) &&
+ props->prop_values[j] != 0) {
+ blob = drmModeGetPropertyBlob(
+ drm_fd, props->prop_values[j]);
+ }
+
+ drmModeFreeProperty(prop);
+
+ if (blob)
+ break;
+ }
+ drmModeFreeObjectProperties(props);
+ }
+
+ if (blob) {
+ const struct drm_format_modifier_blob *b =
+ (const struct drm_format_modifier_blob *)blob->data;
+
+ collect_modifiers_from_blob(&mods, b, format);
+ drmModeFreePropertyBlob(blob);
+ } else {
+ modifiers_append_unique(&mods, DRM_FORMAT_MOD_LINEAR);
+ }
+
+ drmModeFreePlane(p);
+ }
+
+ drmModeFreePlaneResources(pres);
+
+fallback:
+ int count;
+
+ if (mods.nelems == 0)
+ modifiers_append_unique(&mods, DRM_FORMAT_MOD_LINEAR);
+
+ modifiers_finalize(&mods, out, &count);
+ return count;
+}
+
+int igt_get_all_supported_modifiers(int drm_fd, uint32_t format,
+ uint64_t **modifiers_out)
+{
+ igt_assert(modifiers_out);
+ return query_plane_modifiers(drm_fd, format, modifiers_out);
+}
+
+static const uint64_t basic_mods[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ I915_FORMAT_MOD_X_TILED,
+ I915_FORMAT_MOD_Y_TILED,
+ I915_FORMAT_MOD_4_TILED,
+};
+
+int igt_get_basic_tiling_modifiers(int drm_fd, uint32_t format,
+ uint64_t **modifiers_out)
+{
+ uint64_t *all = NULL;
+ int all_count = query_plane_modifiers(drm_fd, format, &all);
+ int count;
+
+ struct modifiers out;
+ modifiers_init(&out);
+
+ for (int i = 0; i < all_count; i++) {
+ for (int j = 0; j < (int)(sizeof(basic_mods)/sizeof(basic_mods[0])); j++) {
+ if (all[i] == basic_mods[j]) {
+ modifiers_append_unique(&out, all[i]);
+ break;
+ }
+ }
+ }
+
+ free(all);
+
+ if (out.nelems == 0)
+ modifiers_append_unique(&out, DRM_FORMAT_MOD_LINEAR);
+
+ modifiers_finalize(&out, modifiers_out, &count);
+ return count;
+}
diff --git a/lib/igt_modifier.h b/lib/igt_modifier.h
new file mode 100644
index 000000000..069ea334a
--- /dev/null
+++ b/lib/igt_modifier.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: MIT */
+
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef __IGT_MODIFIER_H__
+#define __IGT_MODIFIER_H__
+
+#include <stdint.h>
+
+int igt_get_all_supported_modifiers(int drm_fd, uint32_t format,
+ uint64_t **modifiers_out);
+
+int igt_get_basic_tiling_modifiers(int drm_fd, uint32_t format,
+ uint64_t **modifiers_out);
+
+#endif /* __IGT_MODIFIER_H__ */
diff --git a/lib/meson.build b/lib/meson.build
index 5c4829345..ca2867eed 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -99,6 +99,7 @@ lib_sources = [
'igt_draw.c',
'igt_list.c',
'igt_map.c',
+ 'igt_modifier.c',
'igt_panel.c',
'igt_pm.c',
'igt_dummyload.c',
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH i-g-t v2 2/2] DONT_MERGE: Add kms_modifier_list test to verify new modifier helper
2026-04-01 15:25 [PATCH i-g-t v2 0/2] RFC: Add modifier helper and temporary test Jeevan B
2026-04-01 15:25 ` [PATCH i-g-t v2 1/2] lib: Add modifier helper for querying driver-supported modifiers Jeevan B
@ 2026-04-01 15:25 ` Jeevan B
1 sibling, 0 replies; 5+ messages in thread
From: Jeevan B @ 2026-04-01 15:25 UTC (permalink / raw)
To: igt-dev; +Cc: uma.shankar, jani.nikula, Jeevan B
Temporary test to check that the new lib modifier functions work and
print all supported modifiers.
Signed-off-by: Jeevan B <jeevan.b@intel.com>
---
tests/kms_modifier_list.c | 127 ++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
2 files changed, 128 insertions(+)
create mode 100644 tests/kms_modifier_list.c
diff --git a/tests/kms_modifier_list.c b/tests/kms_modifier_list.c
new file mode 100644
index 000000000..2e203855c
--- /dev/null
+++ b/tests/kms_modifier_list.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: MIT */
+
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include "igt.h"
+#include "igt_modifier.h"
+#include <drm_fourcc.h>
+#include <inttypes.h>
+
+IGT_TEST_DESCRIPTION("Validate igt_get_basic_tiling_modifiers() and "
+ "igt_get_all_supported_modifiers().");
+
+/**
+ * TEST: kms modifier list
+ * Category: Display
+ * Description: Validate the igt_get_basic_tiling_modifiers() and
+ * igt_get_all_supported_modifiers() helper functions.
+ * Driver requirement: i915, xe
+ * Mega feature: General Display Features
+ */
+
+/**
+ * SUBTEST: basic-modifiers-nonempty
+ * Description: Verify that igt_get_basic_tiling_modifiers() returns a
+ * non-empty list for DRM_FORMAT_XRGB8888.
+ *
+ * SUBTEST: all-modifiers-nonempty
+ * Description: Verify that igt_get_all_supported_modifiers() returns a
+ * non-empty list for DRM_FORMAT_XRGB8888.
+ *
+ * SUBTEST: basic-subset-of-all
+ * Description: Verify that every modifier in the basic list is also present
+ * in the all-modifiers list.
+ */
+
+static int drm_fd;
+static igt_display_t display;
+
+int igt_main()
+{
+ igt_fixture() {
+ drm_fd = drm_open_driver_master(DRIVER_ANY);
+ igt_display_require(&display, drm_fd);
+ }
+
+ igt_subtest("basic-modifiers-nonempty") {
+ uint64_t *mods = NULL;
+ int count;
+
+ count = igt_get_basic_tiling_modifiers(drm_fd,
+ DRM_FORMAT_XRGB8888,
+ &mods);
+ igt_assert_f(count > 0,
+ "igt_get_basic_tiling_modifiers() returned empty list\n");
+
+ igt_info("Basic modifiers (%d):\n", count);
+ for (int i = 0; i < count; i++) {
+ const char *name = igt_fb_modifier_name(mods[i]);
+ igt_info(" [basic] 0x%" PRIx64 " (%s)\n", mods[i], name);
+ }
+ free(mods);
+ }
+
+ igt_subtest("all-modifiers-nonempty") {
+ uint64_t *mods = NULL;
+ int count;
+
+ count = igt_get_all_supported_modifiers(drm_fd,
+ DRM_FORMAT_XRGB8888,
+ &mods);
+ igt_assert_f(count > 0,
+ "igt_get_all_supported_modifiers() returned empty list\n");
+
+ igt_info("All supported modifiers (%d):\n", count);
+ for (int i = 0; i < count; i++) {
+ const char *name = igt_fb_modifier_name(mods[i]);
+ igt_info(" [all] 0x%" PRIx64 " (%s)\n", mods[i], name);
+ }
+
+ free(mods);
+ }
+
+ igt_subtest("basic-subset-of-all") {
+ uint64_t *basic = NULL, *all = NULL;
+ int basic_count, all_count;
+
+ basic_count = igt_get_basic_tiling_modifiers(drm_fd,
+ DRM_FORMAT_XRGB8888,
+ &basic);
+ all_count = igt_get_all_supported_modifiers(drm_fd,
+ DRM_FORMAT_XRGB8888,
+ &all);
+
+ igt_assert(basic_count > 0);
+ igt_assert(all_count > 0);
+
+ igt_info("Checking: basic-subset-of-all\n");
+ for (int i = 0; i < basic_count; i++) {
+ bool found = false;
+ const char *name = igt_fb_modifier_name(basic[i]);
+
+ for (int j = 0; j < all_count; j++) {
+ if (basic[i] == all[j]) {
+ found = true;
+ break;
+ }
+ }
+
+ igt_info(" [basic] 0x%" PRIx64 " (%s) -> %s\n",
+ basic[i], name, found ? "FOUND" : "NOT FOUND");
+
+ igt_assert_f(found,
+ "basic modifier 0x%"PRIx64" not in all-modifiers list\n",
+ basic[i]);
+ }
+
+ free(basic);
+ free(all);
+ }
+
+ igt_fixture() {
+ igt_display_fini(&display);
+ drm_close_driver(drm_fd);
+ }
+}
diff --git a/tests/meson.build b/tests/meson.build
index cecb4a8ae..348cb9c74 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -46,6 +46,7 @@ test_progs = [
'kms_hdr',
'kms_invalid_mode',
'kms_lease',
+ 'kms_modifier_list',
'kms_multipipe_modeset',
'kms_panel_fitting',
'kms_pipe_crc_basic',
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH i-g-t v2 2/2] DONT_MERGE: Add kms_modifier_list test to verify new modifier helper
2026-04-01 15:31 [PATCH i-g-t v2 0/2] RFC: Add modifier helper and temporary test Jeevan B
@ 2026-04-01 15:31 ` Jeevan B
0 siblings, 0 replies; 5+ messages in thread
From: Jeevan B @ 2026-04-01 15:31 UTC (permalink / raw)
To: igt-dev; +Cc: uma.shankar, jani.nikula, Jeevan B
Temporary test to check that the new lib modifier functions work and
print all supported modifiers.
Signed-off-by: Jeevan B <jeevan.b@intel.com>
---
tests/kms_modifier_list.c | 127 ++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
2 files changed, 128 insertions(+)
create mode 100644 tests/kms_modifier_list.c
diff --git a/tests/kms_modifier_list.c b/tests/kms_modifier_list.c
new file mode 100644
index 000000000..2e203855c
--- /dev/null
+++ b/tests/kms_modifier_list.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: MIT */
+
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include "igt.h"
+#include "igt_modifier.h"
+#include <drm_fourcc.h>
+#include <inttypes.h>
+
+IGT_TEST_DESCRIPTION("Validate igt_get_basic_tiling_modifiers() and "
+ "igt_get_all_supported_modifiers().");
+
+/**
+ * TEST: kms modifier list
+ * Category: Display
+ * Description: Validate the igt_get_basic_tiling_modifiers() and
+ * igt_get_all_supported_modifiers() helper functions.
+ * Driver requirement: i915, xe
+ * Mega feature: General Display Features
+ */
+
+/**
+ * SUBTEST: basic-modifiers-nonempty
+ * Description: Verify that igt_get_basic_tiling_modifiers() returns a
+ * non-empty list for DRM_FORMAT_XRGB8888.
+ *
+ * SUBTEST: all-modifiers-nonempty
+ * Description: Verify that igt_get_all_supported_modifiers() returns a
+ * non-empty list for DRM_FORMAT_XRGB8888.
+ *
+ * SUBTEST: basic-subset-of-all
+ * Description: Verify that every modifier in the basic list is also present
+ * in the all-modifiers list.
+ */
+
+static int drm_fd;
+static igt_display_t display;
+
+int igt_main()
+{
+ igt_fixture() {
+ drm_fd = drm_open_driver_master(DRIVER_ANY);
+ igt_display_require(&display, drm_fd);
+ }
+
+ igt_subtest("basic-modifiers-nonempty") {
+ uint64_t *mods = NULL;
+ int count;
+
+ count = igt_get_basic_tiling_modifiers(drm_fd,
+ DRM_FORMAT_XRGB8888,
+ &mods);
+ igt_assert_f(count > 0,
+ "igt_get_basic_tiling_modifiers() returned empty list\n");
+
+ igt_info("Basic modifiers (%d):\n", count);
+ for (int i = 0; i < count; i++) {
+ const char *name = igt_fb_modifier_name(mods[i]);
+ igt_info(" [basic] 0x%" PRIx64 " (%s)\n", mods[i], name);
+ }
+ free(mods);
+ }
+
+ igt_subtest("all-modifiers-nonempty") {
+ uint64_t *mods = NULL;
+ int count;
+
+ count = igt_get_all_supported_modifiers(drm_fd,
+ DRM_FORMAT_XRGB8888,
+ &mods);
+ igt_assert_f(count > 0,
+ "igt_get_all_supported_modifiers() returned empty list\n");
+
+ igt_info("All supported modifiers (%d):\n", count);
+ for (int i = 0; i < count; i++) {
+ const char *name = igt_fb_modifier_name(mods[i]);
+ igt_info(" [all] 0x%" PRIx64 " (%s)\n", mods[i], name);
+ }
+
+ free(mods);
+ }
+
+ igt_subtest("basic-subset-of-all") {
+ uint64_t *basic = NULL, *all = NULL;
+ int basic_count, all_count;
+
+ basic_count = igt_get_basic_tiling_modifiers(drm_fd,
+ DRM_FORMAT_XRGB8888,
+ &basic);
+ all_count = igt_get_all_supported_modifiers(drm_fd,
+ DRM_FORMAT_XRGB8888,
+ &all);
+
+ igt_assert(basic_count > 0);
+ igt_assert(all_count > 0);
+
+ igt_info("Checking: basic-subset-of-all\n");
+ for (int i = 0; i < basic_count; i++) {
+ bool found = false;
+ const char *name = igt_fb_modifier_name(basic[i]);
+
+ for (int j = 0; j < all_count; j++) {
+ if (basic[i] == all[j]) {
+ found = true;
+ break;
+ }
+ }
+
+ igt_info(" [basic] 0x%" PRIx64 " (%s) -> %s\n",
+ basic[i], name, found ? "FOUND" : "NOT FOUND");
+
+ igt_assert_f(found,
+ "basic modifier 0x%"PRIx64" not in all-modifiers list\n",
+ basic[i]);
+ }
+
+ free(basic);
+ free(all);
+ }
+
+ igt_fixture() {
+ igt_display_fini(&display);
+ drm_close_driver(drm_fd);
+ }
+}
diff --git a/tests/meson.build b/tests/meson.build
index cecb4a8ae..348cb9c74 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -46,6 +46,7 @@ test_progs = [
'kms_hdr',
'kms_invalid_mode',
'kms_lease',
+ 'kms_modifier_list',
'kms_multipipe_modeset',
'kms_panel_fitting',
'kms_pipe_crc_basic',
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH i-g-t v2 1/2] lib: Add modifier helper for querying driver-supported modifiers
2026-04-01 15:25 ` [PATCH i-g-t v2 1/2] lib: Add modifier helper for querying driver-supported modifiers Jeevan B
@ 2026-04-01 16:00 ` Ville Syrjälä
0 siblings, 0 replies; 5+ messages in thread
From: Ville Syrjälä @ 2026-04-01 16:00 UTC (permalink / raw)
To: Jeevan B; +Cc: igt-dev, uma.shankar, jani.nikula
On Wed, Apr 01, 2026 at 08:55:36PM +0530, Jeevan B wrote:
> Introduce a new helper library that collects DRM format modifiers
> reported by KMS planes via the IN_FORMATS property.
We already have this parsed.
> Two functions are
> added:
>
> - igt_get_all_supported_modifiers()
> - igt_get_basic_tiling_modifiers()
>
> These helpers return unique modifier lists for a given format and will
> be used by modifier-related tests.
>
> v2: Update license headers, removes unnecessary inline usage,
> standardizes loops to use int, drops unused casts, introduces
> a small struct to manage modifier lists more cleanly, improves
> allocation handling, simplifies the basic modifier selection
> logic, and update coding‑style improvements.
>
> Signed-off-by: Jeevan B <jeevan.b@intel.com>
> ---
> lib/igt_modifier.c | 242 +++++++++++++++++++++++++++++++++++++++++++++
> lib/igt_modifier.h | 18 ++++
> lib/meson.build | 1 +
> 3 files changed, 261 insertions(+)
> create mode 100644 lib/igt_modifier.c
> create mode 100644 lib/igt_modifier.h
>
> diff --git a/lib/igt_modifier.c b/lib/igt_modifier.c
> new file mode 100644
> index 000000000..ffcf09bc9
> --- /dev/null
> +++ b/lib/igt_modifier.c
> @@ -0,0 +1,242 @@
> +/* SPDX-License-Identifier: MIT */
> +
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +
> +#include <stdlib.h>
> +#include <string.h>
> +#include <stdbool.h>
> +
> +#include <drm_fourcc.h>
> +#include <xf86drm.h>
> +#include <xf86drmMode.h>
> +
> +#include "igt_modifier.h"
> +#include "igt_core.h"
> +#include "drmtest.h"
> +
> +/*
> + * Modifier array with dynamic allocation.
> + */
> +struct modifiers {
> + uint64_t *array;
> + int nelems;
> + int alloc;
> +};
> +
> +static void modifiers_init(struct modifiers *m)
> +{
> + m->array = NULL;
> + m->nelems = 0;
> + m->alloc = 0;
> +}
> +
> +static bool modifiers_contains(const struct modifiers *m, uint64_t val)
> +{
> + for (int i = 0; i < m->nelems; i++)
> + if (m->array[i] == val)
> + return true;
> + return false;
> +}
> +
> +static void modifiers_append_unique(struct modifiers *m, uint64_t val)
> +{
> + if (modifiers_contains(m, val))
> + return;
> +
> + if (m->nelems == m->alloc) {
> + int new_alloc = m->alloc ? m->alloc * 2 : 8;
> + m->array = realloc(m->array, new_alloc * sizeof(uint64_t));
> + igt_assert(m->array);
> +
> + m->alloc = new_alloc;
> + }
> +
> + m->array[m->nelems++] = val;
> +}
> +
> +static void modifiers_finalize(struct modifiers *m, uint64_t **out, int *count)
> +{
> + *out = m->array;
> + *count = m->nelems;
> +}
> +
> +
> +static const uint32_t *
> +blob_formats_ptr(const struct drm_format_modifier_blob *blob)
> +{
> + return (const uint32_t *)((const char *)blob + blob->formats_offset);
> +}
> +
> +static const struct drm_format_modifier *
> +blob_modifiers_ptr(const struct drm_format_modifier_blob *blob)
> +{
> + return (const struct drm_format_modifier *)
> + ((const char *)blob + blob->modifiers_offset);
> +}
> +
> +static void collect_modifiers_from_blob(struct modifiers *m,
> + const struct drm_format_modifier_blob *blob,
> + uint32_t format)
> +{
> + const uint32_t *formats = blob_formats_ptr(blob);
> + const struct drm_format_modifier *mods = blob_modifiers_ptr(blob);
> +
> + int fmt_idx = -1;
> +
> + for (int i = 0; i < (int)blob->count_formats; i++) {
> + if (formats[i] == format) {
> + fmt_idx = i;
> + break;
> + }
> + }
> +
> + if (fmt_idx < 0)
> + return;
> +
> + for (int i = 0; i < (int)blob->count_modifiers; i++) {
> + const struct drm_format_modifier *entry = &mods[i];
> + int rel = fmt_idx - entry->offset;
> +
> + if (rel < 0 || rel >= 64)
> + continue;
> +
> + if (entry->formats & (1ULL << rel))
> + modifiers_append_unique(m, entry->modifier);
> + }
> +}
> +
> +static int query_plane_modifiers(int drm_fd, uint32_t format,
> + uint64_t **out)
> +{
> + struct modifiers mods;
> + drmModePlaneResPtr pres;
> +
> + modifiers_init(&mods);
> +
> + drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
> +
> + pres = drmModeGetPlaneResources(drm_fd);
> + if (!pres)
> + goto fallback;
> +
> + for (int i = 0; i < (int)pres->count_planes; i++) {
> + drmModePlanePtr p;
> + drmModeObjectPropertiesPtr props;
> + drmModePropertyBlobPtr blob;
> + bool supported;
> + int f, j;
> +
> + p = drmModeGetPlane(drm_fd, pres->planes[i]);
> + if (!p)
> + continue;
> +
> + supported = false;
> +
> + for (f = 0; f < (int)p->count_formats; f++) {
> + if (p->formats[f] == format) {
> + supported = true;
> + break;
> + }
> + }
> +
> + if (!supported) {
> + drmModeFreePlane(p);
> + continue;
> + }
> +
> + props = drmModeObjectGetProperties(drm_fd, p->plane_id,
> + DRM_MODE_OBJECT_PLANE);
> +
> + blob = NULL;
> +
> + if (props) {
> + for ( j = 0; j < props->count_props; j++) {
> + drmModePropertyPtr prop =
> + drmModeGetProperty(drm_fd, props->props[j]);
> + if (!prop)
> + continue;
> +
> + if (!strcmp(prop->name, "IN_FORMATS") &&
> + drm_property_type_is(prop, DRM_MODE_PROP_BLOB) &&
> + props->prop_values[j] != 0) {
> + blob = drmModeGetPropertyBlob(
> + drm_fd, props->prop_values[j]);
> + }
> +
> + drmModeFreeProperty(prop);
> +
> + if (blob)
> + break;
> + }
> + drmModeFreeObjectProperties(props);
> + }
> +
> + if (blob) {
> + const struct drm_format_modifier_blob *b =
> + (const struct drm_format_modifier_blob *)blob->data;
> +
> + collect_modifiers_from_blob(&mods, b, format);
> + drmModeFreePropertyBlob(blob);
> + } else {
> + modifiers_append_unique(&mods, DRM_FORMAT_MOD_LINEAR);
> + }
> +
> + drmModeFreePlane(p);
> + }
> +
> + drmModeFreePlaneResources(pres);
> +
> +fallback:
> + int count;
> +
> + if (mods.nelems == 0)
> + modifiers_append_unique(&mods, DRM_FORMAT_MOD_LINEAR);
> +
> + modifiers_finalize(&mods, out, &count);
> + return count;
> +}
> +
> +int igt_get_all_supported_modifiers(int drm_fd, uint32_t format,
> + uint64_t **modifiers_out)
> +{
> + igt_assert(modifiers_out);
> + return query_plane_modifiers(drm_fd, format, modifiers_out);
> +}
> +
> +static const uint64_t basic_mods[] = {
> + DRM_FORMAT_MOD_LINEAR,
> + I915_FORMAT_MOD_X_TILED,
> + I915_FORMAT_MOD_Y_TILED,
> + I915_FORMAT_MOD_4_TILED,
> +};
> +
> +int igt_get_basic_tiling_modifiers(int drm_fd, uint32_t format,
> + uint64_t **modifiers_out)
> +{
> + uint64_t *all = NULL;
> + int all_count = query_plane_modifiers(drm_fd, format, &all);
> + int count;
> +
> + struct modifiers out;
> + modifiers_init(&out);
> +
> + for (int i = 0; i < all_count; i++) {
> + for (int j = 0; j < (int)(sizeof(basic_mods)/sizeof(basic_mods[0])); j++) {
> + if (all[i] == basic_mods[j]) {
> + modifiers_append_unique(&out, all[i]);
> + break;
> + }
> + }
> + }
> +
> + free(all);
> +
> + if (out.nelems == 0)
> + modifiers_append_unique(&out, DRM_FORMAT_MOD_LINEAR);
> +
> + modifiers_finalize(&out, modifiers_out, &count);
> + return count;
> +}
> diff --git a/lib/igt_modifier.h b/lib/igt_modifier.h
> new file mode 100644
> index 000000000..069ea334a
> --- /dev/null
> +++ b/lib/igt_modifier.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: MIT */
> +
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +#ifndef __IGT_MODIFIER_H__
> +#define __IGT_MODIFIER_H__
> +
> +#include <stdint.h>
> +
> +int igt_get_all_supported_modifiers(int drm_fd, uint32_t format,
> + uint64_t **modifiers_out);
> +
> +int igt_get_basic_tiling_modifiers(int drm_fd, uint32_t format,
> + uint64_t **modifiers_out);
> +
> +#endif /* __IGT_MODIFIER_H__ */
> diff --git a/lib/meson.build b/lib/meson.build
> index 5c4829345..ca2867eed 100644
> --- a/lib/meson.build
> +++ b/lib/meson.build
> @@ -99,6 +99,7 @@ lib_sources = [
> 'igt_draw.c',
> 'igt_list.c',
> 'igt_map.c',
> + 'igt_modifier.c',
> 'igt_panel.c',
> 'igt_pm.c',
> 'igt_dummyload.c',
> --
> 2.43.0
--
Ville Syrjälä
Intel
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-04-01 16:01 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-01 15:25 [PATCH i-g-t v2 0/2] RFC: Add modifier helper and temporary test Jeevan B
2026-04-01 15:25 ` [PATCH i-g-t v2 1/2] lib: Add modifier helper for querying driver-supported modifiers Jeevan B
2026-04-01 16:00 ` Ville Syrjälä
2026-04-01 15:25 ` [PATCH i-g-t v2 2/2] DONT_MERGE: Add kms_modifier_list test to verify new modifier helper Jeevan B
-- strict thread matches above, loose matches on Subject: below --
2026-04-01 15:31 [PATCH i-g-t v2 0/2] RFC: Add modifier helper and temporary test Jeevan B
2026-04-01 15:31 ` [PATCH i-g-t v2 2/2] DONT_MERGE: Add kms_modifier_list test to verify new modifier helper Jeevan B
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox