[mutter] kms: Only emit resources-changed signal if we recorded a change



commit a8d11161b6b4967b770c9c28be2ff0e07567a5aa
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Fri Jul 31 21:37:17 2020 +0200

    kms: Only emit resources-changed signal if we recorded a change
    
    Since we cache already all the KMS parameters we care about let's check at
    each device update if anything has really changed and only in such case
    emit a resources-changed signal.
    
    In this way we can also filter out the DRM parameters that when changed
    don't require a full monitors rebuild.
    
    Examples are the gamma settings or the privacy screen parameters, that
    emits an udev "hotplug" event when changed, but we want to register those
    only when we handle the changed property.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1964>

 src/backends/meta-output.c                        |  34 +++++
 src/backends/meta-output.h                        |   4 +
 src/backends/native/meta-gpu-kms.h                |   3 -
 src/backends/native/meta-kms-connector-private.h  |   4 +-
 src/backends/native/meta-kms-connector.c          | 154 ++++++++++++++++++++--
 src/backends/native/meta-kms-crtc-private.h       |   3 +-
 src/backends/native/meta-kms-crtc.c               | 133 ++++++++++++++-----
 src/backends/native/meta-kms-device-private.h     |   3 +-
 src/backends/native/meta-kms-device.c             |  10 +-
 src/backends/native/meta-kms-impl-device.c        |  46 +++++--
 src/backends/native/meta-kms-impl-device.h        |   2 +-
 src/backends/native/meta-kms-mode.c               |   2 +-
 src/backends/native/meta-kms-mode.h               |   3 +
 src/backends/native/meta-kms-types.h              |   7 +
 src/backends/native/meta-kms.c                    |  44 ++++---
 src/backends/native/meta-monitor-manager-native.c |   7 +-
 16 files changed, 365 insertions(+), 94 deletions(-)
---
diff --git a/src/backends/meta-output.c b/src/backends/meta-output.c
index 432697d6d9..36d8cc2273 100644
--- a/src/backends/meta-output.c
+++ b/src/backends/meta-output.c
@@ -463,3 +463,37 @@ meta_output_class_init (MetaOutputClass *klass)
                         G_PARAM_STATIC_STRINGS);
   g_object_class_install_properties (object_class, N_PROPS, obj_props);
 }
+
+gboolean
+meta_tile_info_equal (MetaTileInfo *a,
+                      MetaTileInfo *b)
+{
+  if (a == b)
+    return TRUE;
+
+  if (a->group_id != b->group_id)
+    return FALSE;
+
+  if (a->flags != b->flags)
+    return FALSE;
+
+  if (a->max_h_tiles != b->max_h_tiles)
+    return FALSE;
+
+  if (a->max_v_tiles != b->max_v_tiles)
+    return FALSE;
+
+  if (a->loc_h_tile != b->loc_h_tile)
+    return FALSE;
+
+  if (a->loc_v_tile != b->loc_v_tile)
+    return FALSE;
+
+  if (a->tile_w != b->tile_w)
+    return FALSE;
+
+  if (a->tile_h != b->tile_h)
+    return FALSE;
+
+  return TRUE;
+}
diff --git a/src/backends/meta-output.h b/src/backends/meta-output.h
index b96c118d81..cc055881c3 100644
--- a/src/backends/meta-output.h
+++ b/src/backends/meta-output.h
@@ -106,6 +106,10 @@ typedef struct _MetaOutputInfo
   MetaTileInfo tile_info;
 } MetaOutputInfo;
 
+gboolean
+meta_tile_info_equal (MetaTileInfo *a,
+                      MetaTileInfo *b);
+
 #define META_TYPE_OUTPUT_INFO (meta_output_info_get_type ())
 META_EXPORT_TEST
 GType meta_output_info_get_type (void);
diff --git a/src/backends/native/meta-gpu-kms.h b/src/backends/native/meta-gpu-kms.h
index 06f6e100a7..e6f8b3e879 100644
--- a/src/backends/native/meta-gpu-kms.h
+++ b/src/backends/native/meta-gpu-kms.h
@@ -62,9 +62,6 @@ void meta_gpu_kms_set_power_save_mode (MetaGpuKms    *gpu_kms,
 MetaCrtcMode * meta_gpu_kms_get_mode_from_kms_mode (MetaGpuKms  *gpu_kms,
                                                     MetaKmsMode *kms_mode);
 
-gboolean meta_drm_mode_equal (const drmModeModeInfo *one,
-                              const drmModeModeInfo *two);
-
 MetaGpuKmsFlipClosureContainer * meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms,
                                                                  MetaCrtc   *crtc,
                                                                  GClosure   *flip_closure);
