* [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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ 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; 21+ 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] 21+ messages in thread
* [PATCH i-g-t 0/2] revamp big joiner test @ 2024-03-05 16:36 Kunal Joshi 2024-03-05 16:36 ` [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi 0 siblings, 1 reply; 21+ messages in thread From: Kunal Joshi @ 2024-03-05 16:36 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 | 402 ++++++++++++++++------------------- 3 files changed, 213 insertions(+), 216 deletions(-) -- 2.25.1 ^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib 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; 21+ 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 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] 21+ messages in thread
* [PATCH i-g-t 0/2] add support for choosing big joiner mode @ 2024-01-18 10:46 Kunal Joshi 2024-01-18 10:46 ` [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi 0 siblings, 1 reply; 21+ messages in thread From: Kunal Joshi @ 2024-01-18 10:46 UTC (permalink / raw) To: igt-dev; +Cc: Kunal Joshi add support to choose big joiner mode with environment variable, use default mode if no mode with big joiner found. Kunal Joshi (2): lib/igt_kms: move bigjoiner_mode_found to lib. lib/igt_kms: add support for choosing big joiner mode lib/igt_kms.c | 38 +++++++++++++++++++++++++++++++++--- lib/igt_kms.h | 2 ++ tests/intel/kms_big_joiner.c | 14 +------------ 3 files changed, 38 insertions(+), 16 deletions(-) -- 2.25.1 ^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib. 2024-01-18 10:46 [PATCH i-g-t 0/2] add support for choosing big joiner mode Kunal Joshi @ 2024-01-18 10:46 ` Kunal Joshi 0 siblings, 0 replies; 21+ messages in thread From: Kunal Joshi @ 2024-01-18 10:46 UTC (permalink / raw) To: igt-dev; +Cc: Kunal Joshi move bigjoiner_mode_found to lib/igt_kms with some modification v2: combine both big joiner checks (Bhanu) Cc: Swati Sharma <swati2.sharma@intel.com> 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 | 22 ++++++++++++++++++++++ lib/igt_kms.h | 2 ++ tests/intel/kms_big_joiner.c | 14 +------------- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/igt_kms.c b/lib/igt_kms.c index 1b4d0d761..7a07e62f8 100644 --- a/lib/igt_kms.c +++ b/lib/igt_kms.c @@ -6142,6 +6142,28 @@ 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 + * + * 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..488637d4b 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] 21+ messages in thread
* [PATCH i-g-t 0/2] add support for choosing big joiner mode @ 2024-01-15 10:58 Kunal Joshi 2024-01-15 10:58 ` [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi 0 siblings, 1 reply; 21+ messages in thread From: Kunal Joshi @ 2024-01-15 10:58 UTC (permalink / raw) To: igt-dev; +Cc: Kunal Joshi add support to choose big joiner mode with environment variable, use mode with highest clock if no mode with big joiner found. Kunal Joshi (2): lib/igt_kms: move bigjoiner_mode_found to lib. lib/igt_kms: add support for choosing big joiner mode lib/igt_kms.c | 42 +++++++++++++++++++++++++++++++----- lib/igt_kms.h | 3 +++ tests/intel/kms_big_joiner.c | 14 ++---------- 3 files changed, 42 insertions(+), 17 deletions(-) -- 2.25.1 ^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib. 2024-01-15 10:58 [PATCH i-g-t 0/2] add support for choosing big joiner mode Kunal Joshi @ 2024-01-15 10:58 ` Kunal Joshi 0 siblings, 0 replies; 21+ messages in thread From: Kunal Joshi @ 2024-01-15 10:58 UTC (permalink / raw) To: igt-dev; +Cc: Kunal Joshi move bigjoiner_mode_found to lib/igt_kms with some modification 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 | 18 ++++++++++++++++++ lib/igt_kms.h | 3 +++ tests/intel/kms_big_joiner.c | 14 ++------------ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/lib/igt_kms.c b/lib/igt_kms.c index e4dea1a60..cb6d57c2d 100644 --- a/lib/igt_kms.c +++ b/lib/igt_kms.c @@ -6142,6 +6142,24 @@ 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 + * + * Returns: True if big joiner found in connector modes + */ +bool bigjoiner_mode_found(int drm_fd, drmModeConnector *connector, + int (*sort_method)(const void *, const void*), + drmModeModeInfo *mode, int max_dotclock) +{ + igt_sort_connector_modes(connector, sort_method); + *mode = connector->modes[0]; + + return igt_bigjoiner_possible(mode, max_dotclock); +} + /** * 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..d4464c51a 100644 --- a/lib/igt_kms.h +++ b/lib/igt_kms.h @@ -1212,6 +1212,9 @@ 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 (*sort_method)(const void *, const void*), + drmModeModeInfo *mode, 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..80344d411 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,8 +225,8 @@ 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)) ? + found = (bigjoiner_mode_found(data.drm_fd, connector, sort_drm_modes_by_res_dsc, &mode, max_dotclock) || + bigjoiner_mode_found(data.drm_fd, connector, sort_drm_modes_by_clk_dsc, &mode, max_dotclock)) ? true : false; if (found) { -- 2.25.1 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH i-g-t 0/2] add support for choosing big joiner mode @ 2024-01-12 8:55 Kunal Joshi 2024-01-12 8:55 ` [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi 0 siblings, 1 reply; 21+ messages in thread From: Kunal Joshi @ 2024-01-12 8:55 UTC (permalink / raw) To: igt-dev; +Cc: Kunal Joshi add support to choose big joiner mode with environment variable, use mode with highest clock if no mode with big joiner found. Kunal Joshi (2): lib/igt_kms: move bigjoiner_mode_found to lib. lib/igt_kms: add support for choosing big joiner mode lib/igt_kms.c | 25 ++++++++++++++++++++++++- lib/igt_kms.h | 3 +++ tests/intel/kms_big_joiner.c | 14 ++------------ 3 files changed, 29 insertions(+), 13 deletions(-) -- 2.25.1 ^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib. 2024-01-12 8:55 [PATCH i-g-t 0/2] add support for choosing big joiner mode Kunal Joshi @ 2024-01-12 8:55 ` Kunal Joshi 2024-01-18 9:28 ` Modem, Bhanuprakash 0 siblings, 1 reply; 21+ messages in thread From: Kunal Joshi @ 2024-01-12 8:55 UTC (permalink / raw) To: igt-dev; +Cc: Kunal Joshi move bigjoiner_mode_found to lib/igt_kms with some modification 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 | 19 +++++++++++++++++++ lib/igt_kms.h | 3 +++ tests/intel/kms_big_joiner.c | 14 ++------------ 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/lib/igt_kms.c b/lib/igt_kms.c index e4dea1a60..2c55af05f 100644 --- a/lib/igt_kms.c +++ b/lib/igt_kms.c @@ -6142,6 +6142,25 @@ 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 + * + * Returns: True if big joiner found in connector modes + */ +bool bigjoiner_mode_found(int drm_fd, 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, + igt_get_max_dotclock(drm_fd)); +} + /** * 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..9f5676d35 100644 --- a/lib/igt_kms.h +++ b/lib/igt_kms.h @@ -1212,6 +1212,9 @@ 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 (*sort_method)(const void *, const void*), + drmModeModeInfo *mode); 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..1858c6362 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,8 +225,8 @@ 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)) ? + found = (bigjoiner_mode_found(data.drm_fd, connector, sort_drm_modes_by_res_dsc, &mode) || + bigjoiner_mode_found(data.drm_fd, connector, sort_drm_modes_by_clk_dsc, &mode)) ? true : false; if (found) { -- 2.25.1 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib. 2024-01-12 8:55 ` [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi @ 2024-01-18 9:28 ` Modem, Bhanuprakash 0 siblings, 0 replies; 21+ messages in thread From: Modem, Bhanuprakash @ 2024-01-18 9:28 UTC (permalink / raw) To: Kunal Joshi, igt-dev Hi Kunal, On 12-01-2024 02:25 pm, Kunal Joshi wrote: > move bigjoiner_mode_found to lib/igt_kms with some modification > > 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 | 19 +++++++++++++++++++ > lib/igt_kms.h | 3 +++ > tests/intel/kms_big_joiner.c | 14 ++------------ > 3 files changed, 24 insertions(+), 12 deletions(-) > > diff --git a/lib/igt_kms.c b/lib/igt_kms.c > index e4dea1a60..2c55af05f 100644 > --- a/lib/igt_kms.c > +++ b/lib/igt_kms.c > @@ -6142,6 +6142,25 @@ 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 > + * > + * Returns: True if big joiner found in connector modes > + */ > +bool bigjoiner_mode_found(int drm_fd, drmModeConnector *connector, > + int (*sort_method)(const void *, const void*), > + drmModeModeInfo *mode) > +{ > + igt_sort_connector_modes(connector, sort_method); > + *mode = connector->modes[0]; IMHO, Instead of calling this helper multiple times with different sort methods, let's consolidate here only. Example below: bool bigjoiner_mode_found(int drm_fd, drmModeConnector *connector, int max_dotclock) { igt_sort_connector_modes(connector, sort_drm_modes_by_res_dsc); if (igt_bigjoiner_possible(&connector->modes[0], max_dotclock)) return true; igt_sort_connector_modes(connector, sort_drm_modes_by_clk_dsc); return igt_bigjoiner_possible(&connector->modes[0], max_dotclock); } > + > + return igt_bigjoiner_possible(mode, > + igt_get_max_dotclock(drm_fd)); > +} > + > /** > * 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..9f5676d35 100644 > --- a/lib/igt_kms.h > +++ b/lib/igt_kms.h > @@ -1212,6 +1212,9 @@ 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 (*sort_method)(const void *, const void*), > + drmModeModeInfo *mode); > 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..1858c6362 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,8 +225,8 @@ 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)) ? > + found = (bigjoiner_mode_found(data.drm_fd, connector, sort_drm_modes_by_res_dsc, &mode) || > + bigjoiner_mode_found(data.drm_fd, connector, sort_drm_modes_by_clk_dsc, &mode)) ? > true : false; > > if (found) { ^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2024-03-06 13:41 UTC | newest] Thread overview: 21+ 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 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi 2024-01-18 10:46 [PATCH i-g-t 0/2] add support for choosing big joiner mode Kunal Joshi 2024-01-18 10:46 ` [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi 2024-01-15 10:58 [PATCH i-g-t 0/2] add support for choosing big joiner mode Kunal Joshi 2024-01-15 10:58 ` [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi 2024-01-12 8:55 [PATCH i-g-t 0/2] add support for choosing big joiner mode Kunal Joshi 2024-01-12 8:55 ` [PATCH i-g-t 1/2] lib/igt_kms: move bigjoiner_mode_found to lib Kunal Joshi 2024-01-18 9:28 ` Modem, Bhanuprakash
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox