Igt-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Swati Sharma <swati2.sharma@intel.com>
To: igt-dev@lists.freedesktop.org
Cc: Swati Sharma <swati2.sharma@intel.com>
Subject: [PATCH i-g-t 4/6] tests/kms_color_pipeline: Add FIXED_MATRIX colorop tests
Date: Tue, 28 Jul 2026 00:25:29 +0530	[thread overview]
Message-ID: <20260727185531.4046807-5-swati2.sharma@intel.com> (raw)
In-Reply-To: <20260727185531.4046807-1-swati2.sharma@intel.com>

Add plane color pipeline tests for the DRM_COLOROP_FIXED_MATRIX colorop,
validating color space conversion through the color pipeline framework.

With this, the SDR plane color pipeline looks like:

[YUV Range Correct] -> [1D LUT] -> [CSC] -> [1D LUT]

New subtests:
 - plane-fixed-matrix-yuv601-rgb601
 - plane-fixed-matrix-yuv709-rgb709
 - plane-fixed-matrix-yuv2020-rgb2020
 - plane-fixed-matrix-rgb709-rgb2020
 - plane-fixed-matrix-lut1d-yuv601-rgb601
 - plane-fixed-matrix-lut1d-yuv709-rgb709
 - plane-fixed-matrix-lut1d-yuv2020-rgb2020
 - plane-lut1d-fixed-matrix-lut1d-rgb709-rgb2020
 - plane-yuv-range-correct-yuv-lim
 - plane-yuv-range-correct-fixed-matrix-bt601-yuv-lim
 - plane-yuv-range-correct-fixed-matrix-bt709-yuv-lim
 - plane-yuv-range-correct-fixed-matrix-bt2020-yuv-lim

The test works as follows:
1. Creates a YUYV framebuffer with the appropriate color encoding
2. Converts it to XRGB8888 in software using igt_fb_convert() which
   internally uses igt_ycbcr_to_rgb_matrix() with the matching
   coefficients
3. Displays the SW-converted RGB fb and captures its CRC as reference
4. Programs the HW color pipeline with the FIXED_MATRIX colorop set to
   the corresponding matrix type
5. Displays the original YUYV fb through the HW pipeline and compares
   the resulting CRC against the SW reference

This ensures the HW fixed matrix implementation matches the expected
YCbCr-to-RGB conversion behavior.

The YCbCr range correction tests validate the limited range (conversion
active) path, standalone and chained with the FIXED_MATRIX colorop
matching the SDR plane pipeline. Redundant *-yuv-full range correction
subtests are omitted because the YCBCR_LIMITED_FULL colorop is a no-op
on full-range input, making them equivalent to the plain
plane-fixed-matrix-* tests.

Also refactors ctm_colorop_only() into a generic colorop_type_only()
helper that accepts the colorop type as a parameter.

v2: -Naming changes (CSC_FF -> FIXED_MATRIX)
    -Add YCbCr range correction tests
    -Use SW-generated reference CRC (igt_fb_convert) for YUV tests
    -Remove redundant tests

Assisted-by: Claude Opus 4.6
Signed-off-by: Swati Sharma <swati2.sharma@intel.com>
---
 tests/kms_color_pipeline.c | 388 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 385 insertions(+), 3 deletions(-)

diff --git a/tests/kms_color_pipeline.c b/tests/kms_color_pipeline.c
index 6119a830f..2bd6722a7 100644
--- a/tests/kms_color_pipeline.c
+++ b/tests/kms_color_pipeline.c
@@ -13,6 +13,7 @@
 
 #include "kms_color_helper.h"
 #include "kms_colorop_helper.h"
+#include "igt_color_encoding.h"
 
 #define MAX_COLOROPS	5
 
@@ -69,7 +70,8 @@ static void test_setup(data_t *data, igt_crtc_t *crtc)
 	igt_display_commit_atomic(&data->display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
 }
 
