All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
To: igt-dev@lists.freedesktop.org
Subject: [igt-dev] [PATCH i-g-t v2 4/4] tests/amdgpu: Add HDR tests for amdgpu
Date: Thu, 25 Jul 2019 12:55:29 -0400	[thread overview]
Message-ID: <20190725165529.25775-4-nicholas.kazlauskas@amd.com> (raw)
In-Reply-To: <20190725165529.25775-1-nicholas.kazlauskas@amd.com>

Tests various HDR10 usecases, such as:

- Transitions between 8bpc and 10bpc
- Transitions between SDR and HDR
- Fast static metadata switches
- Display level verification for infoframes using a luminance sensor

The tests require the "output_bpc" debugfs entry to read current
and maximum bpc.

v2: rebase

Cc: Harry Wentland <harry.wentland@amd.com>
Cc: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
---
 tests/Makefile.sources   |   1 +
 tests/amdgpu/amd_hdr.c   | 703 +++++++++++++++++++++++++++++++++++++++
 tests/amdgpu/meson.build |   1 +
 3 files changed, 705 insertions(+)
 create mode 100644 tests/amdgpu/amd_hdr.c

diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 250dbd33..3a81a8ff 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -9,6 +9,7 @@ AMDGPU_TESTS = \
 	amdgpu/amd_bypass \
 	amdgpu/amd_color \
 	amdgpu/amd_cs_nop \
+	amdgpu/amd_hdr \
 	amdgpu/amd_prime \
 	amdgpu/amd_abm \
 	$(NULL)
