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