[igt-dev] [PATCH i-g-t v2] tests/kms_writeback: Enhance kms_writeback for custom modes
Rohith Iyer
quic_rohiiyer at quicinc.com
Thu Jun 23 01:30:03 UTC 2022
Enhance kms_writeback to add support for the below options:
- View all writeback modes
Usage: "./kms_writeback --list-modes"
- Test a standard mode from connector list
Usage: "./kms_writeback --standard <mode_index>"
- Test a custom mode from user input
Usage: "./kms_writeback --custom <mode_parameters>"
Refer to --help for exact syntax
- Dump the writeback output buffer to png file
Usage: "./kms_writeback --dump"
Changes made in V2:
- Removed variable redeclaration
- Changed sscanf format types
Signed-off-by: Rohith Iyer <quic_rohiiyer at quicinc.com>
---
tests/kms_writeback.c | 183 +++++++++++++++++++++++++++++++++++++-----
1 file changed, 161 insertions(+), 22 deletions(-)
diff --git a/tests/kms_writeback.c b/tests/kms_writeback.c
index 6efc72df..4f343b48 100644
--- a/tests/kms_writeback.c
+++ b/tests/kms_writeback.c
@@ -26,11 +26,13 @@
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
+#include <limits.h>
#include "igt.h"
#include "igt_core.h"
#include "igt_fb.h"
#include "sw_sync.h"
+#include "igt_chamelium.h"
IGT_TEST_DESCRIPTION(
"This test validates the expected behavior of the writeback connectors "
@@ -39,6 +41,17 @@ IGT_TEST_DESCRIPTION(
"by using CRC."
);
+typedef struct {
+ bool standard_mode;
+ bool custom_mode;
+ bool list_modes;
+ bool dump_check;
+ int mode_index;
+ drmModeModeInfo user_mode;
+} data_t;
+
+static data_t data;
+
static drmModePropertyBlobRes *get_writeback_formats_blob(igt_output_t *output)
{
drmModePropertyBlobRes *blob = NULL;
@@ -58,29 +71,15 @@ static drmModePropertyBlobRes *get_writeback_formats_blob(igt_output_t *output)
return blob;
}
-static bool check_writeback_config(igt_display_t *display, igt_output_t *output)
+static bool check_writeback_config(igt_display_t *display, igt_output_t *output,
+ drmModeModeInfo override_mode)
{
igt_fb_t input_fb, output_fb;
igt_plane_t *plane;
uint32_t writeback_format = DRM_FORMAT_XRGB8888;
uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
int width, height, ret;
- drmModeModeInfo override_mode = {
- .clock = 25175,
- .hdisplay = 640,
- .hsync_start = 656,
- .hsync_end = 752,
- .htotal = 800,
- .hskew = 0,
- .vdisplay = 480,
- .vsync_start = 490,
- .vsync_end = 492,
- .vtotal = 525,
- .vscan = 0,
- .vrefresh = 60,
- .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
- .name = {"640x480-60"},
- };
+
igt_output_override_mode(output, &override_mode);
width = override_mode.hdisplay;
@@ -109,8 +108,25 @@ static bool check_writeback_config(igt_display_t *display, igt_output_t *output)
static igt_output_t *kms_writeback_get_output(igt_display_t *display)
{
- int i;
enum pipe pipe;
+ int i;
+
+ drmModeModeInfo override_mode = {
+ .clock = 25175,
+ .hdisplay = 640,
+ .hsync_start = 656,
+ .hsync_end = 752,
+ .htotal = 800,
+ .hskew = 0,
+ .vdisplay = 480,
+ .vsync_start = 490,
+ .vsync_end = 492,
+ .vtotal = 525,
+ .vscan = 0,
+ .vrefresh = 60,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ .name = {"640x480-60"},
+ };
for (i = 0; i < display->n_outputs; i++) {
igt_output_t *output = &display->outputs[i];
@@ -121,7 +137,12 @@ static igt_output_t *kms_writeback_get_output(igt_display_t *display)
for_each_pipe(display, pipe) {
igt_output_set_pipe(output, pipe);
- if (check_writeback_config(display, output)) {
+ if (data.custom_mode)
+ override_mode = data.user_mode;
+ if (data.standard_mode)
+ override_mode = output->config.connector->modes[data.mode_index];
+
+ if (check_writeback_config(display, output, override_mode)) {
igt_debug("Using connector %u:%s on pipe %d\n",
output->config.connector->connector_id,
output->name, pipe);
@@ -347,7 +368,114 @@ static void writeback_check_output(igt_output_t *output, igt_plane_t *plane,
igt_remove_fb(output_fb->fd, &second_out_fb);
}
-igt_main
+static void do_single_commit(igt_output_t *output, igt_plane_t *plane, igt_fb_t *in_fb,
+ igt_fb_t *out_fb)
+{
+ uint32_t in_fb_color = 0xffff0000;
+
+ fill_fb(in_fb, in_fb_color);
+
+ igt_plane_set_fb(plane, in_fb);
+ igt_output_set_writeback_fb(output, out_fb);
+
+ igt_display_commit_atomic(output->display, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+ if (out_fb)
+ get_and_wait_out_fence(output);
+}
+
+static void commit_and_dump_fb(igt_display_t *display, igt_output_t *output, igt_plane_t *plane,
+ igt_fb_t *input_fb, drmModeModeInfo *mode)
+{
+ cairo_surface_t *fb_surface_out;
+ char filename_out[PATH_MAX];
+ cairo_status_t status;
+ char *id;
+ unsigned int fb_id;
+ igt_fb_t output_fb;
+
+ id = getenv("IGT_FRAME_DUMP_PATH");
+ fb_id = igt_create_fb(display->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
+ igt_fb_mod_to_tiling(0), &output_fb);
+ igt_require(fb_id > 0);
+
+ do_single_commit(output, plane, input_fb, &output_fb);
+
+ fb_surface_out = igt_get_cairo_surface(display->drm_fd, &output_fb);
+ snprintf(filename_out, PATH_MAX, "%s/%s.png", id, "frame-out");
+ status = cairo_surface_write_to_png(fb_surface_out, filename_out);
+ igt_assert_eq(status, CAIRO_STATUS_SUCCESS);
+
+ igt_remove_fb(display->drm_fd, &output_fb);
+}
+
+static igt_output_t *list_writeback_modes(igt_display_t *display)
+{
+ for (int i = 0; i < display->n_outputs; i++) {
+ igt_output_t *output = &display->outputs[i];
+
+ if (output->config.connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) {
+ for (int j = 0; j < output->config.connector->count_modes; j++) {
+ igt_info("[%d]", j);
+ kmstest_dump_mode(&output->config.connector->modes[j]);
+ }
+ break;
+ }
+ }
+ return NULL;
+}
+
+static int parse_mode_string(char *optarg)
+{
+ return sscanf(optarg, "%u:%hu:%hu:%hu:%hu:%hu:%hu:%hu:%hu:%hu:%hu:%u:%u:%u:%s", &data.user_mode.clock,
+ &data.user_mode.hdisplay, &data.user_mode.hsync_start,
+ &data.user_mode.hsync_end, &data.user_mode.htotal,
+ &data.user_mode.hskew, &data.user_mode.vdisplay,
+ &data.user_mode.vsync_start, &data.user_mode.vsync_end,
+ &data.user_mode.vtotal, &data.user_mode.vscan,
+ &data.user_mode.vrefresh, &data.user_mode.type,
+ &data.user_mode.flags, data.user_mode.name);
+}
+
+static int opt_handler(int option, int option_index, void *_data)
+{
+ switch (option) {
+ case 'l':
+ data.list_modes = true;
+ break;
+ case 's':
+ data.standard_mode = true;
+ data.mode_index = atoi(optarg);
+ break;
+ case 'c':
+ data.custom_mode = true;
+ igt_assert(parse_mode_string(optarg) > 0);
+ break;
+ case 'd':
+ data.dump_check = true;
+ break;
+ default:
+ return IGT_OPT_HANDLER_ERROR;
+ }
+ return IGT_OPT_HANDLER_SUCCESS;
+}
+
+const char *help_str =
+ " --list-modes | -l List of writeback connector modes\n"
+ " --standard | -s Commits a standard mode\n"
+ " --custom | -c Commits a custom mode inputted by user <clock:hdisplay:hsyncstart:hsyncend:"
+ "htotal:hskew:vdisplay:vsyncstart:vsyncend:vtotal:vscan:vrefresh:flags:name>\n"
+ " --dump | -d Prints buffer to file - Use command: export IGT_FRAME_DUMP_PATH=\"<filepath>\""
+ " before running dump. Will skip all other tests.\n";
+
+static const struct option long_options[] = {
+ { .name = "list-modes", .has_arg = false, .val = 'l', },
+ { .name = "standard", .has_arg = true, .val = 's', },
+ { .name = "custom", .has_arg = true, .val = 'c', },
+ { .name = "dump", .has_arg = false, .val = 'd', },
+ {}
+};
+
+igt_main_args("s:c:dl", long_options, help_str, opt_handler, NULL)
{
igt_display_t display;
igt_output_t *output;
@@ -386,15 +514,23 @@ igt_main
&input_fb);
igt_assert(fb_id >= 0);
igt_plane_set_fb(plane, &input_fb);
- }
+ if (data.list_modes)
+ list_writeback_modes(&display);
+ if (data.dump_check)
+ commit_and_dump_fb(&display, output, plane, &input_fb, &mode);
+ }
+ /*
+ * When dump_check or list_modes flag is high, then the following subtests will be skipped
+ * as we do not want to do CRC validation.
+ */
igt_describe("Check the writeback format");
igt_subtest("writeback-pixel-formats") {
+ igt_skip_on(data.dump_check || data.list_modes);
drmModePropertyBlobRes *formats_blob = get_writeback_formats_blob(output);
const char *valid_chars = "01234568 ABCGNRUVXY";
unsigned int i;
char *c;
-
/*
* We don't have a comprehensive list of formats, so just check
* that the blob length is sensible and that it doesn't contain
@@ -412,6 +548,7 @@ igt_main
"(output framebuffer and fence); this test goes through"
"the combination of possible bad options");
igt_subtest("writeback-invalid-parameters") {
+ igt_skip_on(data.dump_check || data.list_modes);
igt_fb_t invalid_output_fb;
fb_id = igt_create_fb(display.drm_fd, mode.hdisplay / 2,
mode.vdisplay / 2,
@@ -427,6 +564,7 @@ igt_main
igt_describe("Validate WRITEBACK_FB_ID with valid and invalid options");
igt_subtest("writeback-fb-id") {
+ igt_skip_on(data.dump_check || data.list_modes);
igt_fb_t output_fb;
fb_id = igt_create_fb(display.drm_fd, mode.hdisplay, mode.vdisplay,
DRM_FORMAT_XRGB8888,
@@ -441,6 +579,7 @@ igt_main
igt_describe("Check writeback output with CRC validation");
igt_subtest("writeback-check-output") {
+ igt_skip_on(data.dump_check || data.list_modes);
igt_fb_t output_fb;
fb_id = igt_create_fb(display.drm_fd, mode.hdisplay, mode.vdisplay,
DRM_FORMAT_XRGB8888,
--
2.17.1
More information about the igt-dev
mailing list