diff --git a/src/backends/native/meta-kms-connector-private.h 
b/src/backends/native/meta-kms-connector-private.h
index 9accf8ccdb..77f9e476a0 100644
--- a/src/backends/native/meta-kms-connector-private.h
+++ b/src/backends/native/meta-kms-connector-private.h
@@ -38,8 +38,8 @@ uint32_t meta_kms_connector_get_prop_id (MetaKmsConnector     *connector,
 const char * meta_kms_connector_get_prop_name (MetaKmsConnector     *connector,
                                                MetaKmsConnectorProp  prop);
 
-void meta_kms_connector_update_state (MetaKmsConnector *connector,
-                                      drmModeRes       *drm_resources);
+MetaKmsUpdateChanges meta_kms_connector_update_state (MetaKmsConnector *connector,
+                                                      drmModeRes       *drm_resources);
 
 void meta_kms_connector_predict_state (MetaKmsConnector *connector,
                                        MetaKmsUpdate    *update);
diff --git a/src/backends/native/meta-kms-connector.c b/src/backends/native/meta-kms-connector.c
index a666bb45cb..01b5720190 100644
--- a/src/backends/native/meta-kms-connector.c
+++ b/src/backends/native/meta-kms-connector.c
@@ -46,6 +46,7 @@ struct _MetaKmsConnector
   uint32_t type_id;
   char *name;
 
+  drmModeConnection connection;
   MetaKmsConnectorState *current_state;
 
   MetaKmsConnectorPropTable prop_table;
@@ -467,18 +468,116 @@ meta_kms_connector_state_free (MetaKmsConnectorState *state)
   g_free (state);
 }
 
