1 /*
2 * Copyright (C) 2017 Red Hat
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
18 */
19
20 #include "config.h"
21
22 #include "backends/edid.h"
23 #include "backends/meta-output.h"
24
25 #include "backends/meta-crtc.h"
26
27 enum
28 {
29 PROP_0,
30
31 PROP_ID,
32 PROP_GPU,
33 PROP_INFO,
34
35 N_PROPS
36 };
37
38 static GParamSpec *obj_props[N_PROPS];
39
40 typedef struct _MetaOutputPrivate
41 {
42 uint64_t id;
43
44 MetaGpu *gpu;
45
46 MetaOutputInfo *info;
47
48 MetaMonitor *monitor;
49
50 /* The CRTC driving this output, NULL if the output is not enabled */
51 MetaCrtc *crtc;
52
53 gboolean is_primary;
54 gboolean is_presentation;
55
56 gboolean is_underscanning;
57
58 int backlight;
59 } MetaOutputPrivate;
60
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(MetaOutput,meta_output,G_TYPE_OBJECT)61 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaOutput, meta_output, G_TYPE_OBJECT)
62
63 G_DEFINE_BOXED_TYPE (MetaOutputInfo, meta_output_info,
64 meta_output_info_ref,
65 meta_output_info_unref)
66
67 MetaOutputInfo *
68 meta_output_info_new (void)
69 {
70 MetaOutputInfo *output_info;
71
72 output_info = g_new0 (MetaOutputInfo, 1);
73 g_ref_count_init (&output_info->ref_count);
74
75 return output_info;
76 }
77
78 MetaOutputInfo *
meta_output_info_ref(MetaOutputInfo * output_info)79 meta_output_info_ref (MetaOutputInfo *output_info)
80 {
81 g_ref_count_inc (&output_info->ref_count);
82 return output_info;
83 }
84
85 void
meta_output_info_unref(MetaOutputInfo * output_info)86 meta_output_info_unref (MetaOutputInfo *output_info)
87 {
88 if (g_ref_count_dec (&output_info->ref_count))
89 {
90 g_free (output_info->name);
91 g_free (output_info->vendor);
92 g_free (output_info->product);
93 g_free (output_info->serial);
94 g_free (output_info->modes);
95 g_free (output_info->possible_crtcs);
96 g_free (output_info->possible_clones);
97 g_free (output_info);
98 }
99 }
100
101 uint64_t
meta_output_get_id(MetaOutput * output)102 meta_output_get_id (MetaOutput *output)
103 {
104 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
105
106 return priv->id;
107 }
108
109 MetaGpu *
meta_output_get_gpu(MetaOutput * output)110 meta_output_get_gpu (MetaOutput *output)
111 {
112 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
113
114 return priv->gpu;
115 }
116
117 MetaMonitor *
meta_output_get_monitor(MetaOutput * output)118 meta_output_get_monitor (MetaOutput *output)
119 {
120 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
121
122 g_warn_if_fail (priv->monitor);
123
124 return priv->monitor;
125 }
126
127 void
meta_output_set_monitor(MetaOutput * output,MetaMonitor * monitor)128 meta_output_set_monitor (MetaOutput *output,
129 MetaMonitor *monitor)
130 {
131 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
132
133 g_warn_if_fail (!priv->monitor);
134
135 priv->monitor = monitor;
136 }
137
138 void
meta_output_unset_monitor(MetaOutput * output)139 meta_output_unset_monitor (MetaOutput *output)
140 {
141 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
142
143 g_warn_if_fail (priv->monitor);
144
145 priv->monitor = NULL;
146 }
147
148 const char *
meta_output_get_name(MetaOutput * output)149 meta_output_get_name (MetaOutput *output)
150 {
151 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
152
153 return priv->info->name;
154 }
155
156 gboolean
meta_output_is_primary(MetaOutput * output)157 meta_output_is_primary (MetaOutput *output)
158 {
159 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
160
161 return priv->is_primary;
162 }
163
164 gboolean
meta_output_is_presentation(MetaOutput * output)165 meta_output_is_presentation (MetaOutput *output)
166 {
167 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
168
169 return priv->is_presentation;
170 }
171
172 gboolean
meta_output_is_underscanning(MetaOutput * output)173 meta_output_is_underscanning (MetaOutput *output)
174 {
175 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
176
177 return priv->is_underscanning;
178 }
179
180 void
meta_output_set_backlight(MetaOutput * output,int backlight)181 meta_output_set_backlight (MetaOutput *output,
182 int backlight)
183 {
184 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
185
186 priv->backlight = backlight;
187 }
188
189 int
meta_output_get_backlight(MetaOutput * output)190 meta_output_get_backlight (MetaOutput *output)
191 {
192 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
193
194 return priv->backlight;
195 }
196
197 void
meta_output_add_possible_clone(MetaOutput * output,MetaOutput * possible_clone)198 meta_output_add_possible_clone (MetaOutput *output,
199 MetaOutput *possible_clone)
200 {
201 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
202 MetaOutputInfo *output_info = priv->info;
203
204 output_info->n_possible_clones++;
205 output_info->possible_clones = g_renew (MetaOutput *,
206 output_info->possible_clones,
207 output_info->n_possible_clones);
208 output_info->possible_clones[output_info->n_possible_clones - 1] =
209 possible_clone;
210 }
211
212 const MetaOutputInfo *
meta_output_get_info(MetaOutput * output)213 meta_output_get_info (MetaOutput *output)
214 {
215 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
216
217 return priv->info;
218 }
219
220 void
meta_output_assign_crtc(MetaOutput * output,MetaCrtc * crtc,const MetaOutputAssignment * output_assignment)221 meta_output_assign_crtc (MetaOutput *output,
222 MetaCrtc *crtc,
223 const MetaOutputAssignment *output_assignment)
224 {
225 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
226
227 g_assert (crtc);
228
229 meta_output_unassign_crtc (output);
230
231 g_set_object (&priv->crtc, crtc);
232
233 meta_crtc_assign_output (crtc, output);
234
235 priv->is_primary = output_assignment->is_primary;
236 priv->is_presentation = output_assignment->is_presentation;
237 priv->is_underscanning = output_assignment->is_underscanning;
238 }
239
240 void
meta_output_unassign_crtc(MetaOutput * output)241 meta_output_unassign_crtc (MetaOutput *output)
242 {
243 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
244
245 if (priv->crtc)
246 {
247 meta_crtc_unassign_output (priv->crtc, output);
248 g_clear_object (&priv->crtc);
249 }
250
251 priv->is_primary = FALSE;
252 priv->is_presentation = FALSE;
253 }
254
255 MetaCrtc *
meta_output_get_assigned_crtc(MetaOutput * output)256 meta_output_get_assigned_crtc (MetaOutput *output)
257 {
258 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
259
260 return priv->crtc;
261 }
262
263 MetaMonitorTransform
meta_output_logical_to_crtc_transform(MetaOutput * output,MetaMonitorTransform transform)264 meta_output_logical_to_crtc_transform (MetaOutput *output,
265 MetaMonitorTransform transform)
266 {
267 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
268 MetaMonitorTransform panel_orientation_transform;
269
270 panel_orientation_transform = priv->info->panel_orientation_transform;
271 return meta_monitor_transform_transform (transform,
272 panel_orientation_transform);
273 }
274
275 MetaMonitorTransform
meta_output_crtc_to_logical_transform(MetaOutput * output,MetaMonitorTransform transform)276 meta_output_crtc_to_logical_transform (MetaOutput *output,
277 MetaMonitorTransform transform)
278 {
279 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
280 MetaMonitorTransform inverted_panel_orientation_transform;
281
282 inverted_panel_orientation_transform =
283 meta_monitor_transform_invert (priv->info->panel_orientation_transform);
284 return meta_monitor_transform_transform (transform,
285 inverted_panel_orientation_transform);
286 }
287
288 void
meta_output_info_parse_edid(MetaOutputInfo * output_info,GBytes * edid)289 meta_output_info_parse_edid (MetaOutputInfo *output_info,
290 GBytes *edid)
291 {
292 MonitorInfo *parsed_edid;
293 size_t len;
294
295 if (!edid)
296 goto out;
297
298 parsed_edid = decode_edid (g_bytes_get_data (edid, &len));
299
300 if (parsed_edid)
301 {
302 output_info->vendor = g_strndup (parsed_edid->manufacturer_code, 4);
303 if (!g_utf8_validate (output_info->vendor, -1, NULL))
304 g_clear_pointer (&output_info->vendor, g_free);
305
306 output_info->product = g_strndup (parsed_edid->dsc_product_name, 14);
307 if (!g_utf8_validate (output_info->product, -1, NULL) ||
308 output_info->product[0] == '\0')
309 {
310 g_clear_pointer (&output_info->product, g_free);
311 output_info->product = g_strdup_printf ("0x%04x", (unsigned) parsed_edid->product_code);
312 }
313
314 output_info->serial = g_strndup (parsed_edid->dsc_serial_number, 14);
315 if (!g_utf8_validate (output_info->serial, -1, NULL) ||
316 output_info->serial[0] == '\0')
317 {
318 g_clear_pointer (&output_info->serial, g_free);
319 output_info->serial = g_strdup_printf ("0x%08x", parsed_edid->serial_number);
320 }
321
322 g_free (parsed_edid);
323 }
324
325 out:
326 if (!output_info->vendor)
327 output_info->vendor = g_strdup ("unknown");
328 if (!output_info->product)
329 output_info->product = g_strdup ("unknown");
330 if (!output_info->serial)
331 output_info->serial = g_strdup ("unknown");
332 }
333
334 gboolean
meta_output_is_laptop(MetaOutput * output)335 meta_output_is_laptop (MetaOutput *output)
336 {
337 const MetaOutputInfo *output_info = meta_output_get_info (output);
338
339 switch (output_info->connector_type)
340 {
341 case META_CONNECTOR_TYPE_eDP:
342 case META_CONNECTOR_TYPE_LVDS:
343 case META_CONNECTOR_TYPE_DSI:
344 return TRUE;
345 default:
346 return FALSE;
347 }
348 }
349
350 static void
meta_output_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)351 meta_output_set_property (GObject *object,
352 guint prop_id,
353 const GValue *value,
354 GParamSpec *pspec)
355 {
356 MetaOutput *output = META_OUTPUT (object);
357 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
358
359 switch (prop_id)
360 {
361 case PROP_ID:
362 priv->id = g_value_get_uint64 (value);
363 break;
364 case PROP_GPU:
365 priv->gpu = g_value_get_object (value);
366 break;
367 case PROP_INFO:
368 priv->info = meta_output_info_ref (g_value_get_boxed (value));
369 break;
370 default:
371 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
372 }
373 }
374
375 static void
meta_output_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)376 meta_output_get_property (GObject *object,
377 guint prop_id,
378 GValue *value,
379 GParamSpec *pspec)
380 {
381 MetaOutput *output = META_OUTPUT (object);
382 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
383
384 switch (prop_id)
385 {
386 case PROP_ID:
387 g_value_set_uint64 (value, priv->id);
388 break;
389 case PROP_GPU:
390 g_value_set_object (value, priv->gpu);
391 break;
392 case PROP_INFO:
393 g_value_set_boxed (value, priv->info);
394 break;
395 default:
396 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
397 }
398 }
399
400 static void
meta_output_dispose(GObject * object)401 meta_output_dispose (GObject *object)
402 {
403 MetaOutput *output = META_OUTPUT (object);
404 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
405
406 g_clear_object (&priv->crtc);
407
408 G_OBJECT_CLASS (meta_output_parent_class)->dispose (object);
409 }
410
411 static void
meta_output_finalize(GObject * object)412 meta_output_finalize (GObject *object)
413 {
414 MetaOutput *output = META_OUTPUT (object);
415 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
416
417 g_clear_pointer (&priv->info, meta_output_info_unref);
418
419 G_OBJECT_CLASS (meta_output_parent_class)->finalize (object);
420 }
421
422 static void
meta_output_init(MetaOutput * output)423 meta_output_init (MetaOutput *output)
424 {
425 MetaOutputPrivate *priv = meta_output_get_instance_private (output);
426
427 priv->backlight = -1;
428 }
429
430 static void
meta_output_class_init(MetaOutputClass * klass)431 meta_output_class_init (MetaOutputClass *klass)
432 {
433 GObjectClass *object_class = G_OBJECT_CLASS (klass);
434
435 object_class->set_property = meta_output_set_property;
436 object_class->get_property = meta_output_get_property;
437 object_class->dispose = meta_output_dispose;
438 object_class->finalize = meta_output_finalize;
439
440 obj_props[PROP_ID] =
441 g_param_spec_uint64 ("id",
442 "id",
443 "CRTC id",
444 0, UINT64_MAX, 0,
445 G_PARAM_READWRITE |
446 G_PARAM_CONSTRUCT_ONLY |
447 G_PARAM_STATIC_STRINGS);
448 obj_props[PROP_GPU] =
449 g_param_spec_object ("gpu",
450 "gpu",
451 "MetaGpu",
452 META_TYPE_GPU,
453 G_PARAM_READWRITE |
454 G_PARAM_CONSTRUCT_ONLY |
455 G_PARAM_STATIC_STRINGS);
456 obj_props[PROP_INFO] =
457 g_param_spec_boxed ("info",
458 "info",
459 "MetaOutputInfo",
460 META_TYPE_OUTPUT_INFO,
461 G_PARAM_READWRITE |
462 G_PARAM_CONSTRUCT_ONLY |
463 G_PARAM_STATIC_STRINGS);
464 g_object_class_install_properties (object_class, N_PROPS, obj_props);
465 }
466
467 gboolean
meta_tile_info_equal(MetaTileInfo * a,MetaTileInfo * b)468 meta_tile_info_equal (MetaTileInfo *a,
469 MetaTileInfo *b)
470 {
471 if (a == b)
472 return TRUE;
473
474 if (a->group_id != b->group_id)
475 return FALSE;
476
477 if (a->flags != b->flags)
478 return FALSE;
479
480 if (a->max_h_tiles != b->max_h_tiles)
481 return FALSE;
482
483 if (a->max_v_tiles != b->max_v_tiles)
484 return FALSE;
485
486 if (a->loc_h_tile != b->loc_h_tile)
487 return FALSE;
488
489 if (a->loc_v_tile != b->loc_v_tile)
490 return FALSE;
491
492 if (a->tile_w != b->tile_w)
493 return FALSE;
494
495 if (a->tile_h != b->tile_h)
496 return FALSE;
497
498 return TRUE;
499 }
500