diff --git a/tests/amdgpu/amd_hdr.c b/tests/amdgpu/amd_hdr.c
new file mode 100644
index 00000000..56eea547
--- /dev/null
+++ b/tests/amdgpu/amd_hdr.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright 2019 Advanced Micro Devices, Inc.
+ *
+ * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 <fcntl.h>
+#include <termios.h>
+#include <unistd.h>
+
+/* DRM HDR definitions. Not in the UAPI header, unfortunately. */
+
+enum hdmi_metadata_type {
+	HDMI_STATIC_METADATA_TYPE1 = 1,
+};
+
+enum hdmi_eotf {
+	HDMI_EOTF_TRADITIONAL_GAMMA_SDR,
+	HDMI_EOTF_TRADITIONAL_GAMMA_HDR,
+	HDMI_EOTF_SMPTE_ST2084,
+};
+
+/* Test flags. */
+enum {
+	TEST_NONE = 0,
+	TEST_DPMS = 1 << 0,
+	TEST_SUSPEND = 1 << 1,
+};
+
+/* BPC connector state. */
+typedef struct output_bpc {
+	unsigned int current;
+	unsigned int maximum;
+} output_bpc_t;
+
+/* Common test data. */
+typedef struct data {
+	igt_display_t display;
+	igt_plane_t *primary;
+	igt_output_t *output;
+	igt_pipe_t *pipe;
+	igt_pipe_crc_t *pipe_crc;
+	drmModeModeInfo *mode;
+	enum pipe pipe_id;
+	int fd;
+	int sensor_fd;
+	int w;
+	int h;
+} data_t;
+
+/* Converts a double to 861-G spec FP format. */
+static uint16_t calc_hdr_float(double val)
+{
+	return (uint16_t)(val * 50000.0);
+}
+
+/* PQ Inverse, L normalized luminance to signal value V. */
+static double calc_pq_inverse(double l)
+{
+	double c1 = 0.8359375;
+	double c2 = 18.8515625;
+	double c3 = 18.6875;
+	double m1 = 0.1593017578125;
+	double m2 = 78.84375;
+	double lm = pow(l, m1);
+
+	return pow((c1 + c2 * lm) / (1.0 + c3 * lm), m2);
+}
+
+/* Asserts that two given values in nits are equal within a given threshold. */
+static void assert_nits_equal(double n0, double n1, double threshold)
+{
+	double diff = fabs(n0 - n1);
+
+	igt_assert_f(diff <= threshold,
+		     "Nits not in threshold: | %.3f - %.3f | > %.3f\n",
+		     n0, n1, threshold);
+}
+
+/* Fills some test values for HDR metadata targeting SDR. */
+static void fill_hdr_output_metadata_sdr(struct hdr_output_metadata *meta)
+{
+	memset(meta, 0, sizeof(*meta));
+
+	meta->metadata_type = HDMI_STATIC_METADATA_TYPE1;
+	meta->hdmi_metadata_type1.eotf = HDMI_EOTF_TRADITIONAL_GAMMA_SDR;
+
+	/* Rec. 709 */
+	meta->hdmi_metadata_type1.display_primaries[0].x =
+		calc_hdr_float(0.640); /* Red */
+	meta->hdmi_metadata_type1.display_primaries[0].y =
+		calc_hdr_float(0.330);
+	meta->hdmi_metadata_type1.display_primaries[1].x =
+		calc_hdr_float(0.300); /* Green */
+	meta->hdmi_metadata_type1.display_primaries[1].y =
+		calc_hdr_float(0.600);
+	meta->hdmi_metadata_type1.display_primaries[2].x =
+		calc_hdr_float(0.150); /* Blue */
+	meta->hdmi_metadata_type1.display_primaries[2].y =
+		calc_hdr_float(0.006);
+	meta->hdmi_metadata_type1.white_point.x = calc_hdr_float(0.3127);
+	meta->hdmi_metadata_type1.white_point.y = calc_hdr_float(0.3290);
+
+	meta->hdmi_metadata_type1.max_display_mastering_luminance = 0;
+	meta->hdmi_metadata_type1.min_display_mastering_luminance = 0;
+	meta->hdmi_metadata_type1.max_fall = 0;
+	meta->hdmi_metadata_type1.max_cll = 0;
+}
+
+/* Fills some test values for ST2048 HDR output metadata.
+ *
+ * Note: there isn't really a standard for what the metadata is supposed
+ * to do on the display side of things. The display is free to ignore it
+ * and clip the output, use it to help tonemap to the content range,
+ * or do anything they want, really.
+ */
+static void fill_hdr_output_metadata_st2048(struct hdr_output_metadata *meta)
+{
+	memset(meta, 0, sizeof(*meta));
+
+	meta->metadata_type = HDMI_STATIC_METADATA_TYPE1;
+	meta->hdmi_metadata_type1.eotf = HDMI_EOTF_SMPTE_ST2084;
+
+	/* Rec. 2020 */
+	meta->hdmi_metadata_type1.display_primaries[0].x =
+		calc_hdr_float(0.708); /* Red */
+	meta->hdmi_metadata_type1.display_primaries[0].y =
+		calc_hdr_float(0.292);
+	meta->hdmi_metadata_type1.display_primaries[1].x =
+		calc_hdr_float(0.170); /* Green */
+	meta->hdmi_metadata_type1.display_primaries[1].y =
+		calc_hdr_float(0.797);
+	meta->hdmi_metadata_type1.display_primaries[2].x =
+		calc_hdr_float(0.131); /* Blue */
+	meta->hdmi_metadata_type1.display_primaries[2].y =
+		calc_hdr_float(0.046);
+	meta->hdmi_metadata_type1.white_point.x = calc_hdr_float(0.3127);
+	meta->hdmi_metadata_type1.white_point.y = calc_hdr_float(0.3290);
+
+	meta->hdmi_metadata_type1.max_display_mastering_luminance =
+		1000; /* 1000 nits */
+	meta->hdmi_metadata_type1.min_display_mastering_luminance =
+		500;				   /* 0.05 nits */
+	meta->hdmi_metadata_type1.max_fall = 1000; /* 1000 nits */
+	meta->hdmi_metadata_type1.max_cll = 500;   /* 500 nits */
+}
+
+/* Sets the HDR output metadata prop. */
+static void set_hdr_output_metadata(data_t *data,
+				    struct hdr_output_metadata const *meta)
+{
+	igt_output_replace_prop_blob(data->output,
+				     IGT_CONNECTOR_HDR_OUTPUT_METADATA, meta,
+				     meta ? sizeof(*meta) : 0);
+}
+
+/* Common test setup. */
+static void test_init(data_t *data)
+{
+	igt_display_t *display = &data->display;
+
+	/* It doesn't matter which pipe we choose on amdpgu. */
+	data->pipe_id = PIPE_A;
+	data->pipe = &data->display.pipes[data->pipe_id];
+
+	igt_display_reset(display);
+
+	/*
+	 * TODO: Look for an output that is HDR capable and favor that.
+	 * But for now just assume that the first connected display supports
+	 * HDR and 10bpc.
+	 */
+	data->output = igt_get_single_output_for_pipe(display, data->pipe_id);
+	igt_require(data->output);
+	igt_require(igt_output_has_prop(data->output, IGT_CONNECTOR_MAX_BPC));
+
+	data->mode = igt_output_get_mode(data->output);
+	igt_assert(data->mode);
+
+	data->primary =
+		igt_pipe_get_plane_type(data->pipe, DRM_PLANE_TYPE_PRIMARY);
+
+	data->pipe_crc = igt_pipe_crc_new(data->fd, data->pipe_id,
+					  INTEL_PIPE_CRC_SOURCE_AUTO);
+
+	igt_output_set_pipe(data->output, data->pipe_id);
+
+	data->w = data->mode->hdisplay;
+	data->h = data->mode->vdisplay;
+	data->sensor_fd = -1;
+}
+
+/* Common test cleanup. */
+static void test_fini(data_t *data)
+{
+	close(data->sensor_fd);
+	igt_pipe_crc_free(data->pipe_crc);
+	igt_display_reset(&data->display);
+}
+
+static void test_cycle_flags(data_t *data, uint32_t test_flags)
+{
+
+	if (test_flags & TEST_DPMS) {
+		kmstest_set_connector_dpms(data->fd,
+					   data->output->config.connector,
+					   DRM_MODE_DPMS_OFF);
+		kmstest_set_connector_dpms(data->fd,
+					   data->output->config.connector,
+					   DRM_MODE_DPMS_ON);
+	}
+
+	if (test_flags & TEST_SUSPEND)
+		igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
+					      SUSPEND_TEST_NONE);
+}
+
+/* Returns the current and maximum bpc from the connector debugfs. */
+static output_bpc_t get_output_bpc(data_t *data)
+{
+	char buf[256];
+	char *start_loc;
+	int fd, res;
+	output_bpc_t info;
+
+	fd = igt_debugfs_connector_dir(data->fd, data->output->name, O_RDONLY);
+	igt_assert(fd >= 0);
+
+	res = igt_debugfs_simple_read(fd, "output_bpc", buf, sizeof(buf));
+	igt_require(res > 0);
+
+	close(fd);
+
+	igt_assert(start_loc = strstr(buf, "Current: "));
+	igt_assert_eq(sscanf(start_loc, "Current: %u", &info.current), 1);
+
+	igt_assert(start_loc = strstr(buf, "Maximum: "));
+	igt_assert_eq(sscanf(start_loc, "Maximum: %u", &info.maximum), 1);
+
+	return info;
+}
+
+/* Verifies that connector has the correct output bpc. */
+static void assert_output_bpc(data_t *data, unsigned int bpc)
+{
+	output_bpc_t info = get_output_bpc(data);
+
+	igt_require_f(info.maximum >= bpc,
+		      "Monitor doesn't support %u bpc, max is %u\n", bpc,
+		      info.maximum);
+
+	igt_assert_eq(info.current, bpc);
+}
+
+/*
+ * Loads the sensor if unloaded. The sensor is a serial to USB interface that
+ * prints the current measured luminance (nits) as a float, separated by a
+ * newline. Uses baudrate 9600.
+ */
+static void open_sensor(data_t *data)
+{
+	struct termios toptions;
+	int res;
+
+	/* Return if already loaded. */
+	if (data->sensor_fd >= 0)
+		return;
+
+	data->sensor_fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
+	if (data->sensor_fd < 0) {
+		igt_info("Luminance sensor not found.\n");
+		return;
+	}
+
+	res = tcgetattr(data->sensor_fd, &toptions);
+	igt_assert_lte(0, res);
+
+	cfsetispeed(&toptions, B9600);
+	cfsetospeed(&toptions, B9600);
+
+	toptions.c_cflag &= ~(PARENB | CSTOPB | CSIZE);
+	toptions.c_cflag |= (CS8 | CREAD | CLOCAL);
+	toptions.c_lflag |= ICANON;
+
+	cfmakeraw(&toptions);
+
+	res = tcsetattr(data->sensor_fd, TCSANOW, &toptions);
+	igt_assert_lte(0, res);
+
+	res = tcsetattr(data->sensor_fd, TCSAFLUSH, &toptions);
+	igt_assert_lte(0, res);
+}
+
+/* Reads a string from the sensor. */
+static void get_sensor_str(data_t *data, char *dst, int dst_bytes)
+{
+	char c = 0;
+	int i = 0;
+
+	igt_require(data->sensor_fd >= 0);
+	igt_set_timeout(3, "Waiting for sensor read\n");
+
+	dst_bytes -= 1;
+
+	while (c != '\n' && i < dst_bytes) {
+		int n = read(data->sensor_fd, &c, 1);
+		igt_assert_lte(0, n);
+
+		dst[i++] = c;
+	}
+
+	igt_reset_timeout();
+
+	if (dst_bytes > 0) {
+		dst[i] = 0;
+	}
+}
+
+/* Returns the current luminance reading from the sensor in cd/m^2. */
+static float get_sensor_nits(data_t *data)
+{
+	float nits = -1.0f;
+	char buf[32];
+
+	/* Sensor opening is deferred until we actually need it - here. */
+	open_sensor(data);
+
+	/* Flush old data from the buffer in case it's been a while. */
+	igt_require(data->sensor_fd >= 0);
+	tcflush(data->sensor_fd, TCIOFLUSH);
+
+	/* Read twice so we get a clean line. */
+	get_sensor_str(data, buf, ARRAY_SIZE(buf));
+	get_sensor_str(data, buf, ARRAY_SIZE(buf));
+
+	sscanf(buf, "%f", &nits);
+
+	return nits;
+}
+
+/* Logs the cursor sensor nits. */
+static void log_sensor_nits(double nits)
+{
+	igt_info("Sensor: %.3f nits\n", nits);
+}
+
+/*
+ * Waits for the monitor to light-up to a given threshold, useful for
+ * post-modeset measurement.
+ */
+static void wait_for_threshold(data_t *data, double threshold)
+{
+	/*
+	 * If we read too quick the sensor might still be lit up.
+	 * Easy hack: just wait a second.
+	 */
+	sleep(1);
+
+	/* Poll sensor until lightup. */
+	igt_set_timeout(5, "Waiting for sensor read\n");
+
+	for (;;) {
+		double nits = get_sensor_nits(data);
+
+		if (nits >= threshold)
+			break;
+	}
+
+	igt_reset_timeout();
+}
+
+/* Skips the test if the output isn't HDR. */
+static void test_require_hdr(data_t *data)
+{
+	igt_require(igt_output_has_prop(data->output,
+					IGT_CONNECTOR_HDR_OUTPUT_METADATA));
+}
+
+/* Fills the FB with a solid color given mapping to a light value in nits. */
+static void draw_light(igt_fb_t *fb, double nits)
+{
+	cairo_t *cr;
+	double l, v;
+	int x, y, w, h;
+
+	cr = igt_get_cairo_ctx(fb->fd, fb);
+
+	l = nits / 10000.0;
+	v = calc_pq_inverse(l);
+
+	/*
+	 * Draw a white rect in the bottom center of the screen for the sensor.
+	 * It's only 10% of the width and height of the screen since not every
+	 * monitor is capable of full HDR brightness for the whole screen.
+	 */
+	w = fb->width * 0.10;
+	h = fb->height * 0.10;
+	x = (fb->width - w) / 2;
+	y = (fb->height - h);
+
+	igt_paint_color(cr, 0, 0, fb->width, fb->height, 0.0, 0.0, 0.0);
+	igt_paint_color(cr, x, y, w, h, v, v, v);
+
+	igt_put_cairo_ctx(fb->fd, fb, cr);
+}
+
+/* Fills the FB with a test HDR pattern. */
+static void draw_hdr_pattern(igt_fb_t *fb)
+{
+	cairo_t *cr = igt_get_cairo_ctx(fb->fd, fb);
+
+	igt_paint_color(cr, 0, 0, fb->width, fb->height, 1.0, 1.0, 1.0);
+	igt_paint_test_pattern(cr, fb->width, fb->height);
+
+	igt_put_cairo_ctx(fb->fd, fb, cr);
+}
+
+/*
+ * Validates switching between different display output bpc modes.
+ * TODO: Hook up a debugfs entry to verify driver behavior beyond
+ * just checking if the commits succeeded.
+ */
+static void test_bpc_switch(data_t *data, uint32_t flags)
+{
+	igt_display_t *display = &data->display;
+	igt_crc_t ref_crc, new_crc;
+	igt_fb_t afb;
+
+	test_init(data);
+
+        /* 10-bit formats are slow, so limit the size. */
+        igt_create_fb(data->fd, 512, 512, DRM_FORMAT_XRGB2101010, 0, &afb);
+	draw_hdr_pattern(&afb);
+
+        /* Start in 8bpc. */
+	igt_plane_set_fb(data->primary, &afb);
+	igt_plane_set_size(data->primary, data->w, data->h);
+	igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 8);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	assert_output_bpc(data, 8);
+
+        /* Switch to 10bpc. */
+        igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 10);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	assert_output_bpc(data, 10);
+
+	/* Verify that the CRC are equal after DPMS or suspend. */
+	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
+	test_cycle_flags(data, flags);
+	igt_pipe_crc_collect_crc(data->pipe_crc, &new_crc);
+
+        /* Drop back to 8bpc. */
+	igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 8);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	assert_output_bpc(data, 8);
+
+	/* CRC capture is clamped to 8bpc, so capture should match. */
+	igt_assert_crc_equal(&ref_crc, &new_crc);
+
+	test_fini(data);
+        igt_remove_fb(data->fd, &afb);
+}
+
+/* Tests swapping static HDR metadata. */
+static void test_static_swap(data_t *data)
+{
+	igt_display_t *display = &data->display;
+	igt_crc_t ref_crc, new_crc;
+	igt_fb_t afb;
+	struct hdr_output_metadata hdr;
+
+	test_init(data);
+	test_require_hdr(data);
+
+	/* 10-bit formats are slow, so limit the size. */
+	igt_create_fb(data->fd, 512, 512, DRM_FORMAT_XRGB2101010, 0, &afb);
+	draw_hdr_pattern(&afb);
+
+	/* Start in SDR. */
+	igt_plane_set_fb(data->primary, &afb);
+	igt_plane_set_size(data->primary, data->w, data->h);
+	igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 8);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	assert_output_bpc(data, 8);
+
+	/* Enter HDR, a modeset is allowed here. */
+	fill_hdr_output_metadata_st2048(&hdr);
+	set_hdr_output_metadata(data, &hdr);
+	igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 10);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	assert_output_bpc(data, 10);
+
+	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
+
+	/* Change the mastering information, no modeset allowed. */
+	hdr.hdmi_metadata_type1.max_display_mastering_luminance = 200;
+	hdr.hdmi_metadata_type1.max_fall = 200;
+	hdr.hdmi_metadata_type1.max_cll = 100;
+
+	set_hdr_output_metadata(data, &hdr);
+	igt_display_commit_atomic(display, 0, NULL);
+
+	/* Enter SDR via metadata, no modeset allowed. */
+	fill_hdr_output_metadata_sdr(&hdr);
+	set_hdr_output_metadata(data, &hdr);
+	igt_display_commit_atomic(display, 0, NULL);
+
+	igt_pipe_crc_collect_crc(data->pipe_crc, &new_crc);
+
+	/* Exit SDR and enter 8bpc, cleanup. */
+	set_hdr_output_metadata(data, NULL);
+	igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 8);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	assert_output_bpc(data, 8);
+
+	/* Verify that the CRC didn't change while cycling metadata. */
+	igt_assert_crc_equal(&ref_crc, &new_crc);
+
+	test_fini(data);
+	igt_remove_fb(data->fd, &afb);
+}
+
+/*
+ * Tests that setting the static metadata actually enters HDR mode.
+ *
+ * Note: This test is display specific in the sense that it requries
+ * a display that is capable of going above SDR brightness levels.
+ * Most HDR400 or higher certified displays should be capable of this.
+ *
+ * Some displays may require first limiting the output brightness
+ * in the OSD for this to work.
+ *
+ * Requires the luminance sensor to be attached to the test machine.
+ */
+static void test_static_output(data_t *data)
+{
+	igt_display_t *display = &data->display;
+	igt_fb_t afb;
+	struct hdr_output_metadata hdr;
+	double lightup = 100.0;
+	double threshold = 15.0;
+	double nits_sdr0, nits_sdr1, nits_sdr2, nits_hdr;
+
+	test_init(data);
+	test_require_hdr(data);
+
+	igt_create_fb(data->fd, data->w, data->h, DRM_FORMAT_XRGB2101010, 0, &afb);
+	draw_light(&afb, 10000.0);
+
+	igt_info("Test SDR, 8bpc\n");
+	igt_plane_set_fb(data->primary, &afb);
+	igt_plane_set_size(data->primary, data->w, data->h);
+	igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 8);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	assert_output_bpc(data, 8);
+
+	wait_for_threshold(data, lightup);
+	nits_sdr0 = get_sensor_nits(data);
+	log_sensor_nits(nits_sdr0);
+
+	igt_info("Test SDR, 10bpc\n");
+	igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 10);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	assert_output_bpc(data, 10);
+
+	wait_for_threshold(data, lightup);
+	nits_sdr1 = get_sensor_nits(data);
+	log_sensor_nits(nits_sdr1);
+
+	igt_info("Test HDR, 10bpc\n");
+	fill_hdr_output_metadata_st2048(&hdr);
+	set_hdr_output_metadata(data, &hdr);
+	igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 10);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+
+	wait_for_threshold(data, lightup);
+	nits_hdr = get_sensor_nits(data);
+	log_sensor_nits(nits_hdr);
+
+	igt_info("Exit HDR into SDR, 8bpc\n");
+	set_hdr_output_metadata(data, NULL);
+	igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 8);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	assert_output_bpc(data, 8);
+
+	wait_for_threshold(data, lightup);
+	nits_sdr2 = get_sensor_nits(data);
+	log_sensor_nits(nits_sdr2);
+
+	/* Verify that all nit values were as expected. */
+	assert_nits_equal(nits_sdr0, nits_sdr1, threshold);
+	assert_nits_equal(nits_sdr0, nits_sdr2, threshold);
+
+	igt_assert_f(nits_hdr - nits_sdr0 > threshold * 2.0,
+		     "No measurable difference between SDR and HDR luminance: "
+		     "threshold=%.1f actual=%.1f\n",
+		     threshold * 2.0, nits_hdr - nits_sdr0);
+
+	test_fini(data);
+	igt_remove_fb(data->fd, &afb);
+}
+
+/* Tests entering and exiting HDR mode. */
+static void test_static_toggle(data_t *data, uint32_t flags)
+{
+	igt_display_t *display = &data->display;
+	igt_crc_t ref_crc, new_crc;
+	igt_fb_t afb;
+	struct hdr_output_metadata hdr;
+
+	test_init(data);
+	test_require_hdr(data);
+
+        /* 10-bit formats are slow, so limit the size. */
+	igt_create_fb(data->fd, 512, 512, DRM_FORMAT_XRGB2101010, 0, &afb);
+	draw_hdr_pattern(&afb);
+
+	fill_hdr_output_metadata_st2048(&hdr);
+
+        /* Start with no metadata. */
+	igt_plane_set_fb(data->primary, &afb);
+	igt_plane_set_size(data->primary, data->w, data->h);
+	set_hdr_output_metadata(data, NULL);
+	igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 8);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	assert_output_bpc(data, 8);
+
+        /* Apply HDR metadata and 10bpc. We expect a modeset for entering. */
+	set_hdr_output_metadata(data, &hdr);
+        igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 10);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	assert_output_bpc(data, 10);
+
+	/* Verify that the CRC are equal after DPMS or suspend. */
+	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
+	test_cycle_flags(data, flags);
+	igt_pipe_crc_collect_crc(data->pipe_crc, &new_crc);
+
+        /* Disable HDR metadata and drop back to 8bpc. We expect a modeset for exiting. */
+	set_hdr_output_metadata(data, NULL);
+	igt_output_set_prop_value(data->output, IGT_CONNECTOR_MAX_BPC, 8);
+	igt_display_commit_atomic(display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	assert_output_bpc(data, 8);
+
+	igt_assert_crc_equal(&ref_crc, &new_crc);
+
+	test_fini(data);
+	igt_remove_fb(data->fd, &afb);
+}
+
+igt_main
+{
+	data_t data;
+
+	igt_skip_on_simulation();
+
+	memset(&data, 0, sizeof(data));
+
+	igt_fixture
+	{
+		data.fd = drm_open_driver_master(DRIVER_AMDGPU);
+
+		kmstest_set_vt_graphics_mode();
+
+		igt_display_require(&data.display, data.fd);
+		igt_require(data.display.is_atomic);
+		igt_display_require_output(&data.display);
+	}
+
+	igt_subtest("bpc-switch") test_bpc_switch(&data, 0);
+	igt_subtest("bpc-switch-dpms") test_bpc_switch(&data, TEST_DPMS);
+	igt_subtest("bpc-switch-suspend") test_bpc_switch(&data, TEST_SUSPEND);
+
+	igt_subtest("static-output") test_static_output(&data);
+	igt_subtest("static-swap") test_static_swap(&data);
+
+	igt_subtest("static-toggle") test_static_toggle(&data, 0);
+	igt_subtest("static-toggle-dpms") test_static_toggle(&data, TEST_DPMS);
+	igt_subtest("static-toggle-suspend")
+		test_static_toggle(&data, TEST_SUSPEND);
+
+	igt_fixture
+	{
+		igt_display_fini(&data.display);
+	}
+}
diff --git a/tests/amdgpu/meson.build b/tests/amdgpu/meson.build
index b7982291..6c6b7feb 100644
--- a/tests/amdgpu/meson.build
+++ b/tests/amdgpu/meson.build
@@ -7,6 +7,7 @@ if libdrm_amdgpu.found()
 			  'amd_bypass',
 			  'amd_color',
 			  'amd_cs_nop',
+			  'amd_hdr',
 			  'amd_prime',
 			]
 	amdgpu_deps += libdrm_amdgpu
-- 
2.17.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

  parent reply	other threads:[~2019-07-25 16:55 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-25 16:55 [igt-dev] [PATCH i-g-t v2 1/4] headers: Bump drm uapi headers Nicholas Kazlauskas
2019-07-25 16:55 ` [igt-dev] [PATCH i-g-t v2 2/4] lib/igt_kms: Add max bpc connector property Nicholas Kazlauskas
2019-07-25 16:55 ` [igt-dev] [PATCH i-g-t v2 3/4] lib/igt_kms: Add HDR_OUTPUT_METADATA " Nicholas Kazlauskas
2019-07-25 16:55 ` Nicholas Kazlauskas [this message]
2019-07-25 17:10 ` [igt-dev] ✗ GitLab.Pipeline: warning for series starting with [i-g-t,v2,1/4] headers: Bump drm uapi headers Patchwork
2019-07-25 17:26 ` [igt-dev] ✗ Fi.CI.BAT: failure " 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=20190725165529.25775-4-nicholas.kazlauskas@amd.com \
    --to=nicholas.kazlauskas@amd.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.