-static void
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaKmsConnectorState,
+                               meta_kms_connector_state_free);
+
+static gboolean
+kms_modes_equal (GList *modes,
+                 GList *other_modes)
+{
+  GList *l;
+
+  if (g_list_length (modes) != g_list_length (other_modes))
+    return FALSE;
+
+  for (l = modes; l; l = l->next)
+    {
+      GList *k;
+      MetaKmsMode *mode = l->data;
+
+      for (k = other_modes; k; k = k->next)
+        {
+          MetaKmsMode *other_mode = k->data;
+
+          if (!meta_kms_mode_equal (mode, other_mode))
+            return FALSE;
+        }
+    }
+
+  return TRUE;
+}
+
+static MetaKmsUpdateChanges
+meta_kms_connector_state_changes (MetaKmsConnectorState *state,
+                                  MetaKmsConnectorState *new_state)
+{
+  if (state->current_crtc_id != new_state->current_crtc_id)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->common_possible_crtcs != new_state->common_possible_crtcs)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->common_possible_clones != new_state->common_possible_clones)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->encoder_device_idxs != new_state->encoder_device_idxs)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->width_mm != new_state->width_mm)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->height_mm != new_state->height_mm)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->has_scaling != new_state->has_scaling)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->non_desktop != new_state->non_desktop)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->subpixel_order != new_state->subpixel_order)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->suggested_x != new_state->suggested_x)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->suggested_y != new_state->suggested_y)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->hotplug_mode_update != new_state->hotplug_mode_update)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->panel_orientation_transform !=
+      new_state->panel_orientation_transform)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (!meta_tile_info_equal (&state->tile_info, &new_state->tile_info))
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if ((state->edid_data && !new_state->edid_data) || !state->edid_data ||
+      !g_bytes_equal (state->edid_data, new_state->edid_data))
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (!kms_modes_equal (state->modes, new_state->modes))
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  return META_KMS_UPDATE_CHANGE_NONE;
+}
+
+static MetaKmsUpdateChanges
 meta_kms_connector_read_state (MetaKmsConnector  *connector,
                                MetaKmsImplDevice *impl_device,
                                drmModeConnector  *drm_connector,
                                drmModeRes        *drm_resources)
 {
-  MetaKmsConnectorState *state;
+  g_autoptr (MetaKmsConnectorState) state = NULL;
+  g_autoptr (MetaKmsConnectorState) current_state = NULL;
+  MetaKmsUpdateChanges connector_changes;
+  MetaKmsUpdateChanges changes;
 
-  g_clear_pointer (&connector->current_state, meta_kms_connector_state_free);
+  current_state = g_steal_pointer (&connector->current_state);
+  changes = META_KMS_UPDATE_CHANGE_NONE;
 
-  if (!drm_connector || drm_connector->connection != DRM_MODE_CONNECTED)
-    return;
+  if (drm_connector->connection != DRM_MODE_CONNECTED)
+    {
+      if (drm_connector->connection != connector->connection)
+        {
+          connector->connection = drm_connector->connection;
+          changes |= META_KMS_UPDATE_CHANGE_FULL;
+        }
+
+      return changes;
+    }
 
   state = meta_kms_connector_state_new ();
 
@@ -495,26 +594,54 @@ meta_kms_connector_read_state (MetaKmsConnector  *connector,
 
   state_set_crtc_state (state, drm_connector, impl_device, drm_resources);
 
-  connector->current_state = state;
+  if (drm_connector->connection != connector->connection)
+    {
+      connector->connection = drm_connector->connection;
+      changes |= META_KMS_UPDATE_CHANGE_FULL;
+    }
 
-  sync_fd_held (connector, impl_device);
+  if (!current_state)
+    connector_changes = META_KMS_UPDATE_CHANGE_FULL;
+  else
+    connector_changes = meta_kms_connector_state_changes (current_state, state);
+
+  if (connector_changes == META_KMS_UPDATE_CHANGE_NONE)
+    {
+      connector->current_state = g_steal_pointer (&current_state);
+    }
+  else
+    {
+      connector->current_state = g_steal_pointer (&state);
+      changes |= connector_changes;
+    }
+
+  if (changes != META_KMS_UPDATE_CHANGE_NONE)
+    sync_fd_held (connector, impl_device);
+
+  return changes;
 }
 
-void
+MetaKmsUpdateChanges
 meta_kms_connector_update_state (MetaKmsConnector *connector,
                                  drmModeRes       *drm_resources)
 {
   MetaKmsImplDevice *impl_device;
   drmModeConnector *drm_connector;
+  MetaKmsUpdateChanges changes;
 
   impl_device = meta_kms_device_get_impl_device (connector->device);
   drm_connector = drmModeGetConnector (meta_kms_impl_device_get_fd (impl_device),
                                        connector->id);
-  meta_kms_connector_read_state (connector, impl_device,
-                                 drm_connector,
-                                 drm_resources);
-  if (drm_connector)
-    drmModeFreeConnector (drm_connector);
+
+  if (!drm_connector)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  changes = meta_kms_connector_read_state (connector, impl_device,
+                                           drm_connector,
+                                           drm_resources);
+  drmModeFreeConnector (drm_connector);
+
+  return changes;
 }
 
 void
@@ -651,6 +778,7 @@ meta_kms_connector_new (MetaKmsImplDevice *impl_device,
 {
   MetaKmsConnector *connector;
 
+  g_assert (drm_connector);
   connector = g_object_new (META_TYPE_KMS_CONNECTOR, NULL);
   connector->device = meta_kms_impl_device_get_device (impl_device);
   connector->id = drm_connector->connector_id;
diff --git a/src/backends/native/meta-kms-crtc-private.h b/src/backends/native/meta-kms-crtc-private.h
index 60c5fd3095..f91731a002 100644
--- a/src/backends/native/meta-kms-crtc-private.h
+++ b/src/backends/native/meta-kms-crtc-private.h
@@ -23,6 +23,7 @@
 #include <xf86drmMode.h>
 
 #include "backends/native/meta-kms-crtc.h"
+#include "backends/native/meta-kms-update-private.h"
 
 typedef enum _MetaKmsCrtcProp
 {
@@ -37,7 +38,7 @@ MetaKmsCrtc * meta_kms_crtc_new (MetaKmsImplDevice  *impl_device,
                                  int                 idx,
                                  GError            **error);
 
-void meta_kms_crtc_update_state (MetaKmsCrtc *crtc);
+MetaKmsUpdateChanges meta_kms_crtc_update_state (MetaKmsCrtc *crtc);
 
 void meta_kms_crtc_predict_state (MetaKmsCrtc   *crtc,
                                   MetaKmsUpdate *update);
diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c
index 51d040b440..3e05060263 100644
--- a/src/backends/native/meta-kms-crtc.c
+++ b/src/backends/native/meta-kms-crtc.c
@@ -94,32 +94,62 @@ meta_kms_crtc_is_active (MetaKmsCrtc *crtc)
 
 static void
 read_gamma_state (MetaKmsCrtc       *crtc,
+                  MetaKmsCrtcState  *crtc_state,
                   MetaKmsImplDevice *impl_device,
                   drmModeCrtc       *drm_crtc)
 {
-  MetaKmsCrtcState *current_state = &crtc->current_state;
-
-  if (current_state->gamma.size != drm_crtc->gamma_size)
+  if (crtc_state->gamma.size != drm_crtc->gamma_size)
     {
-      current_state->gamma.size = drm_crtc->gamma_size;
-
-      current_state->gamma.red = g_realloc_n (current_state->gamma.red,
-                                              drm_crtc->gamma_size,
-                                              sizeof (uint16_t));
-      current_state->gamma.green = g_realloc_n (current_state->gamma.green,
-                                                drm_crtc->gamma_size,
-                                                sizeof (uint16_t));
-      current_state->gamma.blue = g_realloc_n (current_state->gamma.blue,
-                                               drm_crtc->gamma_size,
-                                               sizeof (uint16_t));
+      crtc_state->gamma.size = drm_crtc->gamma_size;
+
+      crtc_state->gamma.red = g_realloc_n (crtc_state->gamma.red,
+                                           drm_crtc->gamma_size,
+                                           sizeof (uint16_t));
+      crtc_state->gamma.green = g_realloc_n (crtc_state->gamma.green,
+                                             drm_crtc->gamma_size,
+                                             sizeof (uint16_t));
+      crtc_state->gamma.blue = g_realloc_n (crtc_state->gamma.blue,
+                                            drm_crtc->gamma_size,
+                                            sizeof (uint16_t));
     }
 
   drmModeCrtcGetGamma (meta_kms_impl_device_get_fd (impl_device),
                        crtc->id,
-                       current_state->gamma.size,
-                       current_state->gamma.red,
-                       current_state->gamma.green,
-                       current_state->gamma.blue);
+                       crtc_state->gamma.size,
+                       crtc_state->gamma.red,
+                       crtc_state->gamma.green,
+                       crtc_state->gamma.blue);
+}
+
+static MetaKmsUpdateChanges
+meta_kms_crtc_state_changes (MetaKmsCrtcState *state,
+                             MetaKmsCrtcState *other_state)
+{
+  if (!meta_rectangle_equal (&state->rect, &other_state->rect))
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->is_drm_mode_valid != other_state->is_drm_mode_valid)
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (!meta_drm_mode_equal (&state->drm_mode, &other_state->drm_mode))
+    return META_KMS_UPDATE_CHANGE_FULL;
+
+  if (state->gamma.size != other_state->gamma.size)
+    return META_KMS_UPDATE_CHANGE_GAMMA;
+
+  if (memcmp (state->gamma.blue, other_state->gamma.blue,
+              state->gamma.size * sizeof (uint16_t)) != 0)
+    return META_KMS_UPDATE_CHANGE_GAMMA;
+
+  if (memcmp (state->gamma.green, other_state->gamma.green,
+              state->gamma.size * sizeof (uint16_t)) != 0)
+    return META_KMS_UPDATE_CHANGE_GAMMA;
+
+  if (memcmp (state->gamma.red, other_state->gamma.red,
+              state->gamma.size * sizeof (uint16_t)) != 0)
+    return META_KMS_UPDATE_CHANGE_GAMMA;
+
+  return META_KMS_UPDATE_CHANGE_NONE;
 }
 
 static int
@@ -141,23 +171,35 @@ find_prop_idx (MetaKmsProp *prop,
 }
 
 static void
+clear_gamma_state (MetaKmsCrtcState *crtc_state)
+{
+  crtc_state->gamma.size = 0;
+  g_clear_pointer (&crtc_state->gamma.red, g_free);
+  g_clear_pointer (&crtc_state->gamma.green, g_free);
+  g_clear_pointer (&crtc_state->gamma.blue, g_free);
+}
+
+static MetaKmsUpdateChanges
 meta_kms_crtc_read_state (MetaKmsCrtc             *crtc,
                           MetaKmsImplDevice       *impl_device,
                           drmModeCrtc             *drm_crtc,
                           drmModeObjectProperties *drm_props)
 {
+  MetaKmsCrtcState crtc_state = {0};
+  MetaKmsUpdateChanges changes = META_KMS_UPDATE_CHANGE_NONE;
   MetaKmsProp *active_prop;
   int active_idx;
 
-  crtc->current_state.rect = (MetaRectangle) {
+  crtc_state.rect = (MetaRectangle) {
     .x = drm_crtc->x,
     .y = drm_crtc->y,
     .width = drm_crtc->width,
     .height = drm_crtc->height,
   };
 
-  crtc->current_state.is_drm_mode_valid = drm_crtc->mode_valid;
-  crtc->current_state.drm_mode = drm_crtc->mode;
+  crtc_state.is_drm_mode_valid = drm_crtc->mode_valid;
+  crtc_state.drm_mode = drm_crtc->mode;
+  crtc_state.gamma.size = 0;
 
   active_prop = &crtc->prop_table.props[META_KMS_CRTC_PROP_ACTIVE];
   if (active_prop->prop_id)
@@ -165,13 +207,36 @@ meta_kms_crtc_read_state (MetaKmsCrtc             *crtc,
       active_idx = find_prop_idx (active_prop,
                                   drm_props->props,
                                   drm_props->count_props);
-      crtc->current_state.is_active = !!drm_props->prop_values[active_idx];
+      crtc_state.is_active = !!drm_props->prop_values[active_idx];
     }
   else
     {
-      crtc->current_state.is_active = drm_crtc->mode_valid;
+      crtc_state.is_active = drm_crtc->mode_valid;
+    }
+
+  if (crtc_state.is_active != crtc->current_state.is_active)
+    {
+      changes |= META_KMS_UPDATE_CHANGE_FULL;
+    }
+  else if (!crtc_state.is_active)
+    {
+      clear_gamma_state (&crtc_state);
+      return changes;
+    }
+
+  read_gamma_state (crtc, &crtc_state, impl_device, drm_crtc);
+
+  changes |= meta_kms_crtc_state_changes (&crtc->current_state, &crtc_state);
+
+  if (changes == META_KMS_UPDATE_CHANGE_NONE)
+    {
+      clear_gamma_state (&crtc_state);
+      return changes;
     }
 
+  clear_gamma_state (&crtc->current_state);
+  crtc->current_state = crtc_state;
+
   meta_topic (META_DEBUG_KMS,
               "Read CRTC %u state: active: %d, mode: %s",
               crtc->id, crtc->current_state.is_active,
@@ -179,13 +244,14 @@ meta_kms_crtc_read_state (MetaKmsCrtc             *crtc,
                 ? crtc->current_state.drm_mode.name
                 : "(nil)");
 
-  read_gamma_state (crtc, impl_device, drm_crtc);
+  return changes;
 }
 
-void
+MetaKmsUpdateChanges
 meta_kms_crtc_update_state (MetaKmsCrtc *crtc)
 {
   MetaKmsImplDevice *impl_device;
+  MetaKmsUpdateChanges changes;
   int fd;
   drmModeCrtc *drm_crtc;
   drmModeObjectProperties *drm_props;
@@ -201,23 +267,17 @@ meta_kms_crtc_update_state (MetaKmsCrtc *crtc)
       crtc->current_state.is_active = FALSE;
       crtc->current_state.rect = (MetaRectangle) { };
       crtc->current_state.is_drm_mode_valid = FALSE;
+      changes = META_KMS_UPDATE_CHANGE_FULL;
       goto out;
     }
 
-  meta_kms_crtc_read_state (crtc, impl_device, drm_crtc, drm_props);
+  changes = meta_kms_crtc_read_state (crtc, impl_device, drm_crtc, drm_props);
 
 out:
   g_clear_pointer (&drm_props, drmModeFreeObjectProperties);
   g_clear_pointer (&drm_crtc, drmModeFreeCrtc);
-}
 
-static void
-clear_gamma_state (MetaKmsCrtc *crtc)
-{
-  crtc->current_state.gamma.size = 0;
-  g_clear_pointer (&crtc->current_state.gamma.red, g_free);
-  g_clear_pointer (&crtc->current_state.gamma.green, g_free);
-  g_clear_pointer (&crtc->current_state.gamma.blue, g_free);
+  return changes;
 }
 
 void
@@ -270,7 +330,7 @@ meta_kms_crtc_predict_state (MetaKmsCrtc   *crtc,
       if (gamma->crtc != crtc)
         continue;
 
-      clear_gamma_state (crtc);
+      clear_gamma_state (&crtc->current_state);
       crtc->current_state.gamma.size = gamma->size;
       crtc->current_state.gamma.red =
         g_memdup2 (gamma->red, gamma->size * sizeof (uint16_t));
@@ -380,7 +440,7 @@ meta_kms_crtc_finalize (GObject *object)
 {
   MetaKmsCrtc *crtc = META_KMS_CRTC (object);
 
-  clear_gamma_state (crtc);
+  clear_gamma_state (&crtc->current_state);
 
   G_OBJECT_CLASS (meta_kms_crtc_parent_class)->finalize (object);
 }
@@ -388,6 +448,7 @@ meta_kms_crtc_finalize (GObject *object)
 static void
 meta_kms_crtc_init (MetaKmsCrtc *crtc)
 {
+  crtc->current_state.gamma.size = 0;
 }
 
 static void
diff --git a/src/backends/native/meta-kms-device-private.h b/src/backends/native/meta-kms-device-private.h
index 41e05a2f70..831f7820a6 100644
--- a/src/backends/native/meta-kms-device-private.h
+++ b/src/backends/native/meta-kms-device-private.h
@@ -21,10 +21,11 @@
 #define META_KMS_DEVICE_PRIVATE_H
 
 #include "backends/native/meta-kms-types.h"
+#include "backends/native/meta-kms-update-private.h"
 
 MetaKmsImplDevice * meta_kms_device_get_impl_device (MetaKmsDevice *device);
 
-void meta_kms_device_update_states_in_impl (MetaKmsDevice *device);
+MetaKmsUpdateChanges meta_kms_device_update_states_in_impl (MetaKmsDevice *device);
 
 void meta_kms_device_predict_states_in_impl (MetaKmsDevice *device,
                                              MetaKmsUpdate *update);
diff --git a/src/backends/native/meta-kms-device.c b/src/backends/native/meta-kms-device.c
index b4d3e58024..beb2360e62 100644
--- a/src/backends/native/meta-kms-device.c
+++ b/src/backends/native/meta-kms-device.c
@@ -186,15 +186,19 @@ meta_kms_device_get_fallback_modes (MetaKmsDevice *device)
   return device->fallback_modes;
 }
 
-void
+MetaKmsUpdateChanges
 meta_kms_device_update_states_in_impl (MetaKmsDevice *device)
 {
   MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
+  MetaKmsUpdateChanges changes;
 
   meta_assert_in_kms_impl (device->kms);
   meta_assert_is_waiting_for_kms_impl_task (device->kms);
 
-  meta_kms_impl_device_update_states (impl_device);
+  changes = meta_kms_impl_device_update_states (impl_device);
+
+  if (changes == META_KMS_UPDATE_CHANGE_NONE)
+    return changes;
 
   g_list_free (device->crtcs);
   device->crtcs = meta_kms_impl_device_copy_crtcs (impl_device);
@@ -204,6 +208,8 @@ meta_kms_device_update_states_in_impl (MetaKmsDevice *device)
 
   g_list_free (device->planes);
   device->planes = meta_kms_impl_device_copy_planes (impl_device);
+
+  return changes;
 }
 
 void
diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c
index e08e672e5e..e616ffd2ae 100644
--- a/src/backends/native/meta-kms-impl-device.c
+++ b/src/backends/native/meta-kms-impl-device.c
@@ -36,7 +36,6 @@
 #include "backends/native/meta-kms-plane-private.h"
 #include "backends/native/meta-kms-plane.h"
 #include "backends/native/meta-kms-private.h"
-#include "backends/native/meta-kms-update-private.h"
 
 #include "meta-default-modes.h"
 #include "meta-private-enum-types.h"
@@ -390,13 +389,14 @@ find_existing_connector (MetaKmsImplDevice *impl_device,
   return NULL;
 }
 
-static void
+static MetaKmsUpdateChanges
 update_connectors (MetaKmsImplDevice *impl_device,
                    drmModeRes        *drm_resources)
 {
   MetaKmsImplDevicePrivate *priv =
     meta_kms_impl_device_get_instance_private (impl_device);
-  GList *connectors = NULL;
+  g_autolist (MetaKmsConnector) connectors = NULL;
+  gboolean needs_full_change = FALSE;
   unsigned int i;
   int fd;
 
@@ -413,17 +413,28 @@ update_connectors (MetaKmsImplDevice *impl_device,
 
       connector = find_existing_connector (impl_device, drm_connector);
       if (connector)
-        connector = g_object_ref (connector);
+        {
+          connector = g_object_ref (connector);
+        }
       else
-        connector = meta_kms_connector_new (impl_device, drm_connector,
-                                            drm_resources);
+        {
+          connector = meta_kms_connector_new (impl_device, drm_connector,
+                                              drm_resources);
+          needs_full_change = TRUE;
+        }
+
       drmModeFreeConnector (drm_connector);
 
       connectors = g_list_prepend (connectors, connector);
     }
 
+  if (!needs_full_change)
+    return META_KMS_UPDATE_CHANGE_NONE;
+
   g_list_free_full (priv->connectors, g_object_unref);
-  priv->connectors = g_list_reverse (connectors);
+  priv->connectors = g_list_reverse (g_steal_pointer (&connectors));
+
+  return META_KMS_UPDATE_CHANGE_FULL;
 }
 
 static MetaKmsPlaneType
@@ -690,7 +701,7 @@ clear_latched_fd_hold (MetaKmsImplDevice *impl_device)
     }
 }
 
-void
+MetaKmsUpdateChanges
 meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device)
 {
   MetaKmsImplDevicePrivate *priv =
@@ -698,6 +709,8 @@ meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device)
   g_autoptr (GError) error = NULL;
   int fd;
   drmModeRes *drm_resources;
