1 /*
2 * Copyright (C) 2018 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/native/meta-kms-update.h"
23 #include "backends/native/meta-kms-update-private.h"
24
25 #include "backends/meta-display-config-shared.h"
26 #include "backends/native/meta-kms-connector.h"
27 #include "backends/native/meta-kms-crtc.h"
28 #include "backends/native/meta-kms-mode-private.h"
29 #include "backends/native/meta-kms-plane.h"
30
31 struct _MetaKmsUpdate
32 {
33 MetaKmsDevice *device;
34
35 gboolean is_locked;
36 uint64_t sequence_number;
37
38 gboolean power_save;
39
40 GList *mode_sets;
41 GList *plane_assignments;
42 GList *connector_updates;
43 GList *crtc_gammas;
44
45 MetaKmsCustomPageFlip *custom_page_flip;
46
47 GList *page_flip_listeners;
48 GList *result_listeners;
49 };
50
51 void
meta_kms_plane_feedback_free(MetaKmsPlaneFeedback * plane_feedback)52 meta_kms_plane_feedback_free (MetaKmsPlaneFeedback *plane_feedback)
53 {
54 g_error_free (plane_feedback->error);
55 g_free (plane_feedback);
56 }
57
58 MetaKmsPlaneFeedback *
meta_kms_plane_feedback_new_take_error(MetaKmsPlane * plane,MetaKmsCrtc * crtc,GError * error)59 meta_kms_plane_feedback_new_take_error (MetaKmsPlane *plane,
60 MetaKmsCrtc *crtc,
61 GError *error)
62 {
63 MetaKmsPlaneFeedback *plane_feedback;
64
65 plane_feedback = g_new0 (MetaKmsPlaneFeedback, 1);
66 *plane_feedback = (MetaKmsPlaneFeedback) {
67 .plane = plane,
68 .crtc = crtc,
69 .error = error,
70 };
71
72 return plane_feedback;
73 }
74
75 MetaKmsFeedback *
meta_kms_feedback_new_passed(GList * failed_planes)76 meta_kms_feedback_new_passed (GList *failed_planes)
77 {
78 MetaKmsFeedback *feedback;
79
80 feedback = g_new0 (MetaKmsFeedback, 1);
81 *feedback = (MetaKmsFeedback) {
82 .result = META_KMS_FEEDBACK_PASSED,
83 .failed_planes = failed_planes,
84 };
85
86 return feedback;
87 }
88
89 MetaKmsFeedback *
meta_kms_feedback_new_failed(GList * failed_planes,GError * error)90 meta_kms_feedback_new_failed (GList *failed_planes,
91 GError *error)
92 {
93 MetaKmsFeedback *feedback;
94
95 feedback = g_new0 (MetaKmsFeedback, 1);
96 *feedback = (MetaKmsFeedback) {
97 .result = META_KMS_FEEDBACK_FAILED,
98 .error = error,
99 .failed_planes = failed_planes,
100 };
101
102 return feedback;
103 }
104
105 void
meta_kms_feedback_free(MetaKmsFeedback * feedback)106 meta_kms_feedback_free (MetaKmsFeedback *feedback)
107 {
108 g_list_free_full (feedback->failed_planes,
109 (GDestroyNotify) meta_kms_plane_feedback_free);
110 g_clear_error (&feedback->error);
111 g_free (feedback);
112 }
113
114 MetaKmsFeedbackResult
meta_kms_feedback_get_result(const MetaKmsFeedback * feedback)115 meta_kms_feedback_get_result (const MetaKmsFeedback *feedback)
116 {
117 return feedback->result;
118 }
119
120 GList *
meta_kms_feedback_get_failed_planes(const MetaKmsFeedback * feedback)121 meta_kms_feedback_get_failed_planes (const MetaKmsFeedback *feedback)
122 {
123 return feedback->failed_planes;
124 }
125
126 const GError *
meta_kms_feedback_get_error(const MetaKmsFeedback * feedback)127 meta_kms_feedback_get_error (const MetaKmsFeedback *feedback)
128 {
129 return feedback->error;
130 }
131
132 static void
meta_kms_fb_damage_free(MetaKmsFbDamage * fb_damage)133 meta_kms_fb_damage_free (MetaKmsFbDamage *fb_damage)
134 {
135 g_free (fb_damage->rects);
136 g_free (fb_damage);
137 }
138
139 static void
meta_kms_plane_assignment_free(MetaKmsPlaneAssignment * plane_assignment)140 meta_kms_plane_assignment_free (MetaKmsPlaneAssignment *plane_assignment)
141 {
142 g_clear_pointer (&plane_assignment->fb_damage, meta_kms_fb_damage_free);
143 g_free (plane_assignment);
144 }
145
146 static void
meta_kms_mode_set_free(MetaKmsModeSet * mode_set)147 meta_kms_mode_set_free (MetaKmsModeSet *mode_set)
148 {
149 g_list_free (mode_set->connectors);
150 g_free (mode_set);
151 }
152
153 static void
meta_kms_page_flip_listener_free(MetaKmsPageFlipListener * listener)154 meta_kms_page_flip_listener_free (MetaKmsPageFlipListener *listener)
155 {
156 g_clear_pointer (&listener->user_data, listener->destroy_notify);
157 g_free (listener);
158 }
159
160 static gboolean
drop_plane_assignment(MetaKmsUpdate * update,MetaKmsPlane * plane,MetaKmsAssignPlaneFlag * out_flags)161 drop_plane_assignment (MetaKmsUpdate *update,
162 MetaKmsPlane *plane,
163 MetaKmsAssignPlaneFlag *out_flags)
164 {
165 GList *l;
166
167 for (l = update->plane_assignments; l; l = l->next)
168 {
169 MetaKmsPlaneAssignment *plane_assignment = l->data;
170
171 if (plane_assignment->plane == plane)
172 {
173 update->plane_assignments =
174 g_list_delete_link (update->plane_assignments, l);
175 if (out_flags)
176 *out_flags = plane_assignment->flags;
177 meta_kms_plane_assignment_free (plane_assignment);
178 return TRUE;
179 }
180 }
181
182 return FALSE;
183 }
184
185 void
meta_kms_update_drop_plane_assignment(MetaKmsUpdate * update,MetaKmsPlane * plane)186 meta_kms_update_drop_plane_assignment (MetaKmsUpdate *update,
187 MetaKmsPlane *plane)
188 {
189 drop_plane_assignment (update, plane, NULL);
190 }
191
192 MetaKmsPlaneAssignment *
meta_kms_update_assign_plane(MetaKmsUpdate * update,MetaKmsCrtc * crtc,MetaKmsPlane * plane,MetaDrmBuffer * buffer,MetaFixed16Rectangle src_rect,MetaRectangle dst_rect,MetaKmsAssignPlaneFlag flags)193 meta_kms_update_assign_plane (MetaKmsUpdate *update,
194 MetaKmsCrtc *crtc,
195 MetaKmsPlane *plane,
196 MetaDrmBuffer *buffer,
197 MetaFixed16Rectangle src_rect,
198 MetaRectangle dst_rect,
199 MetaKmsAssignPlaneFlag flags)
200 {
201 MetaKmsPlaneAssignment *plane_assignment;
202 MetaKmsAssignPlaneFlag old_flags;
203
204 g_assert (!meta_kms_update_is_locked (update));
205 g_assert (meta_kms_crtc_get_device (crtc) == update->device);
206 g_assert (!update->power_save);
207 g_assert (meta_kms_plane_get_device (plane) == update->device);
208 g_assert (meta_kms_plane_get_plane_type (plane) !=
209 META_KMS_PLANE_TYPE_PRIMARY ||
210 !(flags & META_KMS_ASSIGN_PLANE_FLAG_ALLOW_FAIL));
211
212 if (drop_plane_assignment (update, plane, &old_flags))
213 {
214 if (!(old_flags & META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED))
215 flags &= ~META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED;
216 }
217
218 plane_assignment = g_new0 (MetaKmsPlaneAssignment, 1);
219 *plane_assignment = (MetaKmsPlaneAssignment) {
220 .update = update,
221 .crtc = crtc,
222 .plane = plane,
223 .buffer = buffer,
224 .src_rect = src_rect,
225 .dst_rect = dst_rect,
226 .flags = flags,
227 };
228
229 update->plane_assignments = g_list_prepend (update->plane_assignments,
230 plane_assignment);
231
232 return plane_assignment;
233 }
234
235 MetaKmsPlaneAssignment *
meta_kms_update_unassign_plane(MetaKmsUpdate * update,MetaKmsCrtc * crtc,MetaKmsPlane * plane)236 meta_kms_update_unassign_plane (MetaKmsUpdate *update,
237 MetaKmsCrtc *crtc,
238 MetaKmsPlane *plane)
239 {
240 MetaKmsPlaneAssignment *plane_assignment;
241
242 g_assert (!meta_kms_update_is_locked (update));
243 g_assert (meta_kms_crtc_get_device (crtc) == update->device);
244 g_assert (meta_kms_plane_get_device (plane) == update->device);
245 g_assert (!update->power_save);
246
247 plane_assignment = g_new0 (MetaKmsPlaneAssignment, 1);
248 *plane_assignment = (MetaKmsPlaneAssignment) {
249 .update = update,
250 .crtc = crtc,
251 .plane = plane,
252 .buffer = NULL,
253 };
254
255 update->plane_assignments = g_list_prepend (update->plane_assignments,
256 plane_assignment);
257
258 return plane_assignment;
259 }
260
261 void
meta_kms_update_mode_set(MetaKmsUpdate * update,MetaKmsCrtc * crtc,GList * connectors,MetaKmsMode * mode)262 meta_kms_update_mode_set (MetaKmsUpdate *update,
263 MetaKmsCrtc *crtc,
264 GList *connectors,
265 MetaKmsMode *mode)
266 {
267 MetaKmsModeSet *mode_set;
268
269 g_assert (!meta_kms_update_is_locked (update));
270 g_assert (meta_kms_crtc_get_device (crtc) == update->device);
271 g_assert (!update->power_save);
272
273 mode_set = g_new0 (MetaKmsModeSet, 1);
274 *mode_set = (MetaKmsModeSet) {
275 .crtc = crtc,
276 .connectors = connectors,
277 .mode = mode,
278 };
279
280 update->mode_sets = g_list_prepend (update->mode_sets, mode_set);
281 }
282
283 static MetaKmsConnectorUpdate *
ensure_connector_update(MetaKmsUpdate * update,MetaKmsConnector * connector)284 ensure_connector_update (MetaKmsUpdate *update,
285 MetaKmsConnector *connector)
286 {
287 GList *l;
288 MetaKmsConnectorUpdate *connector_update;
289
290 for (l = update->connector_updates; l; l = l->next)
291 {
292 connector_update = l->data;
293
294 if (connector_update->connector == connector)
295 return connector_update;
296 }
297
298 connector_update = g_new0 (MetaKmsConnectorUpdate, 1);
299 connector_update->connector = connector;
300
301 update->connector_updates = g_list_prepend (update->connector_updates,
302 connector_update);
303
304 return connector_update;
305 }
306
307 void
meta_kms_update_set_underscanning(MetaKmsUpdate * update,MetaKmsConnector * connector,uint64_t hborder,uint64_t vborder)308 meta_kms_update_set_underscanning (MetaKmsUpdate *update,
309 MetaKmsConnector *connector,
310 uint64_t hborder,
311 uint64_t vborder)
312 {
313 MetaKmsConnectorUpdate *connector_update;
314
315 g_assert (!meta_kms_update_is_locked (update));
316 g_assert (meta_kms_connector_get_device (connector) == update->device);
317 g_assert (!update->power_save);
318
319 connector_update = ensure_connector_update (update, connector);
320 connector_update->underscanning.has_update = TRUE;
321 connector_update->underscanning.is_active = TRUE;
322 connector_update->underscanning.hborder = hborder;
323 connector_update->underscanning.vborder = vborder;
324 }
325
326 void
meta_kms_update_unset_underscanning(MetaKmsUpdate * update,MetaKmsConnector * connector)327 meta_kms_update_unset_underscanning (MetaKmsUpdate *update,
328 MetaKmsConnector *connector)
329 {
330 MetaKmsConnectorUpdate *connector_update;
331
332 g_assert (!meta_kms_update_is_locked (update));
333 g_assert (meta_kms_connector_get_device (connector) == update->device);
334 g_assert (!update->power_save);
335
336 connector_update = ensure_connector_update (update, connector);
337 connector_update->underscanning.has_update = TRUE;
338 connector_update->underscanning.is_active = FALSE;
339 }
340
341 void
meta_kms_update_set_power_save(MetaKmsUpdate * update)342 meta_kms_update_set_power_save (MetaKmsUpdate *update)
343 {
344 g_assert (!meta_kms_update_is_locked (update));
345 g_assert (!update->mode_sets);
346 g_assert (!update->plane_assignments);
347 g_assert (!update->connector_updates);
348 g_assert (!update->crtc_gammas);
349
350 update->power_save = TRUE;
351 }
352
353 void
meta_kms_crtc_gamma_free(MetaKmsCrtcGamma * gamma)354 meta_kms_crtc_gamma_free (MetaKmsCrtcGamma *gamma)
355 {
356 g_free (gamma->red);
357 g_free (gamma->green);
358 g_free (gamma->blue);
359 g_free (gamma);
360 }
361
362 MetaKmsCrtcGamma *
meta_kms_crtc_gamma_new(MetaKmsCrtc * crtc,int size,const uint16_t * red,const uint16_t * green,const uint16_t * blue)363 meta_kms_crtc_gamma_new (MetaKmsCrtc *crtc,
364 int size,
365 const uint16_t *red,
366 const uint16_t *green,
367 const uint16_t *blue)
368 {
369 MetaKmsCrtcGamma *gamma;
370
371 gamma = g_new0 (MetaKmsCrtcGamma, 1);
372 *gamma = (MetaKmsCrtcGamma) {
373 .crtc = crtc,
374 .size = size,
375 .red = g_memdup2 (red, size * sizeof (*red)),
376 .green = g_memdup2 (green, size * sizeof (*green)),
377 .blue = g_memdup2 (blue, size * sizeof (*blue)),
378 };
379
380 return gamma;
381 }
382
383 void
meta_kms_update_set_crtc_gamma(MetaKmsUpdate * update,MetaKmsCrtc * crtc,int size,const uint16_t * red,const uint16_t * green,const uint16_t * blue)384 meta_kms_update_set_crtc_gamma (MetaKmsUpdate *update,
385 MetaKmsCrtc *crtc,
386 int size,
387 const uint16_t *red,
388 const uint16_t *green,
389 const uint16_t *blue)
390 {
391 MetaKmsCrtcGamma *gamma;
392
393 g_assert (!meta_kms_update_is_locked (update));
394 g_assert (meta_kms_crtc_get_device (crtc) == update->device);
395 g_assert (!update->power_save);
396
397 gamma = meta_kms_crtc_gamma_new (crtc, size, red, green, blue);
398
399 update->crtc_gammas = g_list_prepend (update->crtc_gammas, gamma);
400 }
401
402 void
meta_kms_update_add_page_flip_listener(MetaKmsUpdate * update,MetaKmsCrtc * crtc,const MetaKmsPageFlipListenerVtable * vtable,MetaKmsPageFlipListenerFlag flags,gpointer user_data,GDestroyNotify destroy_notify)403 meta_kms_update_add_page_flip_listener (MetaKmsUpdate *update,
404 MetaKmsCrtc *crtc,
405 const MetaKmsPageFlipListenerVtable *vtable,
406 MetaKmsPageFlipListenerFlag flags,
407 gpointer user_data,
408 GDestroyNotify destroy_notify)
409 {
410 MetaKmsPageFlipListener *listener;
411
412 g_assert (!meta_kms_update_is_locked (update));
413 g_assert (meta_kms_crtc_get_device (crtc) == update->device);
414
415 listener = g_new0 (MetaKmsPageFlipListener, 1);
416 *listener = (MetaKmsPageFlipListener) {
417 .crtc = crtc,
418 .vtable = vtable,
419 .flags = flags,
420 .user_data = user_data,
421 .destroy_notify = destroy_notify,
422 };
423
424 update->page_flip_listeners = g_list_prepend (update->page_flip_listeners,
425 listener);
426 }
427
428 void
meta_kms_update_drop_defunct_page_flip_listeners(MetaKmsUpdate * update)429 meta_kms_update_drop_defunct_page_flip_listeners (MetaKmsUpdate *update)
430 {
431 GList *l;
432
433 l = update->page_flip_listeners;
434 while (l)
435 {
436 MetaKmsPageFlipListener *listener = l->data;
437 GList *l_next = l->next;
438
439 if (listener->flags & META_KMS_PAGE_FLIP_LISTENER_FLAG_DROP_ON_ERROR)
440 {
441 meta_kms_page_flip_listener_free (listener);
442 update->page_flip_listeners =
443 g_list_delete_link (update->page_flip_listeners, l);
444 }
445
446 l = l_next;
447 }
448 }
449
450 void
meta_kms_update_set_custom_page_flip(MetaKmsUpdate * update,MetaKmsCustomPageFlipFunc func,gpointer user_data)451 meta_kms_update_set_custom_page_flip (MetaKmsUpdate *update,
452 MetaKmsCustomPageFlipFunc func,
453 gpointer user_data)
454 {
455 MetaKmsCustomPageFlip *custom_page_flip;
456
457 g_assert (!meta_kms_update_is_locked (update));
458 g_assert (!update->power_save);
459
460 custom_page_flip = g_new0 (MetaKmsCustomPageFlip, 1);
461 custom_page_flip->func = func;
462 custom_page_flip->user_data = user_data;
463
464 update->custom_page_flip = custom_page_flip;
465 }
466
467 void
meta_kms_plane_assignment_set_fb_damage(MetaKmsPlaneAssignment * plane_assignment,const int * rectangles,int n_rectangles)468 meta_kms_plane_assignment_set_fb_damage (MetaKmsPlaneAssignment *plane_assignment,
469 const int *rectangles,
470 int n_rectangles)
471 {
472 MetaKmsFbDamage *fb_damage;
473 struct drm_mode_rect *mode_rects;
474 int i;
475
476 mode_rects = g_new0 (struct drm_mode_rect, n_rectangles);
477 for (i = 0; i < n_rectangles; ++i)
478 {
479 mode_rects[i].x1 = rectangles[i * 4];
480 mode_rects[i].y1 = rectangles[i * 4 + 1];
481 mode_rects[i].x2 = mode_rects[i].x1 + rectangles[i * 4 + 2];
482 mode_rects[i].y2 = mode_rects[i].y1 + rectangles[i * 4 + 3];
483 }
484
485 fb_damage = g_new0 (MetaKmsFbDamage, 1);
486 *fb_damage = (MetaKmsFbDamage) {
487 .rects = mode_rects,
488 .n_rects = n_rectangles,
489 };
490
491 plane_assignment->fb_damage = fb_damage;
492 }
493
494 void
meta_kms_plane_assignment_set_rotation(MetaKmsPlaneAssignment * plane_assignment,uint64_t rotation)495 meta_kms_plane_assignment_set_rotation (MetaKmsPlaneAssignment *plane_assignment,
496 uint64_t rotation)
497 {
498 g_assert (!meta_kms_update_is_locked (plane_assignment->update));
499 g_warn_if_fail (rotation);
500
501 plane_assignment->rotation = rotation;
502 }
503
504 void
meta_kms_plane_assignment_set_cursor_hotspot(MetaKmsPlaneAssignment * plane_assignment,int x,int y)505 meta_kms_plane_assignment_set_cursor_hotspot (MetaKmsPlaneAssignment *plane_assignment,
506 int x,
507 int y)
508 {
509 plane_assignment->cursor_hotspot.is_valid = TRUE;
510 plane_assignment->cursor_hotspot.x = x;
511 plane_assignment->cursor_hotspot.y = y;
512 }
513
514 void
meta_kms_update_add_result_listener(MetaKmsUpdate * update,MetaKmsResultListenerFunc func,gpointer user_data)515 meta_kms_update_add_result_listener (MetaKmsUpdate *update,
516 MetaKmsResultListenerFunc func,
517 gpointer user_data)
518 {
519 MetaKmsResultListener *listener;
520
521 listener = g_new0 (MetaKmsResultListener, 1);
522 *listener = (MetaKmsResultListener) {
523 .func = func,
524 .user_data = user_data,
525 };
526
527 update->result_listeners = g_list_append (update->result_listeners,
528 listener);
529 }
530
531 GList *
meta_kms_update_take_result_listeners(MetaKmsUpdate * update)532 meta_kms_update_take_result_listeners (MetaKmsUpdate *update)
533 {
534 return g_steal_pointer (&update->result_listeners);
535 }
536
537 void
meta_kms_result_listener_notify(MetaKmsResultListener * listener,const MetaKmsFeedback * feedback)538 meta_kms_result_listener_notify (MetaKmsResultListener *listener,
539 const MetaKmsFeedback *feedback)
540 {
541 listener->func (feedback, listener->user_data);
542 }
543
544 void
meta_kms_result_listener_free(MetaKmsResultListener * listener)545 meta_kms_result_listener_free (MetaKmsResultListener *listener)
546 {
547 g_free (listener);
548 }
549
550 MetaKmsPlaneAssignment *
meta_kms_update_get_primary_plane_assignment(MetaKmsUpdate * update,MetaKmsCrtc * crtc)551 meta_kms_update_get_primary_plane_assignment (MetaKmsUpdate *update,
552 MetaKmsCrtc *crtc)
553 {
554 GList *l;
555
556 for (l = meta_kms_update_get_plane_assignments (update); l; l = l->next)
557 {
558 MetaKmsPlaneAssignment *plane_assignment = l->data;
559
560 if (meta_kms_plane_get_plane_type (plane_assignment->plane) !=
561 META_KMS_PLANE_TYPE_PRIMARY)
562 continue;
563
564 if (plane_assignment->crtc != crtc)
565 continue;
566
567 return plane_assignment;
568 }
569
570 return NULL;
571 }
572
573 GList *
meta_kms_update_get_plane_assignments(MetaKmsUpdate * update)574 meta_kms_update_get_plane_assignments (MetaKmsUpdate *update)
575 {
576 return update->plane_assignments;
577 }
578
579 GList *
meta_kms_update_get_mode_sets(MetaKmsUpdate * update)580 meta_kms_update_get_mode_sets (MetaKmsUpdate *update)
581 {
582 return update->mode_sets;
583 }
584
585 GList *
meta_kms_update_get_page_flip_listeners(MetaKmsUpdate * update)586 meta_kms_update_get_page_flip_listeners (MetaKmsUpdate *update)
587 {
588 return update->page_flip_listeners;
589 }
590
591 GList *
meta_kms_update_get_connector_updates(MetaKmsUpdate * update)592 meta_kms_update_get_connector_updates (MetaKmsUpdate *update)
593 {
594 return update->connector_updates;
595 }
596
597 GList *
meta_kms_update_get_crtc_gammas(MetaKmsUpdate * update)598 meta_kms_update_get_crtc_gammas (MetaKmsUpdate *update)
599 {
600 return update->crtc_gammas;
601 }
602
603 gboolean
meta_kms_update_is_power_save(MetaKmsUpdate * update)604 meta_kms_update_is_power_save (MetaKmsUpdate *update)
605 {
606 return update->power_save;
607 }
608
609 void
meta_kms_update_lock(MetaKmsUpdate * update)610 meta_kms_update_lock (MetaKmsUpdate *update)
611 {
612 update->is_locked = TRUE;
613 }
614
615 void
meta_kms_update_unlock(MetaKmsUpdate * update)616 meta_kms_update_unlock (MetaKmsUpdate *update)
617 {
618 update->is_locked = FALSE;
619 }
620
621 gboolean
meta_kms_update_is_locked(MetaKmsUpdate * update)622 meta_kms_update_is_locked (MetaKmsUpdate *update)
623 {
624 return update->is_locked;
625 }
626
627 MetaKmsDevice *
meta_kms_update_get_device(MetaKmsUpdate * update)628 meta_kms_update_get_device (MetaKmsUpdate *update)
629 {
630 return update->device;
631 }
632
633 MetaKmsCustomPageFlip *
meta_kms_update_take_custom_page_flip_func(MetaKmsUpdate * update)634 meta_kms_update_take_custom_page_flip_func (MetaKmsUpdate *update)
635 {
636 return g_steal_pointer (&update->custom_page_flip);
637 }
638
639 void
meta_kms_custom_page_flip_free(MetaKmsCustomPageFlip * custom_page_flip)640 meta_kms_custom_page_flip_free (MetaKmsCustomPageFlip *custom_page_flip)
641 {
642 g_free (custom_page_flip);
643 }
644
645 uint64_t
meta_kms_update_get_sequence_number(MetaKmsUpdate * update)646 meta_kms_update_get_sequence_number (MetaKmsUpdate *update)
647 {
648 return update->sequence_number;
649 }
650
651 MetaKmsUpdate *
meta_kms_update_new(MetaKmsDevice * device)652 meta_kms_update_new (MetaKmsDevice *device)
653 {
654 MetaKmsUpdate *update;
655 static uint64_t sequence_number = 0;
656
657 update = g_new0 (MetaKmsUpdate, 1);
658 update->device = device;
659 update->sequence_number = sequence_number++;
660
661 return update;
662 }
663
664 void
meta_kms_update_free(MetaKmsUpdate * update)665 meta_kms_update_free (MetaKmsUpdate *update)
666 {
667 g_list_free_full (update->result_listeners,
668 (GDestroyNotify) meta_kms_result_listener_free);
669 g_list_free_full (update->plane_assignments,
670 (GDestroyNotify) meta_kms_plane_assignment_free);
671 g_list_free_full (update->mode_sets,
672 (GDestroyNotify) meta_kms_mode_set_free);
673 g_list_free_full (update->page_flip_listeners,
674 (GDestroyNotify) meta_kms_page_flip_listener_free);
675 g_list_free_full (update->connector_updates, g_free);
676 g_list_free_full (update->crtc_gammas, (GDestroyNotify) meta_kms_crtc_gamma_free);
677 g_clear_pointer (&update->custom_page_flip, meta_kms_custom_page_flip_free);
678
679 g_free (update);
680 }
681