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