+  MetaKmsUpdateChanges changes;
+  GList *l;
 
   meta_assert_in_kms_impl (meta_kms_impl_get_kms (priv->impl));
 
@@ -720,20 +733,25 @@ meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device)
       goto err;
     }
 
-  update_connectors (impl_device, drm_resources);
+  changes = update_connectors (impl_device, drm_resources);
+
+  for (l = priv->crtcs; l; l = l->next)
+    changes |= meta_kms_crtc_update_state (META_KMS_CRTC (l->data));
+
+  for (l = priv->connectors; l; l = l->next)
+    changes |= meta_kms_connector_update_state (META_KMS_CONNECTOR (l->data),
+                                                drm_resources);
 
-  g_list_foreach (priv->crtcs, (GFunc) meta_kms_crtc_update_state,
-                  NULL);
-  g_list_foreach (priv->connectors, (GFunc) meta_kms_connector_update_state,
-                  drm_resources);
   drmModeFreeResources (drm_resources);
 
-  return;
+  return changes;
 
 err:
   g_clear_list (&priv->planes, g_object_unref);
   g_clear_list (&priv->crtcs, g_object_unref);
   g_clear_list (&priv->connectors, g_object_unref);
+
+  return META_KMS_UPDATE_CHANGE_FULL;
 }
 
 void
diff --git a/src/backends/native/meta-kms-impl-device.h b/src/backends/native/meta-kms-impl-device.h
index e77024ecd6..caddae3c14 100644
--- a/src/backends/native/meta-kms-impl-device.h
+++ b/src/backends/native/meta-kms-impl-device.h
@@ -135,7 +135,7 @@ void meta_kms_impl_device_hold_fd (MetaKmsImplDevice *impl_device);
 
 void meta_kms_impl_device_unhold_fd (MetaKmsImplDevice *impl_device);
 
-void meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device);
+MetaKmsUpdateChanges meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device);
 
 void meta_kms_impl_device_predict_states (MetaKmsImplDevice *impl_device,
                                           MetaKmsUpdate     *update);
diff --git a/src/backends/native/meta-kms-mode.c b/src/backends/native/meta-kms-mode.c
index 7094cd0dab..a52451620f 100644
--- a/src/backends/native/meta-kms-mode.c
+++ b/src/backends/native/meta-kms-mode.c
@@ -73,7 +73,7 @@ meta_kms_mode_get_drm_mode (MetaKmsMode *mode)
   return &mode->drm_mode;
 }
 
-static gboolean
+gboolean
 meta_drm_mode_equal (const drmModeModeInfo *one,
                      const drmModeModeInfo *two)
 {
diff --git a/src/backends/native/meta-kms-mode.h b/src/backends/native/meta-kms-mode.h
index 40e844796a..f9a4477a44 100644
--- a/src/backends/native/meta-kms-mode.h
+++ b/src/backends/native/meta-kms-mode.h
@@ -42,6 +42,9 @@ const drmModeModeInfo * meta_kms_mode_get_drm_mode (MetaKmsMode *mode);
 gboolean meta_kms_mode_equal (MetaKmsMode *mode,
                               MetaKmsMode *other_mode);
 
+gboolean meta_drm_mode_equal (const drmModeModeInfo *one,
+                              const drmModeModeInfo *two);
+
 unsigned int meta_kms_mode_hash (MetaKmsMode *mode);
 
 #endif /* META_KMS_MODE_H */
diff --git a/src/backends/native/meta-kms-types.h b/src/backends/native/meta-kms-types.h
index 5786ff51fb..64045ef457 100644
--- a/src/backends/native/meta-kms-types.h
+++ b/src/backends/native/meta-kms-types.h
@@ -64,6 +64,13 @@ typedef enum _MetaKmsDeviceFlag
   META_KMS_DEVICE_FLAG_NO_MODE_SETTING = 1 << 4,
 } MetaKmsDeviceFlag;
 
