public inbox for igt-dev@lists.freedesktop.org
 help / color / mirror / Atom feed
From: Jeevan B <jeevan.b@intel.com>
To: igt-dev@lists.freedesktop.org
Cc: uma.shankar@intel.com, Jeevan B <jeevan.b@intel.com>
Subject: [PATCH i-g-t 1/2] lib: Add modifier helper for querying driver-supported modifiers
Date: Wed,  1 Apr 2026 14:28:32 +0530	[thread overview]
Message-ID: <20260401085851.627453-2-jeevan.b@intel.com> (raw)
In-Reply-To: <20260401085851.627453-1-jeevan.b@intel.com>

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.

Signed-off-by: Jeevan B <jeevan.b@intel.com>
---
 lib/igt_modifier.c | 310 +++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_modifier.h |  35 +++++
 lib/meson.build    |   1 +
 3 files changed, 346 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..561afb346
--- /dev/null
+++ b/lib/igt_modifier.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright © 2026 Intel Corporation
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:igt_modifier
+ * @short_description: Helpers to query supported DRM format modifiers
+ * @title: IGT Modifier Helpers
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include <drm_fourcc.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "drmtest.h"
+#include "igt_modifier.h"
+#include "igt_core.h"
+
+/*
+ * Basic tiling modifier candidates.  Only those reported as actually
+ * supported by the driver for the requested format will be returned by
+ * igt_get_basic_tiling_modifiers().
+ */
+static const uint64_t basic_modifier_candidates[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	I915_FORMAT_MOD_X_TILED,
+	I915_FORMAT_MOD_Y_TILED,
+	I915_FORMAT_MOD_4_TILED,
+};
+
+static inline const uint32_t *
+blob_formats_ptr(const struct drm_format_modifier_blob *blob)
+{
+	return (const uint32_t *)((const char *)blob + blob->formats_offset);
+}
+
+static inline 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);
+}
+
+/*
+ * append_unique_modifier - add @mod to @list if not already present.
+ *
+ * @list:  pointer to the growing array (may be reallocated).
+ * @count: current number of entries.
+ * @mod:   modifier to add.
+ *
+ * Returns the new count.
+ */
+static int append_unique_modifier(uint64_t **list, int count, uint64_t mod)
+{
+	for (int i = 0; i < count; i++) {
+		if ((*list)[i] == mod)
+			return count;
+	}
+
+	*list = realloc(*list, (count + 1) * sizeof(**list));
+	igt_assert(*list);
+	(*list)[count] = mod;
+	return count + 1;
+}
+
+/*
+ * collect_modifiers_from_blob - parse an IN_FORMATS blob and collect every
+ * modifier that is paired with @format into @list.
+ *
+ * Returns the updated count of unique modifiers in @list.
+ */
+static int collect_modifiers_from_blob(const struct drm_format_modifier_blob *blob,
+				       uint32_t format,
+				       uint64_t **list, int count)
+{
+	const uint32_t *formats = blob_formats_ptr(blob);
+	const struct drm_format_modifier *mods = blob_modifiers_ptr(blob);
+
+	/* Find the index of @format in the blob's format array. */
+	int fmt_idx = -1;
+
+	for (uint32_t f = 0; f < blob->count_formats; f++) {
+		if (formats[f] == format) {
+			fmt_idx = (int)f;
+			break;
+		}
+	}
+
+	if (fmt_idx < 0)
+		return count;
+
+	/*
+	 * Each drm_format_modifier entry covers a window of 64 formats
+	 * starting at modifier.offset.  Check whether our format index falls
+	 * inside the window and whether the corresponding bit is set.
+	 */
+	for (uint32_t m = 0; m < blob->count_modifiers; m++) {
+		const struct drm_format_modifier *entry = &mods[m];
+		int rel = fmt_idx - (int)entry->offset;
+
+		if (rel < 0 || rel >= 64)
+			continue;
+
+		if (!(entry->formats & (UINT64_C(1) << rel)))
+			continue;
+
+		count = append_unique_modifier(list, count, entry->modifier);
+	}
+
+	return count;
+}
+
+/*
+ * query_plane_modifiers - iterate all KMS planes and collect supported
+ * modifiers for @format via the IN_FORMATS property blob.
+ *
+ * Falls back to DRM_FORMAT_MOD_LINEAR when a plane supports @format in the
+ * legacy format list but exposes no IN_FORMATS blob.
+ *
+ * Returns the number of unique modifiers written into *modifiers_out (>=0).
+ * The caller must free() the returned array.
+ */
+static int query_plane_modifiers(int drm_fd, uint32_t format,
+				 uint64_t **modifiers_out)
+{
+	drmModePlaneResPtr plane_res;
+	uint64_t *list = NULL;
+	int count = 0;
+
+	/* Universal planes capability is needed to see overlay and cursor planes. */
+	drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+
+	plane_res = drmModeGetPlaneResources(drm_fd);
+	if (!plane_res)
+		goto out;
+
+	for (uint32_t p = 0; p < plane_res->count_planes; p++) {
+		drmModePlanePtr plane;
+		drmModeObjectPropertiesPtr props;
+		drmModePropertyBlobPtr blob = NULL;
+		bool format_in_plane = false;
+
+		plane = drmModeGetPlane(drm_fd, plane_res->planes[p]);
+		if (!plane)
+			continue;
+
+		/* Check whether this plane supports @format at all. */
+		for (uint32_t f = 0; f < plane->count_formats; f++) {
+			if (plane->formats[f] == format) {
+				format_in_plane = true;
+				break;
+			}
+		}
+
+		if (!format_in_plane) {
+			drmModeFreePlane(plane);
+			continue;
+		}
+
+		props = drmModeObjectGetProperties(drm_fd, plane->plane_id,
+						   DRM_MODE_OBJECT_PLANE);
+		if (props) {
+			for (uint32_t i = 0; i < props->count_props; i++) {
+				drmModePropertyPtr prop =
+					drmModeGetProperty(drm_fd, props->props[i]);
+				if (!prop)
+					continue;
+
+				if (strcmp(prop->name, "IN_FORMATS") == 0 &&
+				    drm_property_type_is(prop, DRM_MODE_PROP_BLOB) &&
+				    props->prop_values[i] != 0) {
+					blob = drmModeGetPropertyBlob(
+						drm_fd, props->prop_values[i]);
+				}
+
+				drmModeFreeProperty(prop);
+
+				if (blob)
+					break;
+			}
+			drmModeFreeObjectProperties(props);
+		}
+
+		if (blob) {
+			const struct drm_format_modifier_blob *blob_data =
+				(const struct drm_format_modifier_blob *)blob->data;
+
+			count = collect_modifiers_from_blob(blob_data, format,
+							    &list, count);
+			drmModeFreePropertyBlob(blob);
+		} else {
+			/*
+			 * No IN_FORMATS blob: we know the format is supported
+			 * but not which modifiers; assume linear only.
+			 */
+			count = append_unique_modifier(&list, count,
+						       DRM_FORMAT_MOD_LINEAR);
+		}
+
+		drmModeFreePlane(plane);
+	}
+
+	drmModeFreePlaneResources(plane_res);
+
+out:
+	if (count == 0)
+		count = append_unique_modifier(&list, count,
+					       DRM_FORMAT_MOD_LINEAR);
+
+	*modifiers_out = list;
+	return count;
+}
+
+/**
+ * igt_get_all_supported_modifiers:
+ * @drm_fd:       open DRM file descriptor for the device under test
+ * @format:       DRM FOURCC pixel format (e.g. %DRM_FORMAT_XRGB8888)
+ * @modifiers_out: output pointer; set to a malloc'd array of unique modifiers
+ *                 on success. The caller must free() this array.
+ *
+ * Returns the number of modifiers in the returned array (always >= 1 because
+ * %DRM_FORMAT_MOD_LINEAR is used as a fallback).  The list is deduplicated
+ * across all KMS planes; it covers every modifier reported in the %IN_FORMATS
+ * plane property for the given @format on the running platform.
+ *
+ * Returns: number of entries in @modifiers_out (>= 1).
+ */
+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);
+}
+
+/**
+ * igt_get_basic_tiling_modifiers:
+ * @drm_fd:       open DRM file descriptor for the device under test
+ * @format:       DRM FOURCC pixel format (e.g. %DRM_FORMAT_XRGB8888)
+ * @modifiers_out: output pointer; set to a malloc'd array of unique modifiers
+ *                 on success. The caller must free() this array.
+ *
+ * Returns the subset of the "basic" tiling modifiers that are actually
+ * supported by the driver for @format.  The basic set comprises:
+ *
+ * - %DRM_FORMAT_MOD_LINEAR
+ * - %I915_FORMAT_MOD_X_TILED
+ * - %I915_FORMAT_MOD_Y_TILED
+ * - %I915_FORMAT_MOD_4_TILED
+ *
+ * Only modifiers that are actually reported by the driver via the %IN_FORMATS
+ * KMS plane property are included in the result.
+ *
+ * Returns: number of entries in @modifiers_out (>= 1, since at least
+ * %DRM_FORMAT_MOD_LINEAR is always included as a fallback).
+ */
+int igt_get_basic_tiling_modifiers(int drm_fd, uint32_t format,
+				   uint64_t **modifiers_out)
+{
+	uint64_t *all = NULL;
+	uint64_t *basic = NULL;
+	int all_count, basic_count = 0;
+
+	igt_assert(modifiers_out);
+
+	all_count = query_plane_modifiers(drm_fd, format, &all);
+
+	for (int i = 0; i < all_count; i++) {
+		for (int j = 0; j < (int)ARRAY_SIZE(basic_modifier_candidates); j++) {
+			if (all[i] == basic_modifier_candidates[j]) {
+				basic_count = append_unique_modifier(&basic,
+								     basic_count,
+								     all[i]);
+				break;
+			}
+		}
+	}
+
+	free(all);
+
+	if (basic_count == 0)
+		basic_count = append_unique_modifier(&basic, basic_count,
+						     DRM_FORMAT_MOD_LINEAR);
+
+	*modifiers_out = basic;
+	return basic_count;
+}
diff --git a/lib/igt_modifier.h b/lib/igt_modifier.h
new file mode 100644
index 000000000..48ce769f5
--- /dev/null
+++ b/lib/igt_modifier.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2026 Intel Corporation
+ *
+ * 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.
+ */
+
+#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


  reply	other threads:[~2026-04-01  9:00 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-01  8:58 [PATCH i-g-t 0/2] RFC: Add modifier helper and temporary test Jeevan B
2026-04-01  8:58 ` Jeevan B [this message]
2026-04-01 10:14   ` [PATCH i-g-t 1/2] lib: Add modifier helper for querying driver-supported modifiers Jani Nikula
2026-04-01  8:58 ` [PATCH i-g-t 2/2] DONT_MERGE: Add kms_modifier_list test to verify new modifier helper Jeevan B
2026-04-01 14:52 ` ✓ Xe.CI.BAT: success for RFC: Add modifier helper and temporary test Patchwork
2026-04-01 15:27 ` ✗ i915.CI.BAT: failure " Patchwork
2026-04-01 19:23 ` ✓ Xe.CI.FULL: success " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260401085851.627453-2-jeevan.b@intel.com \
    --to=jeevan.b@intel.com \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=uma.shankar@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox