From a51807fc1ee246bb0ffcc5c8dedea000b1616587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Fri, 8 May 2020 23:05:35 +0200 Subject: [PATCH] tests: Move monitor test functions into common utils It's very useful to have common functions for easily creating a monitor test setup for all kinds of tests, so move create_monitor_test_setup() and check_monitor_configuration() and all the structs those are using to monitor-test-utils. https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1243 --- src/tests/monitor-test-utils.c | 601 ++++++++++++++++++++++++++ src/tests/monitor-test-utils.h | 174 ++++++++ src/tests/monitor-unit-tests.c | 762 --------------------------------- 3 files changed, 775 insertions(+), 762 deletions(-) diff --git a/src/tests/monitor-test-utils.c b/src/tests/monitor-test-utils.c index 548815691..6de2682bb 100644 --- a/src/tests/monitor-test-utils.c +++ b/src/tests/monitor-test-utils.c @@ -22,8 +22,12 @@ #include "tests/monitor-test-utils.h" #include "backends/meta-backend-private.h" +#include "backends/meta-crtc.h" +#include "backends/meta-logical-monitor.h" #include "backends/meta-monitor-config-manager.h" #include "backends/meta-monitor-config-store.h" +#include "backends/meta-output.h" +#include "meta-backend-test.h" void set_custom_monitor_config (const char *filename) @@ -79,3 +83,600 @@ read_file (const char *file_path) return g_steal_pointer (&buffer); } + +static MetaOutput * +output_from_winsys_id (MetaBackend *backend, + uint64_t winsys_id) +{ + MetaGpu *gpu = meta_backend_test_get_gpu (META_BACKEND_TEST (backend)); + GList *l; + + for (l = meta_gpu_get_outputs (gpu); l; l = l->next) + { + MetaOutput *output = l->data; + + if (output->winsys_id == winsys_id) + return output; + } + + return NULL; +} + +typedef struct _CheckMonitorModeData +{ + MetaBackend *backend; + MetaTestCaseMonitorCrtcMode *expect_crtc_mode_iter; +} CheckMonitorModeData; + +static gboolean +check_monitor_mode (MetaMonitor *monitor, + MetaMonitorMode *mode, + MetaMonitorCrtcMode *monitor_crtc_mode, + gpointer user_data, + GError **error) +{ + CheckMonitorModeData *data = user_data; + MetaBackend *backend = data->backend; + MetaOutput *output; + MetaCrtcMode *crtc_mode; + int expect_crtc_mode_index; + + output = output_from_winsys_id (backend, + data->expect_crtc_mode_iter->output); + g_assert (monitor_crtc_mode->output == output); + + expect_crtc_mode_index = data->expect_crtc_mode_iter->crtc_mode; + if (expect_crtc_mode_index == -1) + { + crtc_mode = NULL; + } + else + { + MetaGpu *gpu = meta_output_get_gpu (output); + + crtc_mode = g_list_nth_data (meta_gpu_get_modes (gpu), + expect_crtc_mode_index); + } + g_assert (monitor_crtc_mode->crtc_mode == crtc_mode); + + if (crtc_mode) + { + float refresh_rate; + MetaCrtcModeFlag flags; + + refresh_rate = meta_monitor_mode_get_refresh_rate (mode); + flags = meta_monitor_mode_get_flags (mode); + + g_assert_cmpfloat (refresh_rate, ==, crtc_mode->refresh_rate); + g_assert_cmpint (flags, ==, (crtc_mode->flags & HANDLED_CRTC_MODE_FLAGS)); + } + + data->expect_crtc_mode_iter++; + + return TRUE; +} + +static gboolean +check_current_monitor_mode (MetaMonitor *monitor, + MetaMonitorMode *mode, + MetaMonitorCrtcMode *monitor_crtc_mode, + gpointer user_data, + GError **error) +{ + CheckMonitorModeData *data = user_data; + MetaBackend *backend = data->backend; + MetaOutput *output; + MetaCrtc *crtc; + + output = output_from_winsys_id (backend, + data->expect_crtc_mode_iter->output); + crtc = meta_output_get_assigned_crtc (output); + + if (data->expect_crtc_mode_iter->crtc_mode == -1) + { + g_assert_null (crtc); + } + else + { + MetaCrtcConfig *crtc_config; + MetaLogicalMonitor *logical_monitor; + + g_assert_nonnull (crtc); + + crtc_config = crtc->config; + g_assert_nonnull (crtc_config); + + g_assert (monitor_crtc_mode->crtc_mode == crtc_config->mode); + + logical_monitor = meta_monitor_get_logical_monitor (monitor); + g_assert_nonnull (logical_monitor); + } + + + data->expect_crtc_mode_iter++; + + return TRUE; +} + +static MetaLogicalMonitor * +logical_monitor_from_layout (MetaMonitorManager *monitor_manager, + MetaRectangle *layout) +{ + GList *l; + + for (l = monitor_manager->logical_monitors; l; l = l->next) + { + MetaLogicalMonitor *logical_monitor = l->data; + + if (meta_rectangle_equal (layout, &logical_monitor->rect)) + return logical_monitor; + } + + return NULL; +} + +static void +check_logical_monitor (MetaMonitorManager *monitor_manager, + MonitorTestCaseLogicalMonitor *test_logical_monitor) +{ + MetaLogicalMonitor *logical_monitor; + MetaOutput *primary_output; + GList *monitors; + GList *l; + int i; + + logical_monitor = logical_monitor_from_layout (monitor_manager, + &test_logical_monitor->layout); + g_assert_nonnull (logical_monitor); + + g_assert_cmpint (logical_monitor->rect.x, + ==, + test_logical_monitor->layout.x); + g_assert_cmpint (logical_monitor->rect.y, + ==, + test_logical_monitor->layout.y); + g_assert_cmpint (logical_monitor->rect.width, + ==, + test_logical_monitor->layout.width); + g_assert_cmpint (logical_monitor->rect.height, + ==, + test_logical_monitor->layout.height); + g_assert_cmpfloat (logical_monitor->scale, + ==, + test_logical_monitor->scale); + g_assert_cmpuint (logical_monitor->transform, + ==, + test_logical_monitor->transform); + + if (logical_monitor == monitor_manager->primary_logical_monitor) + g_assert (meta_logical_monitor_is_primary (logical_monitor)); + + primary_output = NULL; + monitors = meta_logical_monitor_get_monitors (logical_monitor); + g_assert_cmpint ((int) g_list_length (monitors), + ==, + test_logical_monitor->n_monitors); + + for (i = 0; i < test_logical_monitor->n_monitors; i++) + { + MetaMonitor *monitor = + g_list_nth (monitor_manager->monitors, + test_logical_monitor->monitors[i])->data; + + g_assert_nonnull (g_list_find (monitors, monitor)); + } + + for (l = monitors; l; l = l->next) + { + MetaMonitor *monitor = l->data; + GList *outputs; + GList *l_output; + + outputs = meta_monitor_get_outputs (monitor); + for (l_output = outputs; l_output; l_output = l_output->next) + { + MetaOutput *output = l_output->data; + MetaCrtc *crtc; + + if (output->is_primary) + { + g_assert_null (primary_output); + primary_output = output; + } + + crtc = meta_output_get_assigned_crtc (output); + g_assert (!crtc || + meta_monitor_get_logical_monitor (monitor) == logical_monitor); + g_assert_cmpint (logical_monitor->is_presentation, + ==, + output->is_presentation); + } + } + + if (logical_monitor == monitor_manager->primary_logical_monitor) + g_assert_nonnull (primary_output); +} + +void +check_monitor_configuration (MonitorTestCaseExpect *expect) +{ + MetaBackend *backend = meta_get_backend (); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaMonitorManagerTest *monitor_manager_test = + META_MONITOR_MANAGER_TEST (monitor_manager); + MetaGpu *gpu = meta_backend_test_get_gpu (META_BACKEND_TEST (backend)); + int tiled_monitor_count; + GList *monitors; + GList *crtcs; + int n_logical_monitors; + GList *l; + int i; + + g_assert_cmpint (monitor_manager->screen_width, + ==, + expect->screen_width); + g_assert_cmpint (monitor_manager->screen_height, + ==, + expect->screen_height); + g_assert_cmpint ((int) g_list_length (meta_gpu_get_outputs (gpu)), + ==, + expect->n_outputs); + g_assert_cmpint ((int) g_list_length (meta_gpu_get_crtcs (gpu)), + ==, + expect->n_crtcs); + + tiled_monitor_count = + meta_monitor_manager_test_get_tiled_monitor_count (monitor_manager_test); + g_assert_cmpint (tiled_monitor_count, + ==, + expect->n_tiled_monitors); + + monitors = meta_monitor_manager_get_monitors (monitor_manager); + g_assert_cmpint ((int) g_list_length (monitors), + ==, + expect->n_monitors); + for (l = monitors, i = 0; l; l = l->next, i++) + { + MetaMonitor *monitor = l->data; + GList *outputs; + GList *l_output; + int j; + int width_mm, height_mm; + GList *modes; + GList *l_mode; + MetaMonitorMode *current_mode; + int expected_current_mode_index; + MetaMonitorMode *expected_current_mode; + + outputs = meta_monitor_get_outputs (monitor); + + g_assert_cmpint ((int) g_list_length (outputs), + ==, + expect->monitors[i].n_outputs); + + for (l_output = outputs, j = 0; l_output; l_output = l_output->next, j++) + { + MetaOutput *output = l_output->data; + uint64_t winsys_id = expect->monitors[i].outputs[j]; + + g_assert (output == output_from_winsys_id (backend, winsys_id)); + g_assert_cmpint (expect->monitors[i].is_underscanning, + ==, + output->is_underscanning); + } + + meta_monitor_get_physical_dimensions (monitor, &width_mm, &height_mm); + g_assert_cmpint (width_mm, + ==, + expect->monitors[i].width_mm); + g_assert_cmpint (height_mm, + ==, + expect->monitors[i].height_mm); + + modes = meta_monitor_get_modes (monitor); + g_assert_cmpint (g_list_length (modes), + ==, + expect->monitors[i].n_modes); + + for (l_mode = modes, j = 0; l_mode; l_mode = l_mode->next, j++) + { + MetaMonitorMode *mode = l_mode->data; + int width; + int height; + float refresh_rate; + MetaCrtcModeFlag flags; + CheckMonitorModeData data; + + meta_monitor_mode_get_resolution (mode, &width, &height); + refresh_rate = meta_monitor_mode_get_refresh_rate (mode); + flags = meta_monitor_mode_get_flags (mode); + + g_assert_cmpint (width, + ==, + expect->monitors[i].modes[j].width); + g_assert_cmpint (height, + ==, + expect->monitors[i].modes[j].height); + g_assert_cmpfloat (refresh_rate, + ==, + expect->monitors[i].modes[j].refresh_rate); + g_assert_cmpint (flags, + ==, + expect->monitors[i].modes[j].flags); + + data = (CheckMonitorModeData) { + .backend = backend, + .expect_crtc_mode_iter = + expect->monitors[i].modes[j].crtc_modes + }; + meta_monitor_mode_foreach_output (monitor, mode, + check_monitor_mode, + &data, + NULL); + } + + current_mode = meta_monitor_get_current_mode (monitor); + expected_current_mode_index = expect->monitors[i].current_mode; + if (expected_current_mode_index == -1) + expected_current_mode = NULL; + else + expected_current_mode = g_list_nth (modes, + expected_current_mode_index)->data; + + g_assert (current_mode == expected_current_mode); + if (current_mode) + g_assert (meta_monitor_is_active (monitor)); + else + g_assert (!meta_monitor_is_active (monitor)); + + if (current_mode) + { + CheckMonitorModeData data; + + data = (CheckMonitorModeData) { + .backend = backend, + .expect_crtc_mode_iter = + expect->monitors[i].modes[expected_current_mode_index].crtc_modes + }; + meta_monitor_mode_foreach_output (monitor, expected_current_mode, + check_current_monitor_mode, + &data, + NULL); + } + + meta_monitor_derive_current_mode (monitor); + g_assert (current_mode == meta_monitor_get_current_mode (monitor)); + } + + n_logical_monitors = + meta_monitor_manager_get_num_logical_monitors (monitor_manager); + g_assert_cmpint (n_logical_monitors, + ==, + expect->n_logical_monitors); + + /* + * Check that we have a primary logical monitor (except for headless), + * and that the main output of the first monitor is the only output + * that is marked as primary (further below). Note: outputs being primary or + * not only matters on X11. + */ + if (expect->primary_logical_monitor == -1) + { + g_assert_null (monitor_manager->primary_logical_monitor); + g_assert_null (monitor_manager->logical_monitors); + } + else + { + MonitorTestCaseLogicalMonitor *test_logical_monitor = + &expect->logical_monitors[expect->primary_logical_monitor]; + MetaLogicalMonitor *logical_monitor; + + logical_monitor = + logical_monitor_from_layout (monitor_manager, + &test_logical_monitor->layout); + g_assert (logical_monitor == monitor_manager->primary_logical_monitor); + } + + for (i = 0; i < expect->n_logical_monitors; i++) + { + MonitorTestCaseLogicalMonitor *test_logical_monitor = + &expect->logical_monitors[i]; + + check_logical_monitor (monitor_manager, test_logical_monitor); + } + g_assert_cmpint (n_logical_monitors, ==, i); + + crtcs = meta_gpu_get_crtcs (gpu); + for (l = crtcs, i = 0; l; l = l->next, i++) + { + MetaCrtc *crtc = l->data; + MetaCrtcConfig *crtc_config = crtc->config; + + if (expect->crtcs[i].current_mode == -1) + { + g_assert_null (crtc_config); + } + else + { + MetaCrtcMode *expected_current_mode; + + g_assert_nonnull (crtc_config); + + expected_current_mode = + g_list_nth_data (meta_gpu_get_modes (gpu), + expect->crtcs[i].current_mode); + g_assert (crtc_config->mode == expected_current_mode); + + g_assert_cmpuint (crtc_config->transform, + ==, + expect->crtcs[i].transform); + + g_assert_cmpfloat_with_epsilon (crtc_config->layout.origin.x, + expect->crtcs[i].x, + FLT_EPSILON); + g_assert_cmpfloat_with_epsilon (crtc_config->layout.origin.y, + expect->crtcs[i].y, + FLT_EPSILON); + } + } +} + +static void +meta_output_test_destroy_notify (MetaOutput *output) +{ + g_clear_pointer (&output->driver_private, g_free); +} + +MetaMonitorTestSetup * +create_monitor_test_setup (MonitorTestCaseSetup *setup, + MonitorTestFlag flags) +{ + MetaMonitorTestSetup *test_setup; + int i; + int n_laptop_panels = 0; + int n_normal_panels = 0; + gboolean hotplug_mode_update; + + if (flags & MONITOR_TEST_FLAG_NO_STORED) + hotplug_mode_update = TRUE; + else + hotplug_mode_update = FALSE; + + test_setup = g_new0 (MetaMonitorTestSetup, 1); + + test_setup->modes = NULL; + for (i = 0; i < setup->n_modes; i++) + { + MetaCrtcMode *mode; + + mode = g_object_new (META_TYPE_CRTC_MODE, NULL); + mode->mode_id = i; + mode->width = setup->modes[i].width; + mode->height = setup->modes[i].height; + mode->refresh_rate = setup->modes[i].refresh_rate; + mode->flags = setup->modes[i].flags; + + test_setup->modes = g_list_append (test_setup->modes, mode); + } + + test_setup->crtcs = NULL; + for (i = 0; i < setup->n_crtcs; i++) + { + MetaCrtc *crtc; + + crtc = g_object_new (META_TYPE_CRTC, NULL); + crtc->crtc_id = i + 1; + crtc->all_transforms = ALL_TRANSFORMS; + + test_setup->crtcs = g_list_append (test_setup->crtcs, crtc); + } + + test_setup->outputs = NULL; + for (i = 0; i < setup->n_outputs; i++) + { + MetaOutput *output; + MetaOutputTest *output_test; + int crtc_index; + MetaCrtc *crtc; + int preferred_mode_index; + MetaCrtcMode *preferred_mode; + MetaCrtcMode **modes; + int n_modes; + int j; + MetaCrtc **possible_crtcs; + int n_possible_crtcs; + int scale; + gboolean is_laptop_panel; + const char *serial; + + crtc_index = setup->outputs[i].crtc; + if (crtc_index == -1) + crtc = NULL; + else + crtc = g_list_nth_data (test_setup->crtcs, crtc_index); + + preferred_mode_index = setup->outputs[i].preferred_mode; + if (preferred_mode_index == -1) + preferred_mode = NULL; + else + preferred_mode = g_list_nth_data (test_setup->modes, + preferred_mode_index); + + n_modes = setup->outputs[i].n_modes; + modes = g_new0 (MetaCrtcMode *, n_modes); + for (j = 0; j < n_modes; j++) + { + int mode_index; + + mode_index = setup->outputs[i].modes[j]; + modes[j] = g_list_nth_data (test_setup->modes, mode_index); + } + + n_possible_crtcs = setup->outputs[i].n_possible_crtcs; + possible_crtcs = g_new0 (MetaCrtc *, n_possible_crtcs); + for (j = 0; j < n_possible_crtcs; j++) + { + int possible_crtc_index; + + possible_crtc_index = setup->outputs[i].possible_crtcs[j]; + possible_crtcs[j] = g_list_nth_data (test_setup->crtcs, + possible_crtc_index); + } + + output_test = g_new0 (MetaOutputTest, 1); + + scale = setup->outputs[i].scale; + if (scale < 1) + scale = 1; + + *output_test = (MetaOutputTest) { + .scale = scale + }; + + is_laptop_panel = setup->outputs[i].is_laptop_panel; + + serial = setup->outputs[i].serial; + if (!serial) + serial = "0x123456"; + + output = g_object_new (META_TYPE_OUTPUT, NULL); + + if (crtc) + meta_output_assign_crtc (output, crtc); + output->winsys_id = i; + output->name = (is_laptop_panel ? g_strdup_printf ("eDP-%d", + ++n_laptop_panels) + : g_strdup_printf ("DP-%d", + ++n_normal_panels)); + output->vendor = g_strdup ("MetaProduct's Inc."); + output->product = g_strdup ("MetaMonitor"); + output->serial = g_strdup (serial); + output->suggested_x = -1; + output->suggested_y = -1; + output->hotplug_mode_update = hotplug_mode_update; + output->width_mm = setup->outputs[i].width_mm; + output->height_mm = setup->outputs[i].height_mm; + output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; + output->preferred_mode = preferred_mode; + output->n_modes = n_modes; + output->modes = modes; + output->n_possible_crtcs = n_possible_crtcs; + output->possible_crtcs = possible_crtcs; + output->n_possible_clones = 0; + output->possible_clones = NULL; + output->backlight = -1; + output->connector_type = (is_laptop_panel ? META_CONNECTOR_TYPE_eDP + : META_CONNECTOR_TYPE_DisplayPort); + output->tile_info = setup->outputs[i].tile_info; + output->is_underscanning = setup->outputs[i].is_underscanning; + output->panel_orientation_transform = + setup->outputs[i].panel_orientation_transform; + output->driver_private = output_test; + output->driver_notify = (GDestroyNotify) meta_output_test_destroy_notify; + + test_setup->outputs = g_list_append (test_setup->outputs, output); + } + + return test_setup; +} diff --git a/src/tests/monitor-test-utils.h b/src/tests/monitor-test-utils.h index 0b0dc6d7d..e99799861 100644 --- a/src/tests/monitor-test-utils.h +++ b/src/tests/monitor-test-utils.h @@ -22,8 +22,182 @@ #include +#include "tests/meta-monitor-manager-test.h" +#include "backends/meta-crtc.h" +#include "backends/meta-output.h" + +#define ALL_TRANSFORMS ((1 << (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)) - 1) + +#define MAX_N_MODES 10 +#define MAX_N_OUTPUTS 10 +#define MAX_N_CRTCS 10 +#define MAX_N_MONITORS 10 +#define MAX_N_LOGICAL_MONITORS 10 + +/* + * The following structures are used to define test cases. + * + * Each test case consists of a test case setup and a test case expectaction. + * and a expected result, consisting + * of an array of monitors, logical monitors and a screen size. + * + * TEST CASE SETUP: + * + * A test case setup consists of an array of modes, an array of outputs and an + * array of CRTCs. + * + * A mode has a width and height in pixels, and a refresh rate in updates per + * second. + * + * An output has an array of available modes, and a preferred mode. Modes are + * defined as indices into the modes array of the test case setup. + * + * It also has CRTc and an array of possible CRTCs. Crtcs are defined as indices + * into the CRTC array. The CRTC value -1 means no CRTC. + * + * It also has various meta data, such as physical dimension, tile info and + * scale. + * + * A CRTC only has a current mode. A mode is defined as an index into the modes + * array. + * + * + * TEST CASE EXPECTS: + * + * A test case expects consists of an array of monitors, an array of logical + * monitors, a output and crtc count, and a screen width. + * + * A monitor represents a physical monitor (such as an external monitor, or a + * laptop panel etc). A monitor consists of an array of outputs, defined by + * indices into the setup output array, an array of monitor modes, and the + * current mode, defined by an index into the monitor modes array, and the + * physical dimensions. + * + * A logical monitor represents a region of the total screen area. It contains + * the expected layout and a scale. + */ + +typedef enum _MonitorTestFlag +{ + MONITOR_TEST_FLAG_NONE, + MONITOR_TEST_FLAG_NO_STORED +} MonitorTestFlag; + +typedef struct _MonitorTestCaseMode +{ + int width; + int height; + float refresh_rate; + MetaCrtcModeFlag flags; +} MonitorTestCaseMode; + +typedef struct _MonitorTestCaseOutput +{ + int crtc; + int modes[MAX_N_MODES]; + int n_modes; + int preferred_mode; + int possible_crtcs[MAX_N_CRTCS]; + int n_possible_crtcs; + int width_mm; + int height_mm; + MetaTileInfo tile_info; + float scale; + gboolean is_laptop_panel; + gboolean is_underscanning; + const char *serial; + MetaMonitorTransform panel_orientation_transform; +} MonitorTestCaseOutput; + +typedef struct _MonitorTestCaseCrtc +{ + int current_mode; +} MonitorTestCaseCrtc; + +typedef struct _MonitorTestCaseSetup +{ + MonitorTestCaseMode modes[MAX_N_MODES]; + int n_modes; + + MonitorTestCaseOutput outputs[MAX_N_OUTPUTS]; + int n_outputs; + + MonitorTestCaseCrtc crtcs[MAX_N_CRTCS]; + int n_crtcs; +} MonitorTestCaseSetup; + +typedef struct _MonitorTestCaseMonitorCrtcMode +{ + uint64_t output; + int crtc_mode; +} MetaTestCaseMonitorCrtcMode; + +typedef struct _MonitorTestCaseMonitorMode +{ + int width; + int height; + float refresh_rate; + MetaCrtcModeFlag flags; + MetaTestCaseMonitorCrtcMode crtc_modes[MAX_N_CRTCS]; +} MetaMonitorTestCaseMonitorMode; + +typedef struct _MonitorTestCaseMonitor +{ + uint64_t outputs[MAX_N_OUTPUTS]; + int n_outputs; + MetaMonitorTestCaseMonitorMode modes[MAX_N_MODES]; + int n_modes; + int current_mode; + int width_mm; + int height_mm; + gboolean is_underscanning; +} MonitorTestCaseMonitor; + +typedef struct _MonitorTestCaseLogicalMonitor +{ + MetaRectangle layout; + float scale; + int monitors[MAX_N_MONITORS]; + int n_monitors; + MetaMonitorTransform transform; +} MonitorTestCaseLogicalMonitor; + +typedef struct _MonitorTestCaseCrtcExpect +{ + MetaMonitorTransform transform; + int current_mode; + float x; + float y; +} MonitorTestCaseCrtcExpect; + +typedef struct _MonitorTestCaseExpect +{ + MonitorTestCaseMonitor monitors[MAX_N_MONITORS]; + int n_monitors; + MonitorTestCaseLogicalMonitor logical_monitors[MAX_N_LOGICAL_MONITORS]; + int n_logical_monitors; + int primary_logical_monitor; + int n_outputs; + MonitorTestCaseCrtcExpect crtcs[MAX_N_CRTCS]; + int n_crtcs; + int n_tiled_monitors; + int screen_width; + int screen_height; +} MonitorTestCaseExpect; + +typedef struct _MonitorTestCase +{ + MonitorTestCaseSetup setup; + MonitorTestCaseExpect expect; +} MonitorTestCase; + void set_custom_monitor_config (const char *filename); char * read_file (const char *file_path); +void check_monitor_configuration (MonitorTestCaseExpect *expect); + +MetaMonitorTestSetup * create_monitor_test_setup (MonitorTestCaseSetup *setup, + MonitorTestFlag flags); + #endif /* MONITOR_TEST_UTILS_H */ diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c index 30f2bba88..975c9970c 100644 --- a/src/tests/monitor-unit-tests.c +++ b/src/tests/monitor-unit-tests.c @@ -35,171 +35,6 @@ #include "tests/test-utils.h" #include "x11/meta-x11-display-private.h" -#define ALL_TRANSFORMS ((1 << (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)) - 1) - -#define MAX_N_MODES 10 -#define MAX_N_OUTPUTS 10 -#define MAX_N_CRTCS 10 -#define MAX_N_MONITORS 10 -#define MAX_N_LOGICAL_MONITORS 10 - -/* - * The following structures are used to define test cases. - * - * Each test case consists of a test case setup and a test case expectaction. - * and a expected result, consisting - * of an array of monitors, logical monitors and a screen size. - * - * TEST CASE SETUP: - * - * A test case setup consists of an array of modes, an array of outputs and an - * array of CRTCs. - * - * A mode has a width and height in pixels, and a refresh rate in updates per - * second. - * - * An output has an array of available modes, and a preferred mode. Modes are - * defined as indices into the modes array of the test case setup. - * - * It also has CRTc and an array of possible CRTCs. Crtcs are defined as indices - * into the CRTC array. The CRTC value -1 means no CRTC. - * - * It also has various meta data, such as physical dimension, tile info and - * scale. - * - * A CRTC only has a current mode. A mode is defined as an index into the modes - * array. - * - * - * TEST CASE EXPECTS: - * - * A test case expects consists of an array of monitors, an array of logical - * monitors, a output and crtc count, and a screen width. - * - * A monitor represents a physical monitor (such as an external monitor, or a - * laptop panel etc). A monitor consists of an array of outputs, defined by - * indices into the setup output array, an array of monitor modes, and the - * current mode, defined by an index into the monitor modes array, and the - * physical dimensions. - * - * A logical monitor represents a region of the total screen area. It contains - * the expected layout and a scale. - */ - -typedef enum _MonitorTestFlag -{ - MONITOR_TEST_FLAG_NONE, - MONITOR_TEST_FLAG_NO_STORED -} MonitorTestFlag; - -typedef struct _MonitorTestCaseMode -{ - int width; - int height; - float refresh_rate; - MetaCrtcModeFlag flags; -} MonitorTestCaseMode; - -typedef struct _MonitorTestCaseOutput -{ - int crtc; - int modes[MAX_N_MODES]; - int n_modes; - int preferred_mode; - int possible_crtcs[MAX_N_CRTCS]; - int n_possible_crtcs; - int width_mm; - int height_mm; - MetaTileInfo tile_info; - float scale; - gboolean is_laptop_panel; - gboolean is_underscanning; - const char *serial; - MetaMonitorTransform panel_orientation_transform; -} MonitorTestCaseOutput; - -typedef struct _MonitorTestCaseCrtc -{ - int current_mode; -} MonitorTestCaseCrtc; - -typedef struct _MonitorTestCaseSetup -{ - MonitorTestCaseMode modes[MAX_N_MODES]; - int n_modes; - - MonitorTestCaseOutput outputs[MAX_N_OUTPUTS]; - int n_outputs; - - MonitorTestCaseCrtc crtcs[MAX_N_CRTCS]; - int n_crtcs; -} MonitorTestCaseSetup; - -typedef struct _MonitorTestCaseMonitorCrtcMode -{ - uint64_t output; - int crtc_mode; -} MetaTestCaseMonitorCrtcMode; - -typedef struct _MonitorTestCaseMonitorMode -{ - int width; - int height; - float refresh_rate; - MetaCrtcModeFlag flags; - MetaTestCaseMonitorCrtcMode crtc_modes[MAX_N_CRTCS]; -} MetaMonitorTestCaseMonitorMode; - -typedef struct _MonitorTestCaseMonitor -{ - uint64_t outputs[MAX_N_OUTPUTS]; - int n_outputs; - MetaMonitorTestCaseMonitorMode modes[MAX_N_MODES]; - int n_modes; - int current_mode; - int width_mm; - int height_mm; - gboolean is_underscanning; -} MonitorTestCaseMonitor; - -typedef struct _MonitorTestCaseLogicalMonitor -{ - MetaRectangle layout; - float scale; - int monitors[MAX_N_MONITORS]; - int n_monitors; - MetaMonitorTransform transform; -} MonitorTestCaseLogicalMonitor; - -typedef struct _MonitorTestCaseCrtcExpect -{ - MetaMonitorTransform transform; - int current_mode; - float x; - float y; -} MonitorTestCaseCrtcExpect; - -typedef struct _MonitorTestCaseExpect -{ - MonitorTestCaseMonitor monitors[MAX_N_MONITORS]; - int n_monitors; - MonitorTestCaseLogicalMonitor logical_monitors[MAX_N_LOGICAL_MONITORS]; - int n_logical_monitors; - int primary_logical_monitor; - int n_outputs; - MonitorTestCaseCrtcExpect crtcs[MAX_N_CRTCS]; - int n_crtcs; - int n_tiled_monitors; - int screen_width; - int screen_height; -} MonitorTestCaseExpect; - -typedef struct _MonitorTestCase -{ - MonitorTestCaseSetup setup; - MonitorTestCaseExpect expect; -} MonitorTestCase; - static MonitorTestCase initial_test_case = { .setup = { .modes = { @@ -418,603 +253,6 @@ destroy_monitor_test_clients (void) NULL, NULL); } -static MetaOutput * -output_from_winsys_id (MetaBackend *backend, - uint64_t winsys_id) -{ - MetaGpu *gpu = meta_backend_test_get_gpu (META_BACKEND_TEST (backend)); - GList *l; - - for (l = meta_gpu_get_outputs (gpu); l; l = l->next) - { - MetaOutput *output = l->data; - - if (output->winsys_id == winsys_id) - return output; - } - - return NULL; -} - -typedef struct _CheckMonitorModeData -{ - MetaBackend *backend; - MetaTestCaseMonitorCrtcMode *expect_crtc_mode_iter; -} CheckMonitorModeData; - -static gboolean -check_monitor_mode (MetaMonitor *monitor, - MetaMonitorMode *mode, - MetaMonitorCrtcMode *monitor_crtc_mode, - gpointer user_data, - GError **error) -{ - CheckMonitorModeData *data = user_data; - MetaBackend *backend = data->backend; - MetaOutput *output; - MetaCrtcMode *crtc_mode; - int expect_crtc_mode_index; - - output = output_from_winsys_id (backend, - data->expect_crtc_mode_iter->output); - g_assert (monitor_crtc_mode->output == output); - - expect_crtc_mode_index = data->expect_crtc_mode_iter->crtc_mode; - if (expect_crtc_mode_index == -1) - { - crtc_mode = NULL; - } - else - { - MetaGpu *gpu = meta_output_get_gpu (output); - - crtc_mode = g_list_nth_data (meta_gpu_get_modes (gpu), - expect_crtc_mode_index); - } - g_assert (monitor_crtc_mode->crtc_mode == crtc_mode); - - if (crtc_mode) - { - float refresh_rate; - MetaCrtcModeFlag flags; - - refresh_rate = meta_monitor_mode_get_refresh_rate (mode); - flags = meta_monitor_mode_get_flags (mode); - - g_assert_cmpfloat (refresh_rate, ==, crtc_mode->refresh_rate); - g_assert_cmpint (flags, ==, (crtc_mode->flags & HANDLED_CRTC_MODE_FLAGS)); - } - - data->expect_crtc_mode_iter++; - - return TRUE; -} - -static gboolean -check_current_monitor_mode (MetaMonitor *monitor, - MetaMonitorMode *mode, - MetaMonitorCrtcMode *monitor_crtc_mode, - gpointer user_data, - GError **error) -{ - CheckMonitorModeData *data = user_data; - MetaBackend *backend = data->backend; - MetaOutput *output; - MetaCrtc *crtc; - - output = output_from_winsys_id (backend, - data->expect_crtc_mode_iter->output); - crtc = meta_output_get_assigned_crtc (output); - - if (data->expect_crtc_mode_iter->crtc_mode == -1) - { - g_assert_null (crtc); - } - else - { - MetaCrtcConfig *crtc_config; - MetaLogicalMonitor *logical_monitor; - - g_assert_nonnull (crtc); - - crtc_config = crtc->config; - g_assert_nonnull (crtc_config); - - g_assert (monitor_crtc_mode->crtc_mode == crtc_config->mode); - - logical_monitor = meta_monitor_get_logical_monitor (monitor); - g_assert_nonnull (logical_monitor); - } - - - data->expect_crtc_mode_iter++; - - return TRUE; -} - -static MetaLogicalMonitor * -logical_monitor_from_layout (MetaMonitorManager *monitor_manager, - MetaRectangle *layout) -{ - GList *l; - - for (l = monitor_manager->logical_monitors; l; l = l->next) - { - MetaLogicalMonitor *logical_monitor = l->data; - - if (meta_rectangle_equal (layout, &logical_monitor->rect)) - return logical_monitor; - } - - return NULL; -} - -static void -check_logical_monitor (MetaMonitorManager *monitor_manager, - MonitorTestCaseLogicalMonitor *test_logical_monitor) -{ - MetaLogicalMonitor *logical_monitor; - MetaOutput *primary_output; - GList *monitors; - GList *l; - int i; - - logical_monitor = logical_monitor_from_layout (monitor_manager, - &test_logical_monitor->layout); - g_assert_nonnull (logical_monitor); - - g_assert_cmpint (logical_monitor->rect.x, - ==, - test_logical_monitor->layout.x); - g_assert_cmpint (logical_monitor->rect.y, - ==, - test_logical_monitor->layout.y); - g_assert_cmpint (logical_monitor->rect.width, - ==, - test_logical_monitor->layout.width); - g_assert_cmpint (logical_monitor->rect.height, - ==, - test_logical_monitor->layout.height); - g_assert_cmpfloat (logical_monitor->scale, - ==, - test_logical_monitor->scale); - g_assert_cmpuint (logical_monitor->transform, - ==, - test_logical_monitor->transform); - - if (logical_monitor == monitor_manager->primary_logical_monitor) - g_assert (meta_logical_monitor_is_primary (logical_monitor)); - - primary_output = NULL; - monitors = meta_logical_monitor_get_monitors (logical_monitor); - g_assert_cmpint ((int) g_list_length (monitors), - ==, - test_logical_monitor->n_monitors); - - for (i = 0; i < test_logical_monitor->n_monitors; i++) - { - MetaMonitor *monitor = - g_list_nth (monitor_manager->monitors, - test_logical_monitor->monitors[i])->data; - - g_assert_nonnull (g_list_find (monitors, monitor)); - } - - for (l = monitors; l; l = l->next) - { - MetaMonitor *monitor = l->data; - GList *outputs; - GList *l_output; - - outputs = meta_monitor_get_outputs (monitor); - for (l_output = outputs; l_output; l_output = l_output->next) - { - MetaOutput *output = l_output->data; - MetaCrtc *crtc; - - if (output->is_primary) - { - g_assert_null (primary_output); - primary_output = output; - } - - crtc = meta_output_get_assigned_crtc (output); - g_assert (!crtc || - meta_monitor_get_logical_monitor (monitor) == logical_monitor); - g_assert_cmpint (logical_monitor->is_presentation, - ==, - output->is_presentation); - } - } - - if (logical_monitor == monitor_manager->primary_logical_monitor) - g_assert_nonnull (primary_output); -} - -static void -check_monitor_configuration (MonitorTestCaseExpect *expect) -{ - MetaBackend *backend = meta_get_backend (); - MetaMonitorManager *monitor_manager = - meta_backend_get_monitor_manager (backend); - MetaMonitorManagerTest *monitor_manager_test = - META_MONITOR_MANAGER_TEST (monitor_manager); - MetaGpu *gpu = meta_backend_test_get_gpu (META_BACKEND_TEST (backend)); - int tiled_monitor_count; - GList *monitors; - GList *crtcs; - int n_logical_monitors; - GList *l; - int i; - - g_assert_cmpint (monitor_manager->screen_width, - ==, - expect->screen_width); - g_assert_cmpint (monitor_manager->screen_height, - ==, - expect->screen_height); - g_assert_cmpint ((int) g_list_length (meta_gpu_get_outputs (gpu)), - ==, - expect->n_outputs); - g_assert_cmpint ((int) g_list_length (meta_gpu_get_crtcs (gpu)), - ==, - expect->n_crtcs); - - tiled_monitor_count = - meta_monitor_manager_test_get_tiled_monitor_count (monitor_manager_test); - g_assert_cmpint (tiled_monitor_count, - ==, - expect->n_tiled_monitors); - - monitors = meta_monitor_manager_get_monitors (monitor_manager); - g_assert_cmpint ((int) g_list_length (monitors), - ==, - expect->n_monitors); - for (l = monitors, i = 0; l; l = l->next, i++) - { - MetaMonitor *monitor = l->data; - GList *outputs; - GList *l_output; - int j; - int width_mm, height_mm; - GList *modes; - GList *l_mode; - MetaMonitorMode *current_mode; - int expected_current_mode_index; - MetaMonitorMode *expected_current_mode; - - outputs = meta_monitor_get_outputs (monitor); - - g_assert_cmpint ((int) g_list_length (outputs), - ==, - expect->monitors[i].n_outputs); - - for (l_output = outputs, j = 0; l_output; l_output = l_output->next, j++) - { - MetaOutput *output = l_output->data; - uint64_t winsys_id = expect->monitors[i].outputs[j]; - - g_assert (output == output_from_winsys_id (backend, winsys_id)); - g_assert_cmpint (expect->monitors[i].is_underscanning, - ==, - output->is_underscanning); - } - - meta_monitor_get_physical_dimensions (monitor, &width_mm, &height_mm); - g_assert_cmpint (width_mm, - ==, - expect->monitors[i].width_mm); - g_assert_cmpint (height_mm, - ==, - expect->monitors[i].height_mm); - - modes = meta_monitor_get_modes (monitor); - g_assert_cmpint (g_list_length (modes), - ==, - expect->monitors[i].n_modes); - - for (l_mode = modes, j = 0; l_mode; l_mode = l_mode->next, j++) - { - MetaMonitorMode *mode = l_mode->data; - int width; - int height; - float refresh_rate; - MetaCrtcModeFlag flags; - CheckMonitorModeData data; - - meta_monitor_mode_get_resolution (mode, &width, &height); - refresh_rate = meta_monitor_mode_get_refresh_rate (mode); - flags = meta_monitor_mode_get_flags (mode); - - g_assert_cmpint (width, - ==, - expect->monitors[i].modes[j].width); - g_assert_cmpint (height, - ==, - expect->monitors[i].modes[j].height); - g_assert_cmpfloat (refresh_rate, - ==, - expect->monitors[i].modes[j].refresh_rate); - g_assert_cmpint (flags, - ==, - expect->monitors[i].modes[j].flags); - - data = (CheckMonitorModeData) { - .backend = backend, - .expect_crtc_mode_iter = - expect->monitors[i].modes[j].crtc_modes - }; - meta_monitor_mode_foreach_output (monitor, mode, - check_monitor_mode, - &data, - NULL); - } - - current_mode = meta_monitor_get_current_mode (monitor); - expected_current_mode_index = expect->monitors[i].current_mode; - if (expected_current_mode_index == -1) - expected_current_mode = NULL; - else - expected_current_mode = g_list_nth (modes, - expected_current_mode_index)->data; - - g_assert (current_mode == expected_current_mode); - if (current_mode) - g_assert (meta_monitor_is_active (monitor)); - else - g_assert (!meta_monitor_is_active (monitor)); - - if (current_mode) - { - CheckMonitorModeData data; - - data = (CheckMonitorModeData) { - .backend = backend, - .expect_crtc_mode_iter = - expect->monitors[i].modes[expected_current_mode_index].crtc_modes - }; - meta_monitor_mode_foreach_output (monitor, expected_current_mode, - check_current_monitor_mode, - &data, - NULL); - } - - meta_monitor_derive_current_mode (monitor); - g_assert (current_mode == meta_monitor_get_current_mode (monitor)); - } - - n_logical_monitors = - meta_monitor_manager_get_num_logical_monitors (monitor_manager); - g_assert_cmpint (n_logical_monitors, - ==, - expect->n_logical_monitors); - - /* - * Check that we have a primary logical monitor (except for headless), - * and that the main output of the first monitor is the only output - * that is marked as primary (further below). Note: outputs being primary or - * not only matters on X11. - */ - if (expect->primary_logical_monitor == -1) - { - g_assert_null (monitor_manager->primary_logical_monitor); - g_assert_null (monitor_manager->logical_monitors); - } - else - { - MonitorTestCaseLogicalMonitor *test_logical_monitor = - &expect->logical_monitors[expect->primary_logical_monitor]; - MetaLogicalMonitor *logical_monitor; - - logical_monitor = - logical_monitor_from_layout (monitor_manager, - &test_logical_monitor->layout); - g_assert (logical_monitor == monitor_manager->primary_logical_monitor); - } - - for (i = 0; i < expect->n_logical_monitors; i++) - { - MonitorTestCaseLogicalMonitor *test_logical_monitor = - &expect->logical_monitors[i]; - - check_logical_monitor (monitor_manager, test_logical_monitor); - } - g_assert_cmpint (n_logical_monitors, ==, i); - - crtcs = meta_gpu_get_crtcs (gpu); - for (l = crtcs, i = 0; l; l = l->next, i++) - { - MetaCrtc *crtc = l->data; - MetaCrtcConfig *crtc_config = crtc->config; - - if (expect->crtcs[i].current_mode == -1) - { - g_assert_null (crtc_config); - } - else - { - MetaCrtcMode *expected_current_mode; - - g_assert_nonnull (crtc_config); - - expected_current_mode = - g_list_nth_data (meta_gpu_get_modes (gpu), - expect->crtcs[i].current_mode); - g_assert (crtc_config->mode == expected_current_mode); - - g_assert_cmpuint (crtc_config->transform, - ==, - expect->crtcs[i].transform); - - g_assert_cmpfloat_with_epsilon (crtc_config->layout.origin.x, - expect->crtcs[i].x, - FLT_EPSILON); - g_assert_cmpfloat_with_epsilon (crtc_config->layout.origin.y, - expect->crtcs[i].y, - FLT_EPSILON); - } - } -} - -static void -meta_output_test_destroy_notify (MetaOutput *output) -{ - g_clear_pointer (&output->driver_private, g_free); -} - -static MetaMonitorTestSetup * -create_monitor_test_setup (MonitorTestCaseSetup *setup, - MonitorTestFlag flags) -{ - MetaMonitorTestSetup *test_setup; - int i; - int n_laptop_panels = 0; - int n_normal_panels = 0; - gboolean hotplug_mode_update; - - if (flags & MONITOR_TEST_FLAG_NO_STORED) - hotplug_mode_update = TRUE; - else - hotplug_mode_update = FALSE; - - test_setup = g_new0 (MetaMonitorTestSetup, 1); - - test_setup->modes = NULL; - for (i = 0; i < setup->n_modes; i++) - { - MetaCrtcMode *mode; - - mode = g_object_new (META_TYPE_CRTC_MODE, NULL); - mode->mode_id = i; - mode->width = setup->modes[i].width; - mode->height = setup->modes[i].height; - mode->refresh_rate = setup->modes[i].refresh_rate; - mode->flags = setup->modes[i].flags; - - test_setup->modes = g_list_append (test_setup->modes, mode); - } - - test_setup->crtcs = NULL; - for (i = 0; i < setup->n_crtcs; i++) - { - MetaCrtc *crtc; - - crtc = g_object_new (META_TYPE_CRTC, NULL); - crtc->crtc_id = i + 1; - crtc->all_transforms = ALL_TRANSFORMS; - - test_setup->crtcs = g_list_append (test_setup->crtcs, crtc); - } - - test_setup->outputs = NULL; - for (i = 0; i < setup->n_outputs; i++) - { - MetaOutput *output; - MetaOutputTest *output_test; - int crtc_index; - MetaCrtc *crtc; - int preferred_mode_index; - MetaCrtcMode *preferred_mode; - MetaCrtcMode **modes; - int n_modes; - int j; - MetaCrtc **possible_crtcs; - int n_possible_crtcs; - int scale; - gboolean is_laptop_panel; - const char *serial; - - crtc_index = setup->outputs[i].crtc; - if (crtc_index == -1) - crtc = NULL; - else - crtc = g_list_nth_data (test_setup->crtcs, crtc_index); - - preferred_mode_index = setup->outputs[i].preferred_mode; - if (preferred_mode_index == -1) - preferred_mode = NULL; - else - preferred_mode = g_list_nth_data (test_setup->modes, - preferred_mode_index); - - n_modes = setup->outputs[i].n_modes; - modes = g_new0 (MetaCrtcMode *, n_modes); - for (j = 0; j < n_modes; j++) - { - int mode_index; - - mode_index = setup->outputs[i].modes[j]; - modes[j] = g_list_nth_data (test_setup->modes, mode_index); - } - - n_possible_crtcs = setup->outputs[i].n_possible_crtcs; - possible_crtcs = g_new0 (MetaCrtc *, n_possible_crtcs); - for (j = 0; j < n_possible_crtcs; j++) - { - int possible_crtc_index; - - possible_crtc_index = setup->outputs[i].possible_crtcs[j]; - possible_crtcs[j] = g_list_nth_data (test_setup->crtcs, - possible_crtc_index); - } - - output_test = g_new0 (MetaOutputTest, 1); - - scale = setup->outputs[i].scale; - if (scale < 1) - scale = 1; - - *output_test = (MetaOutputTest) { - .scale = scale - }; - - is_laptop_panel = setup->outputs[i].is_laptop_panel; - - serial = setup->outputs[i].serial; - if (!serial) - serial = "0x123456"; - - output = g_object_new (META_TYPE_OUTPUT, NULL); - - if (crtc) - meta_output_assign_crtc (output, crtc); - output->winsys_id = i; - output->name = (is_laptop_panel ? g_strdup_printf ("eDP-%d", - ++n_laptop_panels) - : g_strdup_printf ("DP-%d", - ++n_normal_panels)); - output->vendor = g_strdup ("MetaProduct's Inc."); - output->product = g_strdup ("MetaMonitor"); - output->serial = g_strdup (serial); - output->suggested_x = -1; - output->suggested_y = -1; - output->hotplug_mode_update = hotplug_mode_update; - output->width_mm = setup->outputs[i].width_mm; - output->height_mm = setup->outputs[i].height_mm; - output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; - output->preferred_mode = preferred_mode; - output->n_modes = n_modes; - output->modes = modes; - output->n_possible_crtcs = n_possible_crtcs; - output->possible_crtcs = possible_crtcs; - output->n_possible_clones = 0; - output->possible_clones = NULL; - output->backlight = -1; - output->connector_type = (is_laptop_panel ? META_CONNECTOR_TYPE_eDP - : META_CONNECTOR_TYPE_DisplayPort); - output->tile_info = setup->outputs[i].tile_info; - output->is_underscanning = setup->outputs[i].is_underscanning; - output->panel_orientation_transform = - setup->outputs[i].panel_orientation_transform; - output->driver_private = output_test; - output->driver_notify = (GDestroyNotify) meta_output_test_destroy_notify; - - test_setup->outputs = g_list_append (test_setup->outputs, output); - } - - return test_setup; -} - static void meta_test_monitor_initial_linear_config (void) {