-static bool ctm_colorop_only(kms_colorop_t *colorops[])
+static bool colorop_type_only(kms_colorop_t *colorops[],
+			      kms_colorop_type_t type)
 {
 	int i;
 
@@ -77,7 +79,7 @@ static bool ctm_colorop_only(kms_colorop_t *colorops[])
 		return false;
 
 	for (i = 0; colorops[i]; i++) {
-		if (colorops[i]->type != KMS_COLOROP_CTM_3X4)
+		if (colorops[i]->type != type)
 			return false;
 	}
 
@@ -155,7 +157,7 @@ static void _test_plane_colorops(data_t *data,
 	 * Use flat colors only when the pipeline
 	 * contains CTM colorops exclusively.
 	 */
-	if (ctm_colorop_only(colorops))
+	if (colorop_type_only(colorops, KMS_COLOROP_CTM_3X4))
 		paint_rectangles(data, mode, fb_colors, &fb);
 	else
 		paint_gradient_rectangles(data, mode, fb_colors, &fb);
@@ -347,6 +349,383 @@ run_tests_for_plane(data_t *data)
 	}
 }
 
+
+/**
+ * Capture reference CRC by converting a YUV framebuffer to RGB in software
+ * using igt_fb_convert(), then displaying the resulting XRGB8888 framebuffer.
+ */
+static void
+capture_sw_converted_ref_crc(data_t *data, igt_output_t *output,
+			     struct igt_fb *yuv_fb, igt_crc_t *crc /* out */)
+{
+	struct igt_fb rgb_ref_fb;
+	igt_plane_t *primary;
+	char *crc_str;
+	int ret;
+
+	primary = igt_output_get_plane(output, DRM_PLANE_TYPE_PRIMARY);
+
+	/* Convert YUV fb to XRGB8888 in software (uses igt_ycbcr_to_rgb_matrix) */
+	igt_fb_convert(&rgb_ref_fb, yuv_fb, DRM_FORMAT_XRGB8888,
+		       DRM_FORMAT_MOD_LINEAR);
+
+	igt_plane_set_fb(primary, &rgb_ref_fb);
+	ret = igt_display_try_commit_atomic(&data->display, 0, NULL);
+	igt_assert(!ret);
+
+	igt_wait_for_vblank(primary->crtc);
+	igt_pipe_crc_collect_crc(data->pipe_crc, crc);
+
+	igt_plane_set_fb(primary, NULL);
+	igt_display_commit_atomic(&data->display, 0, NULL);
+
+	igt_remove_fb(data->drm_fd, &rgb_ref_fb);
+
+	crc_str = igt_crc_to_string(crc);
+	igt_debug("CRC for SW-converted reference fb: %s\n", crc_str);
+	free(crc_str);
+}
+
+static void
+_test_plane_fixed_matrix_colorops(data_t *data,
+				  igt_plane_t *plane,
+				  const color_t *fb_colors,
+				  igt_crc_t *crc_ref,
+				  kms_colorop_t *colorops[],
+				  uint32_t input_format,
+				  enum igt_color_encoding encoding,
+				  enum igt_color_range range)
+{
+	igt_display_t *display = &data->display;
+	drmModeModeInfo *mode = data->mode;
+	igt_colorop_t *color_pipeline;
+	igt_crc_t crc_pipe;
+	struct igt_fb fb;
+	bool is_yuv = igt_format_is_yuv(input_format);
+
+	color_pipeline = get_color_pipeline(display, plane, colorops);
+	igt_skip_on(!color_pipeline);
+
+	if (is_yuv) {
+		igt_assert(igt_create_fb_with_bo_size(data->drm_fd,
+						      mode->hdisplay,
+						      mode->vdisplay,
+						      input_format,
+						      DRM_FORMAT_MOD_LINEAR,
+						      encoding, range,
+						      &fb, 0, 0));
+	} else {
+		igt_assert(igt_create_fb(data->drm_fd,
+					 mode->hdisplay,
+					 mode->vdisplay,
+					 input_format,
+					 DRM_FORMAT_MOD_LINEAR,
+					 &fb));
+	}
+
+	/* Hardware pipeline CRC */
+	set_color_pipeline(display, plane, colorops, color_pipeline);
+	paint_rectangles(data, mode, fb_colors, &fb);
+
+	igt_plane_set_fb(plane, &fb);
+	igt_display_commit_atomic(&data->display, 0, NULL);
+	igt_wait_for_vblank(plane->crtc);
+	igt_pipe_crc_collect_crc(data->pipe_crc, &crc_pipe);
+
+	igt_assert_crc_equal(crc_ref, &crc_pipe);
+
+	/* Cleanup per-test state */
+	set_color_pipeline_bypass(plane);
+	reset_colorops(colorops);
+	igt_plane_set_fb(plane, NULL);
+	igt_display_commit_atomic(&data->display, 0, NULL);
+
+	igt_remove_fb(data->drm_fd, &fb);
+}
+
+static void test_plane_fixed_matrix_colorops(data_t *data, igt_crtc_t *crtc,
+					     const color_t *fb_colors,
+					     kms_colorop_t *colorops[],
+					     uint32_t input_format,
+					     enum igt_color_encoding encoding,
+					     enum igt_color_range range)
+{
+	int n_planes = crtc->n_planes;
+	igt_output_t *output = data->output;
+	drmModeModeInfo *mode = data->mode;
+	igt_plane_t *plane;
+	igt_crc_t ref_crc;
+	bool is_yuv = igt_format_is_yuv(input_format);
+
+	if (is_yuv) {
+		struct igt_fb yuv_fb;
+
+		igt_require(mode);
+
+		/*
+		 * Create a YUV input framebuffer and paint it with the
+		 * test colors. Convert it to XRGB8888 in software to
+		 * generate the reference CRC. This exercises the same
+		 * YCbCr-to-RGB matrix in SW that the HW fixed matrix
+		 * colorop should implement.
+		 */
+		igt_assert(igt_create_fb_with_bo_size(data->drm_fd,
+						      mode->hdisplay,
+						      mode->vdisplay,
+						      input_format,
+						      DRM_FORMAT_MOD_LINEAR,
+						      encoding, range,
+						      &yuv_fb, 0, 0));
+		paint_rectangles(data, mode, fb_colors, &yuv_fb);
+
+		capture_sw_converted_ref_crc(data, output, &yuv_fb, &ref_crc);
+		igt_remove_fb(data->drm_fd, &yuv_fb);
+	} else {
+		capture_ref_crc(data, output, fb_colors, &ref_crc);
+	}
+
+	for (int plane_id = 0; plane_id < n_planes; plane_id++) {
+		plane = igt_output_get_plane(output, plane_id);
+
+		if (!igt_plane_has_prop(plane, IGT_PLANE_COLOR_PIPELINE))
+			continue;
+
+		igt_dynamic_f("pipe-%s-plane-%u", igt_crtc_name(crtc), plane_id)
+			_test_plane_fixed_matrix_colorops(data, plane, fb_colors,
+							  &ref_crc, colorops,
+							  input_format,
+							  encoding, range);
+	}
+}
+
+/**
+ * SUBTEST: plane-fixed-matrix-%s
+ * Description: Test FIXED_MATRIX colorop for color space conversion: %arg[1].
+ *
+ * arg[1]:
+ *
+ * @yuv601-rgb601:		YUV BT.601 to RGB BT.601
+ * @yuv709-rgb709:		YUV BT.709 to RGB BT.709
+ * @yuv2020-rgb2020:		YUV BT.2020 to RGB BT.2020
+ * @rgb709-rgb2020:		RGB BT.709 to RGB BT.2020
+ */
+
+/**
+ * SUBTEST: plane-fixed-matrix-lut1d-%s
+ * Description: Test FIXED_MATRIX + 1D LUT pipeline: %arg[1].
+ *
+ * arg[1]:
+ *
+ * @yuv601-rgb601:		YUV BT.601 to RGB BT.601
+ * @yuv709-rgb709:		YUV BT.709 to RGB BT.709
+ * @yuv2020-rgb2020:		YUV BT.2020 to RGB BT.2020
+ */
+
+/**
+ * SUBTEST: plane-lut1d-fixed-matrix-lut1d-%s
+ * Description: Test 1D LUT + FIXED_MATRIX + 1D LUT pipeline: %arg[1].
+ *
+ * arg[1]:
+ *
+ * @rgb709-rgb2020:		RGB BT.709 to RGB BT.2020
+ */
+
+/**
+ * SUBTEST: plane-yuv-range-correct-%s
+ * Description: Test YCbCr range correction colorop: %arg[1].
+ *
+ * arg[1]:
+ *
+ * @yuv-lim:			YCbCr limited range (conversion active)
+ */
+
+/**
+ * SUBTEST: plane-yuv-range-correct-fixed-matrix-%s
+ * Description: Test YCbCr range correction + FIXED_MATRIX pipeline: %arg[1].
+ *
+ * arg[1]:
+ *
+ * @bt601-yuv-lim:		YCbCr BT.601 limited range with CSC
+ * @bt709-yuv-lim:		YCbCr BT.709 limited range with CSC
+ * @bt2020-yuv-lim:		YCbCr BT.2020 limited range with CSC
+ */
+
+static void
+run_tests_for_fixed_matrix(data_t *data)
+{
+	igt_crtc_t *crtc;
+	igt_output_t *output = NULL;
+
+	static const color_t colors_rgb[] = {
+		{ 1.0, 0.0, 0.0 },
+		{ 0.0, 1.0, 0.0 },
+		{ 0.0, 0.0, 1.0 },
+	};
+
+	kms_colorop_t lut1d_linear = {
+		.type = KMS_COLOROP_CUSTOM_LUT1D,
+		.name = "1D LUT (linear)",
+		.lut1d = &igt_1dlut_linear,
+		.transform = &igt_color_linear,
+	};
+
+	kms_colorop_t fixed_matrix_yuv601_rgb601 = {
+		.type = KMS_COLOROP_FIXED_MATRIX,
+		.name = "FIXED_MATRIX YUV601 to RGB601",
+		.fixed_matrix_info = { .fixed_matrix = KMS_COLOROP_FIXED_MATRIX_YCBCR601_FULL_RGB },
+	};
+	kms_colorop_t fixed_matrix_yuv709_rgb709 = {
+		.type = KMS_COLOROP_FIXED_MATRIX,
+		.name = "FIXED_MATRIX YUV709 to RGB709",
+		.fixed_matrix_info = { .fixed_matrix = KMS_COLOROP_FIXED_MATRIX_YCBCR709_FULL_RGB },
+	};
+	kms_colorop_t fixed_matrix_yuv2020_rgb2020 = {
+		.type = KMS_COLOROP_FIXED_MATRIX,
+		.name = "FIXED_MATRIX YUV2020 to RGB2020",
+		.fixed_matrix_info = { .fixed_matrix = KMS_COLOROP_FIXED_MATRIX_YCBCR2020_NC_FULL_RGB },
+	};
+	kms_colorop_t fixed_matrix_rgb709_rgb2020 = {
+		.type = KMS_COLOROP_FIXED_MATRIX,
+		.name = "FIXED_MATRIX RGB709 to RGB2020",
+		.fixed_matrix_info = { .fixed_matrix = KMS_COLOROP_FIXED_MATRIX_RGB709_RGB2020 },
+	};
+	kms_colorop_t fixed_matrix_ycbcr_limited_full = {
+		.type = KMS_COLOROP_FIXED_MATRIX,
+		.name = "FIXED_MATRIX YCbCr limited to full",
+		.fixed_matrix_info = { .fixed_matrix = KMS_COLOROP_FIXED_MATRIX_YCBCR_LIMITED_FULL },
+	};
+
+	struct {
+		const char *name;
+		const char *subtest_prefix;
+		const color_t *fb_colors;
+		kms_colorop_t *colorops[MAX_COLOROPS];
+		uint32_t input_format;
+		enum igt_color_encoding encoding;
+		enum igt_color_range range;
+	} fixed_matrix_tests[] = {
+		{ .name = "yuv601-rgb601",
+		  .subtest_prefix = "plane-fixed-matrix",
+		  .fb_colors = colors_rgb,
+		  .colorops = { &fixed_matrix_yuv601_rgb601, NULL },
+		  .input_format = DRM_FORMAT_YUYV,
+		  .encoding = IGT_COLOR_YCBCR_BT601,
+		  .range = IGT_COLOR_YCBCR_FULL_RANGE,
+		},
+		{ .name = "yuv709-rgb709",
+		  .subtest_prefix = "plane-fixed-matrix",
+		  .fb_colors = colors_rgb,
+		  .colorops = { &fixed_matrix_yuv709_rgb709, NULL },
+		  .input_format = DRM_FORMAT_YUYV,
+		  .encoding = IGT_COLOR_YCBCR_BT709,
+		  .range = IGT_COLOR_YCBCR_FULL_RANGE,
+		},
+		{ .name = "yuv2020-rgb2020",
+		  .subtest_prefix = "plane-fixed-matrix",
+		  .fb_colors = colors_rgb,
+		  .colorops = { &fixed_matrix_yuv2020_rgb2020, NULL },
+		  .input_format = DRM_FORMAT_YUYV,
+		  .encoding = IGT_COLOR_YCBCR_BT2020,
+		  .range = IGT_COLOR_YCBCR_FULL_RANGE,
+		},
+		{ .name = "rgb709-rgb2020",
+		  .subtest_prefix = "plane-fixed-matrix",
+		  .fb_colors = colors_rgb,
+		  .colorops = { &fixed_matrix_rgb709_rgb2020, NULL },
+		  .input_format = DRM_FORMAT_XRGB8888,
+		},
+		{ .name = "yuv601-rgb601",
+		  .subtest_prefix = "plane-fixed-matrix-lut1d",
+		  .fb_colors = colors_rgb,
+		  .colorops = { &fixed_matrix_yuv601_rgb601, &lut1d_linear, NULL },
+		  .input_format = DRM_FORMAT_YUYV,
+		  .encoding = IGT_COLOR_YCBCR_BT601,
+		  .range = IGT_COLOR_YCBCR_FULL_RANGE,
+		},
+		{ .name = "yuv709-rgb709",
+		  .subtest_prefix = "plane-fixed-matrix-lut1d",
+		  .fb_colors = colors_rgb,
+		  .colorops = { &fixed_matrix_yuv709_rgb709, &lut1d_linear, NULL },
+		  .input_format = DRM_FORMAT_YUYV,
+		  .encoding = IGT_COLOR_YCBCR_BT709,
+		  .range = IGT_COLOR_YCBCR_FULL_RANGE,
+		},
+		{ .name = "yuv2020-rgb2020",
+		  .subtest_prefix = "plane-fixed-matrix-lut1d",
+		  .fb_colors = colors_rgb,
+		  .colorops = { &fixed_matrix_yuv2020_rgb2020, &lut1d_linear, NULL },
+		  .input_format = DRM_FORMAT_YUYV,
+		  .encoding = IGT_COLOR_YCBCR_BT2020,
+		  .range = IGT_COLOR_YCBCR_FULL_RANGE,
+		},
+		{ .name = "rgb709-rgb2020",
+		  .subtest_prefix = "plane-lut1d-fixed-matrix-lut1d",
+		  .fb_colors = colors_rgb,
+		  .colorops = { &lut1d_linear, &fixed_matrix_rgb709_rgb2020, &lut1d_linear, NULL },
+		  .input_format = DRM_FORMAT_XRGB8888,
+		},
+		{ .name = "yuv-lim",
+		  .subtest_prefix = "plane-yuv-range-correct",
+		  .fb_colors = colors_rgb,
+		  .colorops = { &fixed_matrix_ycbcr_limited_full, NULL },
+		  .input_format = DRM_FORMAT_YUYV,
+		  .encoding = IGT_COLOR_YCBCR_BT709,
+		  .range = IGT_COLOR_YCBCR_LIMITED_RANGE,
+		},
+		{ .name = "bt601-yuv-lim",
+		  .subtest_prefix = "plane-yuv-range-correct-fixed-matrix",
+		  .fb_colors = colors_rgb,
+		  .colorops = { &fixed_matrix_ycbcr_limited_full, &fixed_matrix_yuv601_rgb601, NULL },
+		  .input_format = DRM_FORMAT_YUYV,
+		  .encoding = IGT_COLOR_YCBCR_BT601,
+		  .range = IGT_COLOR_YCBCR_LIMITED_RANGE,
+		},
+		{ .name = "bt709-yuv-lim",
+		  .subtest_prefix = "plane-yuv-range-correct-fixed-matrix",
+		  .fb_colors = colors_rgb,
+		  .colorops = { &fixed_matrix_ycbcr_limited_full, &fixed_matrix_yuv709_rgb709, NULL },
+		  .input_format = DRM_FORMAT_YUYV,
+		  .encoding = IGT_COLOR_YCBCR_BT709,
+		  .range = IGT_COLOR_YCBCR_LIMITED_RANGE,
+		},
+		{ .name = "bt2020-yuv-lim",
+		  .subtest_prefix = "plane-yuv-range-correct-fixed-matrix",
+		  .fb_colors = colors_rgb,
+		  .colorops = { &fixed_matrix_ycbcr_limited_full, &fixed_matrix_yuv2020_rgb2020, NULL },
+		  .input_format = DRM_FORMAT_YUYV,
+		  .encoding = IGT_COLOR_YCBCR_BT2020,
+		  .range = IGT_COLOR_YCBCR_LIMITED_RANGE,
+		},
+	};
+
+	for (int i = 0; i < ARRAY_SIZE(fixed_matrix_tests); i++) {
+		igt_describe_f("Test FIXED_MATRIX pipeline: %s-%s",
+			       fixed_matrix_tests[i].subtest_prefix,
+			       fixed_matrix_tests[i].name);
+		igt_subtest_with_dynamic_f("%s-%s",
+					   fixed_matrix_tests[i].subtest_prefix,
+					   fixed_matrix_tests[i].name) {
+			for_each_crtc_with_single_output(&data->display, crtc,
+							 output) {
+				data->output = output;
+
+				if (!crtc_output_combo_valid(data, crtc))
+					continue;
+
+				test_setup(data, crtc);
+
+				test_plane_fixed_matrix_colorops(data, crtc,
+								 fixed_matrix_tests[i].fb_colors,
+								 fixed_matrix_tests[i].colorops,
+								 fixed_matrix_tests[i].input_format,
+								 fixed_matrix_tests[i].encoding,
+								 fixed_matrix_tests[i].range);
+				test_cleanup(data);
+			}
+		}
+	}
+}
+
 int igt_main()
 {
 	data_t data = {};
@@ -372,6 +751,9 @@ int igt_main()
 	igt_subtest_group()
 		run_tests_for_plane(&data);
 
+	igt_subtest_group()
+		run_tests_for_fixed_matrix(&data);
+
 	igt_fixture() {
 		igt_display_fini(&data.display);
 		drm_close_driver(data.drm_fd);
-- 
2.25.1


  parent reply	other threads:[~2026-07-27 18:49 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-27 18:55 [PATCH i-g-t 0/6] Add FIXED_MATRIX colorop tests Swati Sharma
2026-07-27 18:55 ` [PATCH i-g-t 1/6] include/drm-uapi: Add DRM_COLOROP_FIXED_MATRIX definition Swati Sharma
2026-07-27 18:55 ` [PATCH i-g-t 2/6] lib/igt_kms: Add FIXED_MATRIX_TYPE colorop property Swati Sharma
2026-07-27 18:55 ` [PATCH i-g-t 3/6] tests/kms_colorop_helper: Add FIXED_MATRIX colorop support Swati Sharma
2026-07-27 18:55 ` Swati Sharma [this message]
2026-07-27 18:55 ` [PATCH i-g-t 5/6] tests/kms_color_pipeline: Remove unused color_depth and drm_format Swati Sharma
2026-07-27 18:55 ` [PATCH i-g-t 6/6] tests/kms_chamelium_color_pipeline: Add FIXED_MATRIX colorop tests Swati Sharma
2026-07-27 20:59 ` ✓ Xe.CI.BAT: success for Add FIXED_MATRIX colorop tests (rev2) Patchwork
2026-07-27 21:00 ` ✓ i915.CI.BAT: " Patchwork
2026-07-28  0:45 ` ✗ Xe.CI.FULL: failure " Patchwork
2026-07-28  4:38 ` ✗ i915.CI.Full: " 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=20260727185531.4046807-5-swati2.sharma@intel.com \
    --to=swati2.sharma@intel.com \
    --cc=igt-dev@lists.freedesktop.org \
    /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