* [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-05 16:36 [PATCH i-g-t 0/2] revamp big joiner test Kunal Joshi
@ 2024-03-05 16:36 ` Kunal Joshi
0 siblings, 0 replies; 17+ messages in thread
From: Kunal Joshi @ 2024-03-05 16:36 UTC (permalink / raw)
To: igt-dev; +Cc: Kunal Joshi, Karthik B S, Bhanuprakash Modem
big joiner outputs are statically assigned to pipe,
rewrite to assign dynamically
v2: Don't change license (Bhanu)
Add documentation for generate_combinations (Bhanu)
Print the pipe name (Bhanu)
Remove unwanted commit (Bhanu)
Move combine output logic to igt_fixture (Bhanu)
split revamp and force joiner (Bhanu)
Cc: Karthik B S <karthik.b.s@intel.com>
Cc: Bhanuprakash Modem <bhanuprakash.modem@intel.com>
Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
---
tests/intel/kms_big_joiner.c | 392 +++++++++++++++++------------------
1 file changed, 187 insertions(+), 205 deletions(-)
diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
index 28678b958..2bbc23fb5 100644
--- a/tests/intel/kms_big_joiner.c
+++ b/tests/intel/kms_big_joiner.c
@@ -43,16 +43,19 @@
*
* SUBTEST: basic
* Description: Verify the basic modeset on big joiner mode on all pipes
- *
- * SUBTEST: 2x-modeset
- * Description: Verify simultaneous modeset on 2 big joiner outputs
*/
-
IGT_TEST_DESCRIPTION("Test big joiner");
-struct bigjoiner_output {
- uint32_t output_id;
- drmModeModeInfo mode;
+#define MAX_OUTPUTS 256
+#define MAX_COMBINATIONS 1000
+#define INVALID_TEST_OUTPUT 2
+typedef struct {
+ int combination[MAX_OUTPUTS];
+} Combination;
+
+enum joiner_type {
+ BIG_JOINER = 1 << 1,
+ INVALID_JOINER = -1,
};
typedef struct {
@@ -60,274 +63,253 @@ typedef struct {
igt_display_t display;
struct igt_fb fb;
int n_pipes;
- enum pipe pipe1;
- enum pipe pipe2;
- struct bigjoiner_output output[2];
+ uint64_t big_joiner_outputs[IGT_MAX_PIPES];
+ uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
+ uint64_t combined_outputs[IGT_MAX_PIPES];
+ int big_joiner_output_count;
+ int non_big_joiner_output_count;
+ int combined_output_count;
+ int output_count;
+ enum pipe pipe_seq[IGT_MAX_PIPES];
} data_t;
static int max_dotclock;
-static void test_invalid_modeset(data_t *data)
+/*
+ * The generate_combinations function generates combinations of pipe allocations
+ * for a given number of outputs
+ *
+ * @output_count: Number of outputs to allocate pipes for.
+ * @pipe_count: Total number of available pipes.
+ * @pipes_per_output: Number of pipes to be allocated for a single output.
+ * @combinations: Array to store generated combinations.
+ * @num_combinations: Pointer to a variable that stores the number of generated combinations.
+ *
+ * Example (output_count=2, pipe_count=4, pipes_per_output=2):
+ * Combination 1: 0 2
+ * Combination 2: 1 3
+*/
+static void generate_combinations(int output_count, int pipe_count,
+ int pipes_per_output,
+ Combination combinations[MAX_COMBINATIONS],
+ uint64_t *num_combinations)
{
- igt_output_t *output;
- igt_display_t *display = &data->display;
- int ret;
-
- igt_info("Bigjoiner test on ");
- for_each_connected_output(display, output){
- enum pipe p = output->pending_pipe;
- drmModeModeInfo *mode;
- igt_pipe_t *pipe;
- igt_plane_t *plane;
+ int i, index;
+ int current_combination[MAX_OUTPUTS];
- if (p == PIPE_NONE)
- continue;
+ for (i = 0; i < output_count; ++i)
+ current_combination[i] = i * pipes_per_output;
- mode = igt_output_get_mode(output);
- igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
- kmstest_dump_mode(mode);
+ while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
+ for (i = 0; i < output_count; ++i)
+ combinations[*num_combinations].combination[i] = current_combination[i];
- pipe = &display->pipes[p];
- plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
+ (*num_combinations)++;
- igt_plane_set_fb(plane, &data->fb);
- igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
- igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
- }
+ index = output_count - 1;
+ while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
+ index--;
- igt_assert(!igt_check_bigjoiner_support(display));
+ if (index < 0)
+ break;
- /* This commit is expectd to fail as this pipe is being used for big joiner */
- ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
- DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+ current_combination[index]++;
+ for (i = index + 1; i < output_count; ++i)
+ current_combination[i] = current_combination[i - 1] + pipes_per_output;
+ }
+}
- igt_display_reset(&data->display);
- igt_display_commit2(display, COMMIT_ATOMIC);
+static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
+{
+ igt_output_t *output;
- igt_assert_lt(ret, 0);
+ for_each_connected_output(&data->display, output) {
+ if (output->id == output_id)
+ return output;
+ }
+ igt_assert("Output not found\n");
+ return NULL;
}
-static void test_basic_modeset(data_t *data)
+static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
{
+ int i, j, ret;
+ igt_output_t *output;
+ uint64_t *outputs;
+ igt_plane_t *primary[INVALID_TEST_OUTPUT];
+ igt_fb_t fb[INVALID_TEST_OUTPUT];
drmModeModeInfo *mode;
- igt_output_t *output, *bigjoiner_output = NULL;
- igt_display_t *display = &data->display;
- igt_pipe_t *pipe;
- igt_plane_t *plane;
-
- igt_display_reset(display);
- for_each_connected_output(display, output) {
- if (data->output[0].output_id == output->id) {
- bigjoiner_output = output;
- break;
+ outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
+
+ for (i = 0; i < data->n_pipes-1; i++) {
+ igt_display_reset(&data->display);
+ for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
+ output = get_output_by_id_or_assert(data, outputs[j]);
+ igt_assert(output);
+ igt_output_set_pipe(output, data->pipe_seq[i + j]);
+ mode = igt_output_get_mode(output);
+ igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
+ kmstest_pipe_name(data->pipe_seq[i + j]),
+ igt_output_name(output), mode->hdisplay,
+ mode->vdisplay, mode->vrefresh,
+ j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
+ primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+ igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_MOD_LINEAR, &fb[j]);
+ igt_plane_set_fb(primary[j], &fb[j]);
}
+ ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
+ igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
}
-
- igt_output_set_pipe(bigjoiner_output, data->pipe1);
-
- mode = &data->output[0].mode;
- igt_output_override_mode(bigjoiner_output, mode);
-
- pipe = &display->pipes[data->pipe1];
- plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
-
- igt_plane_set_fb(plane, &data->fb);
- igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
- igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
-
- igt_display_commit2(display, COMMIT_ATOMIC);
-
- igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
- igt_plane_set_fb(plane, NULL);
- igt_display_commit2(display, COMMIT_ATOMIC);
}
-static void test_dual_display(data_t *data)
+static void tets_big_joiner_on_last_pipe(data_t *data)
{
+ int i, ret;
+ uint64_t *outputs;
+ igt_output_t *output;
+ igt_plane_t *primary;
+ igt_fb_t fb;
drmModeModeInfo *mode;
- igt_output_t *output, *bigjoiner_output[2];
- igt_display_t *display = &data->display;
- igt_pipe_t *pipe;
- igt_plane_t *plane1, *plane2;
- int count = 0;
-
- igt_display_reset(display);
-
- for_each_connected_output(display, output) {
- if (data->output[count].output_id == output->id) {
- bigjoiner_output[count] = output;
- count++;
- }
- if (count > 1)
- break;
+ outputs = data->big_joiner_outputs;
+ for (i = 0; i < data->big_joiner_output_count; i++) {
+ igt_display_reset(&data->display);
+ output = get_output_by_id_or_assert(data, outputs[i]);
+ igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
+ mode = igt_output_get_mode(output);
+ igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
+ kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
+ igt_output_name(output), mode->hdisplay,
+ mode->vdisplay, mode->vrefresh);
+ primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+ igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_MOD_LINEAR, &fb);
+ igt_plane_set_fb(primary, &fb);
+ ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
+ igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
}
+}
- igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
- igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
-
- /* Set up first big joiner output on Pipe A*/
- mode = &data->output[0].mode;
- igt_output_override_mode(bigjoiner_output[0], mode);
-
- pipe = &display->pipes[data->pipe1];
- plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
-
- igt_plane_set_fb(plane1, &data->fb);
- igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
- igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
-
- /* Set up second big joiner output on Pipe C*/
- mode = &data->output[1].mode;
- igt_output_override_mode(bigjoiner_output[1], mode);
-
- pipe = &display->pipes[data->pipe2];
- plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
-
- igt_plane_set_fb(plane2, &data->fb);
- igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
- igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
-
- igt_display_commit2(display, COMMIT_ATOMIC);
+static void test_basic_modeset(data_t *data, int num_outputs,
+ Combination combinations[MAX_COMBINATIONS],
+ uint64_t num_combinations)
+{
+ int i, j, ret;
+ igt_display_t *display = &data->display;
+ igt_output_t *output[num_outputs];
+ igt_plane_t *primary[num_outputs];
+ igt_fb_t fb[num_outputs];
+ drmModeModeInfo *mode;
- /* Clean up */
- igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
- igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
- igt_plane_set_fb(plane1, NULL);
- igt_plane_set_fb(plane2, NULL);
- igt_display_commit2(display, COMMIT_ATOMIC);
+ for (i = 0; i < num_combinations; i++) {
+ igt_display_reset(display);
+ for (j = 0; j < num_outputs; j++) {
+ output[j] = get_output_by_id_or_assert(data,
+ data->big_joiner_outputs[j]);
+ igt_info("Assigning pipe %s to %s%s",
+ kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
+ output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
+ igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
+ primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
+ mode = igt_output_get_mode(output[j]);
+ igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_MOD_LINEAR, &fb[j]);
+ igt_plane_set_fb(primary[j], &fb[j]);
+ }
+ ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
+ igt_assert_f(ret == 0, "Commit failed\n");
+ }
}
igt_main
{
+ int i, j;
data_t data;
igt_output_t *output;
- drmModeModeInfo mode;
- int valid_output = 0, i, count = 0, j = 0;
- uint16_t width = 0, height = 0;
- enum pipe pipe_seq[IGT_MAX_PIPES];
+ drmModeModeInfo default_mode;
+ i = j = 0;
igt_fixture {
data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
kmstest_set_vt_graphics_mode();
-
igt_display_require(&data.display, data.drm_fd);
igt_require(data.display.is_atomic);
-
max_dotclock = igt_get_max_dotclock(data.drm_fd);
+ data.big_joiner_output_count = 0;
+ data.non_big_joiner_output_count = 0;
+ data.combined_output_count = 0;
+ data.output_count = 0;
for_each_connected_output(&data.display, output) {
bool found = false;
drmModeConnector *connector = output->config.connector;
-
- /*
- * Bigjoiner will come in to the picture when the
- * resolution > 5K or clock > max-dot-clock.
- */
found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
-
if (found) {
- data.output[count].output_id = output->id;
- memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
- count++;
-
- width = max(width, mode.hdisplay);
- height = max(height, mode.vdisplay);
+ data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
+ igt_output_override_mode(output, &connector->modes[0]);
+ } else {
+ data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
+ kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
+ igt_output_override_mode(output, &default_mode);
}
- valid_output++;
+ data.output_count++;
+ }
+
+ if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
+ data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
+ data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
}
data.n_pipes = 0;
for_each_pipe(&data.display, i) {
data.n_pipes++;
- pipe_seq[j] = i;
+ data.pipe_seq[j] = i;
j++;
}
-
- igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
-
- igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
- DRM_FORMAT_MOD_LINEAR, &data.fb);
}
igt_describe("Verify the basic modeset on big joiner mode on all pipes");
igt_subtest_with_dynamic("basic") {
- for (i = 0; i < data.n_pipes - 1; i++) {
- data.pipe1 = pipe_seq[i];
- igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
- test_basic_modeset(&data);
+ igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
+ igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
+
+ for (i = 0; i < data.big_joiner_output_count; i++) {
+ uint64_t num_combinations = 0;
+ Combination combinations[MAX_COMBINATIONS];
+
+ generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
+ igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
+ i+1, data.n_pipes, num_combinations);
+
+ if (num_combinations > 0)
+ igt_dynamic_f("%dx-big-joiner", i+1)
+ test_basic_modeset(&data, i+1, combinations, num_combinations);
+ else
+ break;
}
}
- igt_describe("Verify if the modeset on the adjoining pipe is rejected "
- "when the pipe is active with a big joiner modeset");
igt_subtest_with_dynamic("invalid-modeset") {
- data.pipe1 = pipe_seq[j - 1];
+ igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
+ igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
- igt_display_reset(&data.display);
- for_each_connected_output(&data.display, output) {
- if (data.output[0].output_id != output->id)
- continue;
-
- mode = data.output[0].mode;
- igt_output_set_pipe(output, data.pipe1);
- igt_output_override_mode(output, &mode);
-
- igt_dynamic_f("pipe-%s-%s",
- kmstest_pipe_name(data.pipe1),
- igt_output_name(output))
- test_invalid_modeset(&data);
- }
+ if (data.big_joiner_output_count >= 1)
+ igt_dynamic_f("big_joiner_on_last_pipe")
+ tets_big_joiner_on_last_pipe(&data);
- if(valid_output > 1) {
- for (i = 0; i < data.n_pipes - 1; i++) {
- igt_output_t *first_output = NULL, *second_output = NULL;
-
- data.pipe1 = pipe_seq[i];
- data.pipe2 = pipe_seq[i + 1];
-
- igt_display_reset(&data.display);
- for_each_connected_output(&data.display, output) {
- if (data.output[0].output_id == output->id) {
- first_output = output;
- mode = data.output[0].mode;
-
- igt_output_set_pipe(output, data.pipe1);
- igt_output_override_mode(output, &mode);
- } else if (second_output == NULL) {
- second_output = output;
- igt_output_set_pipe(output, data.pipe2);
-
- break;
- }
- }
-
- igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
- kmstest_pipe_name(data.pipe1),
- igt_output_name(first_output),
- kmstest_pipe_name(data.pipe2),
- igt_output_name(second_output))
- test_invalid_modeset(&data);
- }
- }
- }
+ if (data.big_joiner_output_count > 1)
+ igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
+ test_invalid_modeset_two_joiner(&data, false);
- igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
- igt_subtest_with_dynamic("2x-modeset") {
- igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
- igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
- for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
- data.pipe1 = pipe_seq[i];
- data.pipe2 = pipe_seq[i + 2];
- igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
- test_dual_display(&data);
+ if (data.combined_output_count) {
+ igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
+ test_invalid_modeset_two_joiner(&data, true);
}
}
igt_fixture {
- igt_remove_fb(data.drm_fd, &data.fb);
igt_display_fini(&data.display);
drm_close_driver(data.drm_fd);
}
-}
--
2.25.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH i-g-t 0/2] revamp big joiner test
@ 2024-03-06 5:25 Kunal Joshi
2024-03-06 5:25 ` [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi
` (3 more replies)
0 siblings, 4 replies; 17+ messages in thread
From: Kunal Joshi @ 2024-03-06 5:25 UTC (permalink / raw)
To: igt-dev; +Cc: Kunal Joshi
big joiner outputs are statically assigned to pipe,
rewrite to assign dynamically
Kunal Joshi (2):
lib/igt_kms: move bigjoiner_mode_found to lib
tests/intel/kms_big_joiner: revamp kms_big_joiner
lib/igt_kms.c | 25 +++
lib/igt_kms.h | 2 +
tests/intel/kms_big_joiner.c | 401 ++++++++++++++++-------------------
3 files changed, 213 insertions(+), 215 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib
2024-03-06 5:25 [PATCH i-g-t 0/2] revamp big joiner test Kunal Joshi
@ 2024-03-06 5:25 ` Kunal Joshi
2024-03-06 5:25 ` [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner Kunal Joshi
` (2 subsequent siblings)
3 siblings, 0 replies; 17+ messages in thread
From: Kunal Joshi @ 2024-03-06 5:25 UTC (permalink / raw)
To: igt-dev; +Cc: Kunal Joshi, Karthik B S, Bhanuprakash Modem
move bigjoiner_mode_found to lib
Cc: Karthik B S <karthik.b.s@intel.com>
Cc: Bhanuprakash Modem <bhanuprakash.modem@intel.com>
Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
---
lib/igt_kms.c | 25 +++++++++++++++++++++++++
lib/igt_kms.h | 2 ++
tests/intel/kms_big_joiner.c | 14 +-------------
3 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/lib/igt_kms.c b/lib/igt_kms.c
index e18f6fe59..63c8045c7 100644
--- a/lib/igt_kms.c
+++ b/lib/igt_kms.c
@@ -6143,6 +6143,31 @@ bool igt_bigjoiner_possible(drmModeModeInfo *mode, int max_dotclock)
mode->clock > max_dotclock);
}
+/**
+ * bigjoiner_mode_found:
+ * @connector: libdrm connector
+ * @sort_method: comparator method
+ * @mode: libdrm mode
+ *
+ * Bigjoiner will come in to the picture when the
+ * resolution > 5K or clock > max-dot-clock.
+ *
+ * Returns: True if big joiner found in connector modes
+ */
+bool bigjoiner_mode_found(int drm_fd, drmModeConnector *connector,
+ int max_dotclock)
+{
+ bool found = false;
+
+ igt_sort_connector_modes(connector, sort_drm_modes_by_res_dsc);
+ found = igt_bigjoiner_possible(&connector->modes[0], max_dotclock);
+ if (!found) {
+ igt_sort_connector_modes(connector, sort_drm_modes_by_clk_dsc);
+ found = igt_bigjoiner_possible(&connector->modes[0], max_dotclock);
+ }
+ return found;
+}
+
/**
* igt_check_bigjoiner_support:
* @display: a pointer to an #igt_display_t structure
diff --git a/lib/igt_kms.h b/lib/igt_kms.h
index b3882808b..bab8487d3 100644
--- a/lib/igt_kms.h
+++ b/lib/igt_kms.h
@@ -1212,6 +1212,8 @@ bool igt_max_bpc_constraint(igt_display_t *display, enum pipe pipe,
igt_output_t *output, int bpc);
int igt_get_max_dotclock(int fd);
bool igt_bigjoiner_possible(drmModeModeInfo *mode, int max_dotclock);
+bool bigjoiner_mode_found(int drm_fd, drmModeConnector *connector,
+ int max_dotclock);
bool igt_check_bigjoiner_support(igt_display_t *display);
bool igt_parse_mode_string(const char *mode_string, drmModeModeInfo *mode);
bool intel_pipe_output_combo_valid(igt_display_t *display);
diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
index aba2adfbe..28678b958 100644
--- a/tests/intel/kms_big_joiner.c
+++ b/tests/intel/kms_big_joiner.c
@@ -199,16 +199,6 @@ static void test_dual_display(data_t *data)
igt_display_commit2(display, COMMIT_ATOMIC);
}
-static bool bigjoiner_mode_found(drmModeConnector *connector,
- int (*sort_method)(const void *, const void*),
- drmModeModeInfo *mode)
-{
- igt_sort_connector_modes(connector, sort_method);
- *mode = connector->modes[0];
-
- return igt_bigjoiner_possible(mode, max_dotclock);
-}
-
igt_main
{
data_t data;
@@ -235,9 +225,7 @@ igt_main
* Bigjoiner will come in to the picture when the
* resolution > 5K or clock > max-dot-clock.
*/
- found = (bigjoiner_mode_found(connector, sort_drm_modes_by_res_dsc, &mode) ||
- bigjoiner_mode_found(connector, sort_drm_modes_by_clk_dsc, &mode)) ?
- true : false;
+ found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
if (found) {
data.output[count].output_id = output->id;
--
2.25.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-06 5:25 [PATCH i-g-t 0/2] revamp big joiner test Kunal Joshi
2024-03-06 5:25 ` [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi
@ 2024-03-06 5:25 ` Kunal Joshi
2024-03-06 9:53 ` Lisovskiy, Stanislav
2024-03-06 6:27 ` ✓ CI.xeBAT: success for revamp big joiner test (rev6) Patchwork
2024-03-06 6:28 ` ✗ Fi.CI.BAT: failure " Patchwork
3 siblings, 1 reply; 17+ messages in thread
From: Kunal Joshi @ 2024-03-06 5:25 UTC (permalink / raw)
To: igt-dev; +Cc: Kunal Joshi, Karthik B S, Bhanuprakash Modem
big joiner outputs are statically assigned to pipe,
rewrite to assign dynamically
v2: Don't change license (Bhanu)
Add documentation for generate_combinations (Bhanu)
Print the pipe name (Bhanu)
Remove unwanted commit (Bhanu)
Move combine output logic to igt_fixture (Bhanu)
split revamp and force joiner (Bhanu)
Cc: Karthik B S <karthik.b.s@intel.com>
Cc: Bhanuprakash Modem <bhanuprakash.modem@intel.com>
Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
---
tests/intel/kms_big_joiner.c | 391 +++++++++++++++++------------------
1 file changed, 187 insertions(+), 204 deletions(-)
diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
index 28678b958..ba4097d8b 100644
--- a/tests/intel/kms_big_joiner.c
+++ b/tests/intel/kms_big_joiner.c
@@ -43,16 +43,19 @@
*
* SUBTEST: basic
* Description: Verify the basic modeset on big joiner mode on all pipes
- *
- * SUBTEST: 2x-modeset
- * Description: Verify simultaneous modeset on 2 big joiner outputs
*/
-
IGT_TEST_DESCRIPTION("Test big joiner");
-struct bigjoiner_output {
- uint32_t output_id;
- drmModeModeInfo mode;
+#define MAX_OUTPUTS 256
+#define MAX_COMBINATIONS 1000
+#define INVALID_TEST_OUTPUT 2
+typedef struct {
+ int combination[MAX_OUTPUTS];
+} Combination;
+
+enum joiner_type {
+ BIG_JOINER = 1 << 1,
+ INVALID_JOINER = -1,
};
typedef struct {
@@ -60,273 +63,253 @@ typedef struct {
igt_display_t display;
struct igt_fb fb;
int n_pipes;
- enum pipe pipe1;
- enum pipe pipe2;
- struct bigjoiner_output output[2];
+ uint64_t big_joiner_outputs[IGT_MAX_PIPES];
+ uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
+ uint64_t combined_outputs[IGT_MAX_PIPES];
+ int big_joiner_output_count;
+ int non_big_joiner_output_count;
+ int combined_output_count;
+ int output_count;
+ enum pipe pipe_seq[IGT_MAX_PIPES];
} data_t;
static int max_dotclock;
-static void test_invalid_modeset(data_t *data)
+/*
+ * The generate_combinations function generates combinations of pipe allocations
+ * for a given number of outputs
+ *
+ * @output_count: Number of outputs to allocate pipes for.
+ * @pipe_count: Total number of available pipes.
+ * @pipes_per_output: Number of pipes to be allocated for a single output.
+ * @combinations: Array to store generated combinations.
+ * @num_combinations: Pointer to a variable that stores the number of generated combinations.
+ *
+ * Example (output_count=2, pipe_count=4, pipes_per_output=2):
+ * Combination 1: 0 2
+ * Combination 2: 1 3
+*/
+static void generate_combinations(int output_count, int pipe_count,
+ int pipes_per_output,
+ Combination combinations[MAX_COMBINATIONS],
+ uint64_t *num_combinations)
{
- igt_output_t *output;
- igt_display_t *display = &data->display;
- int ret;
+ int i, index;
+ int current_combination[MAX_OUTPUTS];
- igt_info("Bigjoiner test on ");
- for_each_connected_output(display, output){
- enum pipe p = output->pending_pipe;
- drmModeModeInfo *mode;
- igt_pipe_t *pipe;
- igt_plane_t *plane;
+ for (i = 0; i < output_count; ++i)
+ current_combination[i] = i * pipes_per_output;
- if (p == PIPE_NONE)
- continue;
-
- mode = igt_output_get_mode(output);
- igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
- kmstest_dump_mode(mode);
+ while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
+ for (i = 0; i < output_count; ++i)
+ combinations[*num_combinations].combination[i] = current_combination[i];
- pipe = &display->pipes[p];
- plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
+ (*num_combinations)++;
- igt_plane_set_fb(plane, &data->fb);
- igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
- igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
- }
+ index = output_count - 1;
+ while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
+ index--;
- igt_assert(!igt_check_bigjoiner_support(display));
+ if (index < 0)
+ break;
- /* This commit is expectd to fail as this pipe is being used for big joiner */
- ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
- DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+ current_combination[index]++;
+ for (i = index + 1; i < output_count; ++i)
+ current_combination[i] = current_combination[i - 1] + pipes_per_output;
+ }
+}
- igt_display_reset(&data->display);
- igt_display_commit2(display, COMMIT_ATOMIC);
+static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
+{
+ igt_output_t *output;
- igt_assert_lt(ret, 0);
+ for_each_connected_output(&data->display, output) {
+ if (output->id == output_id)
+ return output;
+ }
+ igt_assert("Output not found\n");
+ return NULL;
}
-static void test_basic_modeset(data_t *data)
+static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
{
+ int i, j, ret;
+ igt_output_t *output;
+ uint64_t *outputs;
+ igt_plane_t *primary[INVALID_TEST_OUTPUT];
+ igt_fb_t fb[INVALID_TEST_OUTPUT];
drmModeModeInfo *mode;
- igt_output_t *output, *bigjoiner_output = NULL;
- igt_display_t *display = &data->display;
- igt_pipe_t *pipe;
- igt_plane_t *plane;
- igt_display_reset(display);
-
- for_each_connected_output(display, output) {
- if (data->output[0].output_id == output->id) {
- bigjoiner_output = output;
- break;
+ outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
+
+ for (i = 0; i < data->n_pipes-1; i++) {
+ igt_display_reset(&data->display);
+ for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
+ output = get_output_by_id_or_assert(data, outputs[j]);
+ igt_assert(output);
+ igt_output_set_pipe(output, data->pipe_seq[i + j]);
+ mode = igt_output_get_mode(output);
+ igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
+ kmstest_pipe_name(data->pipe_seq[i + j]),
+ igt_output_name(output), mode->hdisplay,
+ mode->vdisplay, mode->vrefresh,
+ j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
+ primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+ igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_MOD_LINEAR, &fb[j]);
+ igt_plane_set_fb(primary[j], &fb[j]);
}
+ ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
+ igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
}
-
- igt_output_set_pipe(bigjoiner_output, data->pipe1);
-
- mode = &data->output[0].mode;
- igt_output_override_mode(bigjoiner_output, mode);
-
- pipe = &display->pipes[data->pipe1];
- plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
-
- igt_plane_set_fb(plane, &data->fb);
- igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
- igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
-
- igt_display_commit2(display, COMMIT_ATOMIC);
-
- igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
- igt_plane_set_fb(plane, NULL);
- igt_display_commit2(display, COMMIT_ATOMIC);
}
-static void test_dual_display(data_t *data)
+static void tets_big_joiner_on_last_pipe(data_t *data)
{
+ int i, ret;
+ uint64_t *outputs;
+ igt_output_t *output;
+ igt_plane_t *primary;
+ igt_fb_t fb;
drmModeModeInfo *mode;
- igt_output_t *output, *bigjoiner_output[2];
- igt_display_t *display = &data->display;
- igt_pipe_t *pipe;
- igt_plane_t *plane1, *plane2;
- int count = 0;
-
- igt_display_reset(display);
-
- for_each_connected_output(display, output) {
- if (data->output[count].output_id == output->id) {
- bigjoiner_output[count] = output;
- count++;
- }
- if (count > 1)
- break;
+ outputs = data->big_joiner_outputs;
+ for (i = 0; i < data->big_joiner_output_count; i++) {
+ igt_display_reset(&data->display);
+ output = get_output_by_id_or_assert(data, outputs[i]);
+ igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
+ mode = igt_output_get_mode(output);
+ igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
+ kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
+ igt_output_name(output), mode->hdisplay,
+ mode->vdisplay, mode->vrefresh);
+ primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+ igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_MOD_LINEAR, &fb);
+ igt_plane_set_fb(primary, &fb);
+ ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
+ igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
}
+}
- igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
- igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
-
- /* Set up first big joiner output on Pipe A*/
- mode = &data->output[0].mode;
- igt_output_override_mode(bigjoiner_output[0], mode);
-
- pipe = &display->pipes[data->pipe1];
- plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
-
- igt_plane_set_fb(plane1, &data->fb);
- igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
- igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
-
- /* Set up second big joiner output on Pipe C*/
- mode = &data->output[1].mode;
- igt_output_override_mode(bigjoiner_output[1], mode);
-
- pipe = &display->pipes[data->pipe2];
- plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
-
- igt_plane_set_fb(plane2, &data->fb);
- igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
- igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
-
- igt_display_commit2(display, COMMIT_ATOMIC);
+static void test_basic_modeset(data_t *data, int num_outputs,
+ Combination combinations[MAX_COMBINATIONS],
+ uint64_t num_combinations)
+{
+ int i, j, ret;
+ igt_display_t *display = &data->display;
+ igt_output_t *output[num_outputs];
+ igt_plane_t *primary[num_outputs];
+ igt_fb_t fb[num_outputs];
+ drmModeModeInfo *mode;
- /* Clean up */
- igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
- igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
- igt_plane_set_fb(plane1, NULL);
- igt_plane_set_fb(plane2, NULL);
- igt_display_commit2(display, COMMIT_ATOMIC);
+ for (i = 0; i < num_combinations; i++) {
+ igt_display_reset(display);
+ for (j = 0; j < num_outputs; j++) {
+ output[j] = get_output_by_id_or_assert(data,
+ data->big_joiner_outputs[j]);
+ igt_info("Assigning pipe %s to %s%s",
+ kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
+ output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
+ igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
+ primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
+ mode = igt_output_get_mode(output[j]);
+ igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_MOD_LINEAR, &fb[j]);
+ igt_plane_set_fb(primary[j], &fb[j]);
+ }
+ ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
+ igt_assert_f(ret == 0, "Commit failed\n");
+ }
}
igt_main
{
+ int i, j;
data_t data;
igt_output_t *output;
- drmModeModeInfo mode;
- int valid_output = 0, i, count = 0, j = 0;
- uint16_t width = 0, height = 0;
- enum pipe pipe_seq[IGT_MAX_PIPES];
+ drmModeModeInfo default_mode;
+ i = j = 0;
igt_fixture {
data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
kmstest_set_vt_graphics_mode();
-
igt_display_require(&data.display, data.drm_fd);
igt_require(data.display.is_atomic);
-
max_dotclock = igt_get_max_dotclock(data.drm_fd);
+ data.big_joiner_output_count = 0;
+ data.non_big_joiner_output_count = 0;
+ data.combined_output_count = 0;
+ data.output_count = 0;
for_each_connected_output(&data.display, output) {
bool found = false;
drmModeConnector *connector = output->config.connector;
-
- /*
- * Bigjoiner will come in to the picture when the
- * resolution > 5K or clock > max-dot-clock.
- */
found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
-
if (found) {
- data.output[count].output_id = output->id;
- memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
- count++;
-
- width = max(width, mode.hdisplay);
- height = max(height, mode.vdisplay);
+ data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
+ igt_output_override_mode(output, &connector->modes[0]);
+ } else {
+ data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
+ kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
+ igt_output_override_mode(output, &default_mode);
}
- valid_output++;
+ data.output_count++;
+ }
+
+ if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
+ data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
+ data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
}
data.n_pipes = 0;
for_each_pipe(&data.display, i) {
data.n_pipes++;
- pipe_seq[j] = i;
+ data.pipe_seq[j] = i;
j++;
}
-
- igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
-
- igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
- DRM_FORMAT_MOD_LINEAR, &data.fb);
}
igt_describe("Verify the basic modeset on big joiner mode on all pipes");
igt_subtest_with_dynamic("basic") {
- for (i = 0; i < data.n_pipes - 1; i++) {
- data.pipe1 = pipe_seq[i];
- igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
- test_basic_modeset(&data);
+ igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
+ igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
+
+ for (i = 0; i < data.big_joiner_output_count; i++) {
+ uint64_t num_combinations = 0;
+ Combination combinations[MAX_COMBINATIONS];
+
+ generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
+ igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
+ i+1, data.n_pipes, num_combinations);
+
+ if (num_combinations > 0)
+ igt_dynamic_f("%dx-big-joiner", i+1)
+ test_basic_modeset(&data, i+1, combinations, num_combinations);
+ else
+ break;
}
}
- igt_describe("Verify if the modeset on the adjoining pipe is rejected "
- "when the pipe is active with a big joiner modeset");
igt_subtest_with_dynamic("invalid-modeset") {
- data.pipe1 = pipe_seq[j - 1];
-
- igt_display_reset(&data.display);
- for_each_connected_output(&data.display, output) {
- if (data.output[0].output_id != output->id)
- continue;
-
- mode = data.output[0].mode;
- igt_output_set_pipe(output, data.pipe1);
- igt_output_override_mode(output, &mode);
+ igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
+ igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
- igt_dynamic_f("pipe-%s-%s",
- kmstest_pipe_name(data.pipe1),
- igt_output_name(output))
- test_invalid_modeset(&data);
- }
+ if (data.big_joiner_output_count >= 1)
+ igt_dynamic_f("big_joiner_on_last_pipe")
+ tets_big_joiner_on_last_pipe(&data);
- if(valid_output > 1) {
- for (i = 0; i < data.n_pipes - 1; i++) {
- igt_output_t *first_output = NULL, *second_output = NULL;
-
- data.pipe1 = pipe_seq[i];
- data.pipe2 = pipe_seq[i + 1];
-
- igt_display_reset(&data.display);
- for_each_connected_output(&data.display, output) {
- if (data.output[0].output_id == output->id) {
- first_output = output;
- mode = data.output[0].mode;
-
- igt_output_set_pipe(output, data.pipe1);
- igt_output_override_mode(output, &mode);
- } else if (second_output == NULL) {
- second_output = output;
- igt_output_set_pipe(output, data.pipe2);
-
- break;
- }
- }
-
- igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
- kmstest_pipe_name(data.pipe1),
- igt_output_name(first_output),
- kmstest_pipe_name(data.pipe2),
- igt_output_name(second_output))
- test_invalid_modeset(&data);
- }
- }
- }
+ if (data.big_joiner_output_count > 1)
+ igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
+ test_invalid_modeset_two_joiner(&data, false);
- igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
- igt_subtest_with_dynamic("2x-modeset") {
- igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
- igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
- for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
- data.pipe1 = pipe_seq[i];
- data.pipe2 = pipe_seq[i + 2];
- igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
- test_dual_display(&data);
+ if (data.combined_output_count) {
+ igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
+ test_invalid_modeset_two_joiner(&data, true);
}
}
igt_fixture {
- igt_remove_fb(data.drm_fd, &data.fb);
igt_display_fini(&data.display);
drm_close_driver(data.drm_fd);
}
--
2.25.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* ✓ CI.xeBAT: success for revamp big joiner test (rev6)
2024-03-06 5:25 [PATCH i-g-t 0/2] revamp big joiner test Kunal Joshi
2024-03-06 5:25 ` [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi
2024-03-06 5:25 ` [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner Kunal Joshi
@ 2024-03-06 6:27 ` Patchwork
2024-03-06 6:28 ` ✗ Fi.CI.BAT: failure " Patchwork
3 siblings, 0 replies; 17+ messages in thread
From: Patchwork @ 2024-03-06 6:27 UTC (permalink / raw)
To: Kunal Joshi; +Cc: igt-dev
[-- Attachment #1: Type: text/plain, Size: 814 bytes --]
== Series Details ==
Series: revamp big joiner test (rev6)
URL : https://patchwork.freedesktop.org/series/130572/
State : success
== Summary ==
CI Bug Log - changes from XEIGT_7747_BAT -> XEIGTPW_10784_BAT
====================================================
Summary
-------
**SUCCESS**
No regressions found.
Participating hosts (4 -> 4)
------------------------------
No changes in participating hosts
Changes
-------
No changes found
Build changes
-------------
* IGT: IGT_7747 -> IGTPW_10784
IGTPW_10784: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/index.html
IGT_7747: 7747
xe-905-dd08fd912fdc1b72984a39852fdbee49b97b8ce4: dd08fd912fdc1b72984a39852fdbee49b97b8ce4
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_10784/index.html
[-- Attachment #2: Type: text/html, Size: 1359 bytes --]
^ permalink raw reply [flat|nested] 17+ messages in thread
* ✗ Fi.CI.BAT: failure for revamp big joiner test (rev6)
2024-03-06 5:25 [PATCH i-g-t 0/2] revamp big joiner test Kunal Joshi
` (2 preceding siblings ...)
2024-03-06 6:27 ` ✓ CI.xeBAT: success for revamp big joiner test (rev6) Patchwork
@ 2024-03-06 6:28 ` Patchwork
3 siblings, 0 replies; 17+ messages in thread
From: Patchwork @ 2024-03-06 6:28 UTC (permalink / raw)
To: Kunal Joshi; +Cc: igt-dev
[-- Attachment #1: Type: text/plain, Size: 11244 bytes --]
== Series Details ==
Series: revamp big joiner test (rev6)
URL : https://patchwork.freedesktop.org/series/130572/
State : failure
== Summary ==
CI Bug Log - changes from IGT_7747 -> IGTPW_10784
====================================================
Summary
-------
**FAILURE**
Serious unknown changes coming with IGTPW_10784 absolutely need to be
verified manually.
If you think the reported changes have nothing to do with the changes
introduced in IGTPW_10784, please notify your bug team (I915-ci-infra@lists.freedesktop.org) to allow them
to document this new failure mode, which will reduce false positives in CI.
External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/index.html
Participating hosts (38 -> 38)
------------------------------
Additional (3): bat-dg1-7 bat-kbl-2 bat-mtlp-8
Missing (3): fi-glk-j4005 bat-jsl-1 fi-snb-2520m
Possible new issues
-------------------
Here are the unknown changes that may have been introduced in IGTPW_10784:
### IGT changes ###
#### Possible regressions ####
* igt@i915_selftest@live@gt_engines:
- bat-arls-2: [PASS][1] -> [ABORT][2]
[1]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_7747/bat-arls-2/igt@i915_selftest@live@gt_engines.html
[2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-arls-2/igt@i915_selftest@live@gt_engines.html
Known issues
------------
Here are the changes found in IGTPW_10784 that come from known issues:
### IGT changes ###
#### Issues hit ####
* igt@debugfs_test@basic-hwmon:
- bat-mtlp-8: NOTRUN -> [SKIP][3] ([i915#9318])
[3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@debugfs_test@basic-hwmon.html
* igt@fbdev@info:
- bat-kbl-2: NOTRUN -> [SKIP][4] ([fdo#109271] / [i915#1849])
[4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-kbl-2/igt@fbdev@info.html
* igt@gem_lmem_swapping@parallel-random-engines:
- bat-kbl-2: NOTRUN -> [SKIP][5] ([fdo#109271]) +39 other tests skip
[5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-kbl-2/igt@gem_lmem_swapping@parallel-random-engines.html
* igt@gem_lmem_swapping@verify-random:
- bat-mtlp-8: NOTRUN -> [SKIP][6] ([i915#4613]) +3 other tests skip
[6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@gem_lmem_swapping@verify-random.html
* igt@gem_mmap@basic:
- bat-dg1-7: NOTRUN -> [SKIP][7] ([i915#4083])
[7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@gem_mmap@basic.html
- bat-mtlp-8: NOTRUN -> [SKIP][8] ([i915#4083])
[8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@gem_mmap@basic.html
* igt@gem_mmap_gtt@basic:
- bat-mtlp-8: NOTRUN -> [SKIP][9] ([i915#4077]) +2 other tests skip
[9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@gem_mmap_gtt@basic.html
* igt@gem_render_tiled_blits@basic:
- bat-mtlp-8: NOTRUN -> [SKIP][10] ([i915#4079]) +1 other test skip
[10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@gem_render_tiled_blits@basic.html
* igt@gem_tiled_fence_blits@basic:
- bat-dg1-7: NOTRUN -> [SKIP][11] ([i915#4077]) +2 other tests skip
[11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@gem_tiled_fence_blits@basic.html
* igt@gem_tiled_pread_basic:
- bat-dg1-7: NOTRUN -> [SKIP][12] ([i915#4079]) +1 other test skip
[12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@gem_tiled_pread_basic.html
* igt@i915_pm_rps@basic-api:
- bat-dg1-7: NOTRUN -> [SKIP][13] ([i915#6621])
[13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@i915_pm_rps@basic-api.html
- bat-mtlp-8: NOTRUN -> [SKIP][14] ([i915#6621])
[14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@i915_pm_rps@basic-api.html
* igt@kms_addfb_basic@addfb25-x-tiled-mismatch-legacy:
- bat-dg1-7: NOTRUN -> [SKIP][15] ([i915#4212]) +7 other tests skip
[15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@kms_addfb_basic@addfb25-x-tiled-mismatch-legacy.html
* igt@kms_addfb_basic@addfb25-y-tiled-small-legacy:
- bat-mtlp-8: NOTRUN -> [SKIP][16] ([i915#5190])
[16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@kms_addfb_basic@addfb25-y-tiled-small-legacy.html
* igt@kms_addfb_basic@basic-y-tiled-legacy:
- bat-mtlp-8: NOTRUN -> [SKIP][17] ([i915#4212]) +8 other tests skip
[17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@kms_addfb_basic@basic-y-tiled-legacy.html
- bat-dg1-7: NOTRUN -> [SKIP][18] ([i915#4215])
[18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@kms_addfb_basic@basic-y-tiled-legacy.html
* igt@kms_cursor_legacy@basic-busy-flip-before-cursor-legacy:
- bat-mtlp-8: NOTRUN -> [SKIP][19] ([i915#4213]) +1 other test skip
[19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@kms_cursor_legacy@basic-busy-flip-before-cursor-legacy.html
- bat-dg1-7: NOTRUN -> [SKIP][20] ([i915#4103] / [i915#4213]) +1 other test skip
[20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@kms_cursor_legacy@basic-busy-flip-before-cursor-legacy.html
* igt@kms_dsc@dsc-basic:
- bat-mtlp-8: NOTRUN -> [SKIP][21] ([i915#3555] / [i915#3840] / [i915#9159])
[21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@kms_dsc@dsc-basic.html
- bat-dg1-7: NOTRUN -> [SKIP][22] ([i915#3555] / [i915#3840])
[22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@kms_dsc@dsc-basic.html
* igt@kms_force_connector_basic@force-load-detect:
- bat-mtlp-8: NOTRUN -> [SKIP][23] ([fdo#109285])
[23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@kms_force_connector_basic@force-load-detect.html
- bat-dg1-7: NOTRUN -> [SKIP][24] ([fdo#109285])
[24]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@kms_force_connector_basic@force-load-detect.html
* igt@kms_force_connector_basic@prune-stale-modes:
- bat-mtlp-8: NOTRUN -> [SKIP][25] ([i915#5274])
[25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@kms_force_connector_basic@prune-stale-modes.html
* igt@kms_hdmi_inject@inject-audio:
- bat-dg1-7: NOTRUN -> [SKIP][26] ([i915#433])
[26]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@kms_hdmi_inject@inject-audio.html
* igt@kms_pm_backlight@basic-brightness:
- bat-dg1-7: NOTRUN -> [SKIP][27] ([i915#5354])
[27]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@kms_pm_backlight@basic-brightness.html
* igt@kms_psr@psr-primary-mmap-gtt@edp-1:
- bat-mtlp-8: NOTRUN -> [SKIP][28] ([i915#4077] / [i915#9688])
[28]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@kms_psr@psr-primary-mmap-gtt@edp-1.html
* igt@kms_psr@psr-primary-page-flip:
- bat-dg1-7: NOTRUN -> [SKIP][29] ([i915#9732]) +3 other tests skip
[29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@kms_psr@psr-primary-page-flip.html
* igt@kms_setmode@basic-clone-single-crtc:
- bat-mtlp-8: NOTRUN -> [SKIP][30] ([i915#3555] / [i915#8809])
[30]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@kms_setmode@basic-clone-single-crtc.html
- bat-dg1-7: NOTRUN -> [SKIP][31] ([i915#3555])
[31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@kms_setmode@basic-clone-single-crtc.html
* igt@prime_vgem@basic-fence-flip:
- bat-dg1-7: NOTRUN -> [SKIP][32] ([i915#3708]) +3 other tests skip
[32]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@prime_vgem@basic-fence-flip.html
* igt@prime_vgem@basic-fence-mmap:
- bat-dg1-7: NOTRUN -> [SKIP][33] ([i915#3708] / [i915#4077]) +1 other test skip
[33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg1-7/igt@prime_vgem@basic-fence-mmap.html
- bat-mtlp-8: NOTRUN -> [SKIP][34] ([i915#3708] / [i915#4077]) +1 other test skip
[34]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@prime_vgem@basic-fence-mmap.html
* igt@prime_vgem@basic-fence-read:
- bat-mtlp-8: NOTRUN -> [SKIP][35] ([i915#3708]) +2 other tests skip
[35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-mtlp-8/igt@prime_vgem@basic-fence-read.html
#### Possible fixes ####
* igt@i915_selftest@live@late_gt_pm:
- bat-dg2-8: [ABORT][36] ([i915#10366]) -> [PASS][37]
[36]: https://intel-gfx-ci.01.org/tree/drm-tip/IGT_7747/bat-dg2-8/igt@i915_selftest@live@late_gt_pm.html
[37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/bat-dg2-8/igt@i915_selftest@live@late_gt_pm.html
[fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
[fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
[i915#10366]: https://gitlab.freedesktop.org/drm/intel/issues/10366
[i915#1849]: https://gitlab.freedesktop.org/drm/intel/issues/1849
[i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
[i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
[i915#3840]: https://gitlab.freedesktop.org/drm/intel/issues/3840
[i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
[i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
[i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
[i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
[i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
[i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
[i915#4215]: https://gitlab.freedesktop.org/drm/intel/issues/4215
[i915#433]: https://gitlab.freedesktop.org/drm/intel/issues/433
[i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
[i915#5190]: https://gitlab.freedesktop.org/drm/intel/issues/5190
[i915#5274]: https://gitlab.freedesktop.org/drm/intel/issues/5274
[i915#5354]: https://gitlab.freedesktop.org/drm/intel/issues/5354
[i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
[i915#8809]: https://gitlab.freedesktop.org/drm/intel/issues/8809
[i915#9159]: https://gitlab.freedesktop.org/drm/intel/issues/9159
[i915#9318]: https://gitlab.freedesktop.org/drm/intel/issues/9318
[i915#9688]: https://gitlab.freedesktop.org/drm/intel/issues/9688
[i915#9732]: https://gitlab.freedesktop.org/drm/intel/issues/9732
Build changes
-------------
* CI: CI-20190529 -> None
* IGT: IGT_7747 -> IGTPW_10784
CI-20190529: 20190529
CI_DRM_14395: dd08fd912fdc1b72984a39852fdbee49b97b8ce4 @ git://anongit.freedesktop.org/gfx-ci/linux
IGTPW_10784: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/index.html
IGT_7747: 7747
Testlist changes
----------------
-igt@kms_big_joiner@2x-modeset
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10784/index.html
[-- Attachment #2: Type: text/html, Size: 13749 bytes --]
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-06 5:25 ` [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner Kunal Joshi
@ 2024-03-06 9:53 ` Lisovskiy, Stanislav
2024-03-06 10:11 ` Joshi, Kunal1
0 siblings, 1 reply; 17+ messages in thread
From: Lisovskiy, Stanislav @ 2024-03-06 9:53 UTC (permalink / raw)
To: Kunal Joshi; +Cc: igt-dev, Karthik B S, Bhanuprakash Modem
On Wed, Mar 06, 2024 at 10:55:09AM +0530, Kunal Joshi wrote:
> big joiner outputs are statically assigned to pipe,
> rewrite to assign dynamically
>
> v2: Don't change license (Bhanu)
> Add documentation for generate_combinations (Bhanu)
> Print the pipe name (Bhanu)
> Remove unwanted commit (Bhanu)
> Move combine output logic to igt_fixture (Bhanu)
> split revamp and force joiner (Bhanu)
>
> Cc: Karthik B S <karthik.b.s@intel.com>
> Cc: Bhanuprakash Modem <bhanuprakash.modem@intel.com>
> Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
> ---
> tests/intel/kms_big_joiner.c | 391 +++++++++++++++++------------------
> 1 file changed, 187 insertions(+), 204 deletions(-)
>
> diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
> index 28678b958..ba4097d8b 100644
> --- a/tests/intel/kms_big_joiner.c
> +++ b/tests/intel/kms_big_joiner.c
> @@ -43,16 +43,19 @@
> *
> * SUBTEST: basic
> * Description: Verify the basic modeset on big joiner mode on all pipes
> - *
> - * SUBTEST: 2x-modeset
> - * Description: Verify simultaneous modeset on 2 big joiner outputs
> */
> -
> IGT_TEST_DESCRIPTION("Test big joiner");
>
> -struct bigjoiner_output {
> - uint32_t output_id;
> - drmModeModeInfo mode;
> +#define MAX_OUTPUTS 256
> +#define MAX_COMBINATIONS 1000
> +#define INVALID_TEST_OUTPUT 2
> +typedef struct {
> + int combination[MAX_OUTPUTS];
> +} Combination;
> +
> +enum joiner_type {
> + BIG_JOINER = 1 << 1,
> + INVALID_JOINER = -1,
> };
>
> typedef struct {
> @@ -60,273 +63,253 @@ typedef struct {
> igt_display_t display;
> struct igt_fb fb;
> int n_pipes;
> - enum pipe pipe1;
> - enum pipe pipe2;
> - struct bigjoiner_output output[2];
> + uint64_t big_joiner_outputs[IGT_MAX_PIPES];
> + uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
> + uint64_t combined_outputs[IGT_MAX_PIPES];
> + int big_joiner_output_count;
> + int non_big_joiner_output_count;
> + int combined_output_count;
> + int output_count;
> + enum pipe pipe_seq[IGT_MAX_PIPES];
> } data_t;
>
> static int max_dotclock;
>
> -static void test_invalid_modeset(data_t *data)
> +/*
> + * The generate_combinations function generates combinations of pipe allocations
> + * for a given number of outputs
> + *
> + * @output_count: Number of outputs to allocate pipes for.
> + * @pipe_count: Total number of available pipes.
> + * @pipes_per_output: Number of pipes to be allocated for a single output.
> + * @combinations: Array to store generated combinations.
> + * @num_combinations: Pointer to a variable that stores the number of generated combinations.
> + *
> + * Example (output_count=2, pipe_count=4, pipes_per_output=2):
> + * Combination 1: 0 2
> + * Combination 2: 1 3
I think this might be a bit overcomplicated - just for your information, we can't deliberately
choose which pipes can be used for bigjoiner. On some platforms even only certain pipes, can be
used for bigjoiner.
Moreover the way how driver decides, which pipes are going to be used for bigjoiner is basically
this code in intel_dp.c:
if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
adjusted_mode->crtc_clock))
pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
Means if you try to do a modeset with resolution > 5K or exceed max_dot_clock on crtc->pipe,
then _always_ pipe + 1, going to be used for bigjoiner.
Stan
> +*/
> +static void generate_combinations(int output_count, int pipe_count,
> + int pipes_per_output,
> + Combination combinations[MAX_COMBINATIONS],
> + uint64_t *num_combinations)
> {
> - igt_output_t *output;
> - igt_display_t *display = &data->display;
> - int ret;
> + int i, index;
> + int current_combination[MAX_OUTPUTS];
>
> - igt_info("Bigjoiner test on ");
> - for_each_connected_output(display, output){
> - enum pipe p = output->pending_pipe;
> - drmModeModeInfo *mode;
> - igt_pipe_t *pipe;
> - igt_plane_t *plane;
> + for (i = 0; i < output_count; ++i)
> + current_combination[i] = i * pipes_per_output;
>
> - if (p == PIPE_NONE)
> - continue;
> -
> - mode = igt_output_get_mode(output);
> - igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
> - kmstest_dump_mode(mode);
> + while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
> + for (i = 0; i < output_count; ++i)
> + combinations[*num_combinations].combination[i] = current_combination[i];
>
> - pipe = &display->pipes[p];
> - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> + (*num_combinations)++;
>
> - igt_plane_set_fb(plane, &data->fb);
> - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
> - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> - }
> + index = output_count - 1;
> + while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
> + index--;
>
> - igt_assert(!igt_check_bigjoiner_support(display));
> + if (index < 0)
> + break;
>
> - /* This commit is expectd to fail as this pipe is being used for big joiner */
> - ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
> - DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
> + current_combination[index]++;
> + for (i = index + 1; i < output_count; ++i)
> + current_combination[i] = current_combination[i - 1] + pipes_per_output;
> + }
> +}
>
> - igt_display_reset(&data->display);
> - igt_display_commit2(display, COMMIT_ATOMIC);
> +static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
> +{
> + igt_output_t *output;
>
> - igt_assert_lt(ret, 0);
> + for_each_connected_output(&data->display, output) {
> + if (output->id == output_id)
> + return output;
> + }
> + igt_assert("Output not found\n");
> + return NULL;
> }
>
> -static void test_basic_modeset(data_t *data)
> +static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
> {
> + int i, j, ret;
> + igt_output_t *output;
> + uint64_t *outputs;
> + igt_plane_t *primary[INVALID_TEST_OUTPUT];
> + igt_fb_t fb[INVALID_TEST_OUTPUT];
> drmModeModeInfo *mode;
> - igt_output_t *output, *bigjoiner_output = NULL;
> - igt_display_t *display = &data->display;
> - igt_pipe_t *pipe;
> - igt_plane_t *plane;
>
> - igt_display_reset(display);
> -
> - for_each_connected_output(display, output) {
> - if (data->output[0].output_id == output->id) {
> - bigjoiner_output = output;
> - break;
> + outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
> +
> + for (i = 0; i < data->n_pipes-1; i++) {
> + igt_display_reset(&data->display);
> + for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
> + output = get_output_by_id_or_assert(data, outputs[j]);
> + igt_assert(output);
> + igt_output_set_pipe(output, data->pipe_seq[i + j]);
> + mode = igt_output_get_mode(output);
> + igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
> + kmstest_pipe_name(data->pipe_seq[i + j]),
> + igt_output_name(output), mode->hdisplay,
> + mode->vdisplay, mode->vrefresh,
> + j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
> + primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> + DRM_FORMAT_MOD_LINEAR, &fb[j]);
> + igt_plane_set_fb(primary[j], &fb[j]);
> }
> + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> }
> -
> - igt_output_set_pipe(bigjoiner_output, data->pipe1);
> -
> - mode = &data->output[0].mode;
> - igt_output_override_mode(bigjoiner_output, mode);
> -
> - pipe = &display->pipes[data->pipe1];
> - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> -
> - igt_plane_set_fb(plane, &data->fb);
> - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
> - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> -
> - igt_display_commit2(display, COMMIT_ATOMIC);
> -
> - igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
> - igt_plane_set_fb(plane, NULL);
> - igt_display_commit2(display, COMMIT_ATOMIC);
> }
>
> -static void test_dual_display(data_t *data)
> +static void tets_big_joiner_on_last_pipe(data_t *data)
> {
> + int i, ret;
> + uint64_t *outputs;
> + igt_output_t *output;
> + igt_plane_t *primary;
> + igt_fb_t fb;
> drmModeModeInfo *mode;
> - igt_output_t *output, *bigjoiner_output[2];
> - igt_display_t *display = &data->display;
> - igt_pipe_t *pipe;
> - igt_plane_t *plane1, *plane2;
> - int count = 0;
> -
> - igt_display_reset(display);
> -
> - for_each_connected_output(display, output) {
> - if (data->output[count].output_id == output->id) {
> - bigjoiner_output[count] = output;
> - count++;
> - }
>
> - if (count > 1)
> - break;
> + outputs = data->big_joiner_outputs;
> + for (i = 0; i < data->big_joiner_output_count; i++) {
> + igt_display_reset(&data->display);
> + output = get_output_by_id_or_assert(data, outputs[i]);
> + igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
> + mode = igt_output_get_mode(output);
> + igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
> + kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
> + igt_output_name(output), mode->hdisplay,
> + mode->vdisplay, mode->vrefresh);
> + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> + DRM_FORMAT_MOD_LINEAR, &fb);
> + igt_plane_set_fb(primary, &fb);
> + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> }
> +}
>
> - igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
> - igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
> -
> - /* Set up first big joiner output on Pipe A*/
> - mode = &data->output[0].mode;
> - igt_output_override_mode(bigjoiner_output[0], mode);
> -
> - pipe = &display->pipes[data->pipe1];
> - plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> -
> - igt_plane_set_fb(plane1, &data->fb);
> - igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
> - igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
> -
> - /* Set up second big joiner output on Pipe C*/
> - mode = &data->output[1].mode;
> - igt_output_override_mode(bigjoiner_output[1], mode);
> -
> - pipe = &display->pipes[data->pipe2];
> - plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> -
> - igt_plane_set_fb(plane2, &data->fb);
> - igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
> - igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
> -
> - igt_display_commit2(display, COMMIT_ATOMIC);
> +static void test_basic_modeset(data_t *data, int num_outputs,
> + Combination combinations[MAX_COMBINATIONS],
> + uint64_t num_combinations)
> +{
> + int i, j, ret;
> + igt_display_t *display = &data->display;
> + igt_output_t *output[num_outputs];
> + igt_plane_t *primary[num_outputs];
> + igt_fb_t fb[num_outputs];
> + drmModeModeInfo *mode;
>
> - /* Clean up */
> - igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
> - igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
> - igt_plane_set_fb(plane1, NULL);
> - igt_plane_set_fb(plane2, NULL);
> - igt_display_commit2(display, COMMIT_ATOMIC);
> + for (i = 0; i < num_combinations; i++) {
> + igt_display_reset(display);
> + for (j = 0; j < num_outputs; j++) {
> + output[j] = get_output_by_id_or_assert(data,
> + data->big_joiner_outputs[j]);
> + igt_info("Assigning pipe %s to %s%s",
> + kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
> + output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
> + igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
> + primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
> + mode = igt_output_get_mode(output[j]);
> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> + DRM_FORMAT_MOD_LINEAR, &fb[j]);
> + igt_plane_set_fb(primary[j], &fb[j]);
> + }
> + ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
> + igt_assert_f(ret == 0, "Commit failed\n");
> + }
> }
>
> igt_main
> {
> + int i, j;
> data_t data;
> igt_output_t *output;
> - drmModeModeInfo mode;
> - int valid_output = 0, i, count = 0, j = 0;
> - uint16_t width = 0, height = 0;
> - enum pipe pipe_seq[IGT_MAX_PIPES];
> + drmModeModeInfo default_mode;
>
> + i = j = 0;
> igt_fixture {
> data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
> kmstest_set_vt_graphics_mode();
> -
> igt_display_require(&data.display, data.drm_fd);
> igt_require(data.display.is_atomic);
> -
> max_dotclock = igt_get_max_dotclock(data.drm_fd);
> + data.big_joiner_output_count = 0;
> + data.non_big_joiner_output_count = 0;
> + data.combined_output_count = 0;
> + data.output_count = 0;
>
> for_each_connected_output(&data.display, output) {
> bool found = false;
> drmModeConnector *connector = output->config.connector;
> -
> - /*
> - * Bigjoiner will come in to the picture when the
> - * resolution > 5K or clock > max-dot-clock.
> - */
> found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
> -
> if (found) {
> - data.output[count].output_id = output->id;
> - memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
> - count++;
> -
> - width = max(width, mode.hdisplay);
> - height = max(height, mode.vdisplay);
> + data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
> + igt_output_override_mode(output, &connector->modes[0]);
> + } else {
> + data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
> + kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
> + igt_output_override_mode(output, &default_mode);
> }
> - valid_output++;
> + data.output_count++;
> + }
> +
> + if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
> + data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
> + data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
> }
>
> data.n_pipes = 0;
> for_each_pipe(&data.display, i) {
> data.n_pipes++;
> - pipe_seq[j] = i;
> + data.pipe_seq[j] = i;
> j++;
> }
> -
> - igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
> -
> - igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
> - DRM_FORMAT_MOD_LINEAR, &data.fb);
> }
>
> igt_describe("Verify the basic modeset on big joiner mode on all pipes");
> igt_subtest_with_dynamic("basic") {
> - for (i = 0; i < data.n_pipes - 1; i++) {
> - data.pipe1 = pipe_seq[i];
> - igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
> - test_basic_modeset(&data);
> + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
> + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
> +
> + for (i = 0; i < data.big_joiner_output_count; i++) {
> + uint64_t num_combinations = 0;
> + Combination combinations[MAX_COMBINATIONS];
> +
> + generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
> + igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
> + i+1, data.n_pipes, num_combinations);
> +
> + if (num_combinations > 0)
> + igt_dynamic_f("%dx-big-joiner", i+1)
> + test_basic_modeset(&data, i+1, combinations, num_combinations);
> + else
> + break;
> }
> }
>
> - igt_describe("Verify if the modeset on the adjoining pipe is rejected "
> - "when the pipe is active with a big joiner modeset");
> igt_subtest_with_dynamic("invalid-modeset") {
> - data.pipe1 = pipe_seq[j - 1];
> -
> - igt_display_reset(&data.display);
> - for_each_connected_output(&data.display, output) {
> - if (data.output[0].output_id != output->id)
> - continue;
> -
> - mode = data.output[0].mode;
> - igt_output_set_pipe(output, data.pipe1);
> - igt_output_override_mode(output, &mode);
> + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
> + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
>
> - igt_dynamic_f("pipe-%s-%s",
> - kmstest_pipe_name(data.pipe1),
> - igt_output_name(output))
> - test_invalid_modeset(&data);
> - }
> + if (data.big_joiner_output_count >= 1)
> + igt_dynamic_f("big_joiner_on_last_pipe")
> + tets_big_joiner_on_last_pipe(&data);
>
> - if(valid_output > 1) {
> - for (i = 0; i < data.n_pipes - 1; i++) {
> - igt_output_t *first_output = NULL, *second_output = NULL;
> -
> - data.pipe1 = pipe_seq[i];
> - data.pipe2 = pipe_seq[i + 1];
> -
> - igt_display_reset(&data.display);
> - for_each_connected_output(&data.display, output) {
> - if (data.output[0].output_id == output->id) {
> - first_output = output;
> - mode = data.output[0].mode;
> -
> - igt_output_set_pipe(output, data.pipe1);
> - igt_output_override_mode(output, &mode);
> - } else if (second_output == NULL) {
> - second_output = output;
> - igt_output_set_pipe(output, data.pipe2);
> -
> - break;
> - }
> - }
> -
> - igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
> - kmstest_pipe_name(data.pipe1),
> - igt_output_name(first_output),
> - kmstest_pipe_name(data.pipe2),
> - igt_output_name(second_output))
> - test_invalid_modeset(&data);
> - }
> - }
> - }
> + if (data.big_joiner_output_count > 1)
> + igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
> + test_invalid_modeset_two_joiner(&data, false);
>
> - igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
> - igt_subtest_with_dynamic("2x-modeset") {
> - igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
> - igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
> - for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
> - data.pipe1 = pipe_seq[i];
> - data.pipe2 = pipe_seq[i + 2];
> - igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
> - test_dual_display(&data);
> + if (data.combined_output_count) {
> + igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
> + test_invalid_modeset_two_joiner(&data, true);
> }
> }
>
> igt_fixture {
> - igt_remove_fb(data.drm_fd, &data.fb);
> igt_display_fini(&data.display);
> drm_close_driver(data.drm_fd);
> }
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-06 9:53 ` Lisovskiy, Stanislav
@ 2024-03-06 10:11 ` Joshi, Kunal1
2024-03-06 10:33 ` Lisovskiy, Stanislav
0 siblings, 1 reply; 17+ messages in thread
From: Joshi, Kunal1 @ 2024-03-06 10:11 UTC (permalink / raw)
To: Lisovskiy, Stanislav; +Cc: igt-dev, Karthik B S, Bhanuprakash Modem
[-- Attachment #1: Type: text/plain, Size: 20090 bytes --]
Hello Stan,
On 3/6/2024 3:23 PM, Lisovskiy, Stanislav wrote:
> On Wed, Mar 06, 2024 at 10:55:09AM +0530, Kunal Joshi wrote:
>> big joiner outputs are statically assigned to pipe,
>> rewrite to assign dynamically
>>
>> v2: Don't change license (Bhanu)
>> Add documentation for generate_combinations (Bhanu)
>> Print the pipe name (Bhanu)
>> Remove unwanted commit (Bhanu)
>> Move combine output logic to igt_fixture (Bhanu)
>> split revamp and force joiner (Bhanu)
>>
>> Cc: Karthik B S<karthik.b.s@intel.com>
>> Cc: Bhanuprakash Modem<bhanuprakash.modem@intel.com>
>> Signed-off-by: Kunal Joshi<kunal1.joshi@intel.com>
>> ---
>> tests/intel/kms_big_joiner.c | 391 +++++++++++++++++------------------
>> 1 file changed, 187 insertions(+), 204 deletions(-)
>>
>> diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
>> index 28678b958..ba4097d8b 100644
>> --- a/tests/intel/kms_big_joiner.c
>> +++ b/tests/intel/kms_big_joiner.c
>> @@ -43,16 +43,19 @@
>> *
>> * SUBTEST: basic
>> * Description: Verify the basic modeset on big joiner mode on all pipes
>> - *
>> - * SUBTEST: 2x-modeset
>> - * Description: Verify simultaneous modeset on 2 big joiner outputs
>> */
>> -
>> IGT_TEST_DESCRIPTION("Test big joiner");
>>
>> -struct bigjoiner_output {
>> - uint32_t output_id;
>> - drmModeModeInfo mode;
>> +#define MAX_OUTPUTS 256
>> +#define MAX_COMBINATIONS 1000
>> +#define INVALID_TEST_OUTPUT 2
>> +typedef struct {
>> + int combination[MAX_OUTPUTS];
>> +} Combination;
>> +
>> +enum joiner_type {
>> + BIG_JOINER = 1 << 1,
>> + INVALID_JOINER = -1,
>> };
>>
>> typedef struct {
>> @@ -60,273 +63,253 @@ typedef struct {
>> igt_display_t display;
>> struct igt_fb fb;
>> int n_pipes;
>> - enum pipe pipe1;
>> - enum pipe pipe2;
>> - struct bigjoiner_output output[2];
>> + uint64_t big_joiner_outputs[IGT_MAX_PIPES];
>> + uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
>> + uint64_t combined_outputs[IGT_MAX_PIPES];
>> + int big_joiner_output_count;
>> + int non_big_joiner_output_count;
>> + int combined_output_count;
>> + int output_count;
>> + enum pipe pipe_seq[IGT_MAX_PIPES];
>> } data_t;
>>
>> static int max_dotclock;
>>
>> -static void test_invalid_modeset(data_t *data)
>> +/*
>> + * The generate_combinations function generates combinations of pipe allocations
>> + * for a given number of outputs
>> + *
>> + * @output_count: Number of outputs to allocate pipes for.
>> + * @pipe_count: Total number of available pipes.
>> + * @pipes_per_output: Number of pipes to be allocated for a single output.
>> + * @combinations: Array to store generated combinations.
>> + * @num_combinations: Pointer to a variable that stores the number of generated combinations.
>> + *
>> + * Example (output_count=2, pipe_count=4, pipes_per_output=2):
>> + * Combination 1: 0 2
>> + * Combination 2: 1 3
> I think this might be a bit overcomplicated - just for your information, we can't deliberately
> choose which pipes can be used for bigjoiner. On some platforms even only certain pipes, can be
> used for bigjoiner.
> Moreover the way how driver decides, which pipes are going to be used for bigjoiner is basically
> this code in intel_dp.c:
>
> if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
> adjusted_mode->crtc_clock))
> pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
>
> Means if you try to do a modeset with resolution > 5K or exceed max_dot_clock on crtc->pipe,
> then _always_ pipe + 1, going to be used for bigjoiner.
>
>
> Stan
>
Thanks for the inputs,
Goal here is to try various combination possible,
Suppose a platform supports 5 pipes(A-E) and we have 1 bigjoiner output
(DP-1) then we want to try
DP-1 on PIPE_A
DP-1 on PIPE_B
DP-1 on PIPE_C
DP-1 on PIPE_D
Suppose a platform supports 5 pipes(A-E) and we have 2 bigjoiner output
(DP-1, DP-2) then we want to try
DP-1 on PIPE_A and DP-2 on PIPE_C
DP-1 on PIPE_B and DP-2 on PIPE_D And so on, Going forward this will be
useful we introduce any feature which can allow having more pipes per
output also.
>
>> +*/
>> +static void generate_combinations(int output_count, int pipe_count,
>> + int pipes_per_output,
>> + Combination combinations[MAX_COMBINATIONS],
>> + uint64_t *num_combinations)
>> {
>> - igt_output_t *output;
>> - igt_display_t *display = &data->display;
>> - int ret;
>> + int i, index;
>> + int current_combination[MAX_OUTPUTS];
>>
>> - igt_info("Bigjoiner test on ");
>> - for_each_connected_output(display, output){
>> - enum pipe p = output->pending_pipe;
>> - drmModeModeInfo *mode;
>> - igt_pipe_t *pipe;
>> - igt_plane_t *plane;
>> + for (i = 0; i < output_count; ++i)
>> + current_combination[i] = i * pipes_per_output;
>>
>> - if (p == PIPE_NONE)
>> - continue;
>> -
>> - mode = igt_output_get_mode(output);
>> - igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
>> - kmstest_dump_mode(mode);
>> + while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
>> + for (i = 0; i < output_count; ++i)
>> + combinations[*num_combinations].combination[i] = current_combination[i];
>>
>> - pipe = &display->pipes[p];
>> - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>> + (*num_combinations)++;
>>
>> - igt_plane_set_fb(plane, &data->fb);
>> - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
>> - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
>> - }
>> + index = output_count - 1;
>> + while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
>> + index--;
>>
>> - igt_assert(!igt_check_bigjoiner_support(display));
>> + if (index < 0)
>> + break;
>>
>> - /* This commit is expectd to fail as this pipe is being used for big joiner */
>> - ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
>> - DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
>> + current_combination[index]++;
>> + for (i = index + 1; i < output_count; ++i)
>> + current_combination[i] = current_combination[i - 1] + pipes_per_output;
>> + }
>> +}
>>
>> - igt_display_reset(&data->display);
>> - igt_display_commit2(display, COMMIT_ATOMIC);
>> +static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
>> +{
>> + igt_output_t *output;
>>
>> - igt_assert_lt(ret, 0);
>> + for_each_connected_output(&data->display, output) {
>> + if (output->id == output_id)
>> + return output;
>> + }
>> + igt_assert("Output not found\n");
>> + return NULL;
>> }
>>
>> -static void test_basic_modeset(data_t *data)
>> +static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
>> {
>> + int i, j, ret;
>> + igt_output_t *output;
>> + uint64_t *outputs;
>> + igt_plane_t *primary[INVALID_TEST_OUTPUT];
>> + igt_fb_t fb[INVALID_TEST_OUTPUT];
>> drmModeModeInfo *mode;
>> - igt_output_t *output, *bigjoiner_output = NULL;
>> - igt_display_t *display = &data->display;
>> - igt_pipe_t *pipe;
>> - igt_plane_t *plane;
>>
>> - igt_display_reset(display);
>> -
>> - for_each_connected_output(display, output) {
>> - if (data->output[0].output_id == output->id) {
>> - bigjoiner_output = output;
>> - break;
>> + outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
>> +
>> + for (i = 0; i < data->n_pipes-1; i++) {
>> + igt_display_reset(&data->display);
>> + for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
>> + output = get_output_by_id_or_assert(data, outputs[j]);
>> + igt_assert(output);
>> + igt_output_set_pipe(output, data->pipe_seq[i + j]);
>> + mode = igt_output_get_mode(output);
>> + igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
>> + kmstest_pipe_name(data->pipe_seq[i + j]),
>> + igt_output_name(output), mode->hdisplay,
>> + mode->vdisplay, mode->vrefresh,
>> + j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
>> + primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>> + DRM_FORMAT_MOD_LINEAR, &fb[j]);
>> + igt_plane_set_fb(primary[j], &fb[j]);
>> }
>> + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
>> + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
>> }
>> -
>> - igt_output_set_pipe(bigjoiner_output, data->pipe1);
>> -
>> - mode = &data->output[0].mode;
>> - igt_output_override_mode(bigjoiner_output, mode);
>> -
>> - pipe = &display->pipes[data->pipe1];
>> - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>> -
>> - igt_plane_set_fb(plane, &data->fb);
>> - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
>> - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
>> -
>> - igt_display_commit2(display, COMMIT_ATOMIC);
>> -
>> - igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
>> - igt_plane_set_fb(plane, NULL);
>> - igt_display_commit2(display, COMMIT_ATOMIC);
>> }
>>
>> -static void test_dual_display(data_t *data)
>> +static void tets_big_joiner_on_last_pipe(data_t *data)
>> {
>> + int i, ret;
>> + uint64_t *outputs;
>> + igt_output_t *output;
>> + igt_plane_t *primary;
>> + igt_fb_t fb;
>> drmModeModeInfo *mode;
>> - igt_output_t *output, *bigjoiner_output[2];
>> - igt_display_t *display = &data->display;
>> - igt_pipe_t *pipe;
>> - igt_plane_t *plane1, *plane2;
>> - int count = 0;
>> -
>> - igt_display_reset(display);
>> -
>> - for_each_connected_output(display, output) {
>> - if (data->output[count].output_id == output->id) {
>> - bigjoiner_output[count] = output;
>> - count++;
>> - }
>>
>> - if (count > 1)
>> - break;
>> + outputs = data->big_joiner_outputs;
>> + for (i = 0; i < data->big_joiner_output_count; i++) {
>> + igt_display_reset(&data->display);
>> + output = get_output_by_id_or_assert(data, outputs[i]);
>> + igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
>> + mode = igt_output_get_mode(output);
>> + igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
>> + kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
>> + igt_output_name(output), mode->hdisplay,
>> + mode->vdisplay, mode->vrefresh);
>> + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>> + DRM_FORMAT_MOD_LINEAR, &fb);
>> + igt_plane_set_fb(primary, &fb);
>> + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
>> + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
>> }
>> +}
>>
>> - igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
>> - igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
>> -
>> - /* Set up first big joiner output on Pipe A*/
>> - mode = &data->output[0].mode;
>> - igt_output_override_mode(bigjoiner_output[0], mode);
>> -
>> - pipe = &display->pipes[data->pipe1];
>> - plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>> -
>> - igt_plane_set_fb(plane1, &data->fb);
>> - igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
>> - igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
>> -
>> - /* Set up second big joiner output on Pipe C*/
>> - mode = &data->output[1].mode;
>> - igt_output_override_mode(bigjoiner_output[1], mode);
>> -
>> - pipe = &display->pipes[data->pipe2];
>> - plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>> -
>> - igt_plane_set_fb(plane2, &data->fb);
>> - igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
>> - igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
>> -
>> - igt_display_commit2(display, COMMIT_ATOMIC);
>> +static void test_basic_modeset(data_t *data, int num_outputs,
>> + Combination combinations[MAX_COMBINATIONS],
>> + uint64_t num_combinations)
>> +{
>> + int i, j, ret;
>> + igt_display_t *display = &data->display;
>> + igt_output_t *output[num_outputs];
>> + igt_plane_t *primary[num_outputs];
>> + igt_fb_t fb[num_outputs];
>> + drmModeModeInfo *mode;
>>
>> - /* Clean up */
>> - igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
>> - igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
>> - igt_plane_set_fb(plane1, NULL);
>> - igt_plane_set_fb(plane2, NULL);
>> - igt_display_commit2(display, COMMIT_ATOMIC);
>> + for (i = 0; i < num_combinations; i++) {
>> + igt_display_reset(display);
>> + for (j = 0; j < num_outputs; j++) {
>> + output[j] = get_output_by_id_or_assert(data,
>> + data->big_joiner_outputs[j]);
>> + igt_info("Assigning pipe %s to %s%s",
>> + kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
>> + output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
>> + igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
>> + primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
>> + mode = igt_output_get_mode(output[j]);
>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>> + DRM_FORMAT_MOD_LINEAR, &fb[j]);
>> + igt_plane_set_fb(primary[j], &fb[j]);
>> + }
>> + ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
>> + igt_assert_f(ret == 0, "Commit failed\n");
>> + }
>> }
>>
>> igt_main
>> {
>> + int i, j;
>> data_t data;
>> igt_output_t *output;
>> - drmModeModeInfo mode;
>> - int valid_output = 0, i, count = 0, j = 0;
>> - uint16_t width = 0, height = 0;
>> - enum pipe pipe_seq[IGT_MAX_PIPES];
>> + drmModeModeInfo default_mode;
>>
>> + i = j = 0;
>> igt_fixture {
>> data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
>> kmstest_set_vt_graphics_mode();
>> -
>> igt_display_require(&data.display, data.drm_fd);
>> igt_require(data.display.is_atomic);
>> -
>> max_dotclock = igt_get_max_dotclock(data.drm_fd);
>> + data.big_joiner_output_count = 0;
>> + data.non_big_joiner_output_count = 0;
>> + data.combined_output_count = 0;
>> + data.output_count = 0;
>>
>> for_each_connected_output(&data.display, output) {
>> bool found = false;
>> drmModeConnector *connector = output->config.connector;
>> -
>> - /*
>> - * Bigjoiner will come in to the picture when the
>> - * resolution > 5K or clock > max-dot-clock.
>> - */
>> found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
>> -
>> if (found) {
>> - data.output[count].output_id = output->id;
>> - memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
>> - count++;
>> -
>> - width = max(width, mode.hdisplay);
>> - height = max(height, mode.vdisplay);
>> + data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
>> + igt_output_override_mode(output, &connector->modes[0]);
>> + } else {
>> + data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
>> + kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
>> + igt_output_override_mode(output, &default_mode);
>> }
>> - valid_output++;
>> + data.output_count++;
>> + }
>> +
>> + if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
>> + data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
>> + data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
>> }
>>
>> data.n_pipes = 0;
>> for_each_pipe(&data.display, i) {
>> data.n_pipes++;
>> - pipe_seq[j] = i;
>> + data.pipe_seq[j] = i;
>> j++;
>> }
>> -
>> - igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
>> -
>> - igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
>> - DRM_FORMAT_MOD_LINEAR, &data.fb);
>> }
>>
>> igt_describe("Verify the basic modeset on big joiner mode on all pipes");
>> igt_subtest_with_dynamic("basic") {
>> - for (i = 0; i < data.n_pipes - 1; i++) {
>> - data.pipe1 = pipe_seq[i];
>> - igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
>> - test_basic_modeset(&data);
>> + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
>> + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
>> +
>> + for (i = 0; i < data.big_joiner_output_count; i++) {
>> + uint64_t num_combinations = 0;
>> + Combination combinations[MAX_COMBINATIONS];
>> +
>> + generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
>> + igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
>> + i+1, data.n_pipes, num_combinations);
>> +
>> + if (num_combinations > 0)
>> + igt_dynamic_f("%dx-big-joiner", i+1)
>> + test_basic_modeset(&data, i+1, combinations, num_combinations);
>> + else
>> + break;
>> }
>> }
>>
>> - igt_describe("Verify if the modeset on the adjoining pipe is rejected "
>> - "when the pipe is active with a big joiner modeset");
>> igt_subtest_with_dynamic("invalid-modeset") {
>> - data.pipe1 = pipe_seq[j - 1];
>> -
>> - igt_display_reset(&data.display);
>> - for_each_connected_output(&data.display, output) {
>> - if (data.output[0].output_id != output->id)
>> - continue;
>> -
>> - mode = data.output[0].mode;
>> - igt_output_set_pipe(output, data.pipe1);
>> - igt_output_override_mode(output, &mode);
>> + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
>> + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
>>
>> - igt_dynamic_f("pipe-%s-%s",
>> - kmstest_pipe_name(data.pipe1),
>> - igt_output_name(output))
>> - test_invalid_modeset(&data);
>> - }
>> + if (data.big_joiner_output_count >= 1)
>> + igt_dynamic_f("big_joiner_on_last_pipe")
>> + tets_big_joiner_on_last_pipe(&data);
>>
>> - if(valid_output > 1) {
>> - for (i = 0; i < data.n_pipes - 1; i++) {
>> - igt_output_t *first_output = NULL, *second_output = NULL;
>> -
>> - data.pipe1 = pipe_seq[i];
>> - data.pipe2 = pipe_seq[i + 1];
>> -
>> - igt_display_reset(&data.display);
>> - for_each_connected_output(&data.display, output) {
>> - if (data.output[0].output_id == output->id) {
>> - first_output = output;
>> - mode = data.output[0].mode;
>> -
>> - igt_output_set_pipe(output, data.pipe1);
>> - igt_output_override_mode(output, &mode);
>> - } else if (second_output == NULL) {
>> - second_output = output;
>> - igt_output_set_pipe(output, data.pipe2);
>> -
>> - break;
>> - }
>> - }
>> -
>> - igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
>> - kmstest_pipe_name(data.pipe1),
>> - igt_output_name(first_output),
>> - kmstest_pipe_name(data.pipe2),
>> - igt_output_name(second_output))
>> - test_invalid_modeset(&data);
>> - }
>> - }
>> - }
>> + if (data.big_joiner_output_count > 1)
>> + igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
>> + test_invalid_modeset_two_joiner(&data, false);
>>
>> - igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
>> - igt_subtest_with_dynamic("2x-modeset") {
>> - igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
>> - igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
>> - for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
>> - data.pipe1 = pipe_seq[i];
>> - data.pipe2 = pipe_seq[i + 2];
>> - igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
>> - test_dual_display(&data);
>> + if (data.combined_output_count) {
>> + igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
>> + test_invalid_modeset_two_joiner(&data, true);
>> }
>> }
>>
>> igt_fixture {
>> - igt_remove_fb(data.drm_fd, &data.fb);
>> igt_display_fini(&data.display);
>> drm_close_driver(data.drm_fd);
>> }
>> --
>> 2.25.1
Thanks and Regards
Kunal Joshi
[-- Attachment #2: Type: text/html, Size: 20655 bytes --]
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-06 10:11 ` Joshi, Kunal1
@ 2024-03-06 10:33 ` Lisovskiy, Stanislav
2024-03-06 10:41 ` Joshi, Kunal1
2024-03-06 10:42 ` Lisovskiy, Stanislav
0 siblings, 2 replies; 17+ messages in thread
From: Lisovskiy, Stanislav @ 2024-03-06 10:33 UTC (permalink / raw)
To: Joshi, Kunal1; +Cc: igt-dev, Karthik B S, Bhanuprakash Modem
On Wed, Mar 06, 2024 at 03:41:26PM +0530, Joshi, Kunal1 wrote:
> Hello Stan,
>
> On 3/6/2024 3:23 PM, Lisovskiy, Stanislav wrote:
> > On Wed, Mar 06, 2024 at 10:55:09AM +0530, Kunal Joshi wrote:
> > > big joiner outputs are statically assigned to pipe,
> > > rewrite to assign dynamically
> > >
> > > v2: Don't change license (Bhanu)
> > > Add documentation for generate_combinations (Bhanu)
> > > Print the pipe name (Bhanu)
> > > Remove unwanted commit (Bhanu)
> > > Move combine output logic to igt_fixture (Bhanu)
> > > split revamp and force joiner (Bhanu)
> > >
> > > Cc: Karthik B S<karthik.b.s@intel.com>
> > > Cc: Bhanuprakash Modem<bhanuprakash.modem@intel.com>
> > > Signed-off-by: Kunal Joshi<kunal1.joshi@intel.com>
> > > ---
> > > tests/intel/kms_big_joiner.c | 391 +++++++++++++++++------------------
> > > 1 file changed, 187 insertions(+), 204 deletions(-)
> > >
> > > diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
> > > index 28678b958..ba4097d8b 100644
> > > --- a/tests/intel/kms_big_joiner.c
> > > +++ b/tests/intel/kms_big_joiner.c
> > > @@ -43,16 +43,19 @@
> > > *
> > > * SUBTEST: basic
> > > * Description: Verify the basic modeset on big joiner mode on all pipes
> > > - *
> > > - * SUBTEST: 2x-modeset
> > > - * Description: Verify simultaneous modeset on 2 big joiner outputs
> > > */
> > > -
> > > IGT_TEST_DESCRIPTION("Test big joiner");
> > > -struct bigjoiner_output {
> > > - uint32_t output_id;
> > > - drmModeModeInfo mode;
> > > +#define MAX_OUTPUTS 256
> > > +#define MAX_COMBINATIONS 1000
> > > +#define INVALID_TEST_OUTPUT 2
> > > +typedef struct {
> > > + int combination[MAX_OUTPUTS];
> > > +} Combination;
> > > +
> > > +enum joiner_type {
> > > + BIG_JOINER = 1 << 1,
> > > + INVALID_JOINER = -1,
> > > };
> > > typedef struct {
> > > @@ -60,273 +63,253 @@ typedef struct {
> > > igt_display_t display;
> > > struct igt_fb fb;
> > > int n_pipes;
> > > - enum pipe pipe1;
> > > - enum pipe pipe2;
> > > - struct bigjoiner_output output[2];
> > > + uint64_t big_joiner_outputs[IGT_MAX_PIPES];
> > > + uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
> > > + uint64_t combined_outputs[IGT_MAX_PIPES];
> > > + int big_joiner_output_count;
> > > + int non_big_joiner_output_count;
> > > + int combined_output_count;
> > > + int output_count;
> > > + enum pipe pipe_seq[IGT_MAX_PIPES];
> > > } data_t;
> > > static int max_dotclock;
> > > -static void test_invalid_modeset(data_t *data)
> > > +/*
> > > + * The generate_combinations function generates combinations of pipe allocations
> > > + * for a given number of outputs
> > > + *
> > > + * @output_count: Number of outputs to allocate pipes for.
> > > + * @pipe_count: Total number of available pipes.
> > > + * @pipes_per_output: Number of pipes to be allocated for a single output.
> > > + * @combinations: Array to store generated combinations.
> > > + * @num_combinations: Pointer to a variable that stores the number of generated combinations.
> > > + *
> > > + * Example (output_count=2, pipe_count=4, pipes_per_output=2):
> > > + * Combination 1: 0 2
> > > + * Combination 2: 1 3
> > I think this might be a bit overcomplicated - just for your information, we can't deliberately
> > choose which pipes can be used for bigjoiner. On some platforms even only certain pipes, can be
> > used for bigjoiner.
> > Moreover the way how driver decides, which pipes are going to be used for bigjoiner is basically
> > this code in intel_dp.c:
> >
> > if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
> > adjusted_mode->crtc_clock))
> > pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
> >
> > Means if you try to do a modeset with resolution > 5K or exceed max_dot_clock on crtc->pipe,
> > then _always_ pipe + 1, going to be used for bigjoiner.
> >
> >
> > Stan
> >
> Thanks for the inputs,
> Goal here is to try various combination possible,
> Suppose a platform supports 5 pipes(A-E) and we have 1 bigjoiner output
> (DP-1) then we want to try
> DP-1 on PIPE_A
> DP-1 on PIPE_B
> DP-1 on PIPE_C
> DP-1 on PIPE_D
>
> Suppose a platform supports 5 pipes(A-E) and we have 2 bigjoiner output
> (DP-1, DP-2) then we want to try
> DP-1 on PIPE_A and DP-2 on PIPE_C
> DP-1 on PIPE_B and DP-2 on PIPE_D And so on, Going forward this will be
> useful we introduce any feature which can allow having more pipes per output
> also.
That won't work. BSpec and current driver code allows to use only _adjacent_ pipes.
I.e if you modeset PIPE_A with 5K resolution, then bigjoiner_pipes mask would be
PIPE_A | PIPE_B. If you modeset PIPE_B with 5K resolution it will take PIPE_C as a
slave and so on.
So for instance of you had DP-1 assigned to PIPE_A and DP-2 assigned to PIPE_C by test,
_driver_ will still reassign PIPE_B to DP-2, in order for bigjoiner to work.
That logic is implemented in intel_dp.c, as I mentioned above.
Also you can check the BSpec Bigjoiner programming description.
Stan
>
> >
> > > +*/
> > > +static void generate_combinations(int output_count, int pipe_count,
> > > + int pipes_per_output,
> > > + Combination combinations[MAX_COMBINATIONS],
> > > + uint64_t *num_combinations)
> > > {
> > > - igt_output_t *output;
> > > - igt_display_t *display = &data->display;
> > > - int ret;
> > > + int i, index;
> > > + int current_combination[MAX_OUTPUTS];
> > > - igt_info("Bigjoiner test on ");
> > > - for_each_connected_output(display, output){
> > > - enum pipe p = output->pending_pipe;
> > > - drmModeModeInfo *mode;
> > > - igt_pipe_t *pipe;
> > > - igt_plane_t *plane;
> > > + for (i = 0; i < output_count; ++i)
> > > + current_combination[i] = i * pipes_per_output;
> > > - if (p == PIPE_NONE)
> > > - continue;
> > > -
> > > - mode = igt_output_get_mode(output);
> > > - igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
> > > - kmstest_dump_mode(mode);
> > > + while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
> > > + for (i = 0; i < output_count; ++i)
> > > + combinations[*num_combinations].combination[i] = current_combination[i];
> > > - pipe = &display->pipes[p];
> > > - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > + (*num_combinations)++;
> > > - igt_plane_set_fb(plane, &data->fb);
> > > - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
> > > - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> > > - }
> > > + index = output_count - 1;
> > > + while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
> > > + index--;
> > > - igt_assert(!igt_check_bigjoiner_support(display));
> > > + if (index < 0)
> > > + break;
> > > - /* This commit is expectd to fail as this pipe is being used for big joiner */
> > > - ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
> > > - DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
> > > + current_combination[index]++;
> > > + for (i = index + 1; i < output_count; ++i)
> > > + current_combination[i] = current_combination[i - 1] + pipes_per_output;
> > > + }
> > > +}
> > > - igt_display_reset(&data->display);
> > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > +static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
> > > +{
> > > + igt_output_t *output;
> > > - igt_assert_lt(ret, 0);
> > > + for_each_connected_output(&data->display, output) {
> > > + if (output->id == output_id)
> > > + return output;
> > > + }
> > > + igt_assert("Output not found\n");
> > > + return NULL;
> > > }
> > > -static void test_basic_modeset(data_t *data)
> > > +static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
> > > {
> > > + int i, j, ret;
> > > + igt_output_t *output;
> > > + uint64_t *outputs;
> > > + igt_plane_t *primary[INVALID_TEST_OUTPUT];
> > > + igt_fb_t fb[INVALID_TEST_OUTPUT];
> > > drmModeModeInfo *mode;
> > > - igt_output_t *output, *bigjoiner_output = NULL;
> > > - igt_display_t *display = &data->display;
> > > - igt_pipe_t *pipe;
> > > - igt_plane_t *plane;
> > > - igt_display_reset(display);
> > > -
> > > - for_each_connected_output(display, output) {
> > > - if (data->output[0].output_id == output->id) {
> > > - bigjoiner_output = output;
> > > - break;
> > > + outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
> > > +
> > > + for (i = 0; i < data->n_pipes-1; i++) {
> > > + igt_display_reset(&data->display);
> > > + for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
> > > + output = get_output_by_id_or_assert(data, outputs[j]);
> > > + igt_assert(output);
> > > + igt_output_set_pipe(output, data->pipe_seq[i + j]);
> > > + mode = igt_output_get_mode(output);
> > > + igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
> > > + kmstest_pipe_name(data->pipe_seq[i + j]),
> > > + igt_output_name(output), mode->hdisplay,
> > > + mode->vdisplay, mode->vrefresh,
> > > + j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
> > > + primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > + DRM_FORMAT_MOD_LINEAR, &fb[j]);
> > > + igt_plane_set_fb(primary[j], &fb[j]);
> > > }
> > > + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> > > + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> > > }
> > > -
> > > - igt_output_set_pipe(bigjoiner_output, data->pipe1);
> > > -
> > > - mode = &data->output[0].mode;
> > > - igt_output_override_mode(bigjoiner_output, mode);
> > > -
> > > - pipe = &display->pipes[data->pipe1];
> > > - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > -
> > > - igt_plane_set_fb(plane, &data->fb);
> > > - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
> > > - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> > > -
> > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > -
> > > - igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
> > > - igt_plane_set_fb(plane, NULL);
> > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > }
> > > -static void test_dual_display(data_t *data)
> > > +static void tets_big_joiner_on_last_pipe(data_t *data)
> > > {
> > > + int i, ret;
> > > + uint64_t *outputs;
> > > + igt_output_t *output;
> > > + igt_plane_t *primary;
> > > + igt_fb_t fb;
> > > drmModeModeInfo *mode;
> > > - igt_output_t *output, *bigjoiner_output[2];
> > > - igt_display_t *display = &data->display;
> > > - igt_pipe_t *pipe;
> > > - igt_plane_t *plane1, *plane2;
> > > - int count = 0;
> > > -
> > > - igt_display_reset(display);
> > > -
> > > - for_each_connected_output(display, output) {
> > > - if (data->output[count].output_id == output->id) {
> > > - bigjoiner_output[count] = output;
> > > - count++;
> > > - }
> > > - if (count > 1)
> > > - break;
> > > + outputs = data->big_joiner_outputs;
> > > + for (i = 0; i < data->big_joiner_output_count; i++) {
> > > + igt_display_reset(&data->display);
> > > + output = get_output_by_id_or_assert(data, outputs[i]);
> > > + igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
> > > + mode = igt_output_get_mode(output);
> > > + igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
> > > + kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
> > > + igt_output_name(output), mode->hdisplay,
> > > + mode->vdisplay, mode->vrefresh);
> > > + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > + DRM_FORMAT_MOD_LINEAR, &fb);
> > > + igt_plane_set_fb(primary, &fb);
> > > + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> > > + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> > > }
> > > +}
> > > - igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
> > > - igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
> > > -
> > > - /* Set up first big joiner output on Pipe A*/
> > > - mode = &data->output[0].mode;
> > > - igt_output_override_mode(bigjoiner_output[0], mode);
> > > -
> > > - pipe = &display->pipes[data->pipe1];
> > > - plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > -
> > > - igt_plane_set_fb(plane1, &data->fb);
> > > - igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
> > > - igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
> > > -
> > > - /* Set up second big joiner output on Pipe C*/
> > > - mode = &data->output[1].mode;
> > > - igt_output_override_mode(bigjoiner_output[1], mode);
> > > -
> > > - pipe = &display->pipes[data->pipe2];
> > > - plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > -
> > > - igt_plane_set_fb(plane2, &data->fb);
> > > - igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
> > > - igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
> > > -
> > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > +static void test_basic_modeset(data_t *data, int num_outputs,
> > > + Combination combinations[MAX_COMBINATIONS],
> > > + uint64_t num_combinations)
> > > +{
> > > + int i, j, ret;
> > > + igt_display_t *display = &data->display;
> > > + igt_output_t *output[num_outputs];
> > > + igt_plane_t *primary[num_outputs];
> > > + igt_fb_t fb[num_outputs];
> > > + drmModeModeInfo *mode;
> > > - /* Clean up */
> > > - igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
> > > - igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
> > > - igt_plane_set_fb(plane1, NULL);
> > > - igt_plane_set_fb(plane2, NULL);
> > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > + for (i = 0; i < num_combinations; i++) {
> > > + igt_display_reset(display);
> > > + for (j = 0; j < num_outputs; j++) {
> > > + output[j] = get_output_by_id_or_assert(data,
> > > + data->big_joiner_outputs[j]);
> > > + igt_info("Assigning pipe %s to %s%s",
> > > + kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
> > > + output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
> > > + igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
> > > + primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
> > > + mode = igt_output_get_mode(output[j]);
> > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > + DRM_FORMAT_MOD_LINEAR, &fb[j]);
> > > + igt_plane_set_fb(primary[j], &fb[j]);
> > > + }
> > > + ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
> > > + igt_assert_f(ret == 0, "Commit failed\n");
> > > + }
> > > }
> > > igt_main
> > > {
> > > + int i, j;
> > > data_t data;
> > > igt_output_t *output;
> > > - drmModeModeInfo mode;
> > > - int valid_output = 0, i, count = 0, j = 0;
> > > - uint16_t width = 0, height = 0;
> > > - enum pipe pipe_seq[IGT_MAX_PIPES];
> > > + drmModeModeInfo default_mode;
> > > + i = j = 0;
> > > igt_fixture {
> > > data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
> > > kmstest_set_vt_graphics_mode();
> > > -
> > > igt_display_require(&data.display, data.drm_fd);
> > > igt_require(data.display.is_atomic);
> > > -
> > > max_dotclock = igt_get_max_dotclock(data.drm_fd);
> > > + data.big_joiner_output_count = 0;
> > > + data.non_big_joiner_output_count = 0;
> > > + data.combined_output_count = 0;
> > > + data.output_count = 0;
> > > for_each_connected_output(&data.display, output) {
> > > bool found = false;
> > > drmModeConnector *connector = output->config.connector;
> > > -
> > > - /*
> > > - * Bigjoiner will come in to the picture when the
> > > - * resolution > 5K or clock > max-dot-clock.
> > > - */
> > > found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
> > > -
> > > if (found) {
> > > - data.output[count].output_id = output->id;
> > > - memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
> > > - count++;
> > > -
> > > - width = max(width, mode.hdisplay);
> > > - height = max(height, mode.vdisplay);
> > > + data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
> > > + igt_output_override_mode(output, &connector->modes[0]);
> > > + } else {
> > > + data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
> > > + kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
> > > + igt_output_override_mode(output, &default_mode);
> > > }
> > > - valid_output++;
> > > + data.output_count++;
> > > + }
> > > +
> > > + if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
> > > + data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
> > > + data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
> > > }
> > > data.n_pipes = 0;
> > > for_each_pipe(&data.display, i) {
> > > data.n_pipes++;
> > > - pipe_seq[j] = i;
> > > + data.pipe_seq[j] = i;
> > > j++;
> > > }
> > > -
> > > - igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
> > > -
> > > - igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
> > > - DRM_FORMAT_MOD_LINEAR, &data.fb);
> > > }
> > > igt_describe("Verify the basic modeset on big joiner mode on all pipes");
> > > igt_subtest_with_dynamic("basic") {
> > > - for (i = 0; i < data.n_pipes - 1; i++) {
> > > - data.pipe1 = pipe_seq[i];
> > > - igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
> > > - test_basic_modeset(&data);
> > > + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
> > > + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
> > > +
> > > + for (i = 0; i < data.big_joiner_output_count; i++) {
> > > + uint64_t num_combinations = 0;
> > > + Combination combinations[MAX_COMBINATIONS];
> > > +
> > > + generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
> > > + igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
> > > + i+1, data.n_pipes, num_combinations);
> > > +
> > > + if (num_combinations > 0)
> > > + igt_dynamic_f("%dx-big-joiner", i+1)
> > > + test_basic_modeset(&data, i+1, combinations, num_combinations);
> > > + else
> > > + break;
> > > }
> > > }
> > > - igt_describe("Verify if the modeset on the adjoining pipe is rejected "
> > > - "when the pipe is active with a big joiner modeset");
> > > igt_subtest_with_dynamic("invalid-modeset") {
> > > - data.pipe1 = pipe_seq[j - 1];
> > > -
> > > - igt_display_reset(&data.display);
> > > - for_each_connected_output(&data.display, output) {
> > > - if (data.output[0].output_id != output->id)
> > > - continue;
> > > -
> > > - mode = data.output[0].mode;
> > > - igt_output_set_pipe(output, data.pipe1);
> > > - igt_output_override_mode(output, &mode);
> > > + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
> > > + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
> > > - igt_dynamic_f("pipe-%s-%s",
> > > - kmstest_pipe_name(data.pipe1),
> > > - igt_output_name(output))
> > > - test_invalid_modeset(&data);
> > > - }
> > > + if (data.big_joiner_output_count >= 1)
> > > + igt_dynamic_f("big_joiner_on_last_pipe")
> > > + tets_big_joiner_on_last_pipe(&data);
> > > - if(valid_output > 1) {
> > > - for (i = 0; i < data.n_pipes - 1; i++) {
> > > - igt_output_t *first_output = NULL, *second_output = NULL;
> > > -
> > > - data.pipe1 = pipe_seq[i];
> > > - data.pipe2 = pipe_seq[i + 1];
> > > -
> > > - igt_display_reset(&data.display);
> > > - for_each_connected_output(&data.display, output) {
> > > - if (data.output[0].output_id == output->id) {
> > > - first_output = output;
> > > - mode = data.output[0].mode;
> > > -
> > > - igt_output_set_pipe(output, data.pipe1);
> > > - igt_output_override_mode(output, &mode);
> > > - } else if (second_output == NULL) {
> > > - second_output = output;
> > > - igt_output_set_pipe(output, data.pipe2);
> > > -
> > > - break;
> > > - }
> > > - }
> > > -
> > > - igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
> > > - kmstest_pipe_name(data.pipe1),
> > > - igt_output_name(first_output),
> > > - kmstest_pipe_name(data.pipe2),
> > > - igt_output_name(second_output))
> > > - test_invalid_modeset(&data);
> > > - }
> > > - }
> > > - }
> > > + if (data.big_joiner_output_count > 1)
> > > + igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
> > > + test_invalid_modeset_two_joiner(&data, false);
> > > - igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
> > > - igt_subtest_with_dynamic("2x-modeset") {
> > > - igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
> > > - igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
> > > - for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
> > > - data.pipe1 = pipe_seq[i];
> > > - data.pipe2 = pipe_seq[i + 2];
> > > - igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
> > > - test_dual_display(&data);
> > > + if (data.combined_output_count) {
> > > + igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
> > > + test_invalid_modeset_two_joiner(&data, true);
> > > }
> > > }
> > > igt_fixture {
> > > - igt_remove_fb(data.drm_fd, &data.fb);
> > > igt_display_fini(&data.display);
> > > drm_close_driver(data.drm_fd);
> > > }
> > > --
> > > 2.25.1
> Thanks and Regards
> Kunal Joshi
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-06 10:33 ` Lisovskiy, Stanislav
@ 2024-03-06 10:41 ` Joshi, Kunal1
2024-03-06 11:10 ` Lisovskiy, Stanislav
2024-03-06 10:42 ` Lisovskiy, Stanislav
1 sibling, 1 reply; 17+ messages in thread
From: Joshi, Kunal1 @ 2024-03-06 10:41 UTC (permalink / raw)
To: Lisovskiy, Stanislav; +Cc: igt-dev, Karthik B S, Bhanuprakash Modem
[-- Attachment #1: Type: text/plain, Size: 22592 bytes --]
Hello Stan,
On 3/6/2024 4:03 PM, Lisovskiy, Stanislav wrote:
> On Wed, Mar 06, 2024 at 03:41:26PM +0530, Joshi, Kunal1 wrote:
>> Hello Stan,
>>
>> On 3/6/2024 3:23 PM, Lisovskiy, Stanislav wrote:
>>> On Wed, Mar 06, 2024 at 10:55:09AM +0530, Kunal Joshi wrote:
>>>> big joiner outputs are statically assigned to pipe,
>>>> rewrite to assign dynamically
>>>>
>>>> v2: Don't change license (Bhanu)
>>>> Add documentation for generate_combinations (Bhanu)
>>>> Print the pipe name (Bhanu)
>>>> Remove unwanted commit (Bhanu)
>>>> Move combine output logic to igt_fixture (Bhanu)
>>>> split revamp and force joiner (Bhanu)
>>>>
>>>> Cc: Karthik B S<karthik.b.s@intel.com>
>>>> Cc: Bhanuprakash Modem<bhanuprakash.modem@intel.com>
>>>> Signed-off-by: Kunal Joshi<kunal1.joshi@intel.com>
>>>> ---
>>>> tests/intel/kms_big_joiner.c | 391 +++++++++++++++++------------------
>>>> 1 file changed, 187 insertions(+), 204 deletions(-)
>>>>
>>>> diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
>>>> index 28678b958..ba4097d8b 100644
>>>> --- a/tests/intel/kms_big_joiner.c
>>>> +++ b/tests/intel/kms_big_joiner.c
>>>> @@ -43,16 +43,19 @@
>>>> *
>>>> * SUBTEST: basic
>>>> * Description: Verify the basic modeset on big joiner mode on all pipes
>>>> - *
>>>> - * SUBTEST: 2x-modeset
>>>> - * Description: Verify simultaneous modeset on 2 big joiner outputs
>>>> */
>>>> -
>>>> IGT_TEST_DESCRIPTION("Test big joiner");
>>>> -struct bigjoiner_output {
>>>> - uint32_t output_id;
>>>> - drmModeModeInfo mode;
>>>> +#define MAX_OUTPUTS 256
>>>> +#define MAX_COMBINATIONS 1000
>>>> +#define INVALID_TEST_OUTPUT 2
>>>> +typedef struct {
>>>> + int combination[MAX_OUTPUTS];
>>>> +} Combination;
>>>> +
>>>> +enum joiner_type {
>>>> + BIG_JOINER = 1 << 1,
>>>> + INVALID_JOINER = -1,
>>>> };
>>>> typedef struct {
>>>> @@ -60,273 +63,253 @@ typedef struct {
>>>> igt_display_t display;
>>>> struct igt_fb fb;
>>>> int n_pipes;
>>>> - enum pipe pipe1;
>>>> - enum pipe pipe2;
>>>> - struct bigjoiner_output output[2];
>>>> + uint64_t big_joiner_outputs[IGT_MAX_PIPES];
>>>> + uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
>>>> + uint64_t combined_outputs[IGT_MAX_PIPES];
>>>> + int big_joiner_output_count;
>>>> + int non_big_joiner_output_count;
>>>> + int combined_output_count;
>>>> + int output_count;
>>>> + enum pipe pipe_seq[IGT_MAX_PIPES];
>>>> } data_t;
>>>> static int max_dotclock;
>>>> -static void test_invalid_modeset(data_t *data)
>>>> +/*
>>>> + * The generate_combinations function generates combinations of pipe allocations
>>>> + * for a given number of outputs
>>>> + *
>>>> + * @output_count: Number of outputs to allocate pipes for.
>>>> + * @pipe_count: Total number of available pipes.
>>>> + * @pipes_per_output: Number of pipes to be allocated for a single output.
>>>> + * @combinations: Array to store generated combinations.
>>>> + * @num_combinations: Pointer to a variable that stores the number of generated combinations.
>>>> + *
>>>> + * Example (output_count=2, pipe_count=4, pipes_per_output=2):
>>>> + * Combination 1: 0 2
>>>> + * Combination 2: 1 3
>>> I think this might be a bit overcomplicated - just for your information, we can't deliberately
>>> choose which pipes can be used for bigjoiner. On some platforms even only certain pipes, can be
>>> used for bigjoiner.
>>> Moreover the way how driver decides, which pipes are going to be used for bigjoiner is basically
>>> this code in intel_dp.c:
>>>
>>> if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
>>> adjusted_mode->crtc_clock))
>>> pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
>>>
>>> Means if you try to do a modeset with resolution > 5K or exceed max_dot_clock on crtc->pipe,
>>> then _always_ pipe + 1, going to be used for bigjoiner.
>>>
>>>
>>> Stan
>>>
>> Thanks for the inputs,
>> Goal here is to try various combination possible,
>> Suppose a platform supports 5 pipes(A-E) and we have 1 bigjoiner output
>> (DP-1) then we want to try
>> DP-1 on PIPE_A
>> DP-1 on PIPE_B
>> DP-1 on PIPE_C
>> DP-1 on PIPE_D
>>
>> Suppose a platform supports 5 pipes(A-E) and we have 2 bigjoiner output
>> (DP-1, DP-2) then we want to try
>> DP-1 on PIPE_A and DP-2 on PIPE_C
>> DP-1 on PIPE_B and DP-2 on PIPE_D And so on, Going forward this will be
>> useful we introduce any feature which can allow having more pipes per output
>> also.
> That won't work. BSpec and current driver code allows to use only _adjacent_ pipes.
> I.e if you modeset PIPE_A with 5K resolution, then bigjoiner_pipes mask would be
> PIPE_A | PIPE_B. If you modeset PIPE_B with 5K resolution it will take PIPE_C as a
> slave and so on.
> So for instance of you had DP-1 assigned to PIPE_A and DP-2 assigned to PIPE_C by test,
> _driver_ will still reassign PIPE_B to DP-2, in order for bigjoiner to work.
> That logic is implemented in intel_dp.c, as I mentioned above.
> Also you can check the BSpec Bigjoiner programming description.
>
> Stan
I think there is some confusion here,
Below is result of the test that was executed with current code
https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10766/bat-arls-4/igt@kms_big_joiner@force-joiner-basic@1x-joiner.html
Assigning pipe 0 to DP-3
<7> [44.263216] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
[CRTC:131:pipe B] Used as slave for big joiner master [CRTC:80:pipe A]
Assigning pipe 1 to DP-3
<7> [44.568716] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
[CRTC:182:pipe C] Used as slave for big joiner master [CRTC:131:pipe B]
Assigning pipe 2 to DP-3
<7> [44.909690] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
[CRTC:233:pipe D] Used as slave for big joiner master [CRTC:182:pipe C] So we are leaving one sequential pipe for a output,
Please let me know if i still wasn't able to explain properly.
>
>>>> +*/
>>>> +static void generate_combinations(int output_count, int pipe_count,
>>>> + int pipes_per_output,
>>>> + Combination combinations[MAX_COMBINATIONS],
>>>> + uint64_t *num_combinations)
>>>> {
>>>> - igt_output_t *output;
>>>> - igt_display_t *display = &data->display;
>>>> - int ret;
>>>> + int i, index;
>>>> + int current_combination[MAX_OUTPUTS];
>>>> - igt_info("Bigjoiner test on ");
>>>> - for_each_connected_output(display, output){
>>>> - enum pipe p = output->pending_pipe;
>>>> - drmModeModeInfo *mode;
>>>> - igt_pipe_t *pipe;
>>>> - igt_plane_t *plane;
>>>> + for (i = 0; i < output_count; ++i)
>>>> + current_combination[i] = i * pipes_per_output;
>>>> - if (p == PIPE_NONE)
>>>> - continue;
>>>> -
>>>> - mode = igt_output_get_mode(output);
>>>> - igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
>>>> - kmstest_dump_mode(mode);
>>>> + while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
>>>> + for (i = 0; i < output_count; ++i)
>>>> + combinations[*num_combinations].combination[i] = current_combination[i];
>>>> - pipe = &display->pipes[p];
>>>> - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>> + (*num_combinations)++;
>>>> - igt_plane_set_fb(plane, &data->fb);
>>>> - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
>>>> - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
>>>> - }
>>>> + index = output_count - 1;
>>>> + while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
>>>> + index--;
>>>> - igt_assert(!igt_check_bigjoiner_support(display));
>>>> + if (index < 0)
>>>> + break;
>>>> - /* This commit is expectd to fail as this pipe is being used for big joiner */
>>>> - ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
>>>> - DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
>>>> + current_combination[index]++;
>>>> + for (i = index + 1; i < output_count; ++i)
>>>> + current_combination[i] = current_combination[i - 1] + pipes_per_output;
>>>> + }
>>>> +}
>>>> - igt_display_reset(&data->display);
>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>> +static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
>>>> +{
>>>> + igt_output_t *output;
>>>> - igt_assert_lt(ret, 0);
>>>> + for_each_connected_output(&data->display, output) {
>>>> + if (output->id == output_id)
>>>> + return output;
>>>> + }
>>>> + igt_assert("Output not found\n");
>>>> + return NULL;
>>>> }
>>>> -static void test_basic_modeset(data_t *data)
>>>> +static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
>>>> {
>>>> + int i, j, ret;
>>>> + igt_output_t *output;
>>>> + uint64_t *outputs;
>>>> + igt_plane_t *primary[INVALID_TEST_OUTPUT];
>>>> + igt_fb_t fb[INVALID_TEST_OUTPUT];
>>>> drmModeModeInfo *mode;
>>>> - igt_output_t *output, *bigjoiner_output = NULL;
>>>> - igt_display_t *display = &data->display;
>>>> - igt_pipe_t *pipe;
>>>> - igt_plane_t *plane;
>>>> - igt_display_reset(display);
>>>> -
>>>> - for_each_connected_output(display, output) {
>>>> - if (data->output[0].output_id == output->id) {
>>>> - bigjoiner_output = output;
>>>> - break;
>>>> + outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
>>>> +
>>>> + for (i = 0; i < data->n_pipes-1; i++) {
>>>> + igt_display_reset(&data->display);
>>>> + for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
>>>> + output = get_output_by_id_or_assert(data, outputs[j]);
>>>> + igt_assert(output);
>>>> + igt_output_set_pipe(output, data->pipe_seq[i + j]);
>>>> + mode = igt_output_get_mode(output);
>>>> + igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
>>>> + kmstest_pipe_name(data->pipe_seq[i + j]),
>>>> + igt_output_name(output), mode->hdisplay,
>>>> + mode->vdisplay, mode->vrefresh,
>>>> + j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
>>>> + primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
>>>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>>>> + DRM_FORMAT_MOD_LINEAR, &fb[j]);
>>>> + igt_plane_set_fb(primary[j], &fb[j]);
>>>> }
>>>> + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
>>>> + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
>>>> }
>>>> -
>>>> - igt_output_set_pipe(bigjoiner_output, data->pipe1);
>>>> -
>>>> - mode = &data->output[0].mode;
>>>> - igt_output_override_mode(bigjoiner_output, mode);
>>>> -
>>>> - pipe = &display->pipes[data->pipe1];
>>>> - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>> -
>>>> - igt_plane_set_fb(plane, &data->fb);
>>>> - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
>>>> - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
>>>> -
>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>> -
>>>> - igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
>>>> - igt_plane_set_fb(plane, NULL);
>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>> }
>>>> -static void test_dual_display(data_t *data)
>>>> +static void tets_big_joiner_on_last_pipe(data_t *data)
>>>> {
>>>> + int i, ret;
>>>> + uint64_t *outputs;
>>>> + igt_output_t *output;
>>>> + igt_plane_t *primary;
>>>> + igt_fb_t fb;
>>>> drmModeModeInfo *mode;
>>>> - igt_output_t *output, *bigjoiner_output[2];
>>>> - igt_display_t *display = &data->display;
>>>> - igt_pipe_t *pipe;
>>>> - igt_plane_t *plane1, *plane2;
>>>> - int count = 0;
>>>> -
>>>> - igt_display_reset(display);
>>>> -
>>>> - for_each_connected_output(display, output) {
>>>> - if (data->output[count].output_id == output->id) {
>>>> - bigjoiner_output[count] = output;
>>>> - count++;
>>>> - }
>>>> - if (count > 1)
>>>> - break;
>>>> + outputs = data->big_joiner_outputs;
>>>> + for (i = 0; i < data->big_joiner_output_count; i++) {
>>>> + igt_display_reset(&data->display);
>>>> + output = get_output_by_id_or_assert(data, outputs[i]);
>>>> + igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
>>>> + mode = igt_output_get_mode(output);
>>>> + igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
>>>> + kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
>>>> + igt_output_name(output), mode->hdisplay,
>>>> + mode->vdisplay, mode->vrefresh);
>>>> + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
>>>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>>>> + DRM_FORMAT_MOD_LINEAR, &fb);
>>>> + igt_plane_set_fb(primary, &fb);
>>>> + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
>>>> + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
>>>> }
>>>> +}
>>>> - igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
>>>> - igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
>>>> -
>>>> - /* Set up first big joiner output on Pipe A*/
>>>> - mode = &data->output[0].mode;
>>>> - igt_output_override_mode(bigjoiner_output[0], mode);
>>>> -
>>>> - pipe = &display->pipes[data->pipe1];
>>>> - plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>> -
>>>> - igt_plane_set_fb(plane1, &data->fb);
>>>> - igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
>>>> - igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
>>>> -
>>>> - /* Set up second big joiner output on Pipe C*/
>>>> - mode = &data->output[1].mode;
>>>> - igt_output_override_mode(bigjoiner_output[1], mode);
>>>> -
>>>> - pipe = &display->pipes[data->pipe2];
>>>> - plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>> -
>>>> - igt_plane_set_fb(plane2, &data->fb);
>>>> - igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
>>>> - igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
>>>> -
>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>> +static void test_basic_modeset(data_t *data, int num_outputs,
>>>> + Combination combinations[MAX_COMBINATIONS],
>>>> + uint64_t num_combinations)
>>>> +{
>>>> + int i, j, ret;
>>>> + igt_display_t *display = &data->display;
>>>> + igt_output_t *output[num_outputs];
>>>> + igt_plane_t *primary[num_outputs];
>>>> + igt_fb_t fb[num_outputs];
>>>> + drmModeModeInfo *mode;
>>>> - /* Clean up */
>>>> - igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
>>>> - igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
>>>> - igt_plane_set_fb(plane1, NULL);
>>>> - igt_plane_set_fb(plane2, NULL);
>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>> + for (i = 0; i < num_combinations; i++) {
>>>> + igt_display_reset(display);
>>>> + for (j = 0; j < num_outputs; j++) {
>>>> + output[j] = get_output_by_id_or_assert(data,
>>>> + data->big_joiner_outputs[j]);
>>>> + igt_info("Assigning pipe %s to %s%s",
>>>> + kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
>>>> + output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
>>>> + igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
>>>> + primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
>>>> + mode = igt_output_get_mode(output[j]);
>>>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>>>> + DRM_FORMAT_MOD_LINEAR, &fb[j]);
>>>> + igt_plane_set_fb(primary[j], &fb[j]);
>>>> + }
>>>> + ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
>>>> + igt_assert_f(ret == 0, "Commit failed\n");
>>>> + }
>>>> }
>>>> igt_main
>>>> {
>>>> + int i, j;
>>>> data_t data;
>>>> igt_output_t *output;
>>>> - drmModeModeInfo mode;
>>>> - int valid_output = 0, i, count = 0, j = 0;
>>>> - uint16_t width = 0, height = 0;
>>>> - enum pipe pipe_seq[IGT_MAX_PIPES];
>>>> + drmModeModeInfo default_mode;
>>>> + i = j = 0;
>>>> igt_fixture {
>>>> data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
>>>> kmstest_set_vt_graphics_mode();
>>>> -
>>>> igt_display_require(&data.display, data.drm_fd);
>>>> igt_require(data.display.is_atomic);
>>>> -
>>>> max_dotclock = igt_get_max_dotclock(data.drm_fd);
>>>> + data.big_joiner_output_count = 0;
>>>> + data.non_big_joiner_output_count = 0;
>>>> + data.combined_output_count = 0;
>>>> + data.output_count = 0;
>>>> for_each_connected_output(&data.display, output) {
>>>> bool found = false;
>>>> drmModeConnector *connector = output->config.connector;
>>>> -
>>>> - /*
>>>> - * Bigjoiner will come in to the picture when the
>>>> - * resolution > 5K or clock > max-dot-clock.
>>>> - */
>>>> found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
>>>> -
>>>> if (found) {
>>>> - data.output[count].output_id = output->id;
>>>> - memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
>>>> - count++;
>>>> -
>>>> - width = max(width, mode.hdisplay);
>>>> - height = max(height, mode.vdisplay);
>>>> + data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
>>>> + igt_output_override_mode(output, &connector->modes[0]);
>>>> + } else {
>>>> + data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
>>>> + kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
>>>> + igt_output_override_mode(output, &default_mode);
>>>> }
>>>> - valid_output++;
>>>> + data.output_count++;
>>>> + }
>>>> +
>>>> + if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
>>>> + data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
>>>> + data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
>>>> }
>>>> data.n_pipes = 0;
>>>> for_each_pipe(&data.display, i) {
>>>> data.n_pipes++;
>>>> - pipe_seq[j] = i;
>>>> + data.pipe_seq[j] = i;
>>>> j++;
>>>> }
>>>> -
>>>> - igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
>>>> -
>>>> - igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
>>>> - DRM_FORMAT_MOD_LINEAR, &data.fb);
>>>> }
>>>> igt_describe("Verify the basic modeset on big joiner mode on all pipes");
>>>> igt_subtest_with_dynamic("basic") {
>>>> - for (i = 0; i < data.n_pipes - 1; i++) {
>>>> - data.pipe1 = pipe_seq[i];
>>>> - igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
>>>> - test_basic_modeset(&data);
>>>> + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
>>>> + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
>>>> +
>>>> + for (i = 0; i < data.big_joiner_output_count; i++) {
>>>> + uint64_t num_combinations = 0;
>>>> + Combination combinations[MAX_COMBINATIONS];
>>>> +
>>>> + generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
>>>> + igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
>>>> + i+1, data.n_pipes, num_combinations);
>>>> +
>>>> + if (num_combinations > 0)
>>>> + igt_dynamic_f("%dx-big-joiner", i+1)
>>>> + test_basic_modeset(&data, i+1, combinations, num_combinations);
>>>> + else
>>>> + break;
>>>> }
>>>> }
>>>> - igt_describe("Verify if the modeset on the adjoining pipe is rejected "
>>>> - "when the pipe is active with a big joiner modeset");
>>>> igt_subtest_with_dynamic("invalid-modeset") {
>>>> - data.pipe1 = pipe_seq[j - 1];
>>>> -
>>>> - igt_display_reset(&data.display);
>>>> - for_each_connected_output(&data.display, output) {
>>>> - if (data.output[0].output_id != output->id)
>>>> - continue;
>>>> -
>>>> - mode = data.output[0].mode;
>>>> - igt_output_set_pipe(output, data.pipe1);
>>>> - igt_output_override_mode(output, &mode);
>>>> + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
>>>> + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
>>>> - igt_dynamic_f("pipe-%s-%s",
>>>> - kmstest_pipe_name(data.pipe1),
>>>> - igt_output_name(output))
>>>> - test_invalid_modeset(&data);
>>>> - }
>>>> + if (data.big_joiner_output_count >= 1)
>>>> + igt_dynamic_f("big_joiner_on_last_pipe")
>>>> + tets_big_joiner_on_last_pipe(&data);
>>>> - if(valid_output > 1) {
>>>> - for (i = 0; i < data.n_pipes - 1; i++) {
>>>> - igt_output_t *first_output = NULL, *second_output = NULL;
>>>> -
>>>> - data.pipe1 = pipe_seq[i];
>>>> - data.pipe2 = pipe_seq[i + 1];
>>>> -
>>>> - igt_display_reset(&data.display);
>>>> - for_each_connected_output(&data.display, output) {
>>>> - if (data.output[0].output_id == output->id) {
>>>> - first_output = output;
>>>> - mode = data.output[0].mode;
>>>> -
>>>> - igt_output_set_pipe(output, data.pipe1);
>>>> - igt_output_override_mode(output, &mode);
>>>> - } else if (second_output == NULL) {
>>>> - second_output = output;
>>>> - igt_output_set_pipe(output, data.pipe2);
>>>> -
>>>> - break;
>>>> - }
>>>> - }
>>>> -
>>>> - igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
>>>> - kmstest_pipe_name(data.pipe1),
>>>> - igt_output_name(first_output),
>>>> - kmstest_pipe_name(data.pipe2),
>>>> - igt_output_name(second_output))
>>>> - test_invalid_modeset(&data);
>>>> - }
>>>> - }
>>>> - }
>>>> + if (data.big_joiner_output_count > 1)
>>>> + igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
>>>> + test_invalid_modeset_two_joiner(&data, false);
>>>> - igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
>>>> - igt_subtest_with_dynamic("2x-modeset") {
>>>> - igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
>>>> - igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
>>>> - for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
>>>> - data.pipe1 = pipe_seq[i];
>>>> - data.pipe2 = pipe_seq[i + 2];
>>>> - igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
>>>> - test_dual_display(&data);
>>>> + if (data.combined_output_count) {
>>>> + igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
>>>> + test_invalid_modeset_two_joiner(&data, true);
>>>> }
>>>> }
>>>> igt_fixture {
>>>> - igt_remove_fb(data.drm_fd, &data.fb);
>>>> igt_display_fini(&data.display);
>>>> drm_close_driver(data.drm_fd);
>>>> }
>>>> --
>>>> 2.25.1
>> Thanks and Regards
>> Kunal Joshi
Thanks and Regards
Kunal Joshi
[-- Attachment #2: Type: text/html, Size: 24914 bytes --]
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-06 10:33 ` Lisovskiy, Stanislav
2024-03-06 10:41 ` Joshi, Kunal1
@ 2024-03-06 10:42 ` Lisovskiy, Stanislav
2024-03-06 11:07 ` Modem, Bhanuprakash
1 sibling, 1 reply; 17+ messages in thread
From: Lisovskiy, Stanislav @ 2024-03-06 10:42 UTC (permalink / raw)
To: Joshi, Kunal1; +Cc: igt-dev, Karthik B S, Bhanuprakash Modem
On Wed, Mar 06, 2024 at 12:33:47PM +0200, Lisovskiy, Stanislav wrote:
> On Wed, Mar 06, 2024 at 03:41:26PM +0530, Joshi, Kunal1 wrote:
> > Hello Stan,
> >
> > On 3/6/2024 3:23 PM, Lisovskiy, Stanislav wrote:
> > > On Wed, Mar 06, 2024 at 10:55:09AM +0530, Kunal Joshi wrote:
> > > > big joiner outputs are statically assigned to pipe,
> > > > rewrite to assign dynamically
> > > >
> > > > v2: Don't change license (Bhanu)
> > > > Add documentation for generate_combinations (Bhanu)
> > > > Print the pipe name (Bhanu)
> > > > Remove unwanted commit (Bhanu)
> > > > Move combine output logic to igt_fixture (Bhanu)
> > > > split revamp and force joiner (Bhanu)
> > > >
> > > > Cc: Karthik B S<karthik.b.s@intel.com>
> > > > Cc: Bhanuprakash Modem<bhanuprakash.modem@intel.com>
> > > > Signed-off-by: Kunal Joshi<kunal1.joshi@intel.com>
> > > > ---
> > > > tests/intel/kms_big_joiner.c | 391 +++++++++++++++++------------------
> > > > 1 file changed, 187 insertions(+), 204 deletions(-)
> > > >
> > > > diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
> > > > index 28678b958..ba4097d8b 100644
> > > > --- a/tests/intel/kms_big_joiner.c
> > > > +++ b/tests/intel/kms_big_joiner.c
> > > > @@ -43,16 +43,19 @@
> > > > *
> > > > * SUBTEST: basic
> > > > * Description: Verify the basic modeset on big joiner mode on all pipes
> > > > - *
> > > > - * SUBTEST: 2x-modeset
> > > > - * Description: Verify simultaneous modeset on 2 big joiner outputs
> > > > */
> > > > -
> > > > IGT_TEST_DESCRIPTION("Test big joiner");
> > > > -struct bigjoiner_output {
> > > > - uint32_t output_id;
> > > > - drmModeModeInfo mode;
> > > > +#define MAX_OUTPUTS 256
> > > > +#define MAX_COMBINATIONS 1000
> > > > +#define INVALID_TEST_OUTPUT 2
> > > > +typedef struct {
> > > > + int combination[MAX_OUTPUTS];
> > > > +} Combination;
> > > > +
> > > > +enum joiner_type {
> > > > + BIG_JOINER = 1 << 1,
> > > > + INVALID_JOINER = -1,
> > > > };
> > > > typedef struct {
> > > > @@ -60,273 +63,253 @@ typedef struct {
> > > > igt_display_t display;
> > > > struct igt_fb fb;
> > > > int n_pipes;
> > > > - enum pipe pipe1;
> > > > - enum pipe pipe2;
> > > > - struct bigjoiner_output output[2];
> > > > + uint64_t big_joiner_outputs[IGT_MAX_PIPES];
> > > > + uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
> > > > + uint64_t combined_outputs[IGT_MAX_PIPES];
> > > > + int big_joiner_output_count;
> > > > + int non_big_joiner_output_count;
> > > > + int combined_output_count;
> > > > + int output_count;
> > > > + enum pipe pipe_seq[IGT_MAX_PIPES];
> > > > } data_t;
> > > > static int max_dotclock;
> > > > -static void test_invalid_modeset(data_t *data)
> > > > +/*
> > > > + * The generate_combinations function generates combinations of pipe allocations
> > > > + * for a given number of outputs
> > > > + *
> > > > + * @output_count: Number of outputs to allocate pipes for.
> > > > + * @pipe_count: Total number of available pipes.
> > > > + * @pipes_per_output: Number of pipes to be allocated for a single output.
> > > > + * @combinations: Array to store generated combinations.
> > > > + * @num_combinations: Pointer to a variable that stores the number of generated combinations.
> > > > + *
> > > > + * Example (output_count=2, pipe_count=4, pipes_per_output=2):
> > > > + * Combination 1: 0 2
> > > > + * Combination 2: 1 3
> > > I think this might be a bit overcomplicated - just for your information, we can't deliberately
> > > choose which pipes can be used for bigjoiner. On some platforms even only certain pipes, can be
> > > used for bigjoiner.
> > > Moreover the way how driver decides, which pipes are going to be used for bigjoiner is basically
> > > this code in intel_dp.c:
> > >
> > > if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
> > > adjusted_mode->crtc_clock))
> > > pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
> > >
> > > Means if you try to do a modeset with resolution > 5K or exceed max_dot_clock on crtc->pipe,
> > > then _always_ pipe + 1, going to be used for bigjoiner.
> > >
> > >
> > > Stan
> > >
> > Thanks for the inputs,
> > Goal here is to try various combination possible,
> > Suppose a platform supports 5 pipes(A-E) and we have 1 bigjoiner output
> > (DP-1) then we want to try
> > DP-1 on PIPE_A
> > DP-1 on PIPE_B
> > DP-1 on PIPE_C
> > DP-1 on PIPE_D
> >
> > Suppose a platform supports 5 pipes(A-E) and we have 2 bigjoiner output
> > (DP-1, DP-2) then we want to try
> > DP-1 on PIPE_A and DP-2 on PIPE_C
> > DP-1 on PIPE_B and DP-2 on PIPE_D And so on, Going forward this will be
> > useful we introduce any feature which can allow having more pipes per output
> > also.
>
> That won't work. BSpec and current driver code allows to use only _adjacent_ pipes.
> I.e if you modeset PIPE_A with 5K resolution, then bigjoiner_pipes mask would be
> PIPE_A | PIPE_B. If you modeset PIPE_B with 5K resolution it will take PIPE_C as a
> slave and so on.
> So for instance of you had DP-1 assigned to PIPE_A and DP-2 assigned to PIPE_C by test,
> _driver_ will still reassign PIPE_B to DP-2, in order for bigjoiner to work.
Meant "will still reassign PIPE_B to DP-1" to make > 5K resolution possible on DP-1.
So basically anyway we can't have all possible combinations, but only those which are
allowed by spec.
In this case it can be either
DP-1 bigjoiner on PIPE A|PIPE B
DP-2 bigjoiner on PIPE C|PIPE D
or vice versa
DP-1 bigjoiner on PIPE C|PIPE D
DP-2 bigjoiner on PIPE A|PIPE B
Stan
> That logic is implemented in intel_dp.c, as I mentioned above.
> Also you can check the BSpec Bigjoiner programming description.
>
> Stan
>
>
> >
> > >
> > > > +*/
> > > > +static void generate_combinations(int output_count, int pipe_count,
> > > > + int pipes_per_output,
> > > > + Combination combinations[MAX_COMBINATIONS],
> > > > + uint64_t *num_combinations)
> > > > {
> > > > - igt_output_t *output;
> > > > - igt_display_t *display = &data->display;
> > > > - int ret;
> > > > + int i, index;
> > > > + int current_combination[MAX_OUTPUTS];
> > > > - igt_info("Bigjoiner test on ");
> > > > - for_each_connected_output(display, output){
> > > > - enum pipe p = output->pending_pipe;
> > > > - drmModeModeInfo *mode;
> > > > - igt_pipe_t *pipe;
> > > > - igt_plane_t *plane;
> > > > + for (i = 0; i < output_count; ++i)
> > > > + current_combination[i] = i * pipes_per_output;
> > > > - if (p == PIPE_NONE)
> > > > - continue;
> > > > -
> > > > - mode = igt_output_get_mode(output);
> > > > - igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
> > > > - kmstest_dump_mode(mode);
> > > > + while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
> > > > + for (i = 0; i < output_count; ++i)
> > > > + combinations[*num_combinations].combination[i] = current_combination[i];
> > > > - pipe = &display->pipes[p];
> > > > - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > + (*num_combinations)++;
> > > > - igt_plane_set_fb(plane, &data->fb);
> > > > - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
> > > > - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> > > > - }
> > > > + index = output_count - 1;
> > > > + while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
> > > > + index--;
> > > > - igt_assert(!igt_check_bigjoiner_support(display));
> > > > + if (index < 0)
> > > > + break;
> > > > - /* This commit is expectd to fail as this pipe is being used for big joiner */
> > > > - ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
> > > > - DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
> > > > + current_combination[index]++;
> > > > + for (i = index + 1; i < output_count; ++i)
> > > > + current_combination[i] = current_combination[i - 1] + pipes_per_output;
> > > > + }
> > > > +}
> > > > - igt_display_reset(&data->display);
> > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > +static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
> > > > +{
> > > > + igt_output_t *output;
> > > > - igt_assert_lt(ret, 0);
> > > > + for_each_connected_output(&data->display, output) {
> > > > + if (output->id == output_id)
> > > > + return output;
> > > > + }
> > > > + igt_assert("Output not found\n");
> > > > + return NULL;
> > > > }
> > > > -static void test_basic_modeset(data_t *data)
> > > > +static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
> > > > {
> > > > + int i, j, ret;
> > > > + igt_output_t *output;
> > > > + uint64_t *outputs;
> > > > + igt_plane_t *primary[INVALID_TEST_OUTPUT];
> > > > + igt_fb_t fb[INVALID_TEST_OUTPUT];
> > > > drmModeModeInfo *mode;
> > > > - igt_output_t *output, *bigjoiner_output = NULL;
> > > > - igt_display_t *display = &data->display;
> > > > - igt_pipe_t *pipe;
> > > > - igt_plane_t *plane;
> > > > - igt_display_reset(display);
> > > > -
> > > > - for_each_connected_output(display, output) {
> > > > - if (data->output[0].output_id == output->id) {
> > > > - bigjoiner_output = output;
> > > > - break;
> > > > + outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
> > > > +
> > > > + for (i = 0; i < data->n_pipes-1; i++) {
> > > > + igt_display_reset(&data->display);
> > > > + for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
> > > > + output = get_output_by_id_or_assert(data, outputs[j]);
> > > > + igt_assert(output);
> > > > + igt_output_set_pipe(output, data->pipe_seq[i + j]);
> > > > + mode = igt_output_get_mode(output);
> > > > + igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
> > > > + kmstest_pipe_name(data->pipe_seq[i + j]),
> > > > + igt_output_name(output), mode->hdisplay,
> > > > + mode->vdisplay, mode->vrefresh,
> > > > + j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
> > > > + primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> > > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > > + DRM_FORMAT_MOD_LINEAR, &fb[j]);
> > > > + igt_plane_set_fb(primary[j], &fb[j]);
> > > > }
> > > > + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> > > > + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> > > > }
> > > > -
> > > > - igt_output_set_pipe(bigjoiner_output, data->pipe1);
> > > > -
> > > > - mode = &data->output[0].mode;
> > > > - igt_output_override_mode(bigjoiner_output, mode);
> > > > -
> > > > - pipe = &display->pipes[data->pipe1];
> > > > - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > -
> > > > - igt_plane_set_fb(plane, &data->fb);
> > > > - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
> > > > - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> > > > -
> > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > -
> > > > - igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
> > > > - igt_plane_set_fb(plane, NULL);
> > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > }
> > > > -static void test_dual_display(data_t *data)
> > > > +static void tets_big_joiner_on_last_pipe(data_t *data)
> > > > {
> > > > + int i, ret;
> > > > + uint64_t *outputs;
> > > > + igt_output_t *output;
> > > > + igt_plane_t *primary;
> > > > + igt_fb_t fb;
> > > > drmModeModeInfo *mode;
> > > > - igt_output_t *output, *bigjoiner_output[2];
> > > > - igt_display_t *display = &data->display;
> > > > - igt_pipe_t *pipe;
> > > > - igt_plane_t *plane1, *plane2;
> > > > - int count = 0;
> > > > -
> > > > - igt_display_reset(display);
> > > > -
> > > > - for_each_connected_output(display, output) {
> > > > - if (data->output[count].output_id == output->id) {
> > > > - bigjoiner_output[count] = output;
> > > > - count++;
> > > > - }
> > > > - if (count > 1)
> > > > - break;
> > > > + outputs = data->big_joiner_outputs;
> > > > + for (i = 0; i < data->big_joiner_output_count; i++) {
> > > > + igt_display_reset(&data->display);
> > > > + output = get_output_by_id_or_assert(data, outputs[i]);
> > > > + igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
> > > > + mode = igt_output_get_mode(output);
> > > > + igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
> > > > + kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
> > > > + igt_output_name(output), mode->hdisplay,
> > > > + mode->vdisplay, mode->vrefresh);
> > > > + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> > > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > > + DRM_FORMAT_MOD_LINEAR, &fb);
> > > > + igt_plane_set_fb(primary, &fb);
> > > > + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> > > > + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> > > > }
> > > > +}
> > > > - igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
> > > > - igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
> > > > -
> > > > - /* Set up first big joiner output on Pipe A*/
> > > > - mode = &data->output[0].mode;
> > > > - igt_output_override_mode(bigjoiner_output[0], mode);
> > > > -
> > > > - pipe = &display->pipes[data->pipe1];
> > > > - plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > -
> > > > - igt_plane_set_fb(plane1, &data->fb);
> > > > - igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
> > > > - igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
> > > > -
> > > > - /* Set up second big joiner output on Pipe C*/
> > > > - mode = &data->output[1].mode;
> > > > - igt_output_override_mode(bigjoiner_output[1], mode);
> > > > -
> > > > - pipe = &display->pipes[data->pipe2];
> > > > - plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > -
> > > > - igt_plane_set_fb(plane2, &data->fb);
> > > > - igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
> > > > - igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
> > > > -
> > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > +static void test_basic_modeset(data_t *data, int num_outputs,
> > > > + Combination combinations[MAX_COMBINATIONS],
> > > > + uint64_t num_combinations)
> > > > +{
> > > > + int i, j, ret;
> > > > + igt_display_t *display = &data->display;
> > > > + igt_output_t *output[num_outputs];
> > > > + igt_plane_t *primary[num_outputs];
> > > > + igt_fb_t fb[num_outputs];
> > > > + drmModeModeInfo *mode;
> > > > - /* Clean up */
> > > > - igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
> > > > - igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
> > > > - igt_plane_set_fb(plane1, NULL);
> > > > - igt_plane_set_fb(plane2, NULL);
> > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > + for (i = 0; i < num_combinations; i++) {
> > > > + igt_display_reset(display);
> > > > + for (j = 0; j < num_outputs; j++) {
> > > > + output[j] = get_output_by_id_or_assert(data,
> > > > + data->big_joiner_outputs[j]);
> > > > + igt_info("Assigning pipe %s to %s%s",
> > > > + kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
> > > > + output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
> > > > + igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
> > > > + primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
> > > > + mode = igt_output_get_mode(output[j]);
> > > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > > + DRM_FORMAT_MOD_LINEAR, &fb[j]);
> > > > + igt_plane_set_fb(primary[j], &fb[j]);
> > > > + }
> > > > + ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
> > > > + igt_assert_f(ret == 0, "Commit failed\n");
> > > > + }
> > > > }
> > > > igt_main
> > > > {
> > > > + int i, j;
> > > > data_t data;
> > > > igt_output_t *output;
> > > > - drmModeModeInfo mode;
> > > > - int valid_output = 0, i, count = 0, j = 0;
> > > > - uint16_t width = 0, height = 0;
> > > > - enum pipe pipe_seq[IGT_MAX_PIPES];
> > > > + drmModeModeInfo default_mode;
> > > > + i = j = 0;
> > > > igt_fixture {
> > > > data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
> > > > kmstest_set_vt_graphics_mode();
> > > > -
> > > > igt_display_require(&data.display, data.drm_fd);
> > > > igt_require(data.display.is_atomic);
> > > > -
> > > > max_dotclock = igt_get_max_dotclock(data.drm_fd);
> > > > + data.big_joiner_output_count = 0;
> > > > + data.non_big_joiner_output_count = 0;
> > > > + data.combined_output_count = 0;
> > > > + data.output_count = 0;
> > > > for_each_connected_output(&data.display, output) {
> > > > bool found = false;
> > > > drmModeConnector *connector = output->config.connector;
> > > > -
> > > > - /*
> > > > - * Bigjoiner will come in to the picture when the
> > > > - * resolution > 5K or clock > max-dot-clock.
> > > > - */
> > > > found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
> > > > -
> > > > if (found) {
> > > > - data.output[count].output_id = output->id;
> > > > - memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
> > > > - count++;
> > > > -
> > > > - width = max(width, mode.hdisplay);
> > > > - height = max(height, mode.vdisplay);
> > > > + data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
> > > > + igt_output_override_mode(output, &connector->modes[0]);
> > > > + } else {
> > > > + data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
> > > > + kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
> > > > + igt_output_override_mode(output, &default_mode);
> > > > }
> > > > - valid_output++;
> > > > + data.output_count++;
> > > > + }
> > > > +
> > > > + if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
> > > > + data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
> > > > + data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
> > > > }
> > > > data.n_pipes = 0;
> > > > for_each_pipe(&data.display, i) {
> > > > data.n_pipes++;
> > > > - pipe_seq[j] = i;
> > > > + data.pipe_seq[j] = i;
> > > > j++;
> > > > }
> > > > -
> > > > - igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
> > > > -
> > > > - igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
> > > > - DRM_FORMAT_MOD_LINEAR, &data.fb);
> > > > }
> > > > igt_describe("Verify the basic modeset on big joiner mode on all pipes");
> > > > igt_subtest_with_dynamic("basic") {
> > > > - for (i = 0; i < data.n_pipes - 1; i++) {
> > > > - data.pipe1 = pipe_seq[i];
> > > > - igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
> > > > - test_basic_modeset(&data);
> > > > + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
> > > > + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
> > > > +
> > > > + for (i = 0; i < data.big_joiner_output_count; i++) {
> > > > + uint64_t num_combinations = 0;
> > > > + Combination combinations[MAX_COMBINATIONS];
> > > > +
> > > > + generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
> > > > + igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
> > > > + i+1, data.n_pipes, num_combinations);
> > > > +
> > > > + if (num_combinations > 0)
> > > > + igt_dynamic_f("%dx-big-joiner", i+1)
> > > > + test_basic_modeset(&data, i+1, combinations, num_combinations);
> > > > + else
> > > > + break;
> > > > }
> > > > }
> > > > - igt_describe("Verify if the modeset on the adjoining pipe is rejected "
> > > > - "when the pipe is active with a big joiner modeset");
> > > > igt_subtest_with_dynamic("invalid-modeset") {
> > > > - data.pipe1 = pipe_seq[j - 1];
> > > > -
> > > > - igt_display_reset(&data.display);
> > > > - for_each_connected_output(&data.display, output) {
> > > > - if (data.output[0].output_id != output->id)
> > > > - continue;
> > > > -
> > > > - mode = data.output[0].mode;
> > > > - igt_output_set_pipe(output, data.pipe1);
> > > > - igt_output_override_mode(output, &mode);
> > > > + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
> > > > + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
> > > > - igt_dynamic_f("pipe-%s-%s",
> > > > - kmstest_pipe_name(data.pipe1),
> > > > - igt_output_name(output))
> > > > - test_invalid_modeset(&data);
> > > > - }
> > > > + if (data.big_joiner_output_count >= 1)
> > > > + igt_dynamic_f("big_joiner_on_last_pipe")
> > > > + tets_big_joiner_on_last_pipe(&data);
> > > > - if(valid_output > 1) {
> > > > - for (i = 0; i < data.n_pipes - 1; i++) {
> > > > - igt_output_t *first_output = NULL, *second_output = NULL;
> > > > -
> > > > - data.pipe1 = pipe_seq[i];
> > > > - data.pipe2 = pipe_seq[i + 1];
> > > > -
> > > > - igt_display_reset(&data.display);
> > > > - for_each_connected_output(&data.display, output) {
> > > > - if (data.output[0].output_id == output->id) {
> > > > - first_output = output;
> > > > - mode = data.output[0].mode;
> > > > -
> > > > - igt_output_set_pipe(output, data.pipe1);
> > > > - igt_output_override_mode(output, &mode);
> > > > - } else if (second_output == NULL) {
> > > > - second_output = output;
> > > > - igt_output_set_pipe(output, data.pipe2);
> > > > -
> > > > - break;
> > > > - }
> > > > - }
> > > > -
> > > > - igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
> > > > - kmstest_pipe_name(data.pipe1),
> > > > - igt_output_name(first_output),
> > > > - kmstest_pipe_name(data.pipe2),
> > > > - igt_output_name(second_output))
> > > > - test_invalid_modeset(&data);
> > > > - }
> > > > - }
> > > > - }
> > > > + if (data.big_joiner_output_count > 1)
> > > > + igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
> > > > + test_invalid_modeset_two_joiner(&data, false);
> > > > - igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
> > > > - igt_subtest_with_dynamic("2x-modeset") {
> > > > - igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
> > > > - igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
> > > > - for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
> > > > - data.pipe1 = pipe_seq[i];
> > > > - data.pipe2 = pipe_seq[i + 2];
> > > > - igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
> > > > - test_dual_display(&data);
> > > > + if (data.combined_output_count) {
> > > > + igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
> > > > + test_invalid_modeset_two_joiner(&data, true);
> > > > }
> > > > }
> > > > igt_fixture {
> > > > - igt_remove_fb(data.drm_fd, &data.fb);
> > > > igt_display_fini(&data.display);
> > > > drm_close_driver(data.drm_fd);
> > > > }
> > > > --
> > > > 2.25.1
> > Thanks and Regards
> > Kunal Joshi
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-06 10:42 ` Lisovskiy, Stanislav
@ 2024-03-06 11:07 ` Modem, Bhanuprakash
0 siblings, 0 replies; 17+ messages in thread
From: Modem, Bhanuprakash @ 2024-03-06 11:07 UTC (permalink / raw)
To: Lisovskiy, Stanislav, Joshi, Kunal1; +Cc: igt-dev, Karthik B S
On 06-03-2024 04:12 pm, Lisovskiy, Stanislav wrote:
> On Wed, Mar 06, 2024 at 12:33:47PM +0200, Lisovskiy, Stanislav wrote:
>> On Wed, Mar 06, 2024 at 03:41:26PM +0530, Joshi, Kunal1 wrote:
>>> Hello Stan,
>>>
>>> On 3/6/2024 3:23 PM, Lisovskiy, Stanislav wrote:
>>>> On Wed, Mar 06, 2024 at 10:55:09AM +0530, Kunal Joshi wrote:
>>>>> big joiner outputs are statically assigned to pipe,
>>>>> rewrite to assign dynamically
>>>>>
>>>>> v2: Don't change license (Bhanu)
>>>>> Add documentation for generate_combinations (Bhanu)
>>>>> Print the pipe name (Bhanu)
>>>>> Remove unwanted commit (Bhanu)
>>>>> Move combine output logic to igt_fixture (Bhanu)
>>>>> split revamp and force joiner (Bhanu)
>>>>>
>>>>> Cc: Karthik B S<karthik.b.s@intel.com>
>>>>> Cc: Bhanuprakash Modem<bhanuprakash.modem@intel.com>
>>>>> Signed-off-by: Kunal Joshi<kunal1.joshi@intel.com>
>>>>> ---
>>>>> tests/intel/kms_big_joiner.c | 391 +++++++++++++++++------------------
>>>>> 1 file changed, 187 insertions(+), 204 deletions(-)
>>>>>
>>>>> diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
>>>>> index 28678b958..ba4097d8b 100644
>>>>> --- a/tests/intel/kms_big_joiner.c
>>>>> +++ b/tests/intel/kms_big_joiner.c
>>>>> @@ -43,16 +43,19 @@
>>>>> *
>>>>> * SUBTEST: basic
>>>>> * Description: Verify the basic modeset on big joiner mode on all pipes
>>>>> - *
>>>>> - * SUBTEST: 2x-modeset
>>>>> - * Description: Verify simultaneous modeset on 2 big joiner outputs
>>>>> */
>>>>> -
>>>>> IGT_TEST_DESCRIPTION("Test big joiner");
>>>>> -struct bigjoiner_output {
>>>>> - uint32_t output_id;
>>>>> - drmModeModeInfo mode;
>>>>> +#define MAX_OUTPUTS 256
>>>>> +#define MAX_COMBINATIONS 1000
>>>>> +#define INVALID_TEST_OUTPUT 2
>>>>> +typedef struct {
>>>>> + int combination[MAX_OUTPUTS];
>>>>> +} Combination;
>>>>> +
>>>>> +enum joiner_type {
>>>>> + BIG_JOINER = 1 << 1,
>>>>> + INVALID_JOINER = -1,
>>>>> };
>>>>> typedef struct {
>>>>> @@ -60,273 +63,253 @@ typedef struct {
>>>>> igt_display_t display;
>>>>> struct igt_fb fb;
>>>>> int n_pipes;
>>>>> - enum pipe pipe1;
>>>>> - enum pipe pipe2;
>>>>> - struct bigjoiner_output output[2];
>>>>> + uint64_t big_joiner_outputs[IGT_MAX_PIPES];
>>>>> + uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
>>>>> + uint64_t combined_outputs[IGT_MAX_PIPES];
>>>>> + int big_joiner_output_count;
>>>>> + int non_big_joiner_output_count;
>>>>> + int combined_output_count;
>>>>> + int output_count;
>>>>> + enum pipe pipe_seq[IGT_MAX_PIPES];
>>>>> } data_t;
>>>>> static int max_dotclock;
>>>>> -static void test_invalid_modeset(data_t *data)
>>>>> +/*
>>>>> + * The generate_combinations function generates combinations of pipe allocations
>>>>> + * for a given number of outputs
>>>>> + *
>>>>> + * @output_count: Number of outputs to allocate pipes for.
>>>>> + * @pipe_count: Total number of available pipes.
>>>>> + * @pipes_per_output: Number of pipes to be allocated for a single output.
>>>>> + * @combinations: Array to store generated combinations.
>>>>> + * @num_combinations: Pointer to a variable that stores the number of generated combinations.
>>>>> + *
>>>>> + * Example (output_count=2, pipe_count=4, pipes_per_output=2):
>>>>> + * Combination 1: 0 2
>>>>> + * Combination 2: 1 3
>>>> I think this might be a bit overcomplicated - just for your information, we can't deliberately
>>>> choose which pipes can be used for bigjoiner. On some platforms even only certain pipes, can be
>>>> used for bigjoiner.
>>>> Moreover the way how driver decides, which pipes are going to be used for bigjoiner is basically
>>>> this code in intel_dp.c:
>>>>
>>>> if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
>>>> adjusted_mode->crtc_clock))
>>>> pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
>>>>
>>>> Means if you try to do a modeset with resolution > 5K or exceed max_dot_clock on crtc->pipe,
>>>> then _always_ pipe + 1, going to be used for bigjoiner.
>>>>
>>>>
>>>> Stan
>>>>
>>> Thanks for the inputs,
>>> Goal here is to try various combination possible,
>>> Suppose a platform supports 5 pipes(A-E) and we have 1 bigjoiner output
>>> (DP-1) then we want to try
>>> DP-1 on PIPE_A
>>> DP-1 on PIPE_B
>>> DP-1 on PIPE_C
>>> DP-1 on PIPE_D
>>>
>>> Suppose a platform supports 5 pipes(A-E) and we have 2 bigjoiner output
>>> (DP-1, DP-2) then we want to try
>>> DP-1 on PIPE_A and DP-2 on PIPE_C
>>> DP-1 on PIPE_B and DP-2 on PIPE_D And so on, Going forward this will be
>>> useful we introduce any feature which can allow having more pipes per output
>>> also.
>>
>> That won't work. BSpec and current driver code allows to use only _adjacent_ pipes.
>> I.e if you modeset PIPE_A with 5K resolution, then bigjoiner_pipes mask would be
>> PIPE_A | PIPE_B. If you modeset PIPE_B with 5K resolution it will take PIPE_C as a
>> slave and so on.
>> So for instance of you had DP-1 assigned to PIPE_A and DP-2 assigned to PIPE_C by test,
>> _driver_ will still reassign PIPE_B to DP-2, in order for bigjoiner to work.
>
> Meant "will still reassign PIPE_B to DP-1" to make > 5K resolution possible on DP-1.
> So basically anyway we can't have all possible combinations, but only those which are
> allowed by spec.
>
> In this case it can be either
> DP-1 bigjoiner on PIPE A|PIPE B
> DP-2 bigjoiner on PIPE C|PIPE D
> or vice versa
> DP-1 bigjoiner on PIPE C|PIPE D
> DP-2 bigjoiner on PIPE A|PIPE B
Also, we need to takecare of fused pipes.
Example: If PIPE B is fusedoff, then we can't use PIPE A for bigjoiner.
- Bhanu
>
> Stan
>
>
>> That logic is implemented in intel_dp.c, as I mentioned above.
>> Also you can check the BSpec Bigjoiner programming description.
>>
>> Stan
>>
>>
>>>
>>>>
>>>>> +*/
>>>>> +static void generate_combinations(int output_count, int pipe_count,
>>>>> + int pipes_per_output,
>>>>> + Combination combinations[MAX_COMBINATIONS],
>>>>> + uint64_t *num_combinations)
>>>>> {
>>>>> - igt_output_t *output;
>>>>> - igt_display_t *display = &data->display;
>>>>> - int ret;
>>>>> + int i, index;
>>>>> + int current_combination[MAX_OUTPUTS];
>>>>> - igt_info("Bigjoiner test on ");
>>>>> - for_each_connected_output(display, output){
>>>>> - enum pipe p = output->pending_pipe;
>>>>> - drmModeModeInfo *mode;
>>>>> - igt_pipe_t *pipe;
>>>>> - igt_plane_t *plane;
>>>>> + for (i = 0; i < output_count; ++i)
>>>>> + current_combination[i] = i * pipes_per_output;
>>>>> - if (p == PIPE_NONE)
>>>>> - continue;
>>>>> -
>>>>> - mode = igt_output_get_mode(output);
>>>>> - igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
>>>>> - kmstest_dump_mode(mode);
>>>>> + while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
>>>>> + for (i = 0; i < output_count; ++i)
>>>>> + combinations[*num_combinations].combination[i] = current_combination[i];
>>>>> - pipe = &display->pipes[p];
>>>>> - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>>> + (*num_combinations)++;
>>>>> - igt_plane_set_fb(plane, &data->fb);
>>>>> - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
>>>>> - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
>>>>> - }
>>>>> + index = output_count - 1;
>>>>> + while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
>>>>> + index--;
>>>>> - igt_assert(!igt_check_bigjoiner_support(display));
>>>>> + if (index < 0)
>>>>> + break;
>>>>> - /* This commit is expectd to fail as this pipe is being used for big joiner */
>>>>> - ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
>>>>> - DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
>>>>> + current_combination[index]++;
>>>>> + for (i = index + 1; i < output_count; ++i)
>>>>> + current_combination[i] = current_combination[i - 1] + pipes_per_output;
>>>>> + }
>>>>> +}
>>>>> - igt_display_reset(&data->display);
>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>> +static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
>>>>> +{
>>>>> + igt_output_t *output;
>>>>> - igt_assert_lt(ret, 0);
>>>>> + for_each_connected_output(&data->display, output) {
>>>>> + if (output->id == output_id)
>>>>> + return output;
>>>>> + }
>>>>> + igt_assert("Output not found\n");
>>>>> + return NULL;
>>>>> }
>>>>> -static void test_basic_modeset(data_t *data)
>>>>> +static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
>>>>> {
>>>>> + int i, j, ret;
>>>>> + igt_output_t *output;
>>>>> + uint64_t *outputs;
>>>>> + igt_plane_t *primary[INVALID_TEST_OUTPUT];
>>>>> + igt_fb_t fb[INVALID_TEST_OUTPUT];
>>>>> drmModeModeInfo *mode;
>>>>> - igt_output_t *output, *bigjoiner_output = NULL;
>>>>> - igt_display_t *display = &data->display;
>>>>> - igt_pipe_t *pipe;
>>>>> - igt_plane_t *plane;
>>>>> - igt_display_reset(display);
>>>>> -
>>>>> - for_each_connected_output(display, output) {
>>>>> - if (data->output[0].output_id == output->id) {
>>>>> - bigjoiner_output = output;
>>>>> - break;
>>>>> + outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
>>>>> +
>>>>> + for (i = 0; i < data->n_pipes-1; i++) {
>>>>> + igt_display_reset(&data->display);
>>>>> + for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
>>>>> + output = get_output_by_id_or_assert(data, outputs[j]);
>>>>> + igt_assert(output);
>>>>> + igt_output_set_pipe(output, data->pipe_seq[i + j]);
>>>>> + mode = igt_output_get_mode(output);
>>>>> + igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
>>>>> + kmstest_pipe_name(data->pipe_seq[i + j]),
>>>>> + igt_output_name(output), mode->hdisplay,
>>>>> + mode->vdisplay, mode->vrefresh,
>>>>> + j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
>>>>> + primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
>>>>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>>>>> + DRM_FORMAT_MOD_LINEAR, &fb[j]);
>>>>> + igt_plane_set_fb(primary[j], &fb[j]);
>>>>> }
>>>>> + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
>>>>> + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
>>>>> }
>>>>> -
>>>>> - igt_output_set_pipe(bigjoiner_output, data->pipe1);
>>>>> -
>>>>> - mode = &data->output[0].mode;
>>>>> - igt_output_override_mode(bigjoiner_output, mode);
>>>>> -
>>>>> - pipe = &display->pipes[data->pipe1];
>>>>> - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>>> -
>>>>> - igt_plane_set_fb(plane, &data->fb);
>>>>> - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
>>>>> - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
>>>>> -
>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>> -
>>>>> - igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
>>>>> - igt_plane_set_fb(plane, NULL);
>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>> }
>>>>> -static void test_dual_display(data_t *data)
>>>>> +static void tets_big_joiner_on_last_pipe(data_t *data)
>>>>> {
>>>>> + int i, ret;
>>>>> + uint64_t *outputs;
>>>>> + igt_output_t *output;
>>>>> + igt_plane_t *primary;
>>>>> + igt_fb_t fb;
>>>>> drmModeModeInfo *mode;
>>>>> - igt_output_t *output, *bigjoiner_output[2];
>>>>> - igt_display_t *display = &data->display;
>>>>> - igt_pipe_t *pipe;
>>>>> - igt_plane_t *plane1, *plane2;
>>>>> - int count = 0;
>>>>> -
>>>>> - igt_display_reset(display);
>>>>> -
>>>>> - for_each_connected_output(display, output) {
>>>>> - if (data->output[count].output_id == output->id) {
>>>>> - bigjoiner_output[count] = output;
>>>>> - count++;
>>>>> - }
>>>>> - if (count > 1)
>>>>> - break;
>>>>> + outputs = data->big_joiner_outputs;
>>>>> + for (i = 0; i < data->big_joiner_output_count; i++) {
>>>>> + igt_display_reset(&data->display);
>>>>> + output = get_output_by_id_or_assert(data, outputs[i]);
>>>>> + igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
>>>>> + mode = igt_output_get_mode(output);
>>>>> + igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
>>>>> + kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
>>>>> + igt_output_name(output), mode->hdisplay,
>>>>> + mode->vdisplay, mode->vrefresh);
>>>>> + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
>>>>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>>>>> + DRM_FORMAT_MOD_LINEAR, &fb);
>>>>> + igt_plane_set_fb(primary, &fb);
>>>>> + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
>>>>> + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
>>>>> }
>>>>> +}
>>>>> - igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
>>>>> - igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
>>>>> -
>>>>> - /* Set up first big joiner output on Pipe A*/
>>>>> - mode = &data->output[0].mode;
>>>>> - igt_output_override_mode(bigjoiner_output[0], mode);
>>>>> -
>>>>> - pipe = &display->pipes[data->pipe1];
>>>>> - plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>>> -
>>>>> - igt_plane_set_fb(plane1, &data->fb);
>>>>> - igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
>>>>> - igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
>>>>> -
>>>>> - /* Set up second big joiner output on Pipe C*/
>>>>> - mode = &data->output[1].mode;
>>>>> - igt_output_override_mode(bigjoiner_output[1], mode);
>>>>> -
>>>>> - pipe = &display->pipes[data->pipe2];
>>>>> - plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>>> -
>>>>> - igt_plane_set_fb(plane2, &data->fb);
>>>>> - igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
>>>>> - igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
>>>>> -
>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>> +static void test_basic_modeset(data_t *data, int num_outputs,
>>>>> + Combination combinations[MAX_COMBINATIONS],
>>>>> + uint64_t num_combinations)
>>>>> +{
>>>>> + int i, j, ret;
>>>>> + igt_display_t *display = &data->display;
>>>>> + igt_output_t *output[num_outputs];
>>>>> + igt_plane_t *primary[num_outputs];
>>>>> + igt_fb_t fb[num_outputs];
>>>>> + drmModeModeInfo *mode;
>>>>> - /* Clean up */
>>>>> - igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
>>>>> - igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
>>>>> - igt_plane_set_fb(plane1, NULL);
>>>>> - igt_plane_set_fb(plane2, NULL);
>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>> + for (i = 0; i < num_combinations; i++) {
>>>>> + igt_display_reset(display);
>>>>> + for (j = 0; j < num_outputs; j++) {
>>>>> + output[j] = get_output_by_id_or_assert(data,
>>>>> + data->big_joiner_outputs[j]);
>>>>> + igt_info("Assigning pipe %s to %s%s",
>>>>> + kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
>>>>> + output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
>>>>> + igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
>>>>> + primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
>>>>> + mode = igt_output_get_mode(output[j]);
>>>>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>>>>> + DRM_FORMAT_MOD_LINEAR, &fb[j]);
>>>>> + igt_plane_set_fb(primary[j], &fb[j]);
>>>>> + }
>>>>> + ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
>>>>> + igt_assert_f(ret == 0, "Commit failed\n");
>>>>> + }
>>>>> }
>>>>> igt_main
>>>>> {
>>>>> + int i, j;
>>>>> data_t data;
>>>>> igt_output_t *output;
>>>>> - drmModeModeInfo mode;
>>>>> - int valid_output = 0, i, count = 0, j = 0;
>>>>> - uint16_t width = 0, height = 0;
>>>>> - enum pipe pipe_seq[IGT_MAX_PIPES];
>>>>> + drmModeModeInfo default_mode;
>>>>> + i = j = 0;
>>>>> igt_fixture {
>>>>> data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
>>>>> kmstest_set_vt_graphics_mode();
>>>>> -
>>>>> igt_display_require(&data.display, data.drm_fd);
>>>>> igt_require(data.display.is_atomic);
>>>>> -
>>>>> max_dotclock = igt_get_max_dotclock(data.drm_fd);
>>>>> + data.big_joiner_output_count = 0;
>>>>> + data.non_big_joiner_output_count = 0;
>>>>> + data.combined_output_count = 0;
>>>>> + data.output_count = 0;
>>>>> for_each_connected_output(&data.display, output) {
>>>>> bool found = false;
>>>>> drmModeConnector *connector = output->config.connector;
>>>>> -
>>>>> - /*
>>>>> - * Bigjoiner will come in to the picture when the
>>>>> - * resolution > 5K or clock > max-dot-clock.
>>>>> - */
>>>>> found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
>>>>> -
>>>>> if (found) {
>>>>> - data.output[count].output_id = output->id;
>>>>> - memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
>>>>> - count++;
>>>>> -
>>>>> - width = max(width, mode.hdisplay);
>>>>> - height = max(height, mode.vdisplay);
>>>>> + data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
>>>>> + igt_output_override_mode(output, &connector->modes[0]);
>>>>> + } else {
>>>>> + data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
>>>>> + kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
>>>>> + igt_output_override_mode(output, &default_mode);
>>>>> }
>>>>> - valid_output++;
>>>>> + data.output_count++;
>>>>> + }
>>>>> +
>>>>> + if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
>>>>> + data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
>>>>> + data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
>>>>> }
>>>>> data.n_pipes = 0;
>>>>> for_each_pipe(&data.display, i) {
>>>>> data.n_pipes++;
>>>>> - pipe_seq[j] = i;
>>>>> + data.pipe_seq[j] = i;
>>>>> j++;
>>>>> }
>>>>> -
>>>>> - igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
>>>>> -
>>>>> - igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
>>>>> - DRM_FORMAT_MOD_LINEAR, &data.fb);
>>>>> }
>>>>> igt_describe("Verify the basic modeset on big joiner mode on all pipes");
>>>>> igt_subtest_with_dynamic("basic") {
>>>>> - for (i = 0; i < data.n_pipes - 1; i++) {
>>>>> - data.pipe1 = pipe_seq[i];
>>>>> - igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
>>>>> - test_basic_modeset(&data);
>>>>> + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
>>>>> + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
>>>>> +
>>>>> + for (i = 0; i < data.big_joiner_output_count; i++) {
>>>>> + uint64_t num_combinations = 0;
>>>>> + Combination combinations[MAX_COMBINATIONS];
>>>>> +
>>>>> + generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
>>>>> + igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
>>>>> + i+1, data.n_pipes, num_combinations);
>>>>> +
>>>>> + if (num_combinations > 0)
>>>>> + igt_dynamic_f("%dx-big-joiner", i+1)
>>>>> + test_basic_modeset(&data, i+1, combinations, num_combinations);
>>>>> + else
>>>>> + break;
>>>>> }
>>>>> }
>>>>> - igt_describe("Verify if the modeset on the adjoining pipe is rejected "
>>>>> - "when the pipe is active with a big joiner modeset");
>>>>> igt_subtest_with_dynamic("invalid-modeset") {
>>>>> - data.pipe1 = pipe_seq[j - 1];
>>>>> -
>>>>> - igt_display_reset(&data.display);
>>>>> - for_each_connected_output(&data.display, output) {
>>>>> - if (data.output[0].output_id != output->id)
>>>>> - continue;
>>>>> -
>>>>> - mode = data.output[0].mode;
>>>>> - igt_output_set_pipe(output, data.pipe1);
>>>>> - igt_output_override_mode(output, &mode);
>>>>> + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
>>>>> + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
>>>>> - igt_dynamic_f("pipe-%s-%s",
>>>>> - kmstest_pipe_name(data.pipe1),
>>>>> - igt_output_name(output))
>>>>> - test_invalid_modeset(&data);
>>>>> - }
>>>>> + if (data.big_joiner_output_count >= 1)
>>>>> + igt_dynamic_f("big_joiner_on_last_pipe")
>>>>> + tets_big_joiner_on_last_pipe(&data);
>>>>> - if(valid_output > 1) {
>>>>> - for (i = 0; i < data.n_pipes - 1; i++) {
>>>>> - igt_output_t *first_output = NULL, *second_output = NULL;
>>>>> -
>>>>> - data.pipe1 = pipe_seq[i];
>>>>> - data.pipe2 = pipe_seq[i + 1];
>>>>> -
>>>>> - igt_display_reset(&data.display);
>>>>> - for_each_connected_output(&data.display, output) {
>>>>> - if (data.output[0].output_id == output->id) {
>>>>> - first_output = output;
>>>>> - mode = data.output[0].mode;
>>>>> -
>>>>> - igt_output_set_pipe(output, data.pipe1);
>>>>> - igt_output_override_mode(output, &mode);
>>>>> - } else if (second_output == NULL) {
>>>>> - second_output = output;
>>>>> - igt_output_set_pipe(output, data.pipe2);
>>>>> -
>>>>> - break;
>>>>> - }
>>>>> - }
>>>>> -
>>>>> - igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
>>>>> - kmstest_pipe_name(data.pipe1),
>>>>> - igt_output_name(first_output),
>>>>> - kmstest_pipe_name(data.pipe2),
>>>>> - igt_output_name(second_output))
>>>>> - test_invalid_modeset(&data);
>>>>> - }
>>>>> - }
>>>>> - }
>>>>> + if (data.big_joiner_output_count > 1)
>>>>> + igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
>>>>> + test_invalid_modeset_two_joiner(&data, false);
>>>>> - igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
>>>>> - igt_subtest_with_dynamic("2x-modeset") {
>>>>> - igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
>>>>> - igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
>>>>> - for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
>>>>> - data.pipe1 = pipe_seq[i];
>>>>> - data.pipe2 = pipe_seq[i + 2];
>>>>> - igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
>>>>> - test_dual_display(&data);
>>>>> + if (data.combined_output_count) {
>>>>> + igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
>>>>> + test_invalid_modeset_two_joiner(&data, true);
>>>>> }
>>>>> }
>>>>> igt_fixture {
>>>>> - igt_remove_fb(data.drm_fd, &data.fb);
>>>>> igt_display_fini(&data.display);
>>>>> drm_close_driver(data.drm_fd);
>>>>> }
>>>>> --
>>>>> 2.25.1
>>> Thanks and Regards
>>> Kunal Joshi
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-06 10:41 ` Joshi, Kunal1
@ 2024-03-06 11:10 ` Lisovskiy, Stanislav
2024-03-06 11:28 ` Joshi, Kunal1
0 siblings, 1 reply; 17+ messages in thread
From: Lisovskiy, Stanislav @ 2024-03-06 11:10 UTC (permalink / raw)
To: Joshi, Kunal1; +Cc: igt-dev, Karthik B S, Bhanuprakash Modem
On Wed, Mar 06, 2024 at 04:11:03PM +0530, Joshi, Kunal1 wrote:
> Hello Stan,
>
> On 3/6/2024 4:03 PM, Lisovskiy, Stanislav wrote:
> > On Wed, Mar 06, 2024 at 03:41:26PM +0530, Joshi, Kunal1 wrote:
> > > Hello Stan,
> > >
> > > On 3/6/2024 3:23 PM, Lisovskiy, Stanislav wrote:
> > > > On Wed, Mar 06, 2024 at 10:55:09AM +0530, Kunal Joshi wrote:
> > > > > big joiner outputs are statically assigned to pipe,
> > > > > rewrite to assign dynamically
> > > > >
> > > > > v2: Don't change license (Bhanu)
> > > > > Add documentation for generate_combinations (Bhanu)
> > > > > Print the pipe name (Bhanu)
> > > > > Remove unwanted commit (Bhanu)
> > > > > Move combine output logic to igt_fixture (Bhanu)
> > > > > split revamp and force joiner (Bhanu)
> > > > >
> > > > > Cc: Karthik B S<karthik.b.s@intel.com>
> > > > > Cc: Bhanuprakash Modem<bhanuprakash.modem@intel.com>
> > > > > Signed-off-by: Kunal Joshi<kunal1.joshi@intel.com>
> > > > > ---
> > > > > tests/intel/kms_big_joiner.c | 391 +++++++++++++++++------------------
> > > > > 1 file changed, 187 insertions(+), 204 deletions(-)
> > > > >
> > > > > diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
> > > > > index 28678b958..ba4097d8b 100644
> > > > > --- a/tests/intel/kms_big_joiner.c
> > > > > +++ b/tests/intel/kms_big_joiner.c
> > > > > @@ -43,16 +43,19 @@
> > > > > *
> > > > > * SUBTEST: basic
> > > > > * Description: Verify the basic modeset on big joiner mode on all pipes
> > > > > - *
> > > > > - * SUBTEST: 2x-modeset
> > > > > - * Description: Verify simultaneous modeset on 2 big joiner outputs
> > > > > */
> > > > > -
> > > > > IGT_TEST_DESCRIPTION("Test big joiner");
> > > > > -struct bigjoiner_output {
> > > > > - uint32_t output_id;
> > > > > - drmModeModeInfo mode;
> > > > > +#define MAX_OUTPUTS 256
> > > > > +#define MAX_COMBINATIONS 1000
> > > > > +#define INVALID_TEST_OUTPUT 2
> > > > > +typedef struct {
> > > > > + int combination[MAX_OUTPUTS];
> > > > > +} Combination;
> > > > > +
> > > > > +enum joiner_type {
> > > > > + BIG_JOINER = 1 << 1,
> > > > > + INVALID_JOINER = -1,
> > > > > };
> > > > > typedef struct {
> > > > > @@ -60,273 +63,253 @@ typedef struct {
> > > > > igt_display_t display;
> > > > > struct igt_fb fb;
> > > > > int n_pipes;
> > > > > - enum pipe pipe1;
> > > > > - enum pipe pipe2;
> > > > > - struct bigjoiner_output output[2];
> > > > > + uint64_t big_joiner_outputs[IGT_MAX_PIPES];
> > > > > + uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
> > > > > + uint64_t combined_outputs[IGT_MAX_PIPES];
> > > > > + int big_joiner_output_count;
> > > > > + int non_big_joiner_output_count;
> > > > > + int combined_output_count;
> > > > > + int output_count;
> > > > > + enum pipe pipe_seq[IGT_MAX_PIPES];
> > > > > } data_t;
> > > > > static int max_dotclock;
> > > > > -static void test_invalid_modeset(data_t *data)
> > > > > +/*
> > > > > + * The generate_combinations function generates combinations of pipe allocations
> > > > > + * for a given number of outputs
> > > > > + *
> > > > > + * @output_count: Number of outputs to allocate pipes for.
> > > > > + * @pipe_count: Total number of available pipes.
> > > > > + * @pipes_per_output: Number of pipes to be allocated for a single output.
> > > > > + * @combinations: Array to store generated combinations.
> > > > > + * @num_combinations: Pointer to a variable that stores the number of generated combinations.
> > > > > + *
> > > > > + * Example (output_count=2, pipe_count=4, pipes_per_output=2):
> > > > > + * Combination 1: 0 2
> > > > > + * Combination 2: 1 3
> > > > I think this might be a bit overcomplicated - just for your information, we can't deliberately
> > > > choose which pipes can be used for bigjoiner. On some platforms even only certain pipes, can be
> > > > used for bigjoiner.
> > > > Moreover the way how driver decides, which pipes are going to be used for bigjoiner is basically
> > > > this code in intel_dp.c:
> > > >
> > > > if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
> > > > adjusted_mode->crtc_clock))
> > > > pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
> > > >
> > > > Means if you try to do a modeset with resolution > 5K or exceed max_dot_clock on crtc->pipe,
> > > > then _always_ pipe + 1, going to be used for bigjoiner.
> > > >
> > > >
> > > > Stan
> > > >
> > > Thanks for the inputs,
> > > Goal here is to try various combination possible,
> > > Suppose a platform supports 5 pipes(A-E) and we have 1 bigjoiner output
> > > (DP-1) then we want to try
> > > DP-1 on PIPE_A
> > > DP-1 on PIPE_B
> > > DP-1 on PIPE_C
> > > DP-1 on PIPE_D
> > >
> > > Suppose a platform supports 5 pipes(A-E) and we have 2 bigjoiner output
> > > (DP-1, DP-2) then we want to try
> > > DP-1 on PIPE_A and DP-2 on PIPE_C
> > > DP-1 on PIPE_B and DP-2 on PIPE_D And so on, Going forward this will be
> > > useful we introduce any feature which can allow having more pipes per output
> > > also.
> > That won't work. BSpec and current driver code allows to use only _adjacent_ pipes.
> > I.e if you modeset PIPE_A with 5K resolution, then bigjoiner_pipes mask would be
> > PIPE_A | PIPE_B. If you modeset PIPE_B with 5K resolution it will take PIPE_C as a
> > slave and so on.
> > So for instance of you had DP-1 assigned to PIPE_A and DP-2 assigned to PIPE_C by test,
> > _driver_ will still reassign PIPE_B to DP-2, in order for bigjoiner to work.
> > That logic is implemented in intel_dp.c, as I mentioned above.
> > Also you can check the BSpec Bigjoiner programming description.
> >
> > Stan
> I think there is some confusion here,
>
> Below is result of the test that was executed with current code
> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10766/bat-arls-4/igt@kms_big_joiner@force-joiner-basic@1x-joiner.html
>
> Assigning pipe 0 to DP-3
> <7> [44.263216] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
> [CRTC:131:pipe B] Used as slave for big joiner master [CRTC:80:pipe A]
>
> Assigning pipe 1 to DP-3
> <7> [44.568716] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
> [CRTC:182:pipe C] Used as slave for big joiner master [CRTC:131:pipe B]
> Assigning pipe 2 to DP-3
> <7> [44.909690] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
> [CRTC:233:pipe D] Used as slave for big joiner master [CRTC:182:pipe C] So
> we are leaving one sequential pipe for a output,
> Please let me know if i still wasn't able to explain properly.
Yes, that is correct here. I was just trying to clarify that we can't have all
possible combinations unfortunately.
There are only certain scenarios supported, so could be a bit overkill trying to
approach this combinatorical way, but rather I would see this more like introducing
some mapping table, containing valid mappings or something similar.
I don't think we are going to have more than 5 pipes anyway soon.
That way, it might be way easier to check with spec and maintain this code.
In case if more pipes are supported per output, most likely it won't be that straight
forward as well :)
I would add something like "get_next_master_pipe" function, which you call for each pipe
which is allowed to be master. That function would also take available pipes as a mask.
Then it returns next avaiable master pipe, considering the available pipes mask.
That way you easily generate all allowed combinations, by just modifying available pipes mask.
Stan
>
> >
> > > > > +*/
> > > > > +static void generate_combinations(int output_count, int pipe_count,
> > > > > + int pipes_per_output,
> > > > > + Combination combinations[MAX_COMBINATIONS],
> > > > > + uint64_t *num_combinations)
> > > > > {
> > > > > - igt_output_t *output;
> > > > > - igt_display_t *display = &data->display;
> > > > > - int ret;
> > > > > + int i, index;
> > > > > + int current_combination[MAX_OUTPUTS];
> > > > > - igt_info("Bigjoiner test on ");
> > > > > - for_each_connected_output(display, output){
> > > > > - enum pipe p = output->pending_pipe;
> > > > > - drmModeModeInfo *mode;
> > > > > - igt_pipe_t *pipe;
> > > > > - igt_plane_t *plane;
> > > > > + for (i = 0; i < output_count; ++i)
> > > > > + current_combination[i] = i * pipes_per_output;
> > > > > - if (p == PIPE_NONE)
> > > > > - continue;
> > > > > -
> > > > > - mode = igt_output_get_mode(output);
> > > > > - igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
> > > > > - kmstest_dump_mode(mode);
> > > > > + while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
> > > > > + for (i = 0; i < output_count; ++i)
> > > > > + combinations[*num_combinations].combination[i] = current_combination[i];
> > > > > - pipe = &display->pipes[p];
> > > > > - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > > + (*num_combinations)++;
> > > > > - igt_plane_set_fb(plane, &data->fb);
> > > > > - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
> > > > > - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> > > > > - }
> > > > > + index = output_count - 1;
> > > > > + while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
> > > > > + index--;
> > > > > - igt_assert(!igt_check_bigjoiner_support(display));
> > > > > + if (index < 0)
> > > > > + break;
> > > > > - /* This commit is expectd to fail as this pipe is being used for big joiner */
> > > > > - ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
> > > > > - DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
> > > > > + current_combination[index]++;
> > > > > + for (i = index + 1; i < output_count; ++i)
> > > > > + current_combination[i] = current_combination[i - 1] + pipes_per_output;
> > > > > + }
> > > > > +}
> > > > > - igt_display_reset(&data->display);
> > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > +static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
> > > > > +{
> > > > > + igt_output_t *output;
> > > > > - igt_assert_lt(ret, 0);
> > > > > + for_each_connected_output(&data->display, output) {
> > > > > + if (output->id == output_id)
> > > > > + return output;
> > > > > + }
> > > > > + igt_assert("Output not found\n");
> > > > > + return NULL;
> > > > > }
> > > > > -static void test_basic_modeset(data_t *data)
> > > > > +static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
> > > > > {
> > > > > + int i, j, ret;
> > > > > + igt_output_t *output;
> > > > > + uint64_t *outputs;
> > > > > + igt_plane_t *primary[INVALID_TEST_OUTPUT];
> > > > > + igt_fb_t fb[INVALID_TEST_OUTPUT];
> > > > > drmModeModeInfo *mode;
> > > > > - igt_output_t *output, *bigjoiner_output = NULL;
> > > > > - igt_display_t *display = &data->display;
> > > > > - igt_pipe_t *pipe;
> > > > > - igt_plane_t *plane;
> > > > > - igt_display_reset(display);
> > > > > -
> > > > > - for_each_connected_output(display, output) {
> > > > > - if (data->output[0].output_id == output->id) {
> > > > > - bigjoiner_output = output;
> > > > > - break;
> > > > > + outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
> > > > > +
> > > > > + for (i = 0; i < data->n_pipes-1; i++) {
> > > > > + igt_display_reset(&data->display);
> > > > > + for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
> > > > > + output = get_output_by_id_or_assert(data, outputs[j]);
> > > > > + igt_assert(output);
> > > > > + igt_output_set_pipe(output, data->pipe_seq[i + j]);
> > > > > + mode = igt_output_get_mode(output);
> > > > > + igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
> > > > > + kmstest_pipe_name(data->pipe_seq[i + j]),
> > > > > + igt_output_name(output), mode->hdisplay,
> > > > > + mode->vdisplay, mode->vrefresh,
> > > > > + j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
> > > > > + primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> > > > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > > > + DRM_FORMAT_MOD_LINEAR, &fb[j]);
> > > > > + igt_plane_set_fb(primary[j], &fb[j]);
> > > > > }
> > > > > + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> > > > > + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> > > > > }
> > > > > -
> > > > > - igt_output_set_pipe(bigjoiner_output, data->pipe1);
> > > > > -
> > > > > - mode = &data->output[0].mode;
> > > > > - igt_output_override_mode(bigjoiner_output, mode);
> > > > > -
> > > > > - pipe = &display->pipes[data->pipe1];
> > > > > - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > > -
> > > > > - igt_plane_set_fb(plane, &data->fb);
> > > > > - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
> > > > > - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> > > > > -
> > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > -
> > > > > - igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
> > > > > - igt_plane_set_fb(plane, NULL);
> > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > }
> > > > > -static void test_dual_display(data_t *data)
> > > > > +static void tets_big_joiner_on_last_pipe(data_t *data)
> > > > > {
> > > > > + int i, ret;
> > > > > + uint64_t *outputs;
> > > > > + igt_output_t *output;
> > > > > + igt_plane_t *primary;
> > > > > + igt_fb_t fb;
> > > > > drmModeModeInfo *mode;
> > > > > - igt_output_t *output, *bigjoiner_output[2];
> > > > > - igt_display_t *display = &data->display;
> > > > > - igt_pipe_t *pipe;
> > > > > - igt_plane_t *plane1, *plane2;
> > > > > - int count = 0;
> > > > > -
> > > > > - igt_display_reset(display);
> > > > > -
> > > > > - for_each_connected_output(display, output) {
> > > > > - if (data->output[count].output_id == output->id) {
> > > > > - bigjoiner_output[count] = output;
> > > > > - count++;
> > > > > - }
> > > > > - if (count > 1)
> > > > > - break;
> > > > > + outputs = data->big_joiner_outputs;
> > > > > + for (i = 0; i < data->big_joiner_output_count; i++) {
> > > > > + igt_display_reset(&data->display);
> > > > > + output = get_output_by_id_or_assert(data, outputs[i]);
> > > > > + igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
> > > > > + mode = igt_output_get_mode(output);
> > > > > + igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
> > > > > + kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
> > > > > + igt_output_name(output), mode->hdisplay,
> > > > > + mode->vdisplay, mode->vrefresh);
> > > > > + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> > > > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > > > + DRM_FORMAT_MOD_LINEAR, &fb);
> > > > > + igt_plane_set_fb(primary, &fb);
> > > > > + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> > > > > + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> > > > > }
> > > > > +}
> > > > > - igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
> > > > > - igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
> > > > > -
> > > > > - /* Set up first big joiner output on Pipe A*/
> > > > > - mode = &data->output[0].mode;
> > > > > - igt_output_override_mode(bigjoiner_output[0], mode);
> > > > > -
> > > > > - pipe = &display->pipes[data->pipe1];
> > > > > - plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > > -
> > > > > - igt_plane_set_fb(plane1, &data->fb);
> > > > > - igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
> > > > > - igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
> > > > > -
> > > > > - /* Set up second big joiner output on Pipe C*/
> > > > > - mode = &data->output[1].mode;
> > > > > - igt_output_override_mode(bigjoiner_output[1], mode);
> > > > > -
> > > > > - pipe = &display->pipes[data->pipe2];
> > > > > - plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > > -
> > > > > - igt_plane_set_fb(plane2, &data->fb);
> > > > > - igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
> > > > > - igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
> > > > > -
> > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > +static void test_basic_modeset(data_t *data, int num_outputs,
> > > > > + Combination combinations[MAX_COMBINATIONS],
> > > > > + uint64_t num_combinations)
> > > > > +{
> > > > > + int i, j, ret;
> > > > > + igt_display_t *display = &data->display;
> > > > > + igt_output_t *output[num_outputs];
> > > > > + igt_plane_t *primary[num_outputs];
> > > > > + igt_fb_t fb[num_outputs];
> > > > > + drmModeModeInfo *mode;
> > > > > - /* Clean up */
> > > > > - igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
> > > > > - igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
> > > > > - igt_plane_set_fb(plane1, NULL);
> > > > > - igt_plane_set_fb(plane2, NULL);
> > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > + for (i = 0; i < num_combinations; i++) {
> > > > > + igt_display_reset(display);
> > > > > + for (j = 0; j < num_outputs; j++) {
> > > > > + output[j] = get_output_by_id_or_assert(data,
> > > > > + data->big_joiner_outputs[j]);
> > > > > + igt_info("Assigning pipe %s to %s%s",
> > > > > + kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
> > > > > + output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
> > > > > + igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
> > > > > + primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
> > > > > + mode = igt_output_get_mode(output[j]);
> > > > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > > > + DRM_FORMAT_MOD_LINEAR, &fb[j]);
> > > > > + igt_plane_set_fb(primary[j], &fb[j]);
> > > > > + }
> > > > > + ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
> > > > > + igt_assert_f(ret == 0, "Commit failed\n");
> > > > > + }
> > > > > }
> > > > > igt_main
> > > > > {
> > > > > + int i, j;
> > > > > data_t data;
> > > > > igt_output_t *output;
> > > > > - drmModeModeInfo mode;
> > > > > - int valid_output = 0, i, count = 0, j = 0;
> > > > > - uint16_t width = 0, height = 0;
> > > > > - enum pipe pipe_seq[IGT_MAX_PIPES];
> > > > > + drmModeModeInfo default_mode;
> > > > > + i = j = 0;
> > > > > igt_fixture {
> > > > > data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
> > > > > kmstest_set_vt_graphics_mode();
> > > > > -
> > > > > igt_display_require(&data.display, data.drm_fd);
> > > > > igt_require(data.display.is_atomic);
> > > > > -
> > > > > max_dotclock = igt_get_max_dotclock(data.drm_fd);
> > > > > + data.big_joiner_output_count = 0;
> > > > > + data.non_big_joiner_output_count = 0;
> > > > > + data.combined_output_count = 0;
> > > > > + data.output_count = 0;
> > > > > for_each_connected_output(&data.display, output) {
> > > > > bool found = false;
> > > > > drmModeConnector *connector = output->config.connector;
> > > > > -
> > > > > - /*
> > > > > - * Bigjoiner will come in to the picture when the
> > > > > - * resolution > 5K or clock > max-dot-clock.
> > > > > - */
> > > > > found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
> > > > > -
> > > > > if (found) {
> > > > > - data.output[count].output_id = output->id;
> > > > > - memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
> > > > > - count++;
> > > > > -
> > > > > - width = max(width, mode.hdisplay);
> > > > > - height = max(height, mode.vdisplay);
> > > > > + data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
> > > > > + igt_output_override_mode(output, &connector->modes[0]);
> > > > > + } else {
> > > > > + data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
> > > > > + kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
> > > > > + igt_output_override_mode(output, &default_mode);
> > > > > }
> > > > > - valid_output++;
> > > > > + data.output_count++;
> > > > > + }
> > > > > +
> > > > > + if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
> > > > > + data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
> > > > > + data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
> > > > > }
> > > > > data.n_pipes = 0;
> > > > > for_each_pipe(&data.display, i) {
> > > > > data.n_pipes++;
> > > > > - pipe_seq[j] = i;
> > > > > + data.pipe_seq[j] = i;
> > > > > j++;
> > > > > }
> > > > > -
> > > > > - igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
> > > > > -
> > > > > - igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
> > > > > - DRM_FORMAT_MOD_LINEAR, &data.fb);
> > > > > }
> > > > > igt_describe("Verify the basic modeset on big joiner mode on all pipes");
> > > > > igt_subtest_with_dynamic("basic") {
> > > > > - for (i = 0; i < data.n_pipes - 1; i++) {
> > > > > - data.pipe1 = pipe_seq[i];
> > > > > - igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
> > > > > - test_basic_modeset(&data);
> > > > > + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
> > > > > + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
> > > > > +
> > > > > + for (i = 0; i < data.big_joiner_output_count; i++) {
> > > > > + uint64_t num_combinations = 0;
> > > > > + Combination combinations[MAX_COMBINATIONS];
> > > > > +
> > > > > + generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
> > > > > + igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
> > > > > + i+1, data.n_pipes, num_combinations);
> > > > > +
> > > > > + if (num_combinations > 0)
> > > > > + igt_dynamic_f("%dx-big-joiner", i+1)
> > > > > + test_basic_modeset(&data, i+1, combinations, num_combinations);
> > > > > + else
> > > > > + break;
> > > > > }
> > > > > }
> > > > > - igt_describe("Verify if the modeset on the adjoining pipe is rejected "
> > > > > - "when the pipe is active with a big joiner modeset");
> > > > > igt_subtest_with_dynamic("invalid-modeset") {
> > > > > - data.pipe1 = pipe_seq[j - 1];
> > > > > -
> > > > > - igt_display_reset(&data.display);
> > > > > - for_each_connected_output(&data.display, output) {
> > > > > - if (data.output[0].output_id != output->id)
> > > > > - continue;
> > > > > -
> > > > > - mode = data.output[0].mode;
> > > > > - igt_output_set_pipe(output, data.pipe1);
> > > > > - igt_output_override_mode(output, &mode);
> > > > > + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
> > > > > + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
> > > > > - igt_dynamic_f("pipe-%s-%s",
> > > > > - kmstest_pipe_name(data.pipe1),
> > > > > - igt_output_name(output))
> > > > > - test_invalid_modeset(&data);
> > > > > - }
> > > > > + if (data.big_joiner_output_count >= 1)
> > > > > + igt_dynamic_f("big_joiner_on_last_pipe")
> > > > > + tets_big_joiner_on_last_pipe(&data);
> > > > > - if(valid_output > 1) {
> > > > > - for (i = 0; i < data.n_pipes - 1; i++) {
> > > > > - igt_output_t *first_output = NULL, *second_output = NULL;
> > > > > -
> > > > > - data.pipe1 = pipe_seq[i];
> > > > > - data.pipe2 = pipe_seq[i + 1];
> > > > > -
> > > > > - igt_display_reset(&data.display);
> > > > > - for_each_connected_output(&data.display, output) {
> > > > > - if (data.output[0].output_id == output->id) {
> > > > > - first_output = output;
> > > > > - mode = data.output[0].mode;
> > > > > -
> > > > > - igt_output_set_pipe(output, data.pipe1);
> > > > > - igt_output_override_mode(output, &mode);
> > > > > - } else if (second_output == NULL) {
> > > > > - second_output = output;
> > > > > - igt_output_set_pipe(output, data.pipe2);
> > > > > -
> > > > > - break;
> > > > > - }
> > > > > - }
> > > > > -
> > > > > - igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
> > > > > - kmstest_pipe_name(data.pipe1),
> > > > > - igt_output_name(first_output),
> > > > > - kmstest_pipe_name(data.pipe2),
> > > > > - igt_output_name(second_output))
> > > > > - test_invalid_modeset(&data);
> > > > > - }
> > > > > - }
> > > > > - }
> > > > > + if (data.big_joiner_output_count > 1)
> > > > > + igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
> > > > > + test_invalid_modeset_two_joiner(&data, false);
> > > > > - igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
> > > > > - igt_subtest_with_dynamic("2x-modeset") {
> > > > > - igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
> > > > > - igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
> > > > > - for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
> > > > > - data.pipe1 = pipe_seq[i];
> > > > > - data.pipe2 = pipe_seq[i + 2];
> > > > > - igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
> > > > > - test_dual_display(&data);
> > > > > + if (data.combined_output_count) {
> > > > > + igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
> > > > > + test_invalid_modeset_two_joiner(&data, true);
> > > > > }
> > > > > }
> > > > > igt_fixture {
> > > > > - igt_remove_fb(data.drm_fd, &data.fb);
> > > > > igt_display_fini(&data.display);
> > > > > drm_close_driver(data.drm_fd);
> > > > > }
> > > > > --
> > > > > 2.25.1
> > > Thanks and Regards
> > > Kunal Joshi
> Thanks and Regards
> Kunal Joshi
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-06 11:10 ` Lisovskiy, Stanislav
@ 2024-03-06 11:28 ` Joshi, Kunal1
2024-03-06 12:52 ` Lisovskiy, Stanislav
0 siblings, 1 reply; 17+ messages in thread
From: Joshi, Kunal1 @ 2024-03-06 11:28 UTC (permalink / raw)
To: Lisovskiy, Stanislav; +Cc: igt-dev, Karthik B S, Bhanuprakash Modem
[-- Attachment #1: Type: text/plain, Size: 25184 bytes --]
Hello Stan,
On 3/6/2024 4:40 PM, Lisovskiy, Stanislav wrote:
> On Wed, Mar 06, 2024 at 04:11:03PM +0530, Joshi, Kunal1 wrote:
>> Hello Stan,
>>
>> On 3/6/2024 4:03 PM, Lisovskiy, Stanislav wrote:
>>> On Wed, Mar 06, 2024 at 03:41:26PM +0530, Joshi, Kunal1 wrote:
>>>> Hello Stan,
>>>>
>>>> On 3/6/2024 3:23 PM, Lisovskiy, Stanislav wrote:
>>>>> On Wed, Mar 06, 2024 at 10:55:09AM +0530, Kunal Joshi wrote:
>>>>>> big joiner outputs are statically assigned to pipe,
>>>>>> rewrite to assign dynamically
>>>>>>
>>>>>> v2: Don't change license (Bhanu)
>>>>>> Add documentation for generate_combinations (Bhanu)
>>>>>> Print the pipe name (Bhanu)
>>>>>> Remove unwanted commit (Bhanu)
>>>>>> Move combine output logic to igt_fixture (Bhanu)
>>>>>> split revamp and force joiner (Bhanu)
>>>>>>
>>>>>> Cc: Karthik B S<karthik.b.s@intel.com>
>>>>>> Cc: Bhanuprakash Modem<bhanuprakash.modem@intel.com>
>>>>>> Signed-off-by: Kunal Joshi<kunal1.joshi@intel.com>
>>>>>> ---
>>>>>> tests/intel/kms_big_joiner.c | 391 +++++++++++++++++------------------
>>>>>> 1 file changed, 187 insertions(+), 204 deletions(-)
>>>>>>
>>>>>> diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
>>>>>> index 28678b958..ba4097d8b 100644
>>>>>> --- a/tests/intel/kms_big_joiner.c
>>>>>> +++ b/tests/intel/kms_big_joiner.c
>>>>>> @@ -43,16 +43,19 @@
>>>>>> *
>>>>>> * SUBTEST: basic
>>>>>> * Description: Verify the basic modeset on big joiner mode on all pipes
>>>>>> - *
>>>>>> - * SUBTEST: 2x-modeset
>>>>>> - * Description: Verify simultaneous modeset on 2 big joiner outputs
>>>>>> */
>>>>>> -
>>>>>> IGT_TEST_DESCRIPTION("Test big joiner");
>>>>>> -struct bigjoiner_output {
>>>>>> - uint32_t output_id;
>>>>>> - drmModeModeInfo mode;
>>>>>> +#define MAX_OUTPUTS 256
>>>>>> +#define MAX_COMBINATIONS 1000
>>>>>> +#define INVALID_TEST_OUTPUT 2
>>>>>> +typedef struct {
>>>>>> + int combination[MAX_OUTPUTS];
>>>>>> +} Combination;
>>>>>> +
>>>>>> +enum joiner_type {
>>>>>> + BIG_JOINER = 1 << 1,
>>>>>> + INVALID_JOINER = -1,
>>>>>> };
>>>>>> typedef struct {
>>>>>> @@ -60,273 +63,253 @@ typedef struct {
>>>>>> igt_display_t display;
>>>>>> struct igt_fb fb;
>>>>>> int n_pipes;
>>>>>> - enum pipe pipe1;
>>>>>> - enum pipe pipe2;
>>>>>> - struct bigjoiner_output output[2];
>>>>>> + uint64_t big_joiner_outputs[IGT_MAX_PIPES];
>>>>>> + uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
>>>>>> + uint64_t combined_outputs[IGT_MAX_PIPES];
>>>>>> + int big_joiner_output_count;
>>>>>> + int non_big_joiner_output_count;
>>>>>> + int combined_output_count;
>>>>>> + int output_count;
>>>>>> + enum pipe pipe_seq[IGT_MAX_PIPES];
>>>>>> } data_t;
>>>>>> static int max_dotclock;
>>>>>> -static void test_invalid_modeset(data_t *data)
>>>>>> +/*
>>>>>> + * The generate_combinations function generates combinations of pipe allocations
>>>>>> + * for a given number of outputs
>>>>>> + *
>>>>>> + * @output_count: Number of outputs to allocate pipes for.
>>>>>> + * @pipe_count: Total number of available pipes.
>>>>>> + * @pipes_per_output: Number of pipes to be allocated for a single output.
>>>>>> + * @combinations: Array to store generated combinations.
>>>>>> + * @num_combinations: Pointer to a variable that stores the number of generated combinations.
>>>>>> + *
>>>>>> + * Example (output_count=2, pipe_count=4, pipes_per_output=2):
>>>>>> + * Combination 1: 0 2
>>>>>> + * Combination 2: 1 3
>>>>> I think this might be a bit overcomplicated - just for your information, we can't deliberately
>>>>> choose which pipes can be used for bigjoiner. On some platforms even only certain pipes, can be
>>>>> used for bigjoiner.
>>>>> Moreover the way how driver decides, which pipes are going to be used for bigjoiner is basically
>>>>> this code in intel_dp.c:
>>>>>
>>>>> if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
>>>>> adjusted_mode->crtc_clock))
>>>>> pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
>>>>>
>>>>> Means if you try to do a modeset with resolution > 5K or exceed max_dot_clock on crtc->pipe,
>>>>> then _always_ pipe + 1, going to be used for bigjoiner.
>>>>>
>>>>>
>>>>> Stan
>>>>>
>>>> Thanks for the inputs,
>>>> Goal here is to try various combination possible,
>>>> Suppose a platform supports 5 pipes(A-E) and we have 1 bigjoiner output
>>>> (DP-1) then we want to try
>>>> DP-1 on PIPE_A
>>>> DP-1 on PIPE_B
>>>> DP-1 on PIPE_C
>>>> DP-1 on PIPE_D
>>>>
>>>> Suppose a platform supports 5 pipes(A-E) and we have 2 bigjoiner output
>>>> (DP-1, DP-2) then we want to try
>>>> DP-1 on PIPE_A and DP-2 on PIPE_C
>>>> DP-1 on PIPE_B and DP-2 on PIPE_D And so on, Going forward this will be
>>>> useful we introduce any feature which can allow having more pipes per output
>>>> also.
>>> That won't work. BSpec and current driver code allows to use only _adjacent_ pipes.
>>> I.e if you modeset PIPE_A with 5K resolution, then bigjoiner_pipes mask would be
>>> PIPE_A | PIPE_B. If you modeset PIPE_B with 5K resolution it will take PIPE_C as a
>>> slave and so on.
>>> So for instance of you had DP-1 assigned to PIPE_A and DP-2 assigned to PIPE_C by test,
>>> _driver_ will still reassign PIPE_B to DP-2, in order for bigjoiner to work.
>>> That logic is implemented in intel_dp.c, as I mentioned above.
>>> Also you can check the BSpec Bigjoiner programming description.
>>>
>>> Stan
>> I think there is some confusion here,
>>
>> Below is result of the test that was executed with current code
>> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10766/bat-arls-4/igt@kms_big_joiner@force-joiner-basic@1x-joiner.html
>>
>> Assigning pipe 0 to DP-3
>> <7> [44.263216] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
>> [CRTC:131:pipe B] Used as slave for big joiner master [CRTC:80:pipe A]
>>
>> Assigning pipe 1 to DP-3
>> <7> [44.568716] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
>> [CRTC:182:pipe C] Used as slave for big joiner master [CRTC:131:pipe B]
>> Assigning pipe 2 to DP-3
>> <7> [44.909690] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
>> [CRTC:233:pipe D] Used as slave for big joiner master [CRTC:182:pipe C] So
>> we are leaving one sequential pipe for a output,
>> Please let me know if i still wasn't able to explain properly.
> Yes, that is correct here. I was just trying to clarify that we can't have all
> possible combinations unfortunately.
> There are only certain scenarios supported, so could be a bit overkill trying to
> approach this combinatorical way, but rather I would see this more like introducing
> some mapping table, containing valid mappings or something similar.
> I don't think we are going to have more than 5 pipes anyway soon.
>
> That way, it might be way easier to check with spec and maintain this code.
>
> In case if more pipes are supported per output, most likely it won't be that straight
> forward as well :)
>
> I would add something like "get_next_master_pipe" function, which you call for each pipe
> which is allowed to be master. That function would also take available pipes as a mask.
>
> Then it returns next avaiable master pipe, considering the available pipes mask.
> That way you easily generate all allowed combinations, by just modifying available pipes mask.
>
> Stan
Can you please provide more info on this only certain scenario's supported?
Or just an example where this code won't work will be really useful.
On the overkill part, this to me will only have the combinations which
are valid,
Maybe we just need to exclude those certain scenario's which are
unsupported.
>
>>>>>> +*/
>>>>>> +static void generate_combinations(int output_count, int pipe_count,
>>>>>> + int pipes_per_output,
>>>>>> + Combination combinations[MAX_COMBINATIONS],
>>>>>> + uint64_t *num_combinations)
>>>>>> {
>>>>>> - igt_output_t *output;
>>>>>> - igt_display_t *display = &data->display;
>>>>>> - int ret;
>>>>>> + int i, index;
>>>>>> + int current_combination[MAX_OUTPUTS];
>>>>>> - igt_info("Bigjoiner test on ");
>>>>>> - for_each_connected_output(display, output){
>>>>>> - enum pipe p = output->pending_pipe;
>>>>>> - drmModeModeInfo *mode;
>>>>>> - igt_pipe_t *pipe;
>>>>>> - igt_plane_t *plane;
>>>>>> + for (i = 0; i < output_count; ++i)
>>>>>> + current_combination[i] = i * pipes_per_output;
>>>>>> - if (p == PIPE_NONE)
>>>>>> - continue;
>>>>>> -
>>>>>> - mode = igt_output_get_mode(output);
>>>>>> - igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
>>>>>> - kmstest_dump_mode(mode);
>>>>>> + while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
>>>>>> + for (i = 0; i < output_count; ++i)
>>>>>> + combinations[*num_combinations].combination[i] = current_combination[i];
>>>>>> - pipe = &display->pipes[p];
>>>>>> - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>>>> + (*num_combinations)++;
>>>>>> - igt_plane_set_fb(plane, &data->fb);
>>>>>> - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
>>>>>> - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
>>>>>> - }
>>>>>> + index = output_count - 1;
>>>>>> + while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
>>>>>> + index--;
>>>>>> - igt_assert(!igt_check_bigjoiner_support(display));
>>>>>> + if (index < 0)
>>>>>> + break;
>>>>>> - /* This commit is expectd to fail as this pipe is being used for big joiner */
>>>>>> - ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
>>>>>> - DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
>>>>>> + current_combination[index]++;
>>>>>> + for (i = index + 1; i < output_count; ++i)
>>>>>> + current_combination[i] = current_combination[i - 1] + pipes_per_output;
>>>>>> + }
>>>>>> +}
>>>>>> - igt_display_reset(&data->display);
>>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>>> +static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
>>>>>> +{
>>>>>> + igt_output_t *output;
>>>>>> - igt_assert_lt(ret, 0);
>>>>>> + for_each_connected_output(&data->display, output) {
>>>>>> + if (output->id == output_id)
>>>>>> + return output;
>>>>>> + }
>>>>>> + igt_assert("Output not found\n");
>>>>>> + return NULL;
>>>>>> }
>>>>>> -static void test_basic_modeset(data_t *data)
>>>>>> +static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
>>>>>> {
>>>>>> + int i, j, ret;
>>>>>> + igt_output_t *output;
>>>>>> + uint64_t *outputs;
>>>>>> + igt_plane_t *primary[INVALID_TEST_OUTPUT];
>>>>>> + igt_fb_t fb[INVALID_TEST_OUTPUT];
>>>>>> drmModeModeInfo *mode;
>>>>>> - igt_output_t *output, *bigjoiner_output = NULL;
>>>>>> - igt_display_t *display = &data->display;
>>>>>> - igt_pipe_t *pipe;
>>>>>> - igt_plane_t *plane;
>>>>>> - igt_display_reset(display);
>>>>>> -
>>>>>> - for_each_connected_output(display, output) {
>>>>>> - if (data->output[0].output_id == output->id) {
>>>>>> - bigjoiner_output = output;
>>>>>> - break;
>>>>>> + outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
>>>>>> +
>>>>>> + for (i = 0; i < data->n_pipes-1; i++) {
>>>>>> + igt_display_reset(&data->display);
>>>>>> + for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
>>>>>> + output = get_output_by_id_or_assert(data, outputs[j]);
>>>>>> + igt_assert(output);
>>>>>> + igt_output_set_pipe(output, data->pipe_seq[i + j]);
>>>>>> + mode = igt_output_get_mode(output);
>>>>>> + igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
>>>>>> + kmstest_pipe_name(data->pipe_seq[i + j]),
>>>>>> + igt_output_name(output), mode->hdisplay,
>>>>>> + mode->vdisplay, mode->vrefresh,
>>>>>> + j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
>>>>>> + primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
>>>>>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>>>>>> + DRM_FORMAT_MOD_LINEAR, &fb[j]);
>>>>>> + igt_plane_set_fb(primary[j], &fb[j]);
>>>>>> }
>>>>>> + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
>>>>>> + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
>>>>>> }
>>>>>> -
>>>>>> - igt_output_set_pipe(bigjoiner_output, data->pipe1);
>>>>>> -
>>>>>> - mode = &data->output[0].mode;
>>>>>> - igt_output_override_mode(bigjoiner_output, mode);
>>>>>> -
>>>>>> - pipe = &display->pipes[data->pipe1];
>>>>>> - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>>>> -
>>>>>> - igt_plane_set_fb(plane, &data->fb);
>>>>>> - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
>>>>>> - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
>>>>>> -
>>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>>> -
>>>>>> - igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
>>>>>> - igt_plane_set_fb(plane, NULL);
>>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>>> }
>>>>>> -static void test_dual_display(data_t *data)
>>>>>> +static void tets_big_joiner_on_last_pipe(data_t *data)
>>>>>> {
>>>>>> + int i, ret;
>>>>>> + uint64_t *outputs;
>>>>>> + igt_output_t *output;
>>>>>> + igt_plane_t *primary;
>>>>>> + igt_fb_t fb;
>>>>>> drmModeModeInfo *mode;
>>>>>> - igt_output_t *output, *bigjoiner_output[2];
>>>>>> - igt_display_t *display = &data->display;
>>>>>> - igt_pipe_t *pipe;
>>>>>> - igt_plane_t *plane1, *plane2;
>>>>>> - int count = 0;
>>>>>> -
>>>>>> - igt_display_reset(display);
>>>>>> -
>>>>>> - for_each_connected_output(display, output) {
>>>>>> - if (data->output[count].output_id == output->id) {
>>>>>> - bigjoiner_output[count] = output;
>>>>>> - count++;
>>>>>> - }
>>>>>> - if (count > 1)
>>>>>> - break;
>>>>>> + outputs = data->big_joiner_outputs;
>>>>>> + for (i = 0; i < data->big_joiner_output_count; i++) {
>>>>>> + igt_display_reset(&data->display);
>>>>>> + output = get_output_by_id_or_assert(data, outputs[i]);
>>>>>> + igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
>>>>>> + mode = igt_output_get_mode(output);
>>>>>> + igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
>>>>>> + kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
>>>>>> + igt_output_name(output), mode->hdisplay,
>>>>>> + mode->vdisplay, mode->vrefresh);
>>>>>> + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
>>>>>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>>>>>> + DRM_FORMAT_MOD_LINEAR, &fb);
>>>>>> + igt_plane_set_fb(primary, &fb);
>>>>>> + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
>>>>>> + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
>>>>>> }
>>>>>> +}
>>>>>> - igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
>>>>>> - igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
>>>>>> -
>>>>>> - /* Set up first big joiner output on Pipe A*/
>>>>>> - mode = &data->output[0].mode;
>>>>>> - igt_output_override_mode(bigjoiner_output[0], mode);
>>>>>> -
>>>>>> - pipe = &display->pipes[data->pipe1];
>>>>>> - plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>>>> -
>>>>>> - igt_plane_set_fb(plane1, &data->fb);
>>>>>> - igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
>>>>>> - igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
>>>>>> -
>>>>>> - /* Set up second big joiner output on Pipe C*/
>>>>>> - mode = &data->output[1].mode;
>>>>>> - igt_output_override_mode(bigjoiner_output[1], mode);
>>>>>> -
>>>>>> - pipe = &display->pipes[data->pipe2];
>>>>>> - plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>>>> -
>>>>>> - igt_plane_set_fb(plane2, &data->fb);
>>>>>> - igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
>>>>>> - igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
>>>>>> -
>>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>>> +static void test_basic_modeset(data_t *data, int num_outputs,
>>>>>> + Combination combinations[MAX_COMBINATIONS],
>>>>>> + uint64_t num_combinations)
>>>>>> +{
>>>>>> + int i, j, ret;
>>>>>> + igt_display_t *display = &data->display;
>>>>>> + igt_output_t *output[num_outputs];
>>>>>> + igt_plane_t *primary[num_outputs];
>>>>>> + igt_fb_t fb[num_outputs];
>>>>>> + drmModeModeInfo *mode;
>>>>>> - /* Clean up */
>>>>>> - igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
>>>>>> - igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
>>>>>> - igt_plane_set_fb(plane1, NULL);
>>>>>> - igt_plane_set_fb(plane2, NULL);
>>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>>> + for (i = 0; i < num_combinations; i++) {
>>>>>> + igt_display_reset(display);
>>>>>> + for (j = 0; j < num_outputs; j++) {
>>>>>> + output[j] = get_output_by_id_or_assert(data,
>>>>>> + data->big_joiner_outputs[j]);
>>>>>> + igt_info("Assigning pipe %s to %s%s",
>>>>>> + kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
>>>>>> + output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
>>>>>> + igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
>>>>>> + primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
>>>>>> + mode = igt_output_get_mode(output[j]);
>>>>>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>>>>>> + DRM_FORMAT_MOD_LINEAR, &fb[j]);
>>>>>> + igt_plane_set_fb(primary[j], &fb[j]);
>>>>>> + }
>>>>>> + ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
>>>>>> + igt_assert_f(ret == 0, "Commit failed\n");
>>>>>> + }
>>>>>> }
>>>>>> igt_main
>>>>>> {
>>>>>> + int i, j;
>>>>>> data_t data;
>>>>>> igt_output_t *output;
>>>>>> - drmModeModeInfo mode;
>>>>>> - int valid_output = 0, i, count = 0, j = 0;
>>>>>> - uint16_t width = 0, height = 0;
>>>>>> - enum pipe pipe_seq[IGT_MAX_PIPES];
>>>>>> + drmModeModeInfo default_mode;
>>>>>> + i = j = 0;
>>>>>> igt_fixture {
>>>>>> data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
>>>>>> kmstest_set_vt_graphics_mode();
>>>>>> -
>>>>>> igt_display_require(&data.display, data.drm_fd);
>>>>>> igt_require(data.display.is_atomic);
>>>>>> -
>>>>>> max_dotclock = igt_get_max_dotclock(data.drm_fd);
>>>>>> + data.big_joiner_output_count = 0;
>>>>>> + data.non_big_joiner_output_count = 0;
>>>>>> + data.combined_output_count = 0;
>>>>>> + data.output_count = 0;
>>>>>> for_each_connected_output(&data.display, output) {
>>>>>> bool found = false;
>>>>>> drmModeConnector *connector = output->config.connector;
>>>>>> -
>>>>>> - /*
>>>>>> - * Bigjoiner will come in to the picture when the
>>>>>> - * resolution > 5K or clock > max-dot-clock.
>>>>>> - */
>>>>>> found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
>>>>>> -
>>>>>> if (found) {
>>>>>> - data.output[count].output_id = output->id;
>>>>>> - memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
>>>>>> - count++;
>>>>>> -
>>>>>> - width = max(width, mode.hdisplay);
>>>>>> - height = max(height, mode.vdisplay);
>>>>>> + data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
>>>>>> + igt_output_override_mode(output, &connector->modes[0]);
>>>>>> + } else {
>>>>>> + data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
>>>>>> + kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
>>>>>> + igt_output_override_mode(output, &default_mode);
>>>>>> }
>>>>>> - valid_output++;
>>>>>> + data.output_count++;
>>>>>> + }
>>>>>> +
>>>>>> + if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
>>>>>> + data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
>>>>>> + data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
>>>>>> }
>>>>>> data.n_pipes = 0;
>>>>>> for_each_pipe(&data.display, i) {
>>>>>> data.n_pipes++;
>>>>>> - pipe_seq[j] = i;
>>>>>> + data.pipe_seq[j] = i;
>>>>>> j++;
>>>>>> }
>>>>>> -
>>>>>> - igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
>>>>>> -
>>>>>> - igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
>>>>>> - DRM_FORMAT_MOD_LINEAR, &data.fb);
>>>>>> }
>>>>>> igt_describe("Verify the basic modeset on big joiner mode on all pipes");
>>>>>> igt_subtest_with_dynamic("basic") {
>>>>>> - for (i = 0; i < data.n_pipes - 1; i++) {
>>>>>> - data.pipe1 = pipe_seq[i];
>>>>>> - igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
>>>>>> - test_basic_modeset(&data);
>>>>>> + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
>>>>>> + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
>>>>>> +
>>>>>> + for (i = 0; i < data.big_joiner_output_count; i++) {
>>>>>> + uint64_t num_combinations = 0;
>>>>>> + Combination combinations[MAX_COMBINATIONS];
>>>>>> +
>>>>>> + generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
>>>>>> + igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
>>>>>> + i+1, data.n_pipes, num_combinations);
>>>>>> +
>>>>>> + if (num_combinations > 0)
>>>>>> + igt_dynamic_f("%dx-big-joiner", i+1)
>>>>>> + test_basic_modeset(&data, i+1, combinations, num_combinations);
>>>>>> + else
>>>>>> + break;
>>>>>> }
>>>>>> }
>>>>>> - igt_describe("Verify if the modeset on the adjoining pipe is rejected "
>>>>>> - "when the pipe is active with a big joiner modeset");
>>>>>> igt_subtest_with_dynamic("invalid-modeset") {
>>>>>> - data.pipe1 = pipe_seq[j - 1];
>>>>>> -
>>>>>> - igt_display_reset(&data.display);
>>>>>> - for_each_connected_output(&data.display, output) {
>>>>>> - if (data.output[0].output_id != output->id)
>>>>>> - continue;
>>>>>> -
>>>>>> - mode = data.output[0].mode;
>>>>>> - igt_output_set_pipe(output, data.pipe1);
>>>>>> - igt_output_override_mode(output, &mode);
>>>>>> + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
>>>>>> + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
>>>>>> - igt_dynamic_f("pipe-%s-%s",
>>>>>> - kmstest_pipe_name(data.pipe1),
>>>>>> - igt_output_name(output))
>>>>>> - test_invalid_modeset(&data);
>>>>>> - }
>>>>>> + if (data.big_joiner_output_count >= 1)
>>>>>> + igt_dynamic_f("big_joiner_on_last_pipe")
>>>>>> + tets_big_joiner_on_last_pipe(&data);
>>>>>> - if(valid_output > 1) {
>>>>>> - for (i = 0; i < data.n_pipes - 1; i++) {
>>>>>> - igt_output_t *first_output = NULL, *second_output = NULL;
>>>>>> -
>>>>>> - data.pipe1 = pipe_seq[i];
>>>>>> - data.pipe2 = pipe_seq[i + 1];
>>>>>> -
>>>>>> - igt_display_reset(&data.display);
>>>>>> - for_each_connected_output(&data.display, output) {
>>>>>> - if (data.output[0].output_id == output->id) {
>>>>>> - first_output = output;
>>>>>> - mode = data.output[0].mode;
>>>>>> -
>>>>>> - igt_output_set_pipe(output, data.pipe1);
>>>>>> - igt_output_override_mode(output, &mode);
>>>>>> - } else if (second_output == NULL) {
>>>>>> - second_output = output;
>>>>>> - igt_output_set_pipe(output, data.pipe2);
>>>>>> -
>>>>>> - break;
>>>>>> - }
>>>>>> - }
>>>>>> -
>>>>>> - igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
>>>>>> - kmstest_pipe_name(data.pipe1),
>>>>>> - igt_output_name(first_output),
>>>>>> - kmstest_pipe_name(data.pipe2),
>>>>>> - igt_output_name(second_output))
>>>>>> - test_invalid_modeset(&data);
>>>>>> - }
>>>>>> - }
>>>>>> - }
>>>>>> + if (data.big_joiner_output_count > 1)
>>>>>> + igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
>>>>>> + test_invalid_modeset_two_joiner(&data, false);
>>>>>> - igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
>>>>>> - igt_subtest_with_dynamic("2x-modeset") {
>>>>>> - igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
>>>>>> - igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
>>>>>> - for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
>>>>>> - data.pipe1 = pipe_seq[i];
>>>>>> - data.pipe2 = pipe_seq[i + 2];
>>>>>> - igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
>>>>>> - test_dual_display(&data);
>>>>>> + if (data.combined_output_count) {
>>>>>> + igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
>>>>>> + test_invalid_modeset_two_joiner(&data, true);
>>>>>> }
>>>>>> }
>>>>>> igt_fixture {
>>>>>> - igt_remove_fb(data.drm_fd, &data.fb);
>>>>>> igt_display_fini(&data.display);
>>>>>> drm_close_driver(data.drm_fd);
>>>>>> }
>>>>>> --
>>>>>> 2.25.1
>>>> Thanks and Regards
>>>> Kunal Joshi
>> Thanks and Regards
>> Kunal Joshi
[-- Attachment #2: Type: text/html, Size: 24882 bytes --]
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-06 11:28 ` Joshi, Kunal1
@ 2024-03-06 12:52 ` Lisovskiy, Stanislav
2024-03-06 13:15 ` Joshi, Kunal1
0 siblings, 1 reply; 17+ messages in thread
From: Lisovskiy, Stanislav @ 2024-03-06 12:52 UTC (permalink / raw)
To: Joshi, Kunal1; +Cc: igt-dev, Karthik B S, Bhanuprakash Modem
On Wed, Mar 06, 2024 at 04:58:54PM +0530, Joshi, Kunal1 wrote:
> Hello Stan,
>
> On 3/6/2024 4:40 PM, Lisovskiy, Stanislav wrote:
> > On Wed, Mar 06, 2024 at 04:11:03PM +0530, Joshi, Kunal1 wrote:
> > > Hello Stan,
> > >
> > > On 3/6/2024 4:03 PM, Lisovskiy, Stanislav wrote:
> > > > On Wed, Mar 06, 2024 at 03:41:26PM +0530, Joshi, Kunal1 wrote:
> > > > > Hello Stan,
> > > > >
> > > > > On 3/6/2024 3:23 PM, Lisovskiy, Stanislav wrote:
> > > > > > On Wed, Mar 06, 2024 at 10:55:09AM +0530, Kunal Joshi wrote:
> > > > > > > big joiner outputs are statically assigned to pipe,
> > > > > > > rewrite to assign dynamically
> > > > > > >
> > > > > > > v2: Don't change license (Bhanu)
> > > > > > > Add documentation for generate_combinations (Bhanu)
> > > > > > > Print the pipe name (Bhanu)
> > > > > > > Remove unwanted commit (Bhanu)
> > > > > > > Move combine output logic to igt_fixture (Bhanu)
> > > > > > > split revamp and force joiner (Bhanu)
> > > > > > >
> > > > > > > Cc: Karthik B S<karthik.b.s@intel.com>
> > > > > > > Cc: Bhanuprakash Modem<bhanuprakash.modem@intel.com>
> > > > > > > Signed-off-by: Kunal Joshi<kunal1.joshi@intel.com>
> > > > > > > ---
> > > > > > > tests/intel/kms_big_joiner.c | 391 +++++++++++++++++------------------
> > > > > > > 1 file changed, 187 insertions(+), 204 deletions(-)
> > > > > > >
> > > > > > > diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
> > > > > > > index 28678b958..ba4097d8b 100644
> > > > > > > --- a/tests/intel/kms_big_joiner.c
> > > > > > > +++ b/tests/intel/kms_big_joiner.c
> > > > > > > @@ -43,16 +43,19 @@
> > > > > > > *
> > > > > > > * SUBTEST: basic
> > > > > > > * Description: Verify the basic modeset on big joiner mode on all pipes
> > > > > > > - *
> > > > > > > - * SUBTEST: 2x-modeset
> > > > > > > - * Description: Verify simultaneous modeset on 2 big joiner outputs
> > > > > > > */
> > > > > > > -
> > > > > > > IGT_TEST_DESCRIPTION("Test big joiner");
> > > > > > > -struct bigjoiner_output {
> > > > > > > - uint32_t output_id;
> > > > > > > - drmModeModeInfo mode;
> > > > > > > +#define MAX_OUTPUTS 256
> > > > > > > +#define MAX_COMBINATIONS 1000
> > > > > > > +#define INVALID_TEST_OUTPUT 2
> > > > > > > +typedef struct {
> > > > > > > + int combination[MAX_OUTPUTS];
> > > > > > > +} Combination;
> > > > > > > +
> > > > > > > +enum joiner_type {
> > > > > > > + BIG_JOINER = 1 << 1,
> > > > > > > + INVALID_JOINER = -1,
> > > > > > > };
> > > > > > > typedef struct {
> > > > > > > @@ -60,273 +63,253 @@ typedef struct {
> > > > > > > igt_display_t display;
> > > > > > > struct igt_fb fb;
> > > > > > > int n_pipes;
> > > > > > > - enum pipe pipe1;
> > > > > > > - enum pipe pipe2;
> > > > > > > - struct bigjoiner_output output[2];
> > > > > > > + uint64_t big_joiner_outputs[IGT_MAX_PIPES];
> > > > > > > + uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
> > > > > > > + uint64_t combined_outputs[IGT_MAX_PIPES];
> > > > > > > + int big_joiner_output_count;
> > > > > > > + int non_big_joiner_output_count;
> > > > > > > + int combined_output_count;
> > > > > > > + int output_count;
> > > > > > > + enum pipe pipe_seq[IGT_MAX_PIPES];
> > > > > > > } data_t;
> > > > > > > static int max_dotclock;
> > > > > > > -static void test_invalid_modeset(data_t *data)
> > > > > > > +/*
> > > > > > > + * The generate_combinations function generates combinations of pipe allocations
> > > > > > > + * for a given number of outputs
> > > > > > > + *
> > > > > > > + * @output_count: Number of outputs to allocate pipes for.
> > > > > > > + * @pipe_count: Total number of available pipes.
> > > > > > > + * @pipes_per_output: Number of pipes to be allocated for a single output.
> > > > > > > + * @combinations: Array to store generated combinations.
> > > > > > > + * @num_combinations: Pointer to a variable that stores the number of generated combinations.
> > > > > > > + *
> > > > > > > + * Example (output_count=2, pipe_count=4, pipes_per_output=2):
> > > > > > > + * Combination 1: 0 2
> > > > > > > + * Combination 2: 1 3
> > > > > > I think this might be a bit overcomplicated - just for your information, we can't deliberately
> > > > > > choose which pipes can be used for bigjoiner. On some platforms even only certain pipes, can be
> > > > > > used for bigjoiner.
> > > > > > Moreover the way how driver decides, which pipes are going to be used for bigjoiner is basically
> > > > > > this code in intel_dp.c:
> > > > > >
> > > > > > if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
> > > > > > adjusted_mode->crtc_clock))
> > > > > > pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
> > > > > >
> > > > > > Means if you try to do a modeset with resolution > 5K or exceed max_dot_clock on crtc->pipe,
> > > > > > then _always_ pipe + 1, going to be used for bigjoiner.
> > > > > >
> > > > > >
> > > > > > Stan
> > > > > >
> > > > > Thanks for the inputs,
> > > > > Goal here is to try various combination possible,
> > > > > Suppose a platform supports 5 pipes(A-E) and we have 1 bigjoiner output
> > > > > (DP-1) then we want to try
> > > > > DP-1 on PIPE_A
> > > > > DP-1 on PIPE_B
> > > > > DP-1 on PIPE_C
> > > > > DP-1 on PIPE_D
> > > > >
> > > > > Suppose a platform supports 5 pipes(A-E) and we have 2 bigjoiner output
> > > > > (DP-1, DP-2) then we want to try
> > > > > DP-1 on PIPE_A and DP-2 on PIPE_C
> > > > > DP-1 on PIPE_B and DP-2 on PIPE_D And so on, Going forward this will be
> > > > > useful we introduce any feature which can allow having more pipes per output
> > > > > also.
> > > > That won't work. BSpec and current driver code allows to use only _adjacent_ pipes.
> > > > I.e if you modeset PIPE_A with 5K resolution, then bigjoiner_pipes mask would be
> > > > PIPE_A | PIPE_B. If you modeset PIPE_B with 5K resolution it will take PIPE_C as a
> > > > slave and so on.
> > > > So for instance of you had DP-1 assigned to PIPE_A and DP-2 assigned to PIPE_C by test,
> > > > _driver_ will still reassign PIPE_B to DP-2, in order for bigjoiner to work.
> > > > That logic is implemented in intel_dp.c, as I mentioned above.
> > > > Also you can check the BSpec Bigjoiner programming description.
> > > >
> > > > Stan
> > > I think there is some confusion here,
> > >
> > > Below is result of the test that was executed with current code
> > > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10766/bat-arls-4/igt@kms_big_joiner@force-joiner-basic@1x-joiner.html
> > >
> > > Assigning pipe 0 to DP-3
> > > <7> [44.263216] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
> > > [CRTC:131:pipe B] Used as slave for big joiner master [CRTC:80:pipe A]
> > >
> > > Assigning pipe 1 to DP-3
> > > <7> [44.568716] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
> > > [CRTC:182:pipe C] Used as slave for big joiner master [CRTC:131:pipe B]
> > > Assigning pipe 2 to DP-3
> > > <7> [44.909690] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
> > > [CRTC:233:pipe D] Used as slave for big joiner master [CRTC:182:pipe C] So
> > > we are leaving one sequential pipe for a output,
> > > Please let me know if i still wasn't able to explain properly.
> > Yes, that is correct here. I was just trying to clarify that we can't have all
> > possible combinations unfortunately.
> > There are only certain scenarios supported, so could be a bit overkill trying to
> > approach this combinatorical way, but rather I would see this more like introducing
> > some mapping table, containing valid mappings or something similar.
> > I don't think we are going to have more than 5 pipes anyway soon.
> >
> > That way, it might be way easier to check with spec and maintain this code.
> >
> > In case if more pipes are supported per output, most likely it won't be that straight
> > forward as well :)
> >
> > I would add something like "get_next_master_pipe" function, which you call for each pipe
> > which is allowed to be master. That function would also take available pipes as a mask.
> >
> > Then it returns next avaiable master pipe, considering the available pipes mask.
> > That way you easily generate all allowed combinations, by just modifying available pipes mask.
> >
> > Stan
> Can you please provide more info on this only certain scenario's supported?
> Or just an example where this code won't work will be really useful.
>
> On the overkill part, this to me will only have the combinations which are
> valid,
> Maybe we just need to exclude those certain scenario's which are
> unsupported.
On some platforms, not all pipes can be bigjoiner masters, some pipes can be fused off.
We can of course hardcode this into algorithm, but that would be less readable.
Would be nice to have some table or initial structure to be able to explicitly regulate
this, without altering the actual code.
Stan
> >
> > > > > > > +*/
> > > > > > > +static void generate_combinations(int output_count, int pipe_count,
> > > > > > > + int pipes_per_output,
> > > > > > > + Combination combinations[MAX_COMBINATIONS],
> > > > > > > + uint64_t *num_combinations)
> > > > > > > {
> > > > > > > - igt_output_t *output;
> > > > > > > - igt_display_t *display = &data->display;
> > > > > > > - int ret;
> > > > > > > + int i, index;
> > > > > > > + int current_combination[MAX_OUTPUTS];
> > > > > > > - igt_info("Bigjoiner test on ");
> > > > > > > - for_each_connected_output(display, output){
> > > > > > > - enum pipe p = output->pending_pipe;
> > > > > > > - drmModeModeInfo *mode;
> > > > > > > - igt_pipe_t *pipe;
> > > > > > > - igt_plane_t *plane;
> > > > > > > + for (i = 0; i < output_count; ++i)
> > > > > > > + current_combination[i] = i * pipes_per_output;
> > > > > > > - if (p == PIPE_NONE)
> > > > > > > - continue;
> > > > > > > -
> > > > > > > - mode = igt_output_get_mode(output);
> > > > > > > - igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
> > > > > > > - kmstest_dump_mode(mode);
> > > > > > > + while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
> > > > > > > + for (i = 0; i < output_count; ++i)
> > > > > > > + combinations[*num_combinations].combination[i] = current_combination[i];
> > > > > > > - pipe = &display->pipes[p];
> > > > > > > - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > > > > + (*num_combinations)++;
> > > > > > > - igt_plane_set_fb(plane, &data->fb);
> > > > > > > - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
> > > > > > > - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> > > > > > > - }
> > > > > > > + index = output_count - 1;
> > > > > > > + while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
> > > > > > > + index--;
> > > > > > > - igt_assert(!igt_check_bigjoiner_support(display));
> > > > > > > + if (index < 0)
> > > > > > > + break;
> > > > > > > - /* This commit is expectd to fail as this pipe is being used for big joiner */
> > > > > > > - ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
> > > > > > > - DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
> > > > > > > + current_combination[index]++;
> > > > > > > + for (i = index + 1; i < output_count; ++i)
> > > > > > > + current_combination[i] = current_combination[i - 1] + pipes_per_output;
> > > > > > > + }
> > > > > > > +}
> > > > > > > - igt_display_reset(&data->display);
> > > > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > > > +static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
> > > > > > > +{
> > > > > > > + igt_output_t *output;
> > > > > > > - igt_assert_lt(ret, 0);
> > > > > > > + for_each_connected_output(&data->display, output) {
> > > > > > > + if (output->id == output_id)
> > > > > > > + return output;
> > > > > > > + }
> > > > > > > + igt_assert("Output not found\n");
> > > > > > > + return NULL;
> > > > > > > }
> > > > > > > -static void test_basic_modeset(data_t *data)
> > > > > > > +static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
> > > > > > > {
> > > > > > > + int i, j, ret;
> > > > > > > + igt_output_t *output;
> > > > > > > + uint64_t *outputs;
> > > > > > > + igt_plane_t *primary[INVALID_TEST_OUTPUT];
> > > > > > > + igt_fb_t fb[INVALID_TEST_OUTPUT];
> > > > > > > drmModeModeInfo *mode;
> > > > > > > - igt_output_t *output, *bigjoiner_output = NULL;
> > > > > > > - igt_display_t *display = &data->display;
> > > > > > > - igt_pipe_t *pipe;
> > > > > > > - igt_plane_t *plane;
> > > > > > > - igt_display_reset(display);
> > > > > > > -
> > > > > > > - for_each_connected_output(display, output) {
> > > > > > > - if (data->output[0].output_id == output->id) {
> > > > > > > - bigjoiner_output = output;
> > > > > > > - break;
> > > > > > > + outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
> > > > > > > +
> > > > > > > + for (i = 0; i < data->n_pipes-1; i++) {
> > > > > > > + igt_display_reset(&data->display);
> > > > > > > + for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
> > > > > > > + output = get_output_by_id_or_assert(data, outputs[j]);
> > > > > > > + igt_assert(output);
> > > > > > > + igt_output_set_pipe(output, data->pipe_seq[i + j]);
> > > > > > > + mode = igt_output_get_mode(output);
> > > > > > > + igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
> > > > > > > + kmstest_pipe_name(data->pipe_seq[i + j]),
> > > > > > > + igt_output_name(output), mode->hdisplay,
> > > > > > > + mode->vdisplay, mode->vrefresh,
> > > > > > > + j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
> > > > > > > + primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> > > > > > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > > > > > + DRM_FORMAT_MOD_LINEAR, &fb[j]);
> > > > > > > + igt_plane_set_fb(primary[j], &fb[j]);
> > > > > > > }
> > > > > > > + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> > > > > > > + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> > > > > > > }
> > > > > > > -
> > > > > > > - igt_output_set_pipe(bigjoiner_output, data->pipe1);
> > > > > > > -
> > > > > > > - mode = &data->output[0].mode;
> > > > > > > - igt_output_override_mode(bigjoiner_output, mode);
> > > > > > > -
> > > > > > > - pipe = &display->pipes[data->pipe1];
> > > > > > > - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > > > > -
> > > > > > > - igt_plane_set_fb(plane, &data->fb);
> > > > > > > - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
> > > > > > > - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> > > > > > > -
> > > > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > > > -
> > > > > > > - igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
> > > > > > > - igt_plane_set_fb(plane, NULL);
> > > > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > > > }
> > > > > > > -static void test_dual_display(data_t *data)
> > > > > > > +static void tets_big_joiner_on_last_pipe(data_t *data)
> > > > > > > {
> > > > > > > + int i, ret;
> > > > > > > + uint64_t *outputs;
> > > > > > > + igt_output_t *output;
> > > > > > > + igt_plane_t *primary;
> > > > > > > + igt_fb_t fb;
> > > > > > > drmModeModeInfo *mode;
> > > > > > > - igt_output_t *output, *bigjoiner_output[2];
> > > > > > > - igt_display_t *display = &data->display;
> > > > > > > - igt_pipe_t *pipe;
> > > > > > > - igt_plane_t *plane1, *plane2;
> > > > > > > - int count = 0;
> > > > > > > -
> > > > > > > - igt_display_reset(display);
> > > > > > > -
> > > > > > > - for_each_connected_output(display, output) {
> > > > > > > - if (data->output[count].output_id == output->id) {
> > > > > > > - bigjoiner_output[count] = output;
> > > > > > > - count++;
> > > > > > > - }
> > > > > > > - if (count > 1)
> > > > > > > - break;
> > > > > > > + outputs = data->big_joiner_outputs;
> > > > > > > + for (i = 0; i < data->big_joiner_output_count; i++) {
> > > > > > > + igt_display_reset(&data->display);
> > > > > > > + output = get_output_by_id_or_assert(data, outputs[i]);
> > > > > > > + igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
> > > > > > > + mode = igt_output_get_mode(output);
> > > > > > > + igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
> > > > > > > + kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
> > > > > > > + igt_output_name(output), mode->hdisplay,
> > > > > > > + mode->vdisplay, mode->vrefresh);
> > > > > > > + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> > > > > > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > > > > > + DRM_FORMAT_MOD_LINEAR, &fb);
> > > > > > > + igt_plane_set_fb(primary, &fb);
> > > > > > > + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> > > > > > > + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> > > > > > > }
> > > > > > > +}
> > > > > > > - igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
> > > > > > > - igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
> > > > > > > -
> > > > > > > - /* Set up first big joiner output on Pipe A*/
> > > > > > > - mode = &data->output[0].mode;
> > > > > > > - igt_output_override_mode(bigjoiner_output[0], mode);
> > > > > > > -
> > > > > > > - pipe = &display->pipes[data->pipe1];
> > > > > > > - plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > > > > -
> > > > > > > - igt_plane_set_fb(plane1, &data->fb);
> > > > > > > - igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
> > > > > > > - igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
> > > > > > > -
> > > > > > > - /* Set up second big joiner output on Pipe C*/
> > > > > > > - mode = &data->output[1].mode;
> > > > > > > - igt_output_override_mode(bigjoiner_output[1], mode);
> > > > > > > -
> > > > > > > - pipe = &display->pipes[data->pipe2];
> > > > > > > - plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > > > > -
> > > > > > > - igt_plane_set_fb(plane2, &data->fb);
> > > > > > > - igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
> > > > > > > - igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
> > > > > > > -
> > > > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > > > +static void test_basic_modeset(data_t *data, int num_outputs,
> > > > > > > + Combination combinations[MAX_COMBINATIONS],
> > > > > > > + uint64_t num_combinations)
> > > > > > > +{
> > > > > > > + int i, j, ret;
> > > > > > > + igt_display_t *display = &data->display;
> > > > > > > + igt_output_t *output[num_outputs];
> > > > > > > + igt_plane_t *primary[num_outputs];
> > > > > > > + igt_fb_t fb[num_outputs];
> > > > > > > + drmModeModeInfo *mode;
> > > > > > > - /* Clean up */
> > > > > > > - igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
> > > > > > > - igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
> > > > > > > - igt_plane_set_fb(plane1, NULL);
> > > > > > > - igt_plane_set_fb(plane2, NULL);
> > > > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > > > + for (i = 0; i < num_combinations; i++) {
> > > > > > > + igt_display_reset(display);
> > > > > > > + for (j = 0; j < num_outputs; j++) {
> > > > > > > + output[j] = get_output_by_id_or_assert(data,
> > > > > > > + data->big_joiner_outputs[j]);
> > > > > > > + igt_info("Assigning pipe %s to %s%s",
> > > > > > > + kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
> > > > > > > + output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
> > > > > > > + igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
> > > > > > > + primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
> > > > > > > + mode = igt_output_get_mode(output[j]);
> > > > > > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > > > > > + DRM_FORMAT_MOD_LINEAR, &fb[j]);
> > > > > > > + igt_plane_set_fb(primary[j], &fb[j]);
> > > > > > > + }
> > > > > > > + ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
> > > > > > > + igt_assert_f(ret == 0, "Commit failed\n");
> > > > > > > + }
> > > > > > > }
> > > > > > > igt_main
> > > > > > > {
> > > > > > > + int i, j;
> > > > > > > data_t data;
> > > > > > > igt_output_t *output;
> > > > > > > - drmModeModeInfo mode;
> > > > > > > - int valid_output = 0, i, count = 0, j = 0;
> > > > > > > - uint16_t width = 0, height = 0;
> > > > > > > - enum pipe pipe_seq[IGT_MAX_PIPES];
> > > > > > > + drmModeModeInfo default_mode;
> > > > > > > + i = j = 0;
> > > > > > > igt_fixture {
> > > > > > > data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
> > > > > > > kmstest_set_vt_graphics_mode();
> > > > > > > -
> > > > > > > igt_display_require(&data.display, data.drm_fd);
> > > > > > > igt_require(data.display.is_atomic);
> > > > > > > -
> > > > > > > max_dotclock = igt_get_max_dotclock(data.drm_fd);
> > > > > > > + data.big_joiner_output_count = 0;
> > > > > > > + data.non_big_joiner_output_count = 0;
> > > > > > > + data.combined_output_count = 0;
> > > > > > > + data.output_count = 0;
> > > > > > > for_each_connected_output(&data.display, output) {
> > > > > > > bool found = false;
> > > > > > > drmModeConnector *connector = output->config.connector;
> > > > > > > -
> > > > > > > - /*
> > > > > > > - * Bigjoiner will come in to the picture when the
> > > > > > > - * resolution > 5K or clock > max-dot-clock.
> > > > > > > - */
> > > > > > > found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
> > > > > > > -
> > > > > > > if (found) {
> > > > > > > - data.output[count].output_id = output->id;
> > > > > > > - memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
> > > > > > > - count++;
> > > > > > > -
> > > > > > > - width = max(width, mode.hdisplay);
> > > > > > > - height = max(height, mode.vdisplay);
> > > > > > > + data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
> > > > > > > + igt_output_override_mode(output, &connector->modes[0]);
> > > > > > > + } else {
> > > > > > > + data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
> > > > > > > + kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
> > > > > > > + igt_output_override_mode(output, &default_mode);
> > > > > > > }
> > > > > > > - valid_output++;
> > > > > > > + data.output_count++;
> > > > > > > + }
> > > > > > > +
> > > > > > > + if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
> > > > > > > + data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
> > > > > > > + data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
> > > > > > > }
> > > > > > > data.n_pipes = 0;
> > > > > > > for_each_pipe(&data.display, i) {
> > > > > > > data.n_pipes++;
> > > > > > > - pipe_seq[j] = i;
> > > > > > > + data.pipe_seq[j] = i;
> > > > > > > j++;
> > > > > > > }
> > > > > > > -
> > > > > > > - igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
> > > > > > > -
> > > > > > > - igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
> > > > > > > - DRM_FORMAT_MOD_LINEAR, &data.fb);
> > > > > > > }
> > > > > > > igt_describe("Verify the basic modeset on big joiner mode on all pipes");
> > > > > > > igt_subtest_with_dynamic("basic") {
> > > > > > > - for (i = 0; i < data.n_pipes - 1; i++) {
> > > > > > > - data.pipe1 = pipe_seq[i];
> > > > > > > - igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
> > > > > > > - test_basic_modeset(&data);
> > > > > > > + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
> > > > > > > + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
> > > > > > > +
> > > > > > > + for (i = 0; i < data.big_joiner_output_count; i++) {
> > > > > > > + uint64_t num_combinations = 0;
> > > > > > > + Combination combinations[MAX_COMBINATIONS];
> > > > > > > +
> > > > > > > + generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
> > > > > > > + igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
> > > > > > > + i+1, data.n_pipes, num_combinations);
> > > > > > > +
> > > > > > > + if (num_combinations > 0)
> > > > > > > + igt_dynamic_f("%dx-big-joiner", i+1)
> > > > > > > + test_basic_modeset(&data, i+1, combinations, num_combinations);
> > > > > > > + else
> > > > > > > + break;
> > > > > > > }
> > > > > > > }
> > > > > > > - igt_describe("Verify if the modeset on the adjoining pipe is rejected "
> > > > > > > - "when the pipe is active with a big joiner modeset");
> > > > > > > igt_subtest_with_dynamic("invalid-modeset") {
> > > > > > > - data.pipe1 = pipe_seq[j - 1];
> > > > > > > -
> > > > > > > - igt_display_reset(&data.display);
> > > > > > > - for_each_connected_output(&data.display, output) {
> > > > > > > - if (data.output[0].output_id != output->id)
> > > > > > > - continue;
> > > > > > > -
> > > > > > > - mode = data.output[0].mode;
> > > > > > > - igt_output_set_pipe(output, data.pipe1);
> > > > > > > - igt_output_override_mode(output, &mode);
> > > > > > > + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
> > > > > > > + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
> > > > > > > - igt_dynamic_f("pipe-%s-%s",
> > > > > > > - kmstest_pipe_name(data.pipe1),
> > > > > > > - igt_output_name(output))
> > > > > > > - test_invalid_modeset(&data);
> > > > > > > - }
> > > > > > > + if (data.big_joiner_output_count >= 1)
> > > > > > > + igt_dynamic_f("big_joiner_on_last_pipe")
> > > > > > > + tets_big_joiner_on_last_pipe(&data);
> > > > > > > - if(valid_output > 1) {
> > > > > > > - for (i = 0; i < data.n_pipes - 1; i++) {
> > > > > > > - igt_output_t *first_output = NULL, *second_output = NULL;
> > > > > > > -
> > > > > > > - data.pipe1 = pipe_seq[i];
> > > > > > > - data.pipe2 = pipe_seq[i + 1];
> > > > > > > -
> > > > > > > - igt_display_reset(&data.display);
> > > > > > > - for_each_connected_output(&data.display, output) {
> > > > > > > - if (data.output[0].output_id == output->id) {
> > > > > > > - first_output = output;
> > > > > > > - mode = data.output[0].mode;
> > > > > > > -
> > > > > > > - igt_output_set_pipe(output, data.pipe1);
> > > > > > > - igt_output_override_mode(output, &mode);
> > > > > > > - } else if (second_output == NULL) {
> > > > > > > - second_output = output;
> > > > > > > - igt_output_set_pipe(output, data.pipe2);
> > > > > > > -
> > > > > > > - break;
> > > > > > > - }
> > > > > > > - }
> > > > > > > -
> > > > > > > - igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
> > > > > > > - kmstest_pipe_name(data.pipe1),
> > > > > > > - igt_output_name(first_output),
> > > > > > > - kmstest_pipe_name(data.pipe2),
> > > > > > > - igt_output_name(second_output))
> > > > > > > - test_invalid_modeset(&data);
> > > > > > > - }
> > > > > > > - }
> > > > > > > - }
> > > > > > > + if (data.big_joiner_output_count > 1)
> > > > > > > + igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
> > > > > > > + test_invalid_modeset_two_joiner(&data, false);
> > > > > > > - igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
> > > > > > > - igt_subtest_with_dynamic("2x-modeset") {
> > > > > > > - igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
> > > > > > > - igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
> > > > > > > - for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
> > > > > > > - data.pipe1 = pipe_seq[i];
> > > > > > > - data.pipe2 = pipe_seq[i + 2];
> > > > > > > - igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
> > > > > > > - test_dual_display(&data);
> > > > > > > + if (data.combined_output_count) {
> > > > > > > + igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
> > > > > > > + test_invalid_modeset_two_joiner(&data, true);
> > > > > > > }
> > > > > > > }
> > > > > > > igt_fixture {
> > > > > > > - igt_remove_fb(data.drm_fd, &data.fb);
> > > > > > > igt_display_fini(&data.display);
> > > > > > > drm_close_driver(data.drm_fd);
> > > > > > > }
> > > > > > > --
> > > > > > > 2.25.1
> > > > > Thanks and Regards
> > > > > Kunal Joshi
> > > Thanks and Regards
> > > Kunal Joshi
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-06 12:52 ` Lisovskiy, Stanislav
@ 2024-03-06 13:15 ` Joshi, Kunal1
2024-03-06 13:41 ` Lisovskiy, Stanislav
0 siblings, 1 reply; 17+ messages in thread
From: Joshi, Kunal1 @ 2024-03-06 13:15 UTC (permalink / raw)
To: Lisovskiy, Stanislav; +Cc: igt-dev, Karthik B S, Bhanuprakash Modem
Hello Stan,
On 3/6/2024 6:22 PM, Lisovskiy, Stanislav wrote:
> On Wed, Mar 06, 2024 at 04:58:54PM +0530, Joshi, Kunal1 wrote:
>> Hello Stan,
>>
>> On 3/6/2024 4:40 PM, Lisovskiy, Stanislav wrote:
>>> On Wed, Mar 06, 2024 at 04:11:03PM +0530, Joshi, Kunal1 wrote:
>>>> Hello Stan,
>>>>
>>>> On 3/6/2024 4:03 PM, Lisovskiy, Stanislav wrote:
>>>>> On Wed, Mar 06, 2024 at 03:41:26PM +0530, Joshi, Kunal1 wrote:
>>>>>> Hello Stan,
>>>>>>
>>>>>> On 3/6/2024 3:23 PM, Lisovskiy, Stanislav wrote:
>>>>>>> On Wed, Mar 06, 2024 at 10:55:09AM +0530, Kunal Joshi wrote:
>>>>>>>> big joiner outputs are statically assigned to pipe,
>>>>>>>> rewrite to assign dynamically
>>>>>>>>
>>>>>>>> v2: Don't change license (Bhanu)
>>>>>>>> Add documentation for generate_combinations (Bhanu)
>>>>>>>> Print the pipe name (Bhanu)
>>>>>>>> Remove unwanted commit (Bhanu)
>>>>>>>> Move combine output logic to igt_fixture (Bhanu)
>>>>>>>> split revamp and force joiner (Bhanu)
>>>>>>>>
>>>>>>>> Cc: Karthik B S<karthik.b.s@intel.com>
>>>>>>>> Cc: Bhanuprakash Modem<bhanuprakash.modem@intel.com>
>>>>>>>> Signed-off-by: Kunal Joshi<kunal1.joshi@intel.com>
>>>>>>>> ---
>>>>>>>> tests/intel/kms_big_joiner.c | 391 +++++++++++++++++------------------
>>>>>>>> 1 file changed, 187 insertions(+), 204 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
>>>>>>>> index 28678b958..ba4097d8b 100644
>>>>>>>> --- a/tests/intel/kms_big_joiner.c
>>>>>>>> +++ b/tests/intel/kms_big_joiner.c
>>>>>>>> @@ -43,16 +43,19 @@
>>>>>>>> *
>>>>>>>> * SUBTEST: basic
>>>>>>>> * Description: Verify the basic modeset on big joiner mode on all pipes
>>>>>>>> - *
>>>>>>>> - * SUBTEST: 2x-modeset
>>>>>>>> - * Description: Verify simultaneous modeset on 2 big joiner outputs
>>>>>>>> */
>>>>>>>> -
>>>>>>>> IGT_TEST_DESCRIPTION("Test big joiner");
>>>>>>>> -struct bigjoiner_output {
>>>>>>>> - uint32_t output_id;
>>>>>>>> - drmModeModeInfo mode;
>>>>>>>> +#define MAX_OUTPUTS 256
>>>>>>>> +#define MAX_COMBINATIONS 1000
>>>>>>>> +#define INVALID_TEST_OUTPUT 2
>>>>>>>> +typedef struct {
>>>>>>>> + int combination[MAX_OUTPUTS];
>>>>>>>> +} Combination;
>>>>>>>> +
>>>>>>>> +enum joiner_type {
>>>>>>>> + BIG_JOINER = 1 << 1,
>>>>>>>> + INVALID_JOINER = -1,
>>>>>>>> };
>>>>>>>> typedef struct {
>>>>>>>> @@ -60,273 +63,253 @@ typedef struct {
>>>>>>>> igt_display_t display;
>>>>>>>> struct igt_fb fb;
>>>>>>>> int n_pipes;
>>>>>>>> - enum pipe pipe1;
>>>>>>>> - enum pipe pipe2;
>>>>>>>> - struct bigjoiner_output output[2];
>>>>>>>> + uint64_t big_joiner_outputs[IGT_MAX_PIPES];
>>>>>>>> + uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
>>>>>>>> + uint64_t combined_outputs[IGT_MAX_PIPES];
>>>>>>>> + int big_joiner_output_count;
>>>>>>>> + int non_big_joiner_output_count;
>>>>>>>> + int combined_output_count;
>>>>>>>> + int output_count;
>>>>>>>> + enum pipe pipe_seq[IGT_MAX_PIPES];
>>>>>>>> } data_t;
>>>>>>>> static int max_dotclock;
>>>>>>>> -static void test_invalid_modeset(data_t *data)
>>>>>>>> +/*
>>>>>>>> + * The generate_combinations function generates combinations of pipe allocations
>>>>>>>> + * for a given number of outputs
>>>>>>>> + *
>>>>>>>> + * @output_count: Number of outputs to allocate pipes for.
>>>>>>>> + * @pipe_count: Total number of available pipes.
>>>>>>>> + * @pipes_per_output: Number of pipes to be allocated for a single output.
>>>>>>>> + * @combinations: Array to store generated combinations.
>>>>>>>> + * @num_combinations: Pointer to a variable that stores the number of generated combinations.
>>>>>>>> + *
>>>>>>>> + * Example (output_count=2, pipe_count=4, pipes_per_output=2):
>>>>>>>> + * Combination 1: 0 2
>>>>>>>> + * Combination 2: 1 3
>>>>>>> I think this might be a bit overcomplicated - just for your information, we can't deliberately
>>>>>>> choose which pipes can be used for bigjoiner. On some platforms even only certain pipes, can be
>>>>>>> used for bigjoiner.
>>>>>>> Moreover the way how driver decides, which pipes are going to be used for bigjoiner is basically
>>>>>>> this code in intel_dp.c:
>>>>>>>
>>>>>>> if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
>>>>>>> adjusted_mode->crtc_clock))
>>>>>>> pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
>>>>>>>
>>>>>>> Means if you try to do a modeset with resolution > 5K or exceed max_dot_clock on crtc->pipe,
>>>>>>> then _always_ pipe + 1, going to be used for bigjoiner.
>>>>>>>
>>>>>>>
>>>>>>> Stan
>>>>>>>
>>>>>> Thanks for the inputs,
>>>>>> Goal here is to try various combination possible,
>>>>>> Suppose a platform supports 5 pipes(A-E) and we have 1 bigjoiner output
>>>>>> (DP-1) then we want to try
>>>>>> DP-1 on PIPE_A
>>>>>> DP-1 on PIPE_B
>>>>>> DP-1 on PIPE_C
>>>>>> DP-1 on PIPE_D
>>>>>>
>>>>>> Suppose a platform supports 5 pipes(A-E) and we have 2 bigjoiner output
>>>>>> (DP-1, DP-2) then we want to try
>>>>>> DP-1 on PIPE_A and DP-2 on PIPE_C
>>>>>> DP-1 on PIPE_B and DP-2 on PIPE_D And so on, Going forward this will be
>>>>>> useful we introduce any feature which can allow having more pipes per output
>>>>>> also.
>>>>> That won't work. BSpec and current driver code allows to use only _adjacent_ pipes.
>>>>> I.e if you modeset PIPE_A with 5K resolution, then bigjoiner_pipes mask would be
>>>>> PIPE_A | PIPE_B. If you modeset PIPE_B with 5K resolution it will take PIPE_C as a
>>>>> slave and so on.
>>>>> So for instance of you had DP-1 assigned to PIPE_A and DP-2 assigned to PIPE_C by test,
>>>>> _driver_ will still reassign PIPE_B to DP-2, in order for bigjoiner to work.
>>>>> That logic is implemented in intel_dp.c, as I mentioned above.
>>>>> Also you can check the BSpec Bigjoiner programming description.
>>>>>
>>>>> Stan
>>>> I think there is some confusion here,
>>>>
>>>> Below is result of the test that was executed with current code
>>>> https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10766/bat-arls-4/igt@kms_big_joiner@force-joiner-basic@1x-joiner.html
>>>>
>>>> Assigning pipe 0 to DP-3
>>>> <7> [44.263216] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
>>>> [CRTC:131:pipe B] Used as slave for big joiner master [CRTC:80:pipe A]
>>>>
>>>> Assigning pipe 1 to DP-3
>>>> <7> [44.568716] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
>>>> [CRTC:182:pipe C] Used as slave for big joiner master [CRTC:131:pipe B]
>>>> Assigning pipe 2 to DP-3
>>>> <7> [44.909690] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
>>>> [CRTC:233:pipe D] Used as slave for big joiner master [CRTC:182:pipe C] So
>>>> we are leaving one sequential pipe for a output,
>>>> Please let me know if i still wasn't able to explain properly.
>>> Yes, that is correct here. I was just trying to clarify that we can't have all
>>> possible combinations unfortunately.
>>> There are only certain scenarios supported, so could be a bit overkill trying to
>>> approach this combinatorical way, but rather I would see this more like introducing
>>> some mapping table, containing valid mappings or something similar.
>>> I don't think we are going to have more than 5 pipes anyway soon.
>>>
>>> That way, it might be way easier to check with spec and maintain this code.
>>>
>>> In case if more pipes are supported per output, most likely it won't be that straight
>>> forward as well :)
>>>
>>> I would add something like "get_next_master_pipe" function, which you call for each pipe
>>> which is allowed to be master. That function would also take available pipes as a mask.
>>>
>>> Then it returns next avaiable master pipe, considering the available pipes mask.
>>> That way you easily generate all allowed combinations, by just modifying available pipes mask.
>>>
>>> Stan
>> Can you please provide more info on this only certain scenario's supported?
>> Or just an example where this code won't work will be really useful.
>>
>> On the overkill part, this to me will only have the combinations which are
>> valid,
>> Maybe we just need to exclude those certain scenario's which are
>> unsupported.
> On some platforms, not all pipes can be bigjoiner masters, some pipes can be fused off.
> We can of course hardcode this into algorithm, but that would be less readable.
> Would be nice to have some table or initial structure to be able to explicitly regulate
> this, without altering the actual code.
>
> Stan
I still don't think this is a good idea to have static structure which
needs to be updated again and again for newer platform
also we need to define what pipe need to be used in case of 1x joiner,
2x-joiner and so on respectively.
Or this idea is just over my head.
I would just update logic in below code to discard this fused pipe
data.n_pipes = 0;
for_each_pipe(&data.display, i) {
data.n_pipes++;
data.pipe_seq[j] = i;
j++;
}
>
>>>>>>>> +*/
>>>>>>>> +static void generate_combinations(int output_count, int pipe_count,
>>>>>>>> + int pipes_per_output,
>>>>>>>> + Combination combinations[MAX_COMBINATIONS],
>>>>>>>> + uint64_t *num_combinations)
>>>>>>>> {
>>>>>>>> - igt_output_t *output;
>>>>>>>> - igt_display_t *display = &data->display;
>>>>>>>> - int ret;
>>>>>>>> + int i, index;
>>>>>>>> + int current_combination[MAX_OUTPUTS];
>>>>>>>> - igt_info("Bigjoiner test on ");
>>>>>>>> - for_each_connected_output(display, output){
>>>>>>>> - enum pipe p = output->pending_pipe;
>>>>>>>> - drmModeModeInfo *mode;
>>>>>>>> - igt_pipe_t *pipe;
>>>>>>>> - igt_plane_t *plane;
>>>>>>>> + for (i = 0; i < output_count; ++i)
>>>>>>>> + current_combination[i] = i * pipes_per_output;
>>>>>>>> - if (p == PIPE_NONE)
>>>>>>>> - continue;
>>>>>>>> -
>>>>>>>> - mode = igt_output_get_mode(output);
>>>>>>>> - igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
>>>>>>>> - kmstest_dump_mode(mode);
>>>>>>>> + while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
>>>>>>>> + for (i = 0; i < output_count; ++i)
>>>>>>>> + combinations[*num_combinations].combination[i] = current_combination[i];
>>>>>>>> - pipe = &display->pipes[p];
>>>>>>>> - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>>>>>> + (*num_combinations)++;
>>>>>>>> - igt_plane_set_fb(plane, &data->fb);
>>>>>>>> - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
>>>>>>>> - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
>>>>>>>> - }
>>>>>>>> + index = output_count - 1;
>>>>>>>> + while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
>>>>>>>> + index--;
>>>>>>>> - igt_assert(!igt_check_bigjoiner_support(display));
>>>>>>>> + if (index < 0)
>>>>>>>> + break;
>>>>>>>> - /* This commit is expectd to fail as this pipe is being used for big joiner */
>>>>>>>> - ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
>>>>>>>> - DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
>>>>>>>> + current_combination[index]++;
>>>>>>>> + for (i = index + 1; i < output_count; ++i)
>>>>>>>> + current_combination[i] = current_combination[i - 1] + pipes_per_output;
>>>>>>>> + }
>>>>>>>> +}
>>>>>>>> - igt_display_reset(&data->display);
>>>>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>>>>> +static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
>>>>>>>> +{
>>>>>>>> + igt_output_t *output;
>>>>>>>> - igt_assert_lt(ret, 0);
>>>>>>>> + for_each_connected_output(&data->display, output) {
>>>>>>>> + if (output->id == output_id)
>>>>>>>> + return output;
>>>>>>>> + }
>>>>>>>> + igt_assert("Output not found\n");
>>>>>>>> + return NULL;
>>>>>>>> }
>>>>>>>> -static void test_basic_modeset(data_t *data)
>>>>>>>> +static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
>>>>>>>> {
>>>>>>>> + int i, j, ret;
>>>>>>>> + igt_output_t *output;
>>>>>>>> + uint64_t *outputs;
>>>>>>>> + igt_plane_t *primary[INVALID_TEST_OUTPUT];
>>>>>>>> + igt_fb_t fb[INVALID_TEST_OUTPUT];
>>>>>>>> drmModeModeInfo *mode;
>>>>>>>> - igt_output_t *output, *bigjoiner_output = NULL;
>>>>>>>> - igt_display_t *display = &data->display;
>>>>>>>> - igt_pipe_t *pipe;
>>>>>>>> - igt_plane_t *plane;
>>>>>>>> - igt_display_reset(display);
>>>>>>>> -
>>>>>>>> - for_each_connected_output(display, output) {
>>>>>>>> - if (data->output[0].output_id == output->id) {
>>>>>>>> - bigjoiner_output = output;
>>>>>>>> - break;
>>>>>>>> + outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
>>>>>>>> +
>>>>>>>> + for (i = 0; i < data->n_pipes-1; i++) {
>>>>>>>> + igt_display_reset(&data->display);
>>>>>>>> + for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
>>>>>>>> + output = get_output_by_id_or_assert(data, outputs[j]);
>>>>>>>> + igt_assert(output);
>>>>>>>> + igt_output_set_pipe(output, data->pipe_seq[i + j]);
>>>>>>>> + mode = igt_output_get_mode(output);
>>>>>>>> + igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
>>>>>>>> + kmstest_pipe_name(data->pipe_seq[i + j]),
>>>>>>>> + igt_output_name(output), mode->hdisplay,
>>>>>>>> + mode->vdisplay, mode->vrefresh,
>>>>>>>> + j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
>>>>>>>> + primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
>>>>>>>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>>>>>>>> + DRM_FORMAT_MOD_LINEAR, &fb[j]);
>>>>>>>> + igt_plane_set_fb(primary[j], &fb[j]);
>>>>>>>> }
>>>>>>>> + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
>>>>>>>> + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
>>>>>>>> }
>>>>>>>> -
>>>>>>>> - igt_output_set_pipe(bigjoiner_output, data->pipe1);
>>>>>>>> -
>>>>>>>> - mode = &data->output[0].mode;
>>>>>>>> - igt_output_override_mode(bigjoiner_output, mode);
>>>>>>>> -
>>>>>>>> - pipe = &display->pipes[data->pipe1];
>>>>>>>> - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>>>>>> -
>>>>>>>> - igt_plane_set_fb(plane, &data->fb);
>>>>>>>> - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
>>>>>>>> - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
>>>>>>>> -
>>>>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>>>>> -
>>>>>>>> - igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
>>>>>>>> - igt_plane_set_fb(plane, NULL);
>>>>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>>>>> }
>>>>>>>> -static void test_dual_display(data_t *data)
>>>>>>>> +static void tets_big_joiner_on_last_pipe(data_t *data)
>>>>>>>> {
>>>>>>>> + int i, ret;
>>>>>>>> + uint64_t *outputs;
>>>>>>>> + igt_output_t *output;
>>>>>>>> + igt_plane_t *primary;
>>>>>>>> + igt_fb_t fb;
>>>>>>>> drmModeModeInfo *mode;
>>>>>>>> - igt_output_t *output, *bigjoiner_output[2];
>>>>>>>> - igt_display_t *display = &data->display;
>>>>>>>> - igt_pipe_t *pipe;
>>>>>>>> - igt_plane_t *plane1, *plane2;
>>>>>>>> - int count = 0;
>>>>>>>> -
>>>>>>>> - igt_display_reset(display);
>>>>>>>> -
>>>>>>>> - for_each_connected_output(display, output) {
>>>>>>>> - if (data->output[count].output_id == output->id) {
>>>>>>>> - bigjoiner_output[count] = output;
>>>>>>>> - count++;
>>>>>>>> - }
>>>>>>>> - if (count > 1)
>>>>>>>> - break;
>>>>>>>> + outputs = data->big_joiner_outputs;
>>>>>>>> + for (i = 0; i < data->big_joiner_output_count; i++) {
>>>>>>>> + igt_display_reset(&data->display);
>>>>>>>> + output = get_output_by_id_or_assert(data, outputs[i]);
>>>>>>>> + igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
>>>>>>>> + mode = igt_output_get_mode(output);
>>>>>>>> + igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
>>>>>>>> + kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
>>>>>>>> + igt_output_name(output), mode->hdisplay,
>>>>>>>> + mode->vdisplay, mode->vrefresh);
>>>>>>>> + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
>>>>>>>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>>>>>>>> + DRM_FORMAT_MOD_LINEAR, &fb);
>>>>>>>> + igt_plane_set_fb(primary, &fb);
>>>>>>>> + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
>>>>>>>> + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
>>>>>>>> }
>>>>>>>> +}
>>>>>>>> - igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
>>>>>>>> - igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
>>>>>>>> -
>>>>>>>> - /* Set up first big joiner output on Pipe A*/
>>>>>>>> - mode = &data->output[0].mode;
>>>>>>>> - igt_output_override_mode(bigjoiner_output[0], mode);
>>>>>>>> -
>>>>>>>> - pipe = &display->pipes[data->pipe1];
>>>>>>>> - plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>>>>>> -
>>>>>>>> - igt_plane_set_fb(plane1, &data->fb);
>>>>>>>> - igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
>>>>>>>> - igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
>>>>>>>> -
>>>>>>>> - /* Set up second big joiner output on Pipe C*/
>>>>>>>> - mode = &data->output[1].mode;
>>>>>>>> - igt_output_override_mode(bigjoiner_output[1], mode);
>>>>>>>> -
>>>>>>>> - pipe = &display->pipes[data->pipe2];
>>>>>>>> - plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
>>>>>>>> -
>>>>>>>> - igt_plane_set_fb(plane2, &data->fb);
>>>>>>>> - igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
>>>>>>>> - igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
>>>>>>>> -
>>>>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>>>>> +static void test_basic_modeset(data_t *data, int num_outputs,
>>>>>>>> + Combination combinations[MAX_COMBINATIONS],
>>>>>>>> + uint64_t num_combinations)
>>>>>>>> +{
>>>>>>>> + int i, j, ret;
>>>>>>>> + igt_display_t *display = &data->display;
>>>>>>>> + igt_output_t *output[num_outputs];
>>>>>>>> + igt_plane_t *primary[num_outputs];
>>>>>>>> + igt_fb_t fb[num_outputs];
>>>>>>>> + drmModeModeInfo *mode;
>>>>>>>> - /* Clean up */
>>>>>>>> - igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
>>>>>>>> - igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
>>>>>>>> - igt_plane_set_fb(plane1, NULL);
>>>>>>>> - igt_plane_set_fb(plane2, NULL);
>>>>>>>> - igt_display_commit2(display, COMMIT_ATOMIC);
>>>>>>>> + for (i = 0; i < num_combinations; i++) {
>>>>>>>> + igt_display_reset(display);
>>>>>>>> + for (j = 0; j < num_outputs; j++) {
>>>>>>>> + output[j] = get_output_by_id_or_assert(data,
>>>>>>>> + data->big_joiner_outputs[j]);
>>>>>>>> + igt_info("Assigning pipe %s to %s%s",
>>>>>>>> + kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
>>>>>>>> + output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
>>>>>>>> + igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
>>>>>>>> + primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
>>>>>>>> + mode = igt_output_get_mode(output[j]);
>>>>>>>> + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
>>>>>>>> + DRM_FORMAT_MOD_LINEAR, &fb[j]);
>>>>>>>> + igt_plane_set_fb(primary[j], &fb[j]);
>>>>>>>> + }
>>>>>>>> + ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
>>>>>>>> + igt_assert_f(ret == 0, "Commit failed\n");
>>>>>>>> + }
>>>>>>>> }
>>>>>>>> igt_main
>>>>>>>> {
>>>>>>>> + int i, j;
>>>>>>>> data_t data;
>>>>>>>> igt_output_t *output;
>>>>>>>> - drmModeModeInfo mode;
>>>>>>>> - int valid_output = 0, i, count = 0, j = 0;
>>>>>>>> - uint16_t width = 0, height = 0;
>>>>>>>> - enum pipe pipe_seq[IGT_MAX_PIPES];
>>>>>>>> + drmModeModeInfo default_mode;
>>>>>>>> + i = j = 0;
>>>>>>>> igt_fixture {
>>>>>>>> data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
>>>>>>>> kmstest_set_vt_graphics_mode();
>>>>>>>> -
>>>>>>>> igt_display_require(&data.display, data.drm_fd);
>>>>>>>> igt_require(data.display.is_atomic);
>>>>>>>> -
>>>>>>>> max_dotclock = igt_get_max_dotclock(data.drm_fd);
>>>>>>>> + data.big_joiner_output_count = 0;
>>>>>>>> + data.non_big_joiner_output_count = 0;
>>>>>>>> + data.combined_output_count = 0;
>>>>>>>> + data.output_count = 0;
>>>>>>>> for_each_connected_output(&data.display, output) {
>>>>>>>> bool found = false;
>>>>>>>> drmModeConnector *connector = output->config.connector;
>>>>>>>> -
>>>>>>>> - /*
>>>>>>>> - * Bigjoiner will come in to the picture when the
>>>>>>>> - * resolution > 5K or clock > max-dot-clock.
>>>>>>>> - */
>>>>>>>> found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
>>>>>>>> -
>>>>>>>> if (found) {
>>>>>>>> - data.output[count].output_id = output->id;
>>>>>>>> - memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
>>>>>>>> - count++;
>>>>>>>> -
>>>>>>>> - width = max(width, mode.hdisplay);
>>>>>>>> - height = max(height, mode.vdisplay);
>>>>>>>> + data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
>>>>>>>> + igt_output_override_mode(output, &connector->modes[0]);
>>>>>>>> + } else {
>>>>>>>> + data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
>>>>>>>> + kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
>>>>>>>> + igt_output_override_mode(output, &default_mode);
>>>>>>>> }
>>>>>>>> - valid_output++;
>>>>>>>> + data.output_count++;
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
>>>>>>>> + data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
>>>>>>>> + data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
>>>>>>>> }
>>>>>>>> data.n_pipes = 0;
>>>>>>>> for_each_pipe(&data.display, i) {
>>>>>>>> data.n_pipes++;
>>>>>>>> - pipe_seq[j] = i;
>>>>>>>> + data.pipe_seq[j] = i;
>>>>>>>> j++;
>>>>>>>> }
>>>>>>>> -
>>>>>>>> - igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
>>>>>>>> -
>>>>>>>> - igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
>>>>>>>> - DRM_FORMAT_MOD_LINEAR, &data.fb);
>>>>>>>> }
>>>>>>>> igt_describe("Verify the basic modeset on big joiner mode on all pipes");
>>>>>>>> igt_subtest_with_dynamic("basic") {
>>>>>>>> - for (i = 0; i < data.n_pipes - 1; i++) {
>>>>>>>> - data.pipe1 = pipe_seq[i];
>>>>>>>> - igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
>>>>>>>> - test_basic_modeset(&data);
>>>>>>>> + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
>>>>>>>> + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
>>>>>>>> +
>>>>>>>> + for (i = 0; i < data.big_joiner_output_count; i++) {
>>>>>>>> + uint64_t num_combinations = 0;
>>>>>>>> + Combination combinations[MAX_COMBINATIONS];
>>>>>>>> +
>>>>>>>> + generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
>>>>>>>> + igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
>>>>>>>> + i+1, data.n_pipes, num_combinations);
>>>>>>>> +
>>>>>>>> + if (num_combinations > 0)
>>>>>>>> + igt_dynamic_f("%dx-big-joiner", i+1)
>>>>>>>> + test_basic_modeset(&data, i+1, combinations, num_combinations);
>>>>>>>> + else
>>>>>>>> + break;
>>>>>>>> }
>>>>>>>> }
>>>>>>>> - igt_describe("Verify if the modeset on the adjoining pipe is rejected "
>>>>>>>> - "when the pipe is active with a big joiner modeset");
>>>>>>>> igt_subtest_with_dynamic("invalid-modeset") {
>>>>>>>> - data.pipe1 = pipe_seq[j - 1];
>>>>>>>> -
>>>>>>>> - igt_display_reset(&data.display);
>>>>>>>> - for_each_connected_output(&data.display, output) {
>>>>>>>> - if (data.output[0].output_id != output->id)
>>>>>>>> - continue;
>>>>>>>> -
>>>>>>>> - mode = data.output[0].mode;
>>>>>>>> - igt_output_set_pipe(output, data.pipe1);
>>>>>>>> - igt_output_override_mode(output, &mode);
>>>>>>>> + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
>>>>>>>> + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
>>>>>>>> - igt_dynamic_f("pipe-%s-%s",
>>>>>>>> - kmstest_pipe_name(data.pipe1),
>>>>>>>> - igt_output_name(output))
>>>>>>>> - test_invalid_modeset(&data);
>>>>>>>> - }
>>>>>>>> + if (data.big_joiner_output_count >= 1)
>>>>>>>> + igt_dynamic_f("big_joiner_on_last_pipe")
>>>>>>>> + tets_big_joiner_on_last_pipe(&data);
>>>>>>>> - if(valid_output > 1) {
>>>>>>>> - for (i = 0; i < data.n_pipes - 1; i++) {
>>>>>>>> - igt_output_t *first_output = NULL, *second_output = NULL;
>>>>>>>> -
>>>>>>>> - data.pipe1 = pipe_seq[i];
>>>>>>>> - data.pipe2 = pipe_seq[i + 1];
>>>>>>>> -
>>>>>>>> - igt_display_reset(&data.display);
>>>>>>>> - for_each_connected_output(&data.display, output) {
>>>>>>>> - if (data.output[0].output_id == output->id) {
>>>>>>>> - first_output = output;
>>>>>>>> - mode = data.output[0].mode;
>>>>>>>> -
>>>>>>>> - igt_output_set_pipe(output, data.pipe1);
>>>>>>>> - igt_output_override_mode(output, &mode);
>>>>>>>> - } else if (second_output == NULL) {
>>>>>>>> - second_output = output;
>>>>>>>> - igt_output_set_pipe(output, data.pipe2);
>>>>>>>> -
>>>>>>>> - break;
>>>>>>>> - }
>>>>>>>> - }
>>>>>>>> -
>>>>>>>> - igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
>>>>>>>> - kmstest_pipe_name(data.pipe1),
>>>>>>>> - igt_output_name(first_output),
>>>>>>>> - kmstest_pipe_name(data.pipe2),
>>>>>>>> - igt_output_name(second_output))
>>>>>>>> - test_invalid_modeset(&data);
>>>>>>>> - }
>>>>>>>> - }
>>>>>>>> - }
>>>>>>>> + if (data.big_joiner_output_count > 1)
>>>>>>>> + igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
>>>>>>>> + test_invalid_modeset_two_joiner(&data, false);
>>>>>>>> - igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
>>>>>>>> - igt_subtest_with_dynamic("2x-modeset") {
>>>>>>>> - igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
>>>>>>>> - igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
>>>>>>>> - for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
>>>>>>>> - data.pipe1 = pipe_seq[i];
>>>>>>>> - data.pipe2 = pipe_seq[i + 2];
>>>>>>>> - igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
>>>>>>>> - test_dual_display(&data);
>>>>>>>> + if (data.combined_output_count) {
>>>>>>>> + igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
>>>>>>>> + test_invalid_modeset_two_joiner(&data, true);
>>>>>>>> }
>>>>>>>> }
>>>>>>>> igt_fixture {
>>>>>>>> - igt_remove_fb(data.drm_fd, &data.fb);
>>>>>>>> igt_display_fini(&data.display);
>>>>>>>> drm_close_driver(data.drm_fd);
>>>>>>>> }
>>>>>>>> --
>>>>>>>> 2.25.1
>>>>>> Thanks and Regards
>>>>>> Kunal Joshi
>>>> Thanks and Regards
>>>> Kunal Joshi
Thanks and Regards
Kunal Joshi
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner
2024-03-06 13:15 ` Joshi, Kunal1
@ 2024-03-06 13:41 ` Lisovskiy, Stanislav
0 siblings, 0 replies; 17+ messages in thread
From: Lisovskiy, Stanislav @ 2024-03-06 13:41 UTC (permalink / raw)
To: Joshi, Kunal1; +Cc: igt-dev, Karthik B S, Bhanuprakash Modem
On Wed, Mar 06, 2024 at 06:45:05PM +0530, Joshi, Kunal1 wrote:
> Hello Stan,
>
> On 3/6/2024 6:22 PM, Lisovskiy, Stanislav wrote:
> > On Wed, Mar 06, 2024 at 04:58:54PM +0530, Joshi, Kunal1 wrote:
> > > Hello Stan,
> > >
> > > On 3/6/2024 4:40 PM, Lisovskiy, Stanislav wrote:
> > > > On Wed, Mar 06, 2024 at 04:11:03PM +0530, Joshi, Kunal1 wrote:
> > > > > Hello Stan,
> > > > >
> > > > > On 3/6/2024 4:03 PM, Lisovskiy, Stanislav wrote:
> > > > > > On Wed, Mar 06, 2024 at 03:41:26PM +0530, Joshi, Kunal1 wrote:
> > > > > > > Hello Stan,
> > > > > > >
> > > > > > > On 3/6/2024 3:23 PM, Lisovskiy, Stanislav wrote:
> > > > > > > > On Wed, Mar 06, 2024 at 10:55:09AM +0530, Kunal Joshi wrote:
> > > > > > > > > big joiner outputs are statically assigned to pipe,
> > > > > > > > > rewrite to assign dynamically
> > > > > > > > >
> > > > > > > > > v2: Don't change license (Bhanu)
> > > > > > > > > Add documentation for generate_combinations (Bhanu)
> > > > > > > > > Print the pipe name (Bhanu)
> > > > > > > > > Remove unwanted commit (Bhanu)
> > > > > > > > > Move combine output logic to igt_fixture (Bhanu)
> > > > > > > > > split revamp and force joiner (Bhanu)
> > > > > > > > >
> > > > > > > > > Cc: Karthik B S<karthik.b.s@intel.com>
> > > > > > > > > Cc: Bhanuprakash Modem<bhanuprakash.modem@intel.com>
> > > > > > > > > Signed-off-by: Kunal Joshi<kunal1.joshi@intel.com>
> > > > > > > > > ---
> > > > > > > > > tests/intel/kms_big_joiner.c | 391 +++++++++++++++++------------------
> > > > > > > > > 1 file changed, 187 insertions(+), 204 deletions(-)
> > > > > > > > >
> > > > > > > > > diff --git a/tests/intel/kms_big_joiner.c b/tests/intel/kms_big_joiner.c
> > > > > > > > > index 28678b958..ba4097d8b 100644
> > > > > > > > > --- a/tests/intel/kms_big_joiner.c
> > > > > > > > > +++ b/tests/intel/kms_big_joiner.c
> > > > > > > > > @@ -43,16 +43,19 @@
> > > > > > > > > *
> > > > > > > > > * SUBTEST: basic
> > > > > > > > > * Description: Verify the basic modeset on big joiner mode on all pipes
> > > > > > > > > - *
> > > > > > > > > - * SUBTEST: 2x-modeset
> > > > > > > > > - * Description: Verify simultaneous modeset on 2 big joiner outputs
> > > > > > > > > */
> > > > > > > > > -
> > > > > > > > > IGT_TEST_DESCRIPTION("Test big joiner");
> > > > > > > > > -struct bigjoiner_output {
> > > > > > > > > - uint32_t output_id;
> > > > > > > > > - drmModeModeInfo mode;
> > > > > > > > > +#define MAX_OUTPUTS 256
> > > > > > > > > +#define MAX_COMBINATIONS 1000
> > > > > > > > > +#define INVALID_TEST_OUTPUT 2
> > > > > > > > > +typedef struct {
> > > > > > > > > + int combination[MAX_OUTPUTS];
> > > > > > > > > +} Combination;
> > > > > > > > > +
> > > > > > > > > +enum joiner_type {
> > > > > > > > > + BIG_JOINER = 1 << 1,
> > > > > > > > > + INVALID_JOINER = -1,
> > > > > > > > > };
> > > > > > > > > typedef struct {
> > > > > > > > > @@ -60,273 +63,253 @@ typedef struct {
> > > > > > > > > igt_display_t display;
> > > > > > > > > struct igt_fb fb;
> > > > > > > > > int n_pipes;
> > > > > > > > > - enum pipe pipe1;
> > > > > > > > > - enum pipe pipe2;
> > > > > > > > > - struct bigjoiner_output output[2];
> > > > > > > > > + uint64_t big_joiner_outputs[IGT_MAX_PIPES];
> > > > > > > > > + uint64_t non_big_joiner_outputs[IGT_MAX_PIPES];
> > > > > > > > > + uint64_t combined_outputs[IGT_MAX_PIPES];
> > > > > > > > > + int big_joiner_output_count;
> > > > > > > > > + int non_big_joiner_output_count;
> > > > > > > > > + int combined_output_count;
> > > > > > > > > + int output_count;
> > > > > > > > > + enum pipe pipe_seq[IGT_MAX_PIPES];
> > > > > > > > > } data_t;
> > > > > > > > > static int max_dotclock;
> > > > > > > > > -static void test_invalid_modeset(data_t *data)
> > > > > > > > > +/*
> > > > > > > > > + * The generate_combinations function generates combinations of pipe allocations
> > > > > > > > > + * for a given number of outputs
> > > > > > > > > + *
> > > > > > > > > + * @output_count: Number of outputs to allocate pipes for.
> > > > > > > > > + * @pipe_count: Total number of available pipes.
> > > > > > > > > + * @pipes_per_output: Number of pipes to be allocated for a single output.
> > > > > > > > > + * @combinations: Array to store generated combinations.
> > > > > > > > > + * @num_combinations: Pointer to a variable that stores the number of generated combinations.
> > > > > > > > > + *
> > > > > > > > > + * Example (output_count=2, pipe_count=4, pipes_per_output=2):
> > > > > > > > > + * Combination 1: 0 2
> > > > > > > > > + * Combination 2: 1 3
> > > > > > > > I think this might be a bit overcomplicated - just for your information, we can't deliberately
> > > > > > > > choose which pipes can be used for bigjoiner. On some platforms even only certain pipes, can be
> > > > > > > > used for bigjoiner.
> > > > > > > > Moreover the way how driver decides, which pipes are going to be used for bigjoiner is basically
> > > > > > > > this code in intel_dp.c:
> > > > > > > >
> > > > > > > > if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay,
> > > > > > > > adjusted_mode->crtc_clock))
> > > > > > > > pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe);
> > > > > > > >
> > > > > > > > Means if you try to do a modeset with resolution > 5K or exceed max_dot_clock on crtc->pipe,
> > > > > > > > then _always_ pipe + 1, going to be used for bigjoiner.
> > > > > > > >
> > > > > > > >
> > > > > > > > Stan
> > > > > > > >
> > > > > > > Thanks for the inputs,
> > > > > > > Goal here is to try various combination possible,
> > > > > > > Suppose a platform supports 5 pipes(A-E) and we have 1 bigjoiner output
> > > > > > > (DP-1) then we want to try
> > > > > > > DP-1 on PIPE_A
> > > > > > > DP-1 on PIPE_B
> > > > > > > DP-1 on PIPE_C
> > > > > > > DP-1 on PIPE_D
> > > > > > >
> > > > > > > Suppose a platform supports 5 pipes(A-E) and we have 2 bigjoiner output
> > > > > > > (DP-1, DP-2) then we want to try
> > > > > > > DP-1 on PIPE_A and DP-2 on PIPE_C
> > > > > > > DP-1 on PIPE_B and DP-2 on PIPE_D And so on, Going forward this will be
> > > > > > > useful we introduce any feature which can allow having more pipes per output
> > > > > > > also.
> > > > > > That won't work. BSpec and current driver code allows to use only _adjacent_ pipes.
> > > > > > I.e if you modeset PIPE_A with 5K resolution, then bigjoiner_pipes mask would be
> > > > > > PIPE_A | PIPE_B. If you modeset PIPE_B with 5K resolution it will take PIPE_C as a
> > > > > > slave and so on.
> > > > > > So for instance of you had DP-1 assigned to PIPE_A and DP-2 assigned to PIPE_C by test,
> > > > > > _driver_ will still reassign PIPE_B to DP-2, in order for bigjoiner to work.
> > > > > > That logic is implemented in intel_dp.c, as I mentioned above.
> > > > > > Also you can check the BSpec Bigjoiner programming description.
> > > > > >
> > > > > > Stan
> > > > > I think there is some confusion here,
> > > > >
> > > > > Below is result of the test that was executed with current code
> > > > > https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_10766/bat-arls-4/igt@kms_big_joiner@force-joiner-basic@1x-joiner.html
> > > > >
> > > > > Assigning pipe 0 to DP-3
> > > > > <7> [44.263216] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
> > > > > [CRTC:131:pipe B] Used as slave for big joiner master [CRTC:80:pipe A]
> > > > >
> > > > > Assigning pipe 1 to DP-3
> > > > > <7> [44.568716] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
> > > > > [CRTC:182:pipe C] Used as slave for big joiner master [CRTC:131:pipe B]
> > > > > Assigning pipe 2 to DP-3
> > > > > <7> [44.909690] i915 0000:00:02.0: [drm:intel_atomic_check [i915]]
> > > > > [CRTC:233:pipe D] Used as slave for big joiner master [CRTC:182:pipe C] So
> > > > > we are leaving one sequential pipe for a output,
> > > > > Please let me know if i still wasn't able to explain properly.
> > > > Yes, that is correct here. I was just trying to clarify that we can't have all
> > > > possible combinations unfortunately.
> > > > There are only certain scenarios supported, so could be a bit overkill trying to
> > > > approach this combinatorical way, but rather I would see this more like introducing
> > > > some mapping table, containing valid mappings or something similar.
> > > > I don't think we are going to have more than 5 pipes anyway soon.
> > > >
> > > > That way, it might be way easier to check with spec and maintain this code.
> > > >
> > > > In case if more pipes are supported per output, most likely it won't be that straight
> > > > forward as well :)
> > > >
> > > > I would add something like "get_next_master_pipe" function, which you call for each pipe
> > > > which is allowed to be master. That function would also take available pipes as a mask.
> > > >
> > > > Then it returns next avaiable master pipe, considering the available pipes mask.
> > > > That way you easily generate all allowed combinations, by just modifying available pipes mask.
> > > >
> > > > Stan
> > > Can you please provide more info on this only certain scenario's supported?
> > > Or just an example where this code won't work will be really useful.
> > >
> > > On the overkill part, this to me will only have the combinations which are
> > > valid,
> > > Maybe we just need to exclude those certain scenario's which are
> > > unsupported.
> > On some platforms, not all pipes can be bigjoiner masters, some pipes can be fused off.
> > We can of course hardcode this into algorithm, but that would be less readable.
> > Would be nice to have some table or initial structure to be able to explicitly regulate
> > this, without altering the actual code.
> >
> > Stan
> I still don't think this is a good idea to have static structure which needs
> to be updated again and again for newer platform
> also we need to define what pipe need to be used in case of 1x joiner,
> 2x-joiner and so on respectively.
>
> Or this idea is just over my head.
>
> I would just update logic in below code to discard this fused pipe
>
> data.n_pipes = 0;
> for_each_pipe(&data.display, i) {
> data.n_pipes++;
> data.pipe_seq[j] = i;
> j++;
> }
Yep and then the whole algorithm would be full of such small hardcoded hacks,
moreover reasoning behind those isn't obvious and not easily readable.
Static structure is still way better then static code, which you will have to change as well ;)
However in case of structure it is much easier to change, more explicit and easy to read.
while in code that would some if (weird_condition) pipe++
instead you could just define function which either returns next available master pipe, based
on the config or mask of pipes, which could be masters.
Then this function could have been called from many places, but we would have a _single point_,
where all the design specific changes are reflected, while the algorithm itself would be
much more readable.
For 2 bigjoiners you just mask for instance pipe A/pipe B and it will then return pipe C for next
master, if you pass available pipes mask to it as PIPE_C|PIPE_D and so on.
Stan
>
> >
> > > > > > > > > +*/
> > > > > > > > > +static void generate_combinations(int output_count, int pipe_count,
> > > > > > > > > + int pipes_per_output,
> > > > > > > > > + Combination combinations[MAX_COMBINATIONS],
> > > > > > > > > + uint64_t *num_combinations)
> > > > > > > > > {
> > > > > > > > > - igt_output_t *output;
> > > > > > > > > - igt_display_t *display = &data->display;
> > > > > > > > > - int ret;
> > > > > > > > > + int i, index;
> > > > > > > > > + int current_combination[MAX_OUTPUTS];
> > > > > > > > > - igt_info("Bigjoiner test on ");
> > > > > > > > > - for_each_connected_output(display, output){
> > > > > > > > > - enum pipe p = output->pending_pipe;
> > > > > > > > > - drmModeModeInfo *mode;
> > > > > > > > > - igt_pipe_t *pipe;
> > > > > > > > > - igt_plane_t *plane;
> > > > > > > > > + for (i = 0; i < output_count; ++i)
> > > > > > > > > + current_combination[i] = i * pipes_per_output;
> > > > > > > > > - if (p == PIPE_NONE)
> > > > > > > > > - continue;
> > > > > > > > > -
> > > > > > > > > - mode = igt_output_get_mode(output);
> > > > > > > > > - igt_info("pipe:%s, output:%s, mode:", kmstest_pipe_name(p), igt_output_name(output));
> > > > > > > > > - kmstest_dump_mode(mode);
> > > > > > > > > + while (*num_combinations < MAX_COMBINATIONS && current_combination[0] <= pipe_count - output_count * pipes_per_output) {
> > > > > > > > > + for (i = 0; i < output_count; ++i)
> > > > > > > > > + combinations[*num_combinations].combination[i] = current_combination[i];
> > > > > > > > > - pipe = &display->pipes[p];
> > > > > > > > > - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > > > > > > + (*num_combinations)++;
> > > > > > > > > - igt_plane_set_fb(plane, &data->fb);
> > > > > > > > > - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
> > > > > > > > > - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> > > > > > > > > - }
> > > > > > > > > + index = output_count - 1;
> > > > > > > > > + while (index >= 0 && current_combination[index] == pipe_count - (output_count - index) * pipes_per_output)
> > > > > > > > > + index--;
> > > > > > > > > - igt_assert(!igt_check_bigjoiner_support(display));
> > > > > > > > > + if (index < 0)
> > > > > > > > > + break;
> > > > > > > > > - /* This commit is expectd to fail as this pipe is being used for big joiner */
> > > > > > > > > - ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
> > > > > > > > > - DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
> > > > > > > > > + current_combination[index]++;
> > > > > > > > > + for (i = index + 1; i < output_count; ++i)
> > > > > > > > > + current_combination[i] = current_combination[i - 1] + pipes_per_output;
> > > > > > > > > + }
> > > > > > > > > +}
> > > > > > > > > - igt_display_reset(&data->display);
> > > > > > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > > > > > +static igt_output_t *get_output_by_id_or_assert(data_t *data, uint64_t output_id)
> > > > > > > > > +{
> > > > > > > > > + igt_output_t *output;
> > > > > > > > > - igt_assert_lt(ret, 0);
> > > > > > > > > + for_each_connected_output(&data->display, output) {
> > > > > > > > > + if (output->id == output_id)
> > > > > > > > > + return output;
> > > > > > > > > + }
> > > > > > > > > + igt_assert("Output not found\n");
> > > > > > > > > + return NULL;
> > > > > > > > > }
> > > > > > > > > -static void test_basic_modeset(data_t *data)
> > > > > > > > > +static void test_invalid_modeset_two_joiner(data_t *data, bool combined)
> > > > > > > > > {
> > > > > > > > > + int i, j, ret;
> > > > > > > > > + igt_output_t *output;
> > > > > > > > > + uint64_t *outputs;
> > > > > > > > > + igt_plane_t *primary[INVALID_TEST_OUTPUT];
> > > > > > > > > + igt_fb_t fb[INVALID_TEST_OUTPUT];
> > > > > > > > > drmModeModeInfo *mode;
> > > > > > > > > - igt_output_t *output, *bigjoiner_output = NULL;
> > > > > > > > > - igt_display_t *display = &data->display;
> > > > > > > > > - igt_pipe_t *pipe;
> > > > > > > > > - igt_plane_t *plane;
> > > > > > > > > - igt_display_reset(display);
> > > > > > > > > -
> > > > > > > > > - for_each_connected_output(display, output) {
> > > > > > > > > - if (data->output[0].output_id == output->id) {
> > > > > > > > > - bigjoiner_output = output;
> > > > > > > > > - break;
> > > > > > > > > + outputs = combined ? data->combined_outputs : data->big_joiner_outputs;
> > > > > > > > > +
> > > > > > > > > + for (i = 0; i < data->n_pipes-1; i++) {
> > > > > > > > > + igt_display_reset(&data->display);
> > > > > > > > > + for (j = 0; j < INVALID_TEST_OUTPUT; j++) {
> > > > > > > > > + output = get_output_by_id_or_assert(data, outputs[j]);
> > > > > > > > > + igt_assert(output);
> > > > > > > > > + igt_output_set_pipe(output, data->pipe_seq[i + j]);
> > > > > > > > > + mode = igt_output_get_mode(output);
> > > > > > > > > + igt_info("Assigning pipe %s to %s with mode %dx%d@%d%s",
> > > > > > > > > + kmstest_pipe_name(data->pipe_seq[i + j]),
> > > > > > > > > + igt_output_name(output), mode->hdisplay,
> > > > > > > > > + mode->vdisplay, mode->vrefresh,
> > > > > > > > > + j == INVALID_TEST_OUTPUT - 1 ? "\n" : ", ");
> > > > > > > > > + primary[j] = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> > > > > > > > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > > > > > > > + DRM_FORMAT_MOD_LINEAR, &fb[j]);
> > > > > > > > > + igt_plane_set_fb(primary[j], &fb[j]);
> > > > > > > > > }
> > > > > > > > > + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> > > > > > > > > + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> > > > > > > > > }
> > > > > > > > > -
> > > > > > > > > - igt_output_set_pipe(bigjoiner_output, data->pipe1);
> > > > > > > > > -
> > > > > > > > > - mode = &data->output[0].mode;
> > > > > > > > > - igt_output_override_mode(bigjoiner_output, mode);
> > > > > > > > > -
> > > > > > > > > - pipe = &display->pipes[data->pipe1];
> > > > > > > > > - plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > > > > > > -
> > > > > > > > > - igt_plane_set_fb(plane, &data->fb);
> > > > > > > > > - igt_fb_set_size(&data->fb, plane, mode->hdisplay, mode->vdisplay);
> > > > > > > > > - igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
> > > > > > > > > -
> > > > > > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > > > > > -
> > > > > > > > > - igt_output_set_pipe(bigjoiner_output, PIPE_NONE);
> > > > > > > > > - igt_plane_set_fb(plane, NULL);
> > > > > > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > > > > > }
> > > > > > > > > -static void test_dual_display(data_t *data)
> > > > > > > > > +static void tets_big_joiner_on_last_pipe(data_t *data)
> > > > > > > > > {
> > > > > > > > > + int i, ret;
> > > > > > > > > + uint64_t *outputs;
> > > > > > > > > + igt_output_t *output;
> > > > > > > > > + igt_plane_t *primary;
> > > > > > > > > + igt_fb_t fb;
> > > > > > > > > drmModeModeInfo *mode;
> > > > > > > > > - igt_output_t *output, *bigjoiner_output[2];
> > > > > > > > > - igt_display_t *display = &data->display;
> > > > > > > > > - igt_pipe_t *pipe;
> > > > > > > > > - igt_plane_t *plane1, *plane2;
> > > > > > > > > - int count = 0;
> > > > > > > > > -
> > > > > > > > > - igt_display_reset(display);
> > > > > > > > > -
> > > > > > > > > - for_each_connected_output(display, output) {
> > > > > > > > > - if (data->output[count].output_id == output->id) {
> > > > > > > > > - bigjoiner_output[count] = output;
> > > > > > > > > - count++;
> > > > > > > > > - }
> > > > > > > > > - if (count > 1)
> > > > > > > > > - break;
> > > > > > > > > + outputs = data->big_joiner_outputs;
> > > > > > > > > + for (i = 0; i < data->big_joiner_output_count; i++) {
> > > > > > > > > + igt_display_reset(&data->display);
> > > > > > > > > + output = get_output_by_id_or_assert(data, outputs[i]);
> > > > > > > > > + igt_output_set_pipe(output, data->pipe_seq[data->n_pipes - 1]);
> > > > > > > > > + mode = igt_output_get_mode(output);
> > > > > > > > > + igt_info("Assigning pipe %s to %s with mode %dx%d@%d\n",
> > > > > > > > > + kmstest_pipe_name(data->pipe_seq[data->n_pipes - 1]),
> > > > > > > > > + igt_output_name(output), mode->hdisplay,
> > > > > > > > > + mode->vdisplay, mode->vrefresh);
> > > > > > > > > + primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> > > > > > > > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > > > > > > > + DRM_FORMAT_MOD_LINEAR, &fb);
> > > > > > > > > + igt_plane_set_fb(primary, &fb);
> > > > > > > > > + ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
> > > > > > > > > + igt_assert_f(ret != 0, "Commit shouldn't have passed\n");
> > > > > > > > > }
> > > > > > > > > +}
> > > > > > > > > - igt_output_set_pipe(bigjoiner_output[0], data->pipe1);
> > > > > > > > > - igt_output_set_pipe(bigjoiner_output[1], data->pipe2);
> > > > > > > > > -
> > > > > > > > > - /* Set up first big joiner output on Pipe A*/
> > > > > > > > > - mode = &data->output[0].mode;
> > > > > > > > > - igt_output_override_mode(bigjoiner_output[0], mode);
> > > > > > > > > -
> > > > > > > > > - pipe = &display->pipes[data->pipe1];
> > > > > > > > > - plane1 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > > > > > > -
> > > > > > > > > - igt_plane_set_fb(plane1, &data->fb);
> > > > > > > > > - igt_fb_set_size(&data->fb, plane1, mode->hdisplay, mode->vdisplay);
> > > > > > > > > - igt_plane_set_size(plane1, mode->hdisplay, mode->vdisplay);
> > > > > > > > > -
> > > > > > > > > - /* Set up second big joiner output on Pipe C*/
> > > > > > > > > - mode = &data->output[1].mode;
> > > > > > > > > - igt_output_override_mode(bigjoiner_output[1], mode);
> > > > > > > > > -
> > > > > > > > > - pipe = &display->pipes[data->pipe2];
> > > > > > > > > - plane2 = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
> > > > > > > > > -
> > > > > > > > > - igt_plane_set_fb(plane2, &data->fb);
> > > > > > > > > - igt_fb_set_size(&data->fb, plane2, mode->hdisplay, mode->vdisplay);
> > > > > > > > > - igt_plane_set_size(plane2, mode->hdisplay, mode->vdisplay);
> > > > > > > > > -
> > > > > > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > > > > > +static void test_basic_modeset(data_t *data, int num_outputs,
> > > > > > > > > + Combination combinations[MAX_COMBINATIONS],
> > > > > > > > > + uint64_t num_combinations)
> > > > > > > > > +{
> > > > > > > > > + int i, j, ret;
> > > > > > > > > + igt_display_t *display = &data->display;
> > > > > > > > > + igt_output_t *output[num_outputs];
> > > > > > > > > + igt_plane_t *primary[num_outputs];
> > > > > > > > > + igt_fb_t fb[num_outputs];
> > > > > > > > > + drmModeModeInfo *mode;
> > > > > > > > > - /* Clean up */
> > > > > > > > > - igt_output_set_pipe(bigjoiner_output[0], PIPE_NONE);
> > > > > > > > > - igt_output_set_pipe(bigjoiner_output[1], PIPE_NONE);
> > > > > > > > > - igt_plane_set_fb(plane1, NULL);
> > > > > > > > > - igt_plane_set_fb(plane2, NULL);
> > > > > > > > > - igt_display_commit2(display, COMMIT_ATOMIC);
> > > > > > > > > + for (i = 0; i < num_combinations; i++) {
> > > > > > > > > + igt_display_reset(display);
> > > > > > > > > + for (j = 0; j < num_outputs; j++) {
> > > > > > > > > + output[j] = get_output_by_id_or_assert(data,
> > > > > > > > > + data->big_joiner_outputs[j]);
> > > > > > > > > + igt_info("Assigning pipe %s to %s%s",
> > > > > > > > > + kmstest_pipe_name(data->pipe_seq[combinations[i].combination[j]]),
> > > > > > > > > + output[j]->name, j == num_outputs - 1 ? "\n" : ", ");
> > > > > > > > > + igt_output_set_pipe(output[j], data->pipe_seq[combinations[i].combination[j]]);
> > > > > > > > > + primary[j] = igt_output_get_plane_type(output[j], DRM_PLANE_TYPE_PRIMARY);
> > > > > > > > > + mode = igt_output_get_mode(output[j]);
> > > > > > > > > + igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888,
> > > > > > > > > + DRM_FORMAT_MOD_LINEAR, &fb[j]);
> > > > > > > > > + igt_plane_set_fb(primary[j], &fb[j]);
> > > > > > > > > + }
> > > > > > > > > + ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
> > > > > > > > > + igt_assert_f(ret == 0, "Commit failed\n");
> > > > > > > > > + }
> > > > > > > > > }
> > > > > > > > > igt_main
> > > > > > > > > {
> > > > > > > > > + int i, j;
> > > > > > > > > data_t data;
> > > > > > > > > igt_output_t *output;
> > > > > > > > > - drmModeModeInfo mode;
> > > > > > > > > - int valid_output = 0, i, count = 0, j = 0;
> > > > > > > > > - uint16_t width = 0, height = 0;
> > > > > > > > > - enum pipe pipe_seq[IGT_MAX_PIPES];
> > > > > > > > > + drmModeModeInfo default_mode;
> > > > > > > > > + i = j = 0;
> > > > > > > > > igt_fixture {
> > > > > > > > > data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
> > > > > > > > > kmstest_set_vt_graphics_mode();
> > > > > > > > > -
> > > > > > > > > igt_display_require(&data.display, data.drm_fd);
> > > > > > > > > igt_require(data.display.is_atomic);
> > > > > > > > > -
> > > > > > > > > max_dotclock = igt_get_max_dotclock(data.drm_fd);
> > > > > > > > > + data.big_joiner_output_count = 0;
> > > > > > > > > + data.non_big_joiner_output_count = 0;
> > > > > > > > > + data.combined_output_count = 0;
> > > > > > > > > + data.output_count = 0;
> > > > > > > > > for_each_connected_output(&data.display, output) {
> > > > > > > > > bool found = false;
> > > > > > > > > drmModeConnector *connector = output->config.connector;
> > > > > > > > > -
> > > > > > > > > - /*
> > > > > > > > > - * Bigjoiner will come in to the picture when the
> > > > > > > > > - * resolution > 5K or clock > max-dot-clock.
> > > > > > > > > - */
> > > > > > > > > found = bigjoiner_mode_found(data.drm_fd, connector, max_dotclock);
> > > > > > > > > -
> > > > > > > > > if (found) {
> > > > > > > > > - data.output[count].output_id = output->id;
> > > > > > > > > - memcpy(&data.output[count].mode, &mode, sizeof(drmModeModeInfo));
> > > > > > > > > - count++;
> > > > > > > > > -
> > > > > > > > > - width = max(width, mode.hdisplay);
> > > > > > > > > - height = max(height, mode.vdisplay);
> > > > > > > > > + data.big_joiner_outputs[data.big_joiner_output_count++] = output->id;
> > > > > > > > > + igt_output_override_mode(output, &connector->modes[0]);
> > > > > > > > > + } else {
> > > > > > > > > + data.non_big_joiner_outputs[data.non_big_joiner_output_count++] = output->id;
> > > > > > > > > + kmstest_get_connector_default_mode(data.drm_fd, connector, &default_mode);
> > > > > > > > > + igt_output_override_mode(output, &default_mode);
> > > > > > > > > }
> > > > > > > > > - valid_output++;
> > > > > > > > > + data.output_count++;
> > > > > > > > > + }
> > > > > > > > > +
> > > > > > > > > + if (data.big_joiner_output_count == 1 && data.non_big_joiner_output_count > 0) {
> > > > > > > > > + data.combined_outputs[data.combined_output_count++] = data.big_joiner_outputs[0];
> > > > > > > > > + data.combined_outputs[data.combined_output_count++] = data.non_big_joiner_outputs[0];
> > > > > > > > > }
> > > > > > > > > data.n_pipes = 0;
> > > > > > > > > for_each_pipe(&data.display, i) {
> > > > > > > > > data.n_pipes++;
> > > > > > > > > - pipe_seq[j] = i;
> > > > > > > > > + data.pipe_seq[j] = i;
> > > > > > > > > j++;
> > > > > > > > > }
> > > > > > > > > -
> > > > > > > > > - igt_require_f(count > 0, "No output with 5k+ mode (or) clock > max-dot-clock found\n");
> > > > > > > > > -
> > > > > > > > > - igt_create_pattern_fb(data.drm_fd, width, height, DRM_FORMAT_XRGB8888,
> > > > > > > > > - DRM_FORMAT_MOD_LINEAR, &data.fb);
> > > > > > > > > }
> > > > > > > > > igt_describe("Verify the basic modeset on big joiner mode on all pipes");
> > > > > > > > > igt_subtest_with_dynamic("basic") {
> > > > > > > > > - for (i = 0; i < data.n_pipes - 1; i++) {
> > > > > > > > > - data.pipe1 = pipe_seq[i];
> > > > > > > > > - igt_dynamic_f("pipe-%s", kmstest_pipe_name(pipe_seq[i]))
> > > > > > > > > - test_basic_modeset(&data);
> > > > > > > > > + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
> > > > > > > > > + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
> > > > > > > > > +
> > > > > > > > > + for (i = 0; i < data.big_joiner_output_count; i++) {
> > > > > > > > > + uint64_t num_combinations = 0;
> > > > > > > > > + Combination combinations[MAX_COMBINATIONS];
> > > > > > > > > +
> > > > > > > > > + generate_combinations(i+1, data.n_pipes, BIG_JOINER, combinations, &num_combinations);
> > > > > > > > > + igt_info("Number of combinations for %d outputs and %d pipes are %ld\n",
> > > > > > > > > + i+1, data.n_pipes, num_combinations);
> > > > > > > > > +
> > > > > > > > > + if (num_combinations > 0)
> > > > > > > > > + igt_dynamic_f("%dx-big-joiner", i+1)
> > > > > > > > > + test_basic_modeset(&data, i+1, combinations, num_combinations);
> > > > > > > > > + else
> > > > > > > > > + break;
> > > > > > > > > }
> > > > > > > > > }
> > > > > > > > > - igt_describe("Verify if the modeset on the adjoining pipe is rejected "
> > > > > > > > > - "when the pipe is active with a big joiner modeset");
> > > > > > > > > igt_subtest_with_dynamic("invalid-modeset") {
> > > > > > > > > - data.pipe1 = pipe_seq[j - 1];
> > > > > > > > > -
> > > > > > > > > - igt_display_reset(&data.display);
> > > > > > > > > - for_each_connected_output(&data.display, output) {
> > > > > > > > > - if (data.output[0].output_id != output->id)
> > > > > > > > > - continue;
> > > > > > > > > -
> > > > > > > > > - mode = data.output[0].mode;
> > > > > > > > > - igt_output_set_pipe(output, data.pipe1);
> > > > > > > > > - igt_output_override_mode(output, &mode);
> > > > > > > > > + igt_require_f(data.big_joiner_output_count > 0, "Big joiner output not found\n");
> > > > > > > > > + igt_require_f(data.n_pipes > 1, "Minimum of 2 pipes are required\n");
> > > > > > > > > - igt_dynamic_f("pipe-%s-%s",
> > > > > > > > > - kmstest_pipe_name(data.pipe1),
> > > > > > > > > - igt_output_name(output))
> > > > > > > > > - test_invalid_modeset(&data);
> > > > > > > > > - }
> > > > > > > > > + if (data.big_joiner_output_count >= 1)
> > > > > > > > > + igt_dynamic_f("big_joiner_on_last_pipe")
> > > > > > > > > + tets_big_joiner_on_last_pipe(&data);
> > > > > > > > > - if(valid_output > 1) {
> > > > > > > > > - for (i = 0; i < data.n_pipes - 1; i++) {
> > > > > > > > > - igt_output_t *first_output = NULL, *second_output = NULL;
> > > > > > > > > -
> > > > > > > > > - data.pipe1 = pipe_seq[i];
> > > > > > > > > - data.pipe2 = pipe_seq[i + 1];
> > > > > > > > > -
> > > > > > > > > - igt_display_reset(&data.display);
> > > > > > > > > - for_each_connected_output(&data.display, output) {
> > > > > > > > > - if (data.output[0].output_id == output->id) {
> > > > > > > > > - first_output = output;
> > > > > > > > > - mode = data.output[0].mode;
> > > > > > > > > -
> > > > > > > > > - igt_output_set_pipe(output, data.pipe1);
> > > > > > > > > - igt_output_override_mode(output, &mode);
> > > > > > > > > - } else if (second_output == NULL) {
> > > > > > > > > - second_output = output;
> > > > > > > > > - igt_output_set_pipe(output, data.pipe2);
> > > > > > > > > -
> > > > > > > > > - break;
> > > > > > > > > - }
> > > > > > > > > - }
> > > > > > > > > -
> > > > > > > > > - igt_dynamic_f("pipe-%s-%s-pipe-%s-%s",
> > > > > > > > > - kmstest_pipe_name(data.pipe1),
> > > > > > > > > - igt_output_name(first_output),
> > > > > > > > > - kmstest_pipe_name(data.pipe2),
> > > > > > > > > - igt_output_name(second_output))
> > > > > > > > > - test_invalid_modeset(&data);
> > > > > > > > > - }
> > > > > > > > > - }
> > > > > > > > > - }
> > > > > > > > > + if (data.big_joiner_output_count > 1)
> > > > > > > > > + igt_dynamic_f("invalid_combinations_with_two_bigjoiner")
> > > > > > > > > + test_invalid_modeset_two_joiner(&data, false);
> > > > > > > > > - igt_describe("Verify simultaneous modeset on 2 big joiner outputs");
> > > > > > > > > - igt_subtest_with_dynamic("2x-modeset") {
> > > > > > > > > - igt_require_f(count > 1, "2 outputs with big joiner modes are required\n");
> > > > > > > > > - igt_require_f(data.n_pipes > 3, "Minumum of 4 pipes are required\n");
> > > > > > > > > - for (i = 0; (i + 2) < data.n_pipes - 1; i++) {
> > > > > > > > > - data.pipe1 = pipe_seq[i];
> > > > > > > > > - data.pipe2 = pipe_seq[i + 2];
> > > > > > > > > - igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe_seq[i]), kmstest_pipe_name(pipe_seq[i + 2]))
> > > > > > > > > - test_dual_display(&data);
> > > > > > > > > + if (data.combined_output_count) {
> > > > > > > > > + igt_dynamic_f("invalid_combinations_with_bigjoiner_non_bigjoiner")
> > > > > > > > > + test_invalid_modeset_two_joiner(&data, true);
> > > > > > > > > }
> > > > > > > > > }
> > > > > > > > > igt_fixture {
> > > > > > > > > - igt_remove_fb(data.drm_fd, &data.fb);
> > > > > > > > > igt_display_fini(&data.display);
> > > > > > > > > drm_close_driver(data.drm_fd);
> > > > > > > > > }
> > > > > > > > > --
> > > > > > > > > 2.25.1
> > > > > > > Thanks and Regards
> > > > > > > Kunal Joshi
> > > > > Thanks and Regards
> > > > > Kunal Joshi
> Thanks and Regards
> Kunal Joshi
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2024-03-06 13:41 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-03-06 5:25 [PATCH i-g-t 0/2] revamp big joiner test Kunal Joshi
2024-03-06 5:25 ` [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi
2024-03-06 5:25 ` [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner Kunal Joshi
2024-03-06 9:53 ` Lisovskiy, Stanislav
2024-03-06 10:11 ` Joshi, Kunal1
2024-03-06 10:33 ` Lisovskiy, Stanislav
2024-03-06 10:41 ` Joshi, Kunal1
2024-03-06 11:10 ` Lisovskiy, Stanislav
2024-03-06 11:28 ` Joshi, Kunal1
2024-03-06 12:52 ` Lisovskiy, Stanislav
2024-03-06 13:15 ` Joshi, Kunal1
2024-03-06 13:41 ` Lisovskiy, Stanislav
2024-03-06 10:42 ` Lisovskiy, Stanislav
2024-03-06 11:07 ` Modem, Bhanuprakash
2024-03-06 6:27 ` ✓ CI.xeBAT: success for revamp big joiner test (rev6) Patchwork
2024-03-06 6:28 ` ✗ Fi.CI.BAT: failure " Patchwork
-- strict thread matches above, loose matches on Subject: below --
2024-03-05 16:36 [PATCH i-g-t 0/2] revamp big joiner test Kunal Joshi
2024-03-05 16:36 ` [PATCH i-g-t 2/2] tests/intel/kms_big_joiner: revamp kms_big_joiner Kunal Joshi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox