1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 
3 /*
4  * Copyright (C) 2017 Red Hat, Inc.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "config.h"
21 
22 #include "tests/monitor-test-utils.h"
23 
24 #include <float.h>
25 
26 #include "backends/meta-backend-private.h"
27 #include "backends/meta-crtc.h"
28 #include "backends/meta-logical-monitor.h"
29 #include "backends/meta-monitor-config-manager.h"
30 #include "backends/meta-monitor-config-store.h"
31 #include "backends/meta-output.h"
32 #include "tests/meta-test-utils.h"
33 #include "meta-backend-test.h"
34 
35 MetaGpu *
test_get_gpu(void)36 test_get_gpu (void)
37 {
38   return META_GPU (meta_backend_get_gpus (meta_get_backend ())->data);
39 }
40 
41 void
set_custom_monitor_config(const char * filename)42 set_custom_monitor_config (const char *filename)
43 {
44   MetaBackend *backend = meta_get_backend ();
45   MetaMonitorManager *monitor_manager =
46     meta_backend_get_monitor_manager (backend);
47   MetaMonitorConfigManager *config_manager = monitor_manager->config_manager;
48   MetaMonitorConfigStore *config_store;
49   GError *error = NULL;
50   const char *path;
51 
52   g_assert_nonnull (config_manager);
53 
54   config_store = meta_monitor_config_manager_get_store (config_manager);
55 
56   path = g_test_get_filename (G_TEST_DIST, "tests", "monitor-configs",
57                               filename, NULL);
58   if (!meta_monitor_config_store_set_custom (config_store, path, NULL,
59                                              &error))
60     g_error ("Failed to set custom config: %s", error->message);
61 }
62 
63 char *
read_file(const char * file_path)64 read_file (const char *file_path)
65 {
66   g_autoptr (GFile) file = NULL;
67   g_autoptr (GFileInputStream) input_stream = NULL;
68   g_autoptr (GFileInfo) file_info = NULL;
69   goffset file_size;
70   gsize bytes_read;
71   g_autofree char *buffer = NULL;
72   GError *error = NULL;
73 
74   file = g_file_new_for_path (file_path);
75   input_stream = g_file_read (file, NULL, &error);
76   if (!input_stream)
77     g_error ("Failed to read migrated config file: %s", error->message);
78 
79   file_info = g_file_input_stream_query_info (input_stream,
80                                               G_FILE_ATTRIBUTE_STANDARD_SIZE,
81                                               NULL, &error);
82   if (!file_info)
83     g_error ("Failed to read file info: %s", error->message);
84 
85   file_size = g_file_info_get_size (file_info);
86   buffer = g_malloc0 (file_size + 1);
87 
88   if (!g_input_stream_read_all (G_INPUT_STREAM (input_stream),
89                                 buffer, file_size, &bytes_read, NULL, &error))
90     g_error ("Failed to read file content: %s", error->message);
91   g_assert_cmpint ((goffset) bytes_read, ==, file_size);
92 
93   return g_steal_pointer (&buffer);
94 }
95 
96 static MetaOutput *
output_from_winsys_id(MetaBackend * backend,uint64_t output_id)97 output_from_winsys_id (MetaBackend *backend,
98                        uint64_t     output_id)
99 {
100   MetaGpu *gpu = meta_backend_test_get_gpu (META_BACKEND_TEST (backend));
101   GList *l;
102 
103   for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
104     {
105       MetaOutput *output = l->data;
106 
107       if (meta_output_get_id (output) == output_id)
108         return output;
109     }
110 
111   return NULL;
112 }
113 
114 typedef struct _CheckMonitorModeData
115 {
116   MetaBackend *backend;
117   MetaTestCaseMonitorCrtcMode *expect_crtc_mode_iter;
118 } CheckMonitorModeData;
119 
120 static gboolean
check_monitor_mode(MetaMonitor * monitor,MetaMonitorMode * mode,MetaMonitorCrtcMode * monitor_crtc_mode,gpointer user_data,GError ** error)121 check_monitor_mode (MetaMonitor         *monitor,
122                     MetaMonitorMode     *mode,
123                     MetaMonitorCrtcMode *monitor_crtc_mode,
124                     gpointer             user_data,
125                     GError             **error)
126 {
127   CheckMonitorModeData *data = user_data;
128   MetaBackend *backend = data->backend;
129   MetaOutput *output;
130   MetaCrtcMode *crtc_mode;
131   int expect_crtc_mode_index;
132 
133   output = output_from_winsys_id (backend,
134                                   data->expect_crtc_mode_iter->output);
135   g_assert (monitor_crtc_mode->output == output);
136 
137   expect_crtc_mode_index = data->expect_crtc_mode_iter->crtc_mode;
138   if (expect_crtc_mode_index == -1)
139     {
140       crtc_mode = NULL;
141     }
142   else
143     {
144       MetaGpu *gpu = meta_output_get_gpu (output);
145 
146       crtc_mode = g_list_nth_data (meta_gpu_get_modes (gpu),
147                                    expect_crtc_mode_index);
148     }
149   g_assert (monitor_crtc_mode->crtc_mode == crtc_mode);
150 
151   if (crtc_mode)
152     {
153       const MetaCrtcModeInfo *crtc_mode_info =
154         meta_crtc_mode_get_info (crtc_mode);
155       float refresh_rate;
156       MetaCrtcModeFlag flags;
157 
158       refresh_rate = meta_monitor_mode_get_refresh_rate (mode);
159       flags = meta_monitor_mode_get_flags (mode);
160 
161       g_assert_cmpfloat (refresh_rate, ==, crtc_mode_info->refresh_rate);
162       g_assert_cmpint (flags, ==, (crtc_mode_info->flags &
163                                    HANDLED_CRTC_MODE_FLAGS));
164     }
165 
166   data->expect_crtc_mode_iter++;
167 
168   return TRUE;
169 }
170 
171 static gboolean
check_current_monitor_mode(MetaMonitor * monitor,MetaMonitorMode * mode,MetaMonitorCrtcMode * monitor_crtc_mode,gpointer user_data,GError ** error)172 check_current_monitor_mode (MetaMonitor         *monitor,
173                             MetaMonitorMode     *mode,
174                             MetaMonitorCrtcMode *monitor_crtc_mode,
175                             gpointer             user_data,
176                             GError             **error)
177 {
178   CheckMonitorModeData *data = user_data;
179   MetaBackend *backend = data->backend;
180   MetaOutput *output;
181   MetaCrtc *crtc;
182 
183   output = output_from_winsys_id (backend,
184                                   data->expect_crtc_mode_iter->output);
185   crtc = meta_output_get_assigned_crtc (output);
186 
187   if (data->expect_crtc_mode_iter->crtc_mode == -1)
188     {
189       g_assert_null (crtc);
190     }
191   else
192     {
193       const MetaCrtcConfig *crtc_config;
194       MetaLogicalMonitor *logical_monitor;
195 
196       g_assert_nonnull (crtc);
197 
198       crtc_config = meta_crtc_get_config (crtc);
199       g_assert_nonnull (crtc_config);
200 
201       g_assert (monitor_crtc_mode->crtc_mode == crtc_config->mode);
202 
203       logical_monitor = meta_monitor_get_logical_monitor (monitor);
204       g_assert_nonnull (logical_monitor);
205     }
206 
207 
208   data->expect_crtc_mode_iter++;
209 
210   return TRUE;
211 }
212 
213 static MetaLogicalMonitor *
logical_monitor_from_layout(MetaMonitorManager * monitor_manager,MetaRectangle * layout)214 logical_monitor_from_layout (MetaMonitorManager *monitor_manager,
215                              MetaRectangle      *layout)
216 {
217   GList *l;
218 
219   for (l = monitor_manager->logical_monitors; l; l = l->next)
220     {
221       MetaLogicalMonitor *logical_monitor = l->data;
222 
223       if (meta_rectangle_equal (layout, &logical_monitor->rect))
224         return logical_monitor;
225     }
226 
227   return NULL;
228 }
229 
230 static void
check_logical_monitor(MetaMonitorManager * monitor_manager,MonitorTestCaseLogicalMonitor * test_logical_monitor,GList ** all_crtcs)231 check_logical_monitor (MetaMonitorManager             *monitor_manager,
232                        MonitorTestCaseLogicalMonitor  *test_logical_monitor,
233                        GList                         **all_crtcs)
234 {
235   MetaLogicalMonitor *logical_monitor;
236   MetaOutput *primary_output;
237   GList *monitors;
238   GList *l;
239   int i;
240 
241   logical_monitor = logical_monitor_from_layout (monitor_manager,
242                                                  &test_logical_monitor->layout);
243   g_assert_nonnull (logical_monitor);
244 
245   g_assert_cmpint (logical_monitor->rect.x,
246                    ==,
247                    test_logical_monitor->layout.x);
248   g_assert_cmpint (logical_monitor->rect.y,
249                    ==,
250                    test_logical_monitor->layout.y);
251   g_assert_cmpint (logical_monitor->rect.width,
252                    ==,
253                    test_logical_monitor->layout.width);
254   g_assert_cmpint (logical_monitor->rect.height,
255                    ==,
256                    test_logical_monitor->layout.height);
257   g_assert_cmpfloat (logical_monitor->scale,
258                      ==,
259                      test_logical_monitor->scale);
260   g_assert_cmpuint (logical_monitor->transform,
261                     ==,
262                     test_logical_monitor->transform);
263 
264   if (logical_monitor == monitor_manager->primary_logical_monitor)
265     g_assert (meta_logical_monitor_is_primary (logical_monitor));
266 
267   primary_output = NULL;
268   monitors = meta_logical_monitor_get_monitors (logical_monitor);
269   g_assert_cmpint ((int) g_list_length (monitors),
270                    ==,
271                    test_logical_monitor->n_monitors);
272 
273   for (i = 0; i < test_logical_monitor->n_monitors; i++)
274     {
275       MetaMonitor *monitor =
276         g_list_nth (monitor_manager->monitors,
277                     test_logical_monitor->monitors[i])->data;
278 
279       g_assert_nonnull (g_list_find (monitors, monitor));
280     }
281 
282   for (l = monitors; l; l = l->next)
283     {
284       MetaMonitor *monitor = l->data;
285       GList *outputs;
286       GList *l_output;
287 
288       outputs = meta_monitor_get_outputs (monitor);
289       for (l_output = outputs; l_output; l_output = l_output->next)
290         {
291           MetaOutput *output = l_output->data;
292           MetaCrtc *crtc;
293 
294           g_assert (meta_output_get_monitor (output) == monitor);
295 
296           if (meta_output_is_primary (output))
297             {
298               g_assert_null (primary_output);
299               primary_output = output;
300             }
301 
302           crtc = meta_output_get_assigned_crtc (output);
303           if (crtc)
304             {
305               g_assert (meta_monitor_get_logical_monitor (monitor) ==
306                         logical_monitor);
307               g_assert (g_list_find ((GList *) meta_crtc_get_outputs (crtc),
308                                      output));
309               *all_crtcs = g_list_remove (*all_crtcs, crtc);
310             }
311           else
312             {
313               g_assert_null (crtc);
314             }
315 
316           g_assert_cmpint (logical_monitor->is_presentation,
317                            ==,
318                            meta_output_is_presentation (output));
319         }
320     }
321 
322   if (logical_monitor == monitor_manager->primary_logical_monitor)
323     g_assert_nonnull (primary_output);
324 }
325 
326 void
check_monitor_configuration(MonitorTestCaseExpect * expect)327 check_monitor_configuration (MonitorTestCaseExpect *expect)
328 {
329   MetaBackend *backend = meta_get_backend ();
330   MetaRenderer *renderer = meta_backend_get_renderer (backend);
331   MetaMonitorManager *monitor_manager =
332     meta_backend_get_monitor_manager (backend);
333   MetaMonitorManagerTest *monitor_manager_test =
334     META_MONITOR_MANAGER_TEST (monitor_manager);
335   MetaGpu *gpu = meta_backend_test_get_gpu (META_BACKEND_TEST (backend));
336   int tiled_monitor_count;
337   GList *monitors;
338   GList *crtcs;
339   int n_logical_monitors;
340   GList *all_crtcs;
341   GList *l;
342   int i;
343 
344   g_assert_cmpint (monitor_manager->screen_width,
345                    ==,
346                    expect->screen_width);
347   g_assert_cmpint (monitor_manager->screen_height,
348                    ==,
349                    expect->screen_height);
350   g_assert_cmpint ((int) g_list_length (meta_gpu_get_outputs (gpu)),
351                    ==,
352                    expect->n_outputs);
353   g_assert_cmpint ((int) g_list_length (meta_gpu_get_crtcs (gpu)),
354                    ==,
355                    expect->n_crtcs);
356 
357   tiled_monitor_count =
358     meta_monitor_manager_test_get_tiled_monitor_count (monitor_manager_test);
359   g_assert_cmpint (tiled_monitor_count,
360                    ==,
361                    expect->n_tiled_monitors);
362 
363   monitors = meta_monitor_manager_get_monitors (monitor_manager);
364   g_assert_cmpint ((int) g_list_length (monitors),
365                    ==,
366                    expect->n_monitors);
367   for (l = monitors, i = 0; l; l = l->next, i++)
368     {
369       MetaMonitor *monitor = l->data;
370       MetaOutput *main_output;
371       const MetaOutputInfo *main_output_info;
372       GList *outputs;
373       GList *l_output;
374       int j;
375       int width_mm, height_mm;
376       GList *modes;
377       GList *l_mode;
378       MetaMonitorMode *current_mode;
379       int expected_current_mode_index;
380       MetaMonitorMode *expected_current_mode;
381 
382       outputs = meta_monitor_get_outputs (monitor);
383       g_debug ("Checking monitor %d", i);
384 
385       g_assert_cmpint ((int) g_list_length (outputs),
386                        ==,
387                        expect->monitors[i].n_outputs);
388 
389       for (l_output = outputs, j = 0; l_output; l_output = l_output->next, j++)
390         {
391           MetaOutput *output = l_output->data;
392           uint64_t winsys_id = expect->monitors[i].outputs[j];
393 
394           g_assert (output == output_from_winsys_id (backend, winsys_id));
395           g_assert_cmpint (expect->monitors[i].is_underscanning,
396                            ==,
397                            meta_output_is_underscanning (output));
398         }
399 
400       meta_monitor_get_physical_dimensions (monitor, &width_mm, &height_mm);
401       g_assert_cmpint (width_mm,
402                        ==,
403                        expect->monitors[i].width_mm);
404       g_assert_cmpint (height_mm,
405                        ==,
406                        expect->monitors[i].height_mm);
407 
408       main_output = meta_monitor_get_main_output (monitor);
409       main_output_info = meta_output_get_info (main_output);
410       g_assert_cmpstr (meta_monitor_get_connector (monitor), ==,
411                        main_output_info->name);
412       g_assert_cmpstr (meta_monitor_get_vendor (monitor), ==,
413                        main_output_info->vendor);
414       g_assert_cmpstr (meta_monitor_get_product (monitor), ==,
415                        main_output_info->product);
416       g_assert_cmpstr (meta_monitor_get_serial (monitor), ==,
417                        main_output_info->serial);
418       g_assert_cmpint (meta_monitor_get_connector_type (monitor), ==,
419                        main_output_info->connector_type);
420 
421       modes = meta_monitor_get_modes (monitor);
422       g_assert_cmpint (g_list_length (modes),
423                        ==,
424                        expect->monitors[i].n_modes);
425 
426       for (l_mode = modes, j = 0; l_mode; l_mode = l_mode->next, j++)
427         {
428           MetaMonitorMode *mode = l_mode->data;
429           int width;
430           int height;
431           float refresh_rate;
432           MetaCrtcModeFlag flags;
433           CheckMonitorModeData data;
434 
435           meta_monitor_mode_get_resolution (mode, &width, &height);
436           refresh_rate = meta_monitor_mode_get_refresh_rate (mode);
437           flags = meta_monitor_mode_get_flags (mode);
438 
439           g_debug ("Checking mode %dx%d @ %f", width, height, refresh_rate);
440 
441           g_assert_cmpint (width,
442                            ==,
443                            expect->monitors[i].modes[j].width);
444           g_assert_cmpint (height,
445                            ==,
446                            expect->monitors[i].modes[j].height);
447           g_assert_cmpfloat (refresh_rate,
448                              ==,
449                              expect->monitors[i].modes[j].refresh_rate);
450           g_assert_cmpint (flags,
451                            ==,
452                            expect->monitors[i].modes[j].flags);
453 
454           data = (CheckMonitorModeData) {
455             .backend = backend,
456             .expect_crtc_mode_iter =
457               expect->monitors[i].modes[j].crtc_modes
458           };
459           meta_monitor_mode_foreach_output (monitor, mode,
460                                             check_monitor_mode,
461                                             &data,
462                                             NULL);
463         }
464 
465       current_mode = meta_monitor_get_current_mode (monitor);
466       expected_current_mode_index = expect->monitors[i].current_mode;
467       if (expected_current_mode_index == -1)
468         expected_current_mode = NULL;
469       else
470         expected_current_mode = g_list_nth (modes,
471                                             expected_current_mode_index)->data;
472 
473       g_assert (current_mode == expected_current_mode);
474       if (current_mode)
475         g_assert (meta_monitor_is_active (monitor));
476       else
477         g_assert (!meta_monitor_is_active (monitor));
478 
479       if (current_mode)
480         {
481           CheckMonitorModeData data;
482 
483           data = (CheckMonitorModeData) {
484             .backend = backend,
485             .expect_crtc_mode_iter =
486               expect->monitors[i].modes[expected_current_mode_index].crtc_modes
487           };
488           meta_monitor_mode_foreach_output (monitor, expected_current_mode,
489                                             check_current_monitor_mode,
490                                             &data,
491                                             NULL);
492         }
493 
494       meta_monitor_derive_current_mode (monitor);
495       g_assert (current_mode == meta_monitor_get_current_mode (monitor));
496     }
497 
498   n_logical_monitors =
499     meta_monitor_manager_get_num_logical_monitors (monitor_manager);
500   g_assert_cmpint (n_logical_monitors,
501                    ==,
502                    expect->n_logical_monitors);
503 
504   /*
505    * Check that we have a primary logical monitor (except for headless),
506    * and that the main output of the first monitor is the only output
507    * that is marked as primary (further below). Note: outputs being primary or
508    * not only matters on X11.
509    */
510   if (expect->primary_logical_monitor == -1)
511     {
512       g_assert_null (monitor_manager->primary_logical_monitor);
513       g_assert_null (monitor_manager->logical_monitors);
514     }
515   else
516     {
517       MonitorTestCaseLogicalMonitor *test_logical_monitor =
518         &expect->logical_monitors[expect->primary_logical_monitor];
519       MetaLogicalMonitor *logical_monitor;
520 
521       logical_monitor =
522         logical_monitor_from_layout (monitor_manager,
523                                      &test_logical_monitor->layout);
524       g_assert (logical_monitor == monitor_manager->primary_logical_monitor);
525     }
526 
527   all_crtcs = NULL;
528   for (l = meta_backend_get_gpus (backend); l; l = l->next)
529     {
530       MetaGpu *gpu = l->data;
531 
532       all_crtcs = g_list_concat (all_crtcs,
533                                  g_list_copy (meta_gpu_get_crtcs (gpu)));
534     }
535 
536   for (i = 0; i < expect->n_logical_monitors; i++)
537     {
538       MonitorTestCaseLogicalMonitor *test_logical_monitor =
539         &expect->logical_monitors[i];
540 
541       check_logical_monitor (monitor_manager, test_logical_monitor, &all_crtcs);
542     }
543   g_assert_cmpint (n_logical_monitors, ==, i);
544 
545   for (l = all_crtcs; l; l = l->next)
546     {
547       MetaCrtc *crtc = l->data;
548 
549       g_assert_null (meta_crtc_get_outputs (crtc));
550     }
551   g_list_free (all_crtcs);
552 
553   crtcs = meta_gpu_get_crtcs (gpu);
554   for (l = crtcs, i = 0; l; l = l->next, i++)
555     {
556       MetaCrtc *crtc = l->data;
557       const MetaCrtcConfig *crtc_config = meta_crtc_get_config (crtc);
558 
559       g_debug ("Checking CRTC %d", i);
560 
561       if (expect->crtcs[i].current_mode == -1)
562         {
563           g_assert_null (meta_crtc_get_outputs (crtc));
564           g_assert_null (crtc_config);
565         }
566       else
567         {
568           MetaCrtcMode *expected_current_mode;
569           const GList *outputs = meta_crtc_get_outputs (crtc);
570           const GList *l_output;
571           MetaRendererView *view;
572           cairo_rectangle_int_t view_layout;
573 
574           for (l_output = outputs;
575                l_output;
576                l_output = l_output->next)
577             {
578               MetaOutput *output = l_output->data;
579 
580               g_debug ("Checking CRTC Output %d",
581                        g_list_index ((GList *) outputs, output));
582 
583               g_assert (meta_output_get_assigned_crtc (output) == crtc);
584               g_assert_null (g_list_find (l_output->next, output));
585             }
586 
587           g_assert_nonnull (crtc_config);
588 
589           expected_current_mode =
590             g_list_nth_data (meta_gpu_get_modes (gpu),
591                              expect->crtcs[i].current_mode);
592           g_assert (crtc_config->mode == expected_current_mode);
593 
594           g_assert_cmpuint (crtc_config->transform,
595                             ==,
596                             expect->crtcs[i].transform);
597 
598           g_assert_cmpfloat_with_epsilon (crtc_config->layout.origin.x,
599                                           expect->crtcs[i].x,
600                                           FLT_EPSILON);
601           g_assert_cmpfloat_with_epsilon (crtc_config->layout.origin.y,
602                                           expect->crtcs[i].y,
603                                           FLT_EPSILON);
604 
605           view = meta_renderer_get_view_for_crtc (renderer, crtc);
606           g_assert_nonnull (view);
607           clutter_stage_view_get_layout (CLUTTER_STAGE_VIEW (view),
608                                          &view_layout);
609           g_assert_cmpfloat_with_epsilon (crtc_config->layout.origin.x,
610                                           view_layout.x,
611                                           FLT_EPSILON);
612           g_assert_cmpfloat_with_epsilon (crtc_config->layout.origin.y,
613                                           view_layout.y,
614                                           FLT_EPSILON);
615           g_assert_cmpfloat_with_epsilon (crtc_config->layout.size.width,
616                                           view_layout.width,
617                                           FLT_EPSILON);
618           g_assert_cmpfloat_with_epsilon (crtc_config->layout.size.height,
619                                           view_layout.height,
620                                           FLT_EPSILON);
621         }
622     }
623 }
624 
625 MetaMonitorTestSetup *
create_monitor_test_setup(MonitorTestCaseSetup * setup,MonitorTestFlag flags)626 create_monitor_test_setup (MonitorTestCaseSetup *setup,
627                            MonitorTestFlag       flags)
628 {
629   MetaMonitorTestSetup *test_setup;
630   int i;
631   int n_laptop_panels = 0;
632   int n_normal_panels = 0;
633 
634   test_setup = g_new0 (MetaMonitorTestSetup, 1);
635 
636   test_setup->modes = NULL;
637   for (i = 0; i < setup->n_modes; i++)
638     {
639       g_autoptr (MetaCrtcModeInfo) crtc_mode_info = NULL;
640       MetaCrtcMode *mode;
641 
642       crtc_mode_info = meta_crtc_mode_info_new ();
643       crtc_mode_info->width = setup->modes[i].width;
644       crtc_mode_info->height = setup->modes[i].height;
645       crtc_mode_info->refresh_rate = setup->modes[i].refresh_rate;
646       crtc_mode_info->flags = setup->modes[i].flags;
647 
648       mode = g_object_new (META_TYPE_CRTC_MODE,
649                            "id", (uint64_t) i,
650                            "info", crtc_mode_info,
651                            NULL);
652 
653       test_setup->modes = g_list_append (test_setup->modes, mode);
654     }
655 
656   test_setup->crtcs = NULL;
657   for (i = 0; i < setup->n_crtcs; i++)
658     {
659       MetaCrtc *crtc;
660 
661       crtc = g_object_new (META_TYPE_CRTC_TEST,
662                            "id", (uint64_t) i + 1,
663                            "gpu", test_get_gpu (),
664                            NULL);
665 
666       test_setup->crtcs = g_list_append (test_setup->crtcs, crtc);
667     }
668 
669   test_setup->outputs = NULL;
670   for (i = 0; i < setup->n_outputs; i++)
671     {
672       MetaOutput *output;
673       MetaOutputTest *output_test;
674       int crtc_index;
675       MetaCrtc *crtc;
676       int preferred_mode_index;
677       MetaCrtcMode *preferred_mode;
678       MetaCrtcMode **modes;
679       int n_modes;
680       int j;
681       MetaCrtc **possible_crtcs;
682       int n_possible_crtcs;
683       int scale;
684       gboolean is_laptop_panel;
685       const char *serial;
686       g_autoptr (MetaOutputInfo) output_info = NULL;
687 
688       crtc_index = setup->outputs[i].crtc;
689       if (crtc_index == -1)
690         crtc = NULL;
691       else
692         crtc = g_list_nth_data (test_setup->crtcs, crtc_index);
693 
694       preferred_mode_index = setup->outputs[i].preferred_mode;
695       if (preferred_mode_index == -1)
696         preferred_mode = NULL;
697       else
698         preferred_mode = g_list_nth_data (test_setup->modes,
699                                           preferred_mode_index);
700 
701       n_modes = setup->outputs[i].n_modes;
702       modes = g_new0 (MetaCrtcMode *, n_modes);
703       for (j = 0; j < n_modes; j++)
704         {
705           int mode_index;
706 
707           mode_index = setup->outputs[i].modes[j];
708           modes[j] = g_list_nth_data (test_setup->modes, mode_index);
709         }
710 
711       n_possible_crtcs = setup->outputs[i].n_possible_crtcs;
712       possible_crtcs = g_new0 (MetaCrtc *, n_possible_crtcs);
713       for (j = 0; j < n_possible_crtcs; j++)
714         {
715           int possible_crtc_index;
716 
717           possible_crtc_index = setup->outputs[i].possible_crtcs[j];
718           possible_crtcs[j] = g_list_nth_data (test_setup->crtcs,
719                                                possible_crtc_index);
720         }
721 
722       scale = setup->outputs[i].scale;
723       if (scale < 1)
724         scale = 1;
725 
726       is_laptop_panel = setup->outputs[i].is_laptop_panel;
727 
728       serial = setup->outputs[i].serial;
729       if (!serial)
730         serial = "0x123456";
731 
732       output_info = meta_output_info_new ();
733 
734       output_info->name = (is_laptop_panel
735                            ? g_strdup_printf ("eDP-%d", ++n_laptop_panels)
736                            : g_strdup_printf ("DP-%d", ++n_normal_panels));
737       output_info->vendor = g_strdup ("MetaProduct's Inc.");
738       output_info->product = g_strdup ("MetaMonitor");
739       output_info->serial = g_strdup (serial);
740       if (setup->outputs[i].hotplug_mode)
741         {
742           output_info->hotplug_mode_update = TRUE;
743           output_info->suggested_x = setup->outputs[i].suggested_x;
744           output_info->suggested_y = setup->outputs[i].suggested_y;
745         }
746       else if (flags & MONITOR_TEST_FLAG_NO_STORED)
747         {
748           output_info->hotplug_mode_update = TRUE;
749           output_info->suggested_x = -1;
750           output_info->suggested_y = -1;
751         }
752       output_info->width_mm = setup->outputs[i].width_mm;
753       output_info->height_mm = setup->outputs[i].height_mm;
754       output_info->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
755       output_info->preferred_mode = preferred_mode;
756       output_info->n_modes = n_modes;
757       output_info->modes = modes;
758       output_info->n_possible_crtcs = n_possible_crtcs;
759       output_info->possible_crtcs = possible_crtcs;
760       output_info->n_possible_clones = 0;
761       output_info->possible_clones = NULL;
762       output_info->connector_type = (is_laptop_panel ? META_CONNECTOR_TYPE_eDP
763                                      : META_CONNECTOR_TYPE_DisplayPort);
764       output_info->tile_info = setup->outputs[i].tile_info;
765       output_info->panel_orientation_transform =
766         setup->outputs[i].panel_orientation_transform;
767 
768       output = g_object_new (META_TYPE_OUTPUT_TEST,
769                              "id", (uint64_t) i,
770                              "gpu", test_get_gpu (),
771                              "info", output_info,
772                              NULL);
773 
774       output_test = META_OUTPUT_TEST (output);
775       output_test->scale = scale;
776 
777       if (crtc)
778         {
779           MetaOutputAssignment output_assignment;
780 
781           output_assignment = (MetaOutputAssignment) {
782             .is_underscanning = setup->outputs[i].is_underscanning,
783           };
784           meta_output_assign_crtc (output, crtc, &output_assignment);
785         }
786 
787       test_setup->outputs = g_list_append (test_setup->outputs, output);
788     }
789 
790   return test_setup;
791 }
792 
793 static void
check_expected_scales(MetaMonitor * monitor,MetaMonitorMode * monitor_mode,MetaMonitorScalesConstraint constraints,int n_expected_scales,float * expected_scales)794 check_expected_scales (MetaMonitor                 *monitor,
795                        MetaMonitorMode             *monitor_mode,
796                        MetaMonitorScalesConstraint  constraints,
797                        int                          n_expected_scales,
798                        float                       *expected_scales)
799 {
800   g_autofree float *scales = NULL;
801   int n_supported_scales;
802   int width, height;
803   int i;
804 
805   scales = meta_monitor_calculate_supported_scales (monitor, monitor_mode,
806                                                     constraints,
807                                                     &n_supported_scales);
808   g_assert_cmpint (n_expected_scales, ==, n_supported_scales);
809 
810   meta_monitor_mode_get_resolution (monitor_mode, &width, &height);
811 
812   for (i = 0; i < n_supported_scales; i++)
813     {
814       g_assert_cmpfloat (scales[i], >, 0.0);
815       g_assert_cmpfloat_with_epsilon (scales[i], expected_scales[i], 0.000001);
816 
817       if (!(constraints & META_MONITOR_SCALES_CONSTRAINT_NO_FRAC))
818         {
819           /* Also ensure that the scale will generate an integral resolution */
820           g_assert_cmpfloat (fmodf (width / scales[i], 1.0), ==, 0.0);
821           g_assert_cmpfloat (fmodf (height / scales[i], 1.0), ==, 0.0);
822         }
823 
824       if (i > 0)
825         {
826           /* And that scales are sorted and unique */
827           g_assert_cmpfloat (scales[i], >, scales[i-1]);
828           g_assert_false (G_APPROX_VALUE (scales[i], scales[i-1], 0.000001));
829         }
830     }
831 }
832 
check_monitor_scales(MonitorTestCaseExpect * expect,MetaMonitorScalesConstraint scales_constraints)833 void check_monitor_scales (MonitorTestCaseExpect       *expect,
834                            MetaMonitorScalesConstraint  scales_constraints)
835 {
836   MetaBackend *backend = meta_get_backend ();
837   MetaMonitorManager *monitor_manager =
838     meta_backend_get_monitor_manager (backend);
839 
840   GList *monitors;
841   GList *l;
842   int i;
843 
844   monitors = meta_monitor_manager_get_monitors (monitor_manager);
845   g_assert_cmpuint (g_list_length (monitors), ==, expect->n_monitors);
846 
847   for (l = monitors, i = 0; l; l = l->next, i++)
848     {
849       MetaMonitor *monitor = l->data;
850       MonitorTestCaseMonitor *expected_monitor = &expect->monitors[i];
851       GList *modes = meta_monitor_get_modes (monitor);
852       GList *k;
853       int j;
854 
855       g_debug ("Checking monitor %d", i);
856       g_assert_cmpuint (g_list_length (modes), ==, expected_monitor->n_modes);
857 
858       for (j = 0, k = modes; k; k = k->next, j++)
859         {
860           MetaMonitorMode *monitor_mode = k->data;
861           MetaMonitorTestCaseMonitorMode *expected_mode =
862             &expected_monitor->modes[j];
863           int width, height;
864 
865           meta_monitor_mode_get_resolution (monitor_mode, &width, &height);
866           g_debug ("Checking %s scaling values for mode %dx%d",
867             (scales_constraints & META_MONITOR_SCALES_CONSTRAINT_NO_FRAC) ?
868             "integer" : "fractional", width, height);
869 
870           g_assert_cmpint (width, ==, expected_mode->width);
871           g_assert_cmpint (height, ==, expected_mode->height);
872 
873           check_expected_scales (monitor, monitor_mode, scales_constraints,
874                                  expected_mode->n_scales,
875                                  expected_mode->scales);
876         }
877     }
878 }
879