+typedef enum _MetaKmsUpdateChanges
+{
+  META_KMS_UPDATE_CHANGE_NONE = 0,
+  META_KMS_UPDATE_CHANGE_GAMMA = 1 << 0,
+  META_KMS_UPDATE_CHANGE_FULL = -1,
+} MetaKmsUpdateChanges;
+
 typedef enum _MetaKmsPlaneType MetaKmsPlaneType;
 
 typedef enum _MetaKmsPropType
diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c
index 70feccc223..6676db3e75 100644
--- a/src/backends/native/meta-kms.c
+++ b/src/backends/native/meta-kms.c
@@ -29,6 +29,8 @@
 #include "backends/native/meta-udev.h"
 #include "cogl/cogl.h"
 
+#include "meta-private-enum-types.h"
+
 /**
  * SECTION:kms
  * @short description: KMS abstraction
@@ -563,17 +565,25 @@ meta_kms_is_waiting_for_impl_task (MetaKms *kms)
   return kms->waiting_for_impl_task;
 }
 
-static void
-meta_kms_update_states_in_impl (MetaKms *kms)
+static MetaKmsUpdateChanges
+meta_kms_update_states_in_impl (MetaKms  *kms)
 {
+  MetaKmsUpdateChanges changes = META_KMS_UPDATE_CHANGE_NONE;
+  GList *l;
+
   COGL_TRACE_BEGIN_SCOPED (MetaKmsUpdateStates,
                            "KMS (update states)");
 
   meta_assert_in_kms_impl (kms);
 
-  g_list_foreach (kms->devices,
-                  (GFunc) meta_kms_device_update_states_in_impl,
-                  NULL);
+  for (l = kms->devices; l; l = l->next)
+    {
+      MetaKmsDevice *kms_device = META_KMS_DEVICE (l->data);
+
+      changes |= meta_kms_device_update_states_in_impl (kms_device);
+    }
+
+  return changes;
 }
 
 static gpointer
@@ -583,30 +593,27 @@ update_states_in_impl (MetaKmsImpl  *impl,
 {
   MetaKms *kms = meta_kms_impl_get_kms (impl);
 
-  meta_kms_update_states_in_impl (kms);
-
-  return GINT_TO_POINTER (TRUE);
+  return GUINT_TO_POINTER (meta_kms_update_states_in_impl (kms));
 }
 
-static gboolean
-meta_kms_update_states_sync (MetaKms  *kms,
-                             GError  **error)
+static MetaKmsUpdateChanges
+meta_kms_update_states_sync (MetaKms  *kms)
 {
   gpointer ret;
 
-  ret = meta_kms_run_impl_task_sync (kms, update_states_in_impl, NULL, error);
-  return GPOINTER_TO_INT (ret);
+  ret = meta_kms_run_impl_task_sync (kms, update_states_in_impl, NULL, NULL);
+  return GPOINTER_TO_UINT (ret);
 }
 
 static void
 handle_hotplug_event (MetaKms *kms)
 {
-  g_autoptr (GError) error = NULL;
+  MetaKmsUpdateChanges changes;
 
-  if (!meta_kms_update_states_sync (kms, &error))
-    g_warning ("Updating KMS state failed: %s", error->message);
+  changes = meta_kms_update_states_sync (kms);
 
-  g_signal_emit (kms, signals[RESOURCES_CHANGED], 0);
+  if (changes != META_KMS_UPDATE_CHANGE_NONE)
+    g_signal_emit (kms, signals[RESOURCES_CHANGED], 0, changes);
 }
 
 void
@@ -750,5 +757,6 @@ meta_kms_class_init (MetaKmsClass *klass)
                   G_SIGNAL_RUN_LAST,
                   0,
                   NULL, NULL, NULL,
-                  G_TYPE_NONE, 0);
+                  G_TYPE_NONE, 1,
+                  META_TYPE_KMS_UPDATE_CHANGES);
 }
diff --git a/src/backends/native/meta-monitor-manager-native.c 
b/src/backends/native/meta-monitor-manager-native.c
index 2d598af12b..d76972df85 100644
--- a/src/backends/native/meta-monitor-manager-native.c
+++ b/src/backends/native/meta-monitor-manager-native.c
@@ -508,9 +508,12 @@ handle_hotplug_event (MetaMonitorManager *manager)
 }
 
 static void
-on_kms_resources_changed (MetaKms            *kms,
-                          MetaMonitorManager *manager)
+on_kms_resources_changed (MetaKms              *kms,
+                          MetaKmsUpdateChanges  changes,
+                          MetaMonitorManager   *manager)
 {
+  g_assert (changes != META_KMS_UPDATE_CHANGE_NONE);
+
   handle_hotplug_event (manager);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]