1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 
3 /*
4  * Copyright (C) 2013 Red Hat Inc.
5  * Copyright (C) 2018 DisplayLink (UK) Ltd.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20  * 02111-1307, USA.
21  *
22  * Author: Giovanni Campagna <gcampagn@redhat.com>
23  */
24 
25 /**
26  * SECTION:meta-monitor-manager-native
27  * @title: MetaMonitorManagerNative
28  * @short_description: A subclass of #MetaMonitorManager using Linux DRM
29  *
30  * #MetaMonitorManagerNative is a subclass of #MetaMonitorManager which
31  * implements its functionality "natively": it uses the appropriate
32  * functions of the Linux DRM kernel module and using a udev client.
33  *
34  * See also #MetaMonitorManagerXrandr for an implementation using XRandR.
35  */
36 
37 #include "backends/meta-monitor.h"
38 #include "config.h"
39 
40 #include "backends/native/meta-monitor-manager-native.h"
41 
42 #include <drm.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 
47 #include "backends/meta-backend-private.h"
48 #include "backends/meta-crtc.h"
49 #include "backends/meta-monitor-config-manager.h"
50 #include "backends/meta-output.h"
51 #include "backends/native/meta-backend-native.h"
52 #include "backends/native/meta-crtc-kms.h"
53 #include "backends/native/meta-gpu-kms.h"
54 #include "backends/native/meta-kms-update.h"
55 #include "backends/native/meta-kms.h"
56 #include "backends/native/meta-launcher.h"
57 #include "backends/native/meta-output-kms.h"
58 #include "backends/native/meta-renderer-native.h"
59 #include "backends/native/meta-virtual-monitor-native.h"
60 #include "clutter/clutter.h"
61 #include "meta/main.h"
62 #include "meta/meta-x11-errors.h"
63 
64 #include "meta-dbus-display-config.h"
65 
66 enum
67 {
68   PROP_0,
69 
70   PROP_NEED_OUTPUTS,
71 
72   N_PROPS
73 };
74 
75 static GParamSpec *obj_props[N_PROPS];
76 
77 struct _MetaMonitorManagerNative
78 {
79   MetaMonitorManager parent_instance;
80 
81   gulong kms_resources_changed_handler_id;
82 
83   GHashTable *crtc_gamma_cache;
84 
85   gboolean needs_outputs;
86 };
87 
88 struct _MetaMonitorManagerNativeClass
89 {
90   MetaMonitorManagerClass parent_class;
91 };
92 
93 #define VIRTUAL_OUTPUT_ID_BIT (((uint64_t) 1) << 63)
94 
95 static void
96 initable_iface_init (GInitableIface *initable_iface);
97 
G_DEFINE_TYPE_WITH_CODE(MetaMonitorManagerNative,meta_monitor_manager_native,META_TYPE_MONITOR_MANAGER,G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,initable_iface_init))98 G_DEFINE_TYPE_WITH_CODE (MetaMonitorManagerNative, meta_monitor_manager_native,
99                          META_TYPE_MONITOR_MANAGER,
100                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
101                                                 initable_iface_init))
102 
103 static GBytes *
104 meta_monitor_manager_native_read_edid (MetaMonitorManager *manager,
105                                        MetaOutput         *output)
106 {
107   return meta_output_native_read_edid (META_OUTPUT_NATIVE (output));
108 }
109 
110 static void
meta_monitor_manager_native_read_current_state(MetaMonitorManager * manager)111 meta_monitor_manager_native_read_current_state (MetaMonitorManager *manager)
112 {
113   MetaMonitorManagerClass *parent_class =
114     META_MONITOR_MANAGER_CLASS (meta_monitor_manager_native_parent_class);
115   MetaPowerSave power_save_mode;
116 
117   power_save_mode = meta_monitor_manager_get_power_save_mode (manager);
118   if (power_save_mode != META_POWER_SAVE_ON)
119     meta_monitor_manager_power_save_mode_changed (manager,
120                                                   META_POWER_SAVE_ON);
121 
122   parent_class->read_current_state (manager);
123 }
124 
125 uint64_t
meta_power_save_to_dpms_state(MetaPowerSave power_save)126 meta_power_save_to_dpms_state (MetaPowerSave power_save)
127 {
128   switch (power_save)
129     {
130     case META_POWER_SAVE_ON:
131       return DRM_MODE_DPMS_ON;
132     case META_POWER_SAVE_STANDBY:
133       return DRM_MODE_DPMS_STANDBY;
134     case META_POWER_SAVE_SUSPEND:
135       return DRM_MODE_DPMS_SUSPEND;
136     case META_POWER_SAVE_OFF:
137       return DRM_MODE_DPMS_OFF;
138     case META_POWER_SAVE_UNSUPPORTED:
139       return DRM_MODE_DPMS_ON;
140     }
141 
142   g_warn_if_reached ();
143   return DRM_MODE_DPMS_ON;
144 }
145 
146 static void
meta_monitor_manager_native_set_power_save_mode(MetaMonitorManager * manager,MetaPowerSave mode)147 meta_monitor_manager_native_set_power_save_mode (MetaMonitorManager *manager,
148                                                  MetaPowerSave       mode)
149 {
150   MetaBackend *backend = meta_monitor_manager_get_backend (manager);
151   MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
152   MetaKms *kms = meta_backend_native_get_kms (backend_native);
153   GList *l;
154 
155   for (l = meta_backend_get_gpus (backend); l; l = l->next)
156     {
157       MetaGpuKms *gpu_kms = l->data;
158 
159       switch (mode)
160         {
161         case META_POWER_SAVE_ON:
162         case META_POWER_SAVE_UNSUPPORTED:
163           {
164             g_list_foreach (meta_gpu_get_crtcs (META_GPU (gpu_kms)),
165                             (GFunc) meta_crtc_kms_invalidate_gamma,
166                             NULL);
167             break;
168           }
169         case META_POWER_SAVE_STANDBY:
170         case META_POWER_SAVE_SUSPEND:
171         case META_POWER_SAVE_OFF:
172           {
173             MetaKmsDevice *kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
174             MetaKmsUpdate *kms_update;
175             MetaKmsUpdateFlag flags;
176             g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
177 
178             kms_update = meta_kms_ensure_pending_update (kms, kms_device);
179             meta_kms_update_set_power_save (kms_update);
180 
181             flags = META_KMS_UPDATE_FLAG_NONE;
182             kms_feedback = meta_kms_post_pending_update_sync (kms,
183                                                               kms_device,
184                                                               flags);
185             if (meta_kms_feedback_get_result (kms_feedback) !=
186                 META_KMS_FEEDBACK_PASSED)
187               {
188                 g_warning ("Failed to enter power saving mode: %s",
189                            meta_kms_feedback_get_error (kms_feedback)->message);
190               }
191             break;
192           }
193         }
194     }
195 }
196 
197 static void
meta_monitor_manager_native_ensure_initial_config(MetaMonitorManager * manager)198 meta_monitor_manager_native_ensure_initial_config (MetaMonitorManager *manager)
199 {
200   MetaMonitorsConfig *config;
201 
202   config = meta_monitor_manager_ensure_configured (manager);
203 
204   meta_monitor_manager_update_logical_state (manager, config);
205 }
206 
207 static void
apply_crtc_assignments(MetaMonitorManager * manager,MetaCrtcAssignment ** crtcs,unsigned int n_crtcs,MetaOutputAssignment ** outputs,unsigned int n_outputs)208 apply_crtc_assignments (MetaMonitorManager    *manager,
209                         MetaCrtcAssignment   **crtcs,
210                         unsigned int           n_crtcs,
211                         MetaOutputAssignment **outputs,
212                         unsigned int           n_outputs)
213 {
214   MetaBackend *backend = meta_monitor_manager_get_backend (manager);
215   g_autoptr (GList) to_configure_outputs = NULL;
216   g_autoptr (GList) to_configure_crtcs = NULL;
217   unsigned i;
218   GList *gpus;
219   GList *l;
220 
221   gpus = meta_backend_get_gpus (backend);
222   for (l = gpus; l; l = l->next)
223     {
224       MetaGpu *gpu = l->data;
225       GList *crtcs;
226       GList *outputs;
227 
228       outputs = g_list_copy (meta_gpu_get_outputs (gpu));
229       to_configure_outputs = g_list_concat (to_configure_outputs, outputs);
230 
231       crtcs = g_list_copy (meta_gpu_get_crtcs (gpu));
232       to_configure_crtcs = g_list_concat (to_configure_crtcs, crtcs);
233     }
234 
235   for (l = meta_monitor_manager_get_virtual_monitors (manager); l; l = l->next)
236     {
237       MetaVirtualMonitor *virtual_monitor = l->data;
238       MetaOutput *output = meta_virtual_monitor_get_output (virtual_monitor);
239       MetaCrtc *crtc = meta_virtual_monitor_get_crtc (virtual_monitor);
240 
241       to_configure_outputs = g_list_append (to_configure_outputs, output);
242       to_configure_crtcs = g_list_append (to_configure_crtcs, crtc);
243     }
244 
245   for (i = 0; i < n_crtcs; i++)
246     {
247       MetaCrtcAssignment *crtc_assignment = crtcs[i];
248       MetaCrtc *crtc = crtc_assignment->crtc;
249 
250       to_configure_crtcs = g_list_remove (to_configure_crtcs, crtc);
251 
252       if (crtc_assignment->mode == NULL)
253         {
254           meta_crtc_unset_config (crtc);
255         }
256       else
257         {
258           unsigned int j;
259 
260           meta_crtc_set_config (crtc,
261                                 &crtc_assignment->layout,
262                                 crtc_assignment->mode,
263                                 crtc_assignment->transform);
264 
265           for (j = 0; j < crtc_assignment->outputs->len; j++)
266             {
267               MetaOutput *output = g_ptr_array_index (crtc_assignment->outputs,
268                                                       j);
269               MetaOutputAssignment *output_assignment;
270 
271               to_configure_outputs = g_list_remove (to_configure_outputs,
272                                                     output);
273 
274               output_assignment = meta_find_output_assignment (outputs,
275                                                                n_outputs,
276                                                                output);
277               meta_output_assign_crtc (output, crtc, output_assignment);
278             }
279         }
280     }
281 
282   g_list_foreach (to_configure_crtcs,
283                   (GFunc) meta_crtc_unset_config,
284                   NULL);
285   g_list_foreach (to_configure_outputs,
286                   (GFunc) meta_output_unassign_crtc,
287                   NULL);
288 }
289 
290 static void
update_screen_size(MetaMonitorManager * manager,MetaMonitorsConfig * config)291 update_screen_size (MetaMonitorManager *manager,
292                     MetaMonitorsConfig *config)
293 {
294   GList *l;
295   int screen_width = 0;
296   int screen_height = 0;
297 
298   for (l = config->logical_monitor_configs; l; l = l->next)
299     {
300       MetaLogicalMonitorConfig *logical_monitor_config = l->data;
301       int right_edge;
302       int bottom_edge;
303 
304       right_edge = (logical_monitor_config->layout.width +
305                     logical_monitor_config->layout.x);
306       if (right_edge > screen_width)
307         screen_width = right_edge;
308 
309       bottom_edge = (logical_monitor_config->layout.height +
310                      logical_monitor_config->layout.y);
311       if (bottom_edge > screen_height)
312         screen_height = bottom_edge;
313     }
314 
315   manager->screen_width = screen_width;
316   manager->screen_height = screen_height;
317 }
318 
319 static gboolean
meta_monitor_manager_native_apply_monitors_config(MetaMonitorManager * manager,MetaMonitorsConfig * config,MetaMonitorsConfigMethod method,GError ** error)320 meta_monitor_manager_native_apply_monitors_config (MetaMonitorManager        *manager,
321                                                    MetaMonitorsConfig        *config,
322                                                    MetaMonitorsConfigMethod   method,
323                                                    GError                   **error)
324 {
325   GPtrArray *crtc_assignments;
326   GPtrArray *output_assignments;
327 
328   if (!config)
329     {
330       if (!manager->in_init)
331         {
332           MetaBackend *backend = meta_get_backend ();
333           MetaRenderer *renderer = meta_backend_get_renderer (backend);
334 
335           meta_renderer_native_reset_modes (META_RENDERER_NATIVE (renderer));
336         }
337 
338       manager->screen_width = META_MONITOR_MANAGER_MIN_SCREEN_WIDTH;
339       manager->screen_height = META_MONITOR_MANAGER_MIN_SCREEN_HEIGHT;
340       meta_monitor_manager_rebuild (manager, NULL);
341       return TRUE;
342     }
343 
344   if (!meta_monitor_config_manager_assign (manager, config,
345                                            &crtc_assignments,
346                                            &output_assignments,
347                                            error))
348     return FALSE;
349 
350   if (method == META_MONITORS_CONFIG_METHOD_VERIFY)
351     {
352       g_ptr_array_free (crtc_assignments, TRUE);
353       g_ptr_array_free (output_assignments, TRUE);
354       return TRUE;
355     }
356 
357   apply_crtc_assignments (manager,
358                           (MetaCrtcAssignment **) crtc_assignments->pdata,
359                           crtc_assignments->len,
360                           (MetaOutputAssignment **) output_assignments->pdata,
361                           output_assignments->len);
362 
363   g_ptr_array_free (crtc_assignments, TRUE);
364   g_ptr_array_free (output_assignments, TRUE);
365 
366   update_screen_size (manager, config);
367   meta_monitor_manager_rebuild (manager, config);
368 
369   return TRUE;
370 }
371 
372 static void
meta_monitor_manager_native_get_crtc_gamma(MetaMonitorManager * manager,MetaCrtc * crtc,gsize * size,unsigned short ** red,unsigned short ** green,unsigned short ** blue)373 meta_monitor_manager_native_get_crtc_gamma (MetaMonitorManager  *manager,
374                                             MetaCrtc            *crtc,
375                                             gsize               *size,
376                                             unsigned short     **red,
377                                             unsigned short     **green,
378                                             unsigned short     **blue)
379 {
380   MetaKmsCrtc *kms_crtc;
381   const MetaKmsCrtcState *crtc_state;
382 
383   g_return_if_fail (META_IS_CRTC_KMS (crtc));
384 
385   kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
386   crtc_state = meta_kms_crtc_get_current_state (kms_crtc);
387 
388   *size = crtc_state->gamma.size;
389   *red = g_memdup2 (crtc_state->gamma.red, *size * sizeof **red);
390   *green = g_memdup2 (crtc_state->gamma.green, *size * sizeof **green);
391   *blue = g_memdup2 (crtc_state->gamma.blue, *size * sizeof **blue);
392 }
393 
394 static char *
generate_gamma_ramp_string(size_t size,unsigned short * red,unsigned short * green,unsigned short * blue)395 generate_gamma_ramp_string (size_t          size,
396                             unsigned short *red,
397                             unsigned short *green,
398                             unsigned short *blue)
399 {
400   GString *string;
401   int color;
402 
403   string = g_string_new ("[");
404   for (color = 0; color < 3; color++)
405     {
406       unsigned short **color_ptr = NULL;
407       char color_char;
408       size_t i;
409 
410       switch (color)
411         {
412         case 0:
413           color_ptr = &red;
414           color_char = 'r';
415           break;
416         case 1:
417           color_ptr = &green;
418           color_char = 'g';
419           break;
420         case 2:
421           color_ptr = &blue;
422           color_char = 'b';
423           break;
424         }
425 
426       g_assert (color_ptr);
427       g_string_append_printf (string, " %c: ", color_char);
428       for (i = 0; i < MIN (4, size); i++)
429         {
430           int j;
431 
432           if (size > 4)
433             {
434               if (i == 2)
435                 g_string_append (string, ",...");
436 
437               if (i >= 2)
438                 j = i + (size - 4);
439               else
440                 j = i;
441             }
442           else
443             {
444               j = i;
445             }
446           g_string_append_printf (string, "%s%hu",
447                                   j == 0 ? "" : ",",
448                                   (*color_ptr)[i]);
449         }
450     }
451 
452   g_string_append (string, " ]");
453 
454   return g_string_free (string, FALSE);
455 }
456 
457 MetaKmsCrtcGamma *
meta_monitor_manager_native_get_cached_crtc_gamma(MetaMonitorManagerNative * manager_native,MetaCrtcKms * crtc_kms)458 meta_monitor_manager_native_get_cached_crtc_gamma (MetaMonitorManagerNative *manager_native,
459                                                    MetaCrtcKms              *crtc_kms)
460 {
461   uint64_t crtc_id;
462 
463   crtc_id = meta_crtc_get_id (META_CRTC (crtc_kms));
464   return g_hash_table_lookup (manager_native->crtc_gamma_cache,
465                               GUINT_TO_POINTER (crtc_id));
466 }
467 
468 static void
meta_monitor_manager_native_set_crtc_gamma(MetaMonitorManager * manager,MetaCrtc * crtc,gsize size,unsigned short * red,unsigned short * green,unsigned short * blue)469 meta_monitor_manager_native_set_crtc_gamma (MetaMonitorManager *manager,
470                                             MetaCrtc           *crtc,
471                                             gsize               size,
472                                             unsigned short     *red,
473                                             unsigned short     *green,
474                                             unsigned short     *blue)
475 {
476   MetaMonitorManagerNative *manager_native =
477     META_MONITOR_MANAGER_NATIVE (manager);
478   MetaCrtcKms *crtc_kms;
479   MetaKmsCrtc *kms_crtc;
480   g_autofree char *gamma_ramp_string = NULL;
481   MetaBackend *backend = meta_monitor_manager_get_backend (manager);
482   ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
483 
484   g_return_if_fail (META_IS_CRTC_KMS (crtc));
485 
486   crtc_kms = META_CRTC_KMS (crtc);
487   kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
488 
489   g_hash_table_replace (manager_native->crtc_gamma_cache,
490                         GUINT_TO_POINTER (meta_crtc_get_id (crtc)),
491                         meta_kms_crtc_gamma_new (kms_crtc, size,
492                                                  red, green, blue));
493 
494   gamma_ramp_string = generate_gamma_ramp_string (size, red, green, blue);
495   g_debug ("Setting CRTC (%" G_GUINT64_FORMAT ") gamma to %s",
496            meta_crtc_get_id (crtc), gamma_ramp_string);
497 
498   meta_crtc_kms_invalidate_gamma (crtc_kms);
499   clutter_stage_schedule_update (stage);
500 }
501 
502 static void
handle_hotplug_event(MetaMonitorManager * manager)503 handle_hotplug_event (MetaMonitorManager *manager)
504 {
505   meta_monitor_manager_reload (manager);
506 }
507 
508 static void
on_kms_resources_changed(MetaKms * kms,MetaKmsUpdateChanges changes,MetaMonitorManager * manager)509 on_kms_resources_changed (MetaKms              *kms,
510                           MetaKmsUpdateChanges  changes,
511                           MetaMonitorManager   *manager)
512 {
513   g_assert (changes != META_KMS_UPDATE_CHANGE_NONE);
514 
515   if (changes == META_KMS_UPDATE_CHANGE_GAMMA)
516     {
517       meta_dbus_display_config_emit_monitors_changed (manager->display_config);
518       return;
519     }
520 
521   handle_hotplug_event (manager);
522 }
523 
524 static void
meta_monitor_manager_native_connect_hotplug_handler(MetaMonitorManagerNative * manager_native)525 meta_monitor_manager_native_connect_hotplug_handler (MetaMonitorManagerNative *manager_native)
526 {
527   MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native);
528   MetaBackend *backend = meta_monitor_manager_get_backend (manager);
529   MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
530   MetaKms *kms = meta_backend_native_get_kms (backend_native);
531 
532   manager_native->kms_resources_changed_handler_id =
533     g_signal_connect (kms, "resources-changed",
534                       G_CALLBACK (on_kms_resources_changed), manager);
535 }
536 
537 static void
meta_monitor_manager_native_disconnect_hotplug_handler(MetaMonitorManagerNative * manager_native)538 meta_monitor_manager_native_disconnect_hotplug_handler (MetaMonitorManagerNative *manager_native)
539 {
540   MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native);
541   MetaBackend *backend = meta_monitor_manager_get_backend (manager);
542   MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
543   MetaKms *kms = meta_backend_native_get_kms (backend_native);
544 
545   g_clear_signal_handler (&manager_native->kms_resources_changed_handler_id, kms);
546 }
547 
548 void
meta_monitor_manager_native_pause(MetaMonitorManagerNative * manager_native)549 meta_monitor_manager_native_pause (MetaMonitorManagerNative *manager_native)
550 {
551   meta_monitor_manager_native_disconnect_hotplug_handler (manager_native);
552 }
553 
554 void
meta_monitor_manager_native_resume(MetaMonitorManagerNative * manager_native)555 meta_monitor_manager_native_resume (MetaMonitorManagerNative *manager_native)
556 {
557   MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native);
558   MetaBackend *backend = meta_monitor_manager_get_backend (manager);
559   GList *l;
560 
561   meta_monitor_manager_native_connect_hotplug_handler (manager_native);
562 
563   for (l = meta_backend_get_gpus (backend); l; l = l->next)
564     {
565       MetaGpu *gpu = l->data;
566 
567       g_list_foreach (meta_gpu_get_crtcs (gpu),
568                       (GFunc) meta_crtc_kms_invalidate_gamma,
569                       NULL);
570     }
571 }
572 
573 static gboolean
meta_monitor_manager_native_is_transform_handled(MetaMonitorManager * manager,MetaCrtc * crtc,MetaMonitorTransform transform)574 meta_monitor_manager_native_is_transform_handled (MetaMonitorManager  *manager,
575                                                   MetaCrtc            *crtc,
576                                                   MetaMonitorTransform transform)
577 {
578   return meta_crtc_native_is_transform_handled (META_CRTC_NATIVE (crtc),
579                                                 transform);
580 }
581 
582 static MetaMonitorScalesConstraint
get_monitor_scale_constraints_from_layout_mode(MetaLogicalMonitorLayoutMode layout_mode)583 get_monitor_scale_constraints_from_layout_mode (MetaLogicalMonitorLayoutMode layout_mode)
584 {
585   MetaMonitorScalesConstraint constraints =
586     META_MONITOR_SCALES_CONSTRAINT_NONE;
587 
588   switch (layout_mode)
589     {
590     case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
591       break;
592     case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
593       constraints |= META_MONITOR_SCALES_CONSTRAINT_NO_FRAC;
594       break;
595     }
596 
597   return constraints;
598 }
599 
600 static float
meta_monitor_manager_native_calculate_monitor_mode_scale(MetaMonitorManager * manager,MetaLogicalMonitorLayoutMode layout_mode,MetaMonitor * monitor,MetaMonitorMode * monitor_mode)601 meta_monitor_manager_native_calculate_monitor_mode_scale (MetaMonitorManager           *manager,
602                                                           MetaLogicalMonitorLayoutMode  layout_mode,
603                                                           MetaMonitor                  *monitor,
604                                                           MetaMonitorMode              *monitor_mode)
605 {
606   MetaMonitorScalesConstraint constraints =
607     get_monitor_scale_constraints_from_layout_mode (layout_mode);
608 
609   return meta_monitor_calculate_mode_scale (monitor, monitor_mode, constraints);
610 }
611 
612 static float *
meta_monitor_manager_native_calculate_supported_scales(MetaMonitorManager * manager,MetaLogicalMonitorLayoutMode layout_mode,MetaMonitor * monitor,MetaMonitorMode * monitor_mode,int * n_supported_scales)613 meta_monitor_manager_native_calculate_supported_scales (MetaMonitorManager           *manager,
614                                                         MetaLogicalMonitorLayoutMode  layout_mode,
615                                                         MetaMonitor                  *monitor,
616                                                         MetaMonitorMode              *monitor_mode,
617                                                         int                          *n_supported_scales)
618 {
619   MetaMonitorScalesConstraint constraints =
620     get_monitor_scale_constraints_from_layout_mode (layout_mode);
621 
622   return meta_monitor_calculate_supported_scales (monitor, monitor_mode,
623                                                   constraints,
624                                                   n_supported_scales);
625 }
626 
627 static MetaMonitorManagerCapability
meta_monitor_manager_native_get_capabilities(MetaMonitorManager * manager)628 meta_monitor_manager_native_get_capabilities (MetaMonitorManager *manager)
629 {
630   MetaBackend *backend = meta_monitor_manager_get_backend (manager);
631   MetaSettings *settings = meta_backend_get_settings (backend);
632   MetaMonitorManagerCapability capabilities =
633     META_MONITOR_MANAGER_CAPABILITY_NONE;
634 
635   if (meta_settings_is_experimental_feature_enabled (
636         settings,
637         META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER))
638     capabilities |= META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE;
639 
640   return capabilities;
641 }
642 
643 static gboolean
meta_monitor_manager_native_get_max_screen_size(MetaMonitorManager * manager,int * max_width,int * max_height)644 meta_monitor_manager_native_get_max_screen_size (MetaMonitorManager *manager,
645                                                  int                *max_width,
646                                                  int                *max_height)
647 {
648   return FALSE;
649 }
650 
651 static MetaLogicalMonitorLayoutMode
meta_monitor_manager_native_get_default_layout_mode(MetaMonitorManager * manager)652 meta_monitor_manager_native_get_default_layout_mode (MetaMonitorManager *manager)
653 {
654   MetaBackend *backend = meta_monitor_manager_get_backend (manager);
655   MetaSettings *settings = meta_backend_get_settings (backend);
656 
657   if (meta_settings_is_experimental_feature_enabled (
658         settings,
659         META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER))
660     return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
661   else
662     return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
663 }
664 
665 static MetaVirtualMonitorNative *
find_virtual_monitor(MetaMonitorManagerNative * manager_native,uint64_t id)666 find_virtual_monitor (MetaMonitorManagerNative *manager_native,
667                       uint64_t                  id)
668 {
669   MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native);
670   GList *l;
671 
672   for (l = meta_monitor_manager_get_virtual_monitors (manager); l; l = l->next)
673     {
674       MetaVirtualMonitorNative *virtual_monitor_native = l->data;
675 
676       if (meta_virtual_monitor_native_get_id (virtual_monitor_native) == id)
677         return virtual_monitor_native;
678     }
679 
680   return NULL;
681 }
682 
683 static uint64_t
allocate_virtual_monitor_id(MetaMonitorManagerNative * manager_native)684 allocate_virtual_monitor_id (MetaMonitorManagerNative *manager_native)
685 {
686   uint64_t id;
687 
688   id = 0;
689 
690   while (TRUE)
691     {
692       if (!find_virtual_monitor (manager_native, id))
693         return id;
694 
695       id++;
696     }
697 }
698 
699 static MetaVirtualMonitor *
meta_monitor_manager_native_create_virtual_monitor(MetaMonitorManager * manager,const MetaVirtualMonitorInfo * info,GError ** error)700 meta_monitor_manager_native_create_virtual_monitor (MetaMonitorManager            *manager,
701                                                     const MetaVirtualMonitorInfo  *info,
702                                                     GError                       **error)
703 {
704   MetaMonitorManagerNative *manager_native =
705     META_MONITOR_MANAGER_NATIVE (manager);
706   MetaVirtualMonitorNative *virtual_monitor_native;
707   uint64_t id;
708 
709   id = allocate_virtual_monitor_id (manager_native);
710   virtual_monitor_native = meta_virtual_monitor_native_new (id, info);
711   return META_VIRTUAL_MONITOR (virtual_monitor_native);
712 }
713 
714 static void
meta_monitor_manager_native_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)715 meta_monitor_manager_native_set_property (GObject      *object,
716                                           guint         prop_id,
717                                           const GValue *value,
718                                           GParamSpec   *pspec)
719 {
720   MetaMonitorManagerNative *manager_native =
721     META_MONITOR_MANAGER_NATIVE (object);
722 
723   switch (prop_id)
724     {
725     case PROP_NEED_OUTPUTS:
726       manager_native->needs_outputs = g_value_get_boolean (value);
727       break;
728     default:
729       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
730       break;
731     }
732 }
733 
734 static void
meta_monitor_manager_native_dispose(GObject * object)735 meta_monitor_manager_native_dispose (GObject *object)
736 {
737   MetaMonitorManagerNative *manager_native =
738     META_MONITOR_MANAGER_NATIVE (object);
739 
740   g_clear_pointer (&manager_native->crtc_gamma_cache,
741                    g_hash_table_unref);
742 
743   G_OBJECT_CLASS (meta_monitor_manager_native_parent_class)->dispose (object);
744 }
745 
746 static gboolean
meta_monitor_manager_native_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)747 meta_monitor_manager_native_initable_init (GInitable    *initable,
748                                            GCancellable *cancellable,
749                                            GError      **error)
750 {
751   MetaMonitorManagerNative *manager_native =
752     META_MONITOR_MANAGER_NATIVE (initable);
753   MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native);
754   MetaBackend *backend = meta_monitor_manager_get_backend (manager);
755   gboolean can_have_outputs;
756   GList *l;
757 
758   meta_monitor_manager_native_connect_hotplug_handler (manager_native);
759 
760   can_have_outputs = FALSE;
761   for (l = meta_backend_get_gpus (backend); l; l = l->next)
762     {
763       MetaGpuKms *gpu_kms = l->data;
764 
765       if (meta_gpu_kms_can_have_outputs (gpu_kms))
766         {
767           can_have_outputs = TRUE;
768           break;
769         }
770     }
771 
772   if (manager_native->needs_outputs && !can_have_outputs)
773     {
774       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
775                    "No GPUs with outputs found");
776       return FALSE;
777     }
778 
779   manager_native->crtc_gamma_cache =
780     g_hash_table_new_full (NULL, NULL,
781                            NULL,
782                            (GDestroyNotify) meta_kms_crtc_gamma_free);
783 
784   return TRUE;
785 }
786 
787 static void
initable_iface_init(GInitableIface * initable_iface)788 initable_iface_init (GInitableIface *initable_iface)
789 {
790   initable_iface->init = meta_monitor_manager_native_initable_init;
791 }
792 
793 static void
meta_monitor_manager_native_init(MetaMonitorManagerNative * manager_native)794 meta_monitor_manager_native_init (MetaMonitorManagerNative *manager_native)
795 {
796   manager_native->needs_outputs = TRUE;
797 }
798 
799 static void
meta_monitor_manager_native_class_init(MetaMonitorManagerNativeClass * klass)800 meta_monitor_manager_native_class_init (MetaMonitorManagerNativeClass *klass)
801 {
802   GObjectClass *object_class = G_OBJECT_CLASS (klass);
803   MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
804 
805   object_class->set_property = meta_monitor_manager_native_set_property;
806   object_class->dispose = meta_monitor_manager_native_dispose;
807 
808   manager_class->read_edid =
809     meta_monitor_manager_native_read_edid;
810   manager_class->read_current_state =
811     meta_monitor_manager_native_read_current_state;
812   manager_class->ensure_initial_config =
813     meta_monitor_manager_native_ensure_initial_config;
814   manager_class->apply_monitors_config =
815     meta_monitor_manager_native_apply_monitors_config;
816   manager_class->set_power_save_mode =
817     meta_monitor_manager_native_set_power_save_mode;
818   manager_class->get_crtc_gamma =
819     meta_monitor_manager_native_get_crtc_gamma;
820   manager_class->set_crtc_gamma =
821     meta_monitor_manager_native_set_crtc_gamma;
822   manager_class->is_transform_handled =
823     meta_monitor_manager_native_is_transform_handled;
824   manager_class->calculate_monitor_mode_scale =
825     meta_monitor_manager_native_calculate_monitor_mode_scale;
826   manager_class->calculate_supported_scales =
827     meta_monitor_manager_native_calculate_supported_scales;
828   manager_class->get_capabilities =
829     meta_monitor_manager_native_get_capabilities;
830   manager_class->get_max_screen_size =
831     meta_monitor_manager_native_get_max_screen_size;
832   manager_class->get_default_layout_mode =
833     meta_monitor_manager_native_get_default_layout_mode;
834   manager_class->create_virtual_monitor =
835     meta_monitor_manager_native_create_virtual_monitor;
836 
837   obj_props[PROP_NEED_OUTPUTS] =
838     g_param_spec_boolean ("needs-outputs",
839                           "needs-outputs",
840                           "Whether any outputs are needed for operation",
841                           TRUE,
842                           G_PARAM_WRITABLE |
843                           G_PARAM_CONSTRUCT_ONLY |
844                           G_PARAM_STATIC_STRINGS);
845   g_object_class_install_properties (object_class, N_PROPS, obj_props);
846 }
847