[mutter] color-device: Pass calibration state separately when creating profile



commit 9aa9cacb3d9f1038e420feeeaffe89663e8f5f0b
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Tue Aug 30 23:30:35 2022 +0200

    color-device: Pass calibration state separately when creating profile
    
    This allows using two separate ICC profiles for one "color profile",
    which is necessary to properly support color transform
    calibration profiles from an EFI variable.
    
    These types of profiles are intended to be applied using the color
    transformation matrix (CTM) property on the output, which makes the
    presented output match sRGB. In order to avoid color profile aware
    clients making the wrong assumption, we must set the profile exposed
    externally to be what is the expected perceived result, i.e. sRGB, while
    still applying CTM from the real ICC profile.
    
    The separation is done by introducing a MetaColorCalibration struct,
    that is filled with relevant data. For profiles coming from EFI, a
    created profile is practically an sRGB one, but the calibration data
    comes from EFI, while for other profiles, the calibration data and the
    ICC profile itself come from the same source.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2568>

 src/backends/meta-color-device.c          |  89 +++++++++++++---
 src/backends/meta-color-profile.c         |  92 ++++++++++++----
 src/backends/meta-color-profile.h         |  36 +++++--
 src/backends/meta-color-store.c           |  10 +-
 src/backends/x11/meta-color-manager-x11.c | 146 +++++---------------------
 src/tests/color-management-tests.c        | 169 ++++++++++++++++++++++++++++++
 6 files changed, 373 insertions(+), 169 deletions(-)
---
diff --git a/src/backends/meta-color-device.c b/src/backends/meta-color-device.c
index 4641616a1e..f8240606ac 100644
--- a/src/backends/meta-color-device.c
+++ b/src/backends/meta-color-device.c
@@ -612,6 +612,8 @@ typedef struct
   char *file_path;
   GBytes *bytes;
   CdIcc *cd_icc;
+
+  MetaColorCalibration *color_calibration;
 } GenerateProfileData;
 
 static void
@@ -620,6 +622,7 @@ generate_profile_data_free (GenerateProfileData *data)
   g_free (data->file_path);
   g_clear_object (&data->cd_icc);
   g_clear_pointer (&data->bytes, g_bytes_unref);
+  g_clear_pointer (&data->color_calibration, meta_color_calibration_free);
   g_free (data);
 }
 
@@ -655,7 +658,8 @@ on_profile_written (GObject      *source_object,
   color_profile =
     meta_color_profile_new_from_icc (color_manager,
                                      g_steal_pointer (&data->cd_icc),
-                                     g_steal_pointer (&data->bytes));
+                                     g_steal_pointer (&data->bytes),
+                                     g_steal_pointer (&data->color_calibration));
   g_task_return_pointer (task, color_profile, g_object_unref);
 }
 
@@ -939,6 +943,8 @@ create_device_profile_from_edid (MetaColorDevice *color_device,
       cd_icc_add_metadata (cd_icc, CD_PROFILE_METADATA_FILE_CHECKSUM,
                            file_md5_checksum);
 
+      data->color_calibration =
+        meta_color_calibration_new (cd_icc, NULL);
       data->cd_icc = g_steal_pointer (&cd_icc);
       data->bytes = bytes;
       save_icc_profile (file_path, task);
@@ -951,6 +957,16 @@ create_device_profile_from_edid (MetaColorDevice *color_device,
     }
 }
 
+static void
+set_icc_checksum (CdIcc  *cd_icc,
+                  GBytes *bytes)
+{
+  g_autofree char *md5_checksum = NULL;
+
+  md5_checksum = g_compute_checksum_for_bytes (G_CHECKSUM_MD5, bytes);
+  cd_icc_add_metadata (cd_icc, CD_PROFILE_METADATA_FILE_CHECKSUM, md5_checksum);
+}
+
 static void
 on_efi_panel_color_info_loaded (GObject      *source_object,
                                 GAsyncResult *res,
@@ -970,37 +986,75 @@ on_efi_panel_color_info_loaded (GObject      *source_object,
                                    NULL,
                                    &error))
     {
-      g_autoptr (CdIcc) cd_icc = NULL;
+      g_autoptr (CdIcc) calibration_cd_icc = NULL;
+      g_autoptr (CdIcc) srgb_cd_icc = NULL;
 
       meta_topic (META_DEBUG_COLOR,
                   "Generating ICC profile for '%s' from EFI variable",
                   meta_color_device_get_id (color_device));
 
-      cd_icc = cd_icc_new ();
-      if (cd_icc_load_data (cd_icc,
+      srgb_cd_icc = cd_icc_new ();
+      if (!cd_icc_create_default_full (srgb_cd_icc,
+                                       CD_ICC_LOAD_FLAGS_PRIMARIES,
+                                       &error))
+        {
+          g_warning ("Failed to generate sRGB profile: %s",
+                     error->message);
+          goto out;
+        }
+
+      calibration_cd_icc = cd_icc_new ();
+      if (cd_icc_load_data (calibration_cd_icc,
                             (uint8_t *) contents,
                             length,
-                            CD_ICC_LOAD_FLAGS_METADATA,
+                            (CD_ICC_LOAD_FLAGS_METADATA |
+                             CD_ICC_LOAD_FLAGS_PRIMARIES),
                             &error))
         {
           GenerateProfileData *data = g_task_get_task_data (task);
           const char *file_path = data->file_path;
-          g_autofree char *file_md5_checksum = NULL;
-          GBytes *bytes;
-
-          bytes = g_bytes_new_take (g_steal_pointer (&contents), length);
+          g_autoptr (GBytes) calibration_bytes = NULL;
+          g_autoptr (GBytes) srgb_bytes = NULL;
+          CdMat3x3 csc;
+
+          srgb_bytes = cd_icc_save_data (srgb_cd_icc,
+                                         CD_ICC_SAVE_FLAGS_NONE,
+                                         &error);
+          if (!srgb_bytes)
+            {
+              g_warning ("Failed to save sRGB profile: %s",
+                         error->message);
+              goto out;
+            }
+
+          calibration_bytes = g_bytes_new_take (g_steal_pointer (&contents), length);
 
           /* Set metadata needed by colord */
-          cd_icc_add_metadata (cd_icc, CD_PROFILE_PROPERTY_FILENAME,
-                               file_path);
 
-          file_md5_checksum = g_compute_checksum_for_bytes (G_CHECKSUM_MD5,
-                                                            bytes);
-          cd_icc_add_metadata (cd_icc, CD_PROFILE_METADATA_FILE_CHECKSUM,
-                               file_md5_checksum);
+          cd_icc_add_metadata (calibration_cd_icc, CD_PROFILE_PROPERTY_FILENAME,
+                               "/dev/null");
+          set_icc_checksum (calibration_cd_icc, calibration_bytes);
 
-          data->cd_icc = g_steal_pointer (&cd_icc);
-          data->bytes = bytes;
+          cd_icc_add_metadata (srgb_cd_icc, CD_PROFILE_PROPERTY_FILENAME,
+                               file_path);
+          cd_icc_add_metadata (srgb_cd_icc, CD_PROFILE_PROPERTY_TITLE,
+                               "Factory calibrated (sRGB)");
+          set_icc_checksum (srgb_cd_icc, srgb_bytes);
+
+          if (!cd_icc_utils_get_adaptation_matrix (calibration_cd_icc,
+                                                   srgb_cd_icc,
+                                                   &csc,
+                                                   &error))
+            {
+              g_warning ("Failed to calculate adaption matrix: %s",
+                         error->message);
+              goto out;
+            }
+
+          data->color_calibration =
+            meta_color_calibration_new (calibration_cd_icc, &csc);
+          data->cd_icc = g_steal_pointer (&srgb_cd_icc);
+          data->bytes = g_steal_pointer (&srgb_bytes);
           save_icc_profile (file_path, g_steal_pointer (&task));
           return;
         }
@@ -1022,6 +1076,7 @@ on_efi_panel_color_info_loaded (GObject      *source_object,
         g_warning ("Failed to read EFI panel color info: %s", error->message);
     }
 
+out:
   create_device_profile_from_edid (color_device, g_steal_pointer (&task));
 }
 
diff --git a/src/backends/meta-color-profile.c b/src/backends/meta-color-profile.c
index b844c45776..573acadb86 100644
--- a/src/backends/meta-color-profile.c
+++ b/src/backends/meta-color-profile.c
@@ -24,7 +24,6 @@
 
 #include <colord.h>
 #include <gio/gio.h>
-#include <lcms2.h>
 
 #include "backends/meta-color-manager-private.h"
 
@@ -45,6 +44,7 @@ struct _MetaColorProfile
 
   CdIcc *cd_icc;
   GBytes *bytes;
+  MetaColorCalibration *calibration;
 
   char *cd_profile_id;
   gboolean is_owner;
@@ -146,6 +146,7 @@ meta_color_profile_finalize (GObject *object)
   g_clear_object (&color_profile->cd_icc);
   g_clear_pointer (&color_profile->bytes, g_bytes_unref);
   g_clear_object (&color_profile->cd_profile);
+  g_clear_pointer (&color_profile->calibration, meta_color_calibration_free);
 
   G_OBJECT_CLASS (meta_color_profile_parent_class)->finalize (object);
 }
@@ -263,9 +264,10 @@ create_cd_profile (MetaColorProfile *color_profile,
 }
 
 MetaColorProfile *
-meta_color_profile_new_from_icc (MetaColorManager *color_manager,
-                                 CdIcc            *cd_icc,
-                                 GBytes           *raw_bytes)
+meta_color_profile_new_from_icc (MetaColorManager     *color_manager,
+                                 CdIcc                *cd_icc,
+                                 GBytes               *raw_bytes,
+                                 MetaColorCalibration *color_calibration)
 {
   MetaColorProfile *color_profile;
   const char *checksum;
@@ -277,6 +279,7 @@ meta_color_profile_new_from_icc (MetaColorManager *color_manager,
   color_profile->color_manager = color_manager;
   color_profile->cd_icc = cd_icc;
   color_profile->bytes = raw_bytes;
+  color_profile->calibration = color_calibration;
   color_profile->cancellable = g_cancellable_new ();
   color_profile->is_owner = TRUE;
 
@@ -300,10 +303,11 @@ notify_ready_idle (gpointer user_data)
 }
 
 MetaColorProfile *
-meta_color_profile_new_from_cd_profile (MetaColorManager *color_manager,
-                                        CdProfile        *cd_profile,
-                                        CdIcc            *cd_icc,
-                                        GBytes           *raw_bytes)
+meta_color_profile_new_from_cd_profile (MetaColorManager     *color_manager,
+                                        CdProfile            *cd_profile,
+                                        CdIcc                *cd_icc,
+                                        GBytes               *raw_bytes,
+                                        MetaColorCalibration *color_calibration)
 {
   MetaColorProfile *color_profile;
   const char *checksum;
@@ -312,6 +316,7 @@ meta_color_profile_new_from_cd_profile (MetaColorManager *color_manager,
   color_profile->color_manager = color_manager;
   color_profile->cd_icc = cd_icc;
   color_profile->bytes = raw_bytes;
+  color_profile->calibration = color_calibration;
   color_profile->cancellable = g_cancellable_new ();
   color_profile->is_owner = FALSE;
 
@@ -378,8 +383,7 @@ meta_color_profile_get_file_path (MetaColorProfile *color_profile)
 const char *
 meta_color_profile_get_brightness_profile (MetaColorProfile *color_profile)
 {
-  return cd_profile_get_metadata_item (color_profile->cd_profile,
-                                       CD_PROFILE_METADATA_SCREEN_BRIGHTNESS);
+  return color_profile->calibration->brightness_profile;
 }
 
 static void
@@ -405,10 +409,10 @@ set_blackbody_color_for_temperature (CdColorRGB   *blackbody_color,
 }
 
 static MetaGammaLut *
-generate_gamma_lut_from_vcgt (MetaColorProfile    *color_profile,
-                              const cmsToneCurve **vcgt,
-                              unsigned int         temperature,
-                              size_t               lut_size)
+generate_gamma_lut_from_vcgt (MetaColorProfile  *color_profile,
+                              cmsToneCurve     **vcgt,
+                              unsigned int       temperature,
+                              size_t             lut_size)
 {
   CdColorRGB blackbody_color;
   MetaGammaLut *lut;
@@ -484,17 +488,12 @@ meta_color_profile_generate_gamma_lut (MetaColorProfile *color_profile,
                                        unsigned int      temperature,
                                        size_t            lut_size)
 {
-  cmsHPROFILE lcms_profile;
-  const cmsToneCurve **vcgt;
-
   g_return_val_if_fail (lut_size > 0, NULL);
 
-  lcms_profile = cd_icc_get_handle (color_profile->cd_icc);
-  vcgt = cmsReadTag (lcms_profile, cmsSigVcgtTag);
-
-  if (vcgt && *vcgt)
+  if (color_profile->calibration->has_vcgt)
     {
-      return generate_gamma_lut_from_vcgt (color_profile, vcgt,
+      return generate_gamma_lut_from_vcgt (color_profile,
+                                           color_profile->calibration->vcgt,
                                            temperature, lut_size);
     }
   else
@@ -502,3 +501,52 @@ meta_color_profile_generate_gamma_lut (MetaColorProfile *color_profile,
       return generate_gamma_lut (color_profile, temperature, lut_size);
     }
 }
+
+const MetaColorCalibration *
+meta_color_profile_get_calibration (MetaColorProfile *color_profile)
+{
+  return color_profile->calibration;
+}
+
+MetaColorCalibration *
+meta_color_calibration_new (CdIcc          *cd_icc,
+                            const CdMat3x3 *adaptation_matrix)
+{
+  MetaColorCalibration *color_calibration;
+  cmsHPROFILE lcms_profile;
+  const cmsToneCurve **vcgt;
+  const char *brightness_profile;
+
+  color_calibration = g_new0 (MetaColorCalibration, 1);
+
+  lcms_profile = cd_icc_get_handle (cd_icc);
+  vcgt = cmsReadTag (lcms_profile, cmsSigVcgtTag);
+  if (vcgt && vcgt[0])
+    {
+      color_calibration->has_vcgt = TRUE;
+      color_calibration->vcgt[0] = cmsDupToneCurve (vcgt[0]);
+      color_calibration->vcgt[1] = cmsDupToneCurve (vcgt[1]);
+      color_calibration->vcgt[2] = cmsDupToneCurve (vcgt[2]);
+    }
+
+  brightness_profile =
+    cd_icc_get_metadata_item (cd_icc, CD_PROFILE_METADATA_SCREEN_BRIGHTNESS);
+  if (brightness_profile)
+    color_calibration->brightness_profile = g_strdup (brightness_profile);
+
+  if (adaptation_matrix)
+    {
+      color_calibration->has_adaptation_matrix = TRUE;
+      color_calibration->adaptation_matrix = *adaptation_matrix;
+    }
+
+  return color_calibration;
+}
+
+void
+meta_color_calibration_free (MetaColorCalibration *color_calibration)
+{
+  cmsFreeToneCurveTriple (color_calibration->vcgt);
+  g_free (color_calibration->brightness_profile);
+  g_free (color_calibration);
+}
diff --git a/src/backends/meta-color-profile.h b/src/backends/meta-color-profile.h
index 53f2400296..2b240d0b34 100644
--- a/src/backends/meta-color-profile.h
+++ b/src/backends/meta-color-profile.h
@@ -20,24 +20,38 @@
 
 #include <colord.h>
 #include <glib-object.h>
+#include <lcms2.h>
 #include <stdint.h>
 
 #include "backends/meta-backend-types.h"
 #include "core/util-private.h"
 
+typedef struct _MetaColorCalibration
+{
+  gboolean has_vcgt;
+  cmsToneCurve *vcgt[3];
+
+  gboolean has_adaptation_matrix;
+  CdMat3x3 adaptation_matrix;
+
+  char *brightness_profile;
+} MetaColorCalibration;
+
 #define META_TYPE_COLOR_PROFILE (meta_color_profile_get_type ())
 G_DECLARE_FINAL_TYPE (MetaColorProfile, meta_color_profile,
                       META, COLOR_PROFILE,
                       GObject)
 
-MetaColorProfile * meta_color_profile_new_from_icc (MetaColorManager *color_manager,
-                                                    CdIcc            *icc,
-                                                    GBytes           *raw_bytes);
+MetaColorProfile * meta_color_profile_new_from_icc (MetaColorManager     *color_manager,
+                                                    CdIcc                *cd_icc,
+                                                    GBytes               *raw_bytes,
+                                                    MetaColorCalibration *color_calibration);
 
-MetaColorProfile * meta_color_profile_new_from_cd_profile (MetaColorManager *color_manager,
-                                                           CdProfile        *cd_profile,
-                                                           CdIcc            *cd_icc,
-                                                           GBytes           *raw_bytes);
+MetaColorProfile * meta_color_profile_new_from_cd_profile (MetaColorManager     *color_manager,
+                                                           CdProfile            *cd_profile,
+                                                           CdIcc                *cd_icc,
+                                                           GBytes               *raw_bytes,
+                                                           MetaColorCalibration *color_calibration);
 
 gboolean meta_color_profile_equals_bytes (MetaColorProfile *color_profile,
                                           GBytes           *bytes);
@@ -64,4 +78,12 @@ MetaGammaLut * meta_color_profile_generate_gamma_lut (MetaColorProfile *color_pr
                                                       unsigned int      temperature,
                                                       size_t            lut_size);
 
+META_EXPORT_TEST
+const MetaColorCalibration * meta_color_profile_get_calibration (MetaColorProfile *color_profile);
+
+MetaColorCalibration * meta_color_calibration_new (CdIcc          *cd_icc,
+                                                   const CdMat3x3 *adaptation_matrix);
+
+void meta_color_calibration_free (MetaColorCalibration *color_calibration);
+
 #endif /* META_COLOR_PROFILE_H */
diff --git a/src/backends/meta-color-store.c b/src/backends/meta-color-store.c
index 088049d32d..ae01883906 100644
--- a/src/backends/meta-color-store.c
+++ b/src/backends/meta-color-store.c
@@ -116,6 +116,7 @@ create_profile_from_contents (MetaColorStore *color_store,
   g_autoptr (GError) error = NULL;
   g_autoptr (GBytes) bytes = NULL;
   g_autofree char *file_md5_checksum = NULL;
+  MetaColorCalibration *color_calibration;
   MetaColorProfile *color_profile;
 
   cd_icc = cd_icc_new ();
@@ -139,10 +140,12 @@ create_profile_from_contents (MetaColorStore *color_store,
                                                     bytes);
   cd_icc_add_metadata (cd_icc, CD_PROFILE_METADATA_FILE_CHECKSUM,
                        file_md5_checksum);
+  color_calibration = meta_color_calibration_new (cd_icc, NULL);
   color_profile =
     meta_color_profile_new_from_icc (color_store->color_manager,
                                      g_steal_pointer (&cd_icc),
-                                     g_steal_pointer (&bytes));
+                                     g_steal_pointer (&bytes),
+                                     color_calibration);
 
   g_signal_connect (color_profile, "ready",
                     G_CALLBACK (on_directory_profile_ready),
@@ -598,6 +601,7 @@ on_cd_profile_contents_loaded (GObject      *source_object,
   g_autoptr (CdIcc) cd_icc = NULL;
   g_autofree char *file_md5_checksum = NULL;
   GBytes *bytes;
+  MetaColorCalibration *color_calibration;
   MetaColorProfile *color_profile;
 
   if (!g_file_load_contents_finish (file, res,
@@ -631,11 +635,13 @@ on_cd_profile_contents_loaded (GObject      *source_object,
                        file_md5_checksum);
 
   bytes = g_bytes_new_take (g_steal_pointer (&contents), length);
+  color_calibration = meta_color_calibration_new (cd_icc, NULL);
   color_profile =
     meta_color_profile_new_from_cd_profile (color_manager,
                                             cd_profile,
                                             g_steal_pointer (&cd_icc),
-                                            bytes);
+                                            bytes,
+                                            color_calibration);
 
   g_hash_table_insert (color_store->profiles,
                        g_strdup (meta_color_profile_get_id (color_profile)),
diff --git a/src/backends/x11/meta-color-manager-x11.c b/src/backends/x11/meta-color-manager-x11.c
index fbe7357c1c..64ecfc8497 100644
--- a/src/backends/x11/meta-color-manager-x11.c
+++ b/src/backends/x11/meta-color-manager-x11.c
@@ -34,9 +34,6 @@
 struct _MetaColorManagerX11
 {
   MetaColorManager parent;
-
-  CdIcc *srgb_cd_icc;
-  GBytes *srgb_icc_bytes;
 };
 
 G_DEFINE_TYPE (MetaColorManagerX11, meta_color_manager_x11,
@@ -46,57 +43,10 @@ G_DEFINE_TYPE (MetaColorManagerX11, meta_color_manager_x11,
 #define ICC_PROFILE_IN_X_VERSION_MAJOR 0
 #define ICC_PROFILE_IN_X_VERSION_MINOR 3
 
-static CdIcc *
-ensure_srgb_profile (MetaColorManagerX11 *color_manager_x11)
-{
-  CdIcc *srgb_cd_icc;
-  g_autoptr (GError) error = NULL;
-
-  if (color_manager_x11->srgb_cd_icc)
-    return color_manager_x11->srgb_cd_icc;
-
-  srgb_cd_icc = cd_icc_new ();
-  if (!cd_icc_create_default_full (srgb_cd_icc,
-                                   CD_ICC_LOAD_FLAGS_PRIMARIES,
-                                   &error))
-    {
-      g_warning_once ("Failed to create sRGB ICC profile: %s", error->message);
-      return NULL;
-    }
-
-  color_manager_x11->srgb_cd_icc = srgb_cd_icc;
-  return srgb_cd_icc;
-}
-
-static GBytes *
-ensure_srgb_profile_bytes (MetaColorManagerX11 *color_manager_x11)
-{
-  CdIcc *srgb_cd_icc;
-  g_autoptr (GError) error = NULL;
-  GBytes *bytes;
-
-  srgb_cd_icc = ensure_srgb_profile (color_manager_x11);
-  if (!srgb_cd_icc)
-    return NULL;
-
-  bytes = cd_icc_save_data (srgb_cd_icc,
-                            CD_ICC_SAVE_FLAGS_NONE,
-                            &error);
-  if (!bytes)
-    {
-      g_warning_once ("Failed to export sRGB ICC profile: %s", error->message);
-      return NULL;
-    }
-
-  color_manager_x11->srgb_icc_bytes = bytes;
-  return bytes;
-}
-
 static void
-update_root_window_atom (MetaColorManagerX11 *color_manager_x11,
-                         MetaColorDevice     *color_device)
+update_root_window_atom (MetaColorManager *color_manager,
+                         MetaColorDevice  *color_device)
 {
-  MetaColorManager *color_manager = META_COLOR_MANAGER (color_manager_x11);
   MetaBackend *backend = meta_color_manager_get_backend (color_manager);
   MetaBackendX11 *backend_x11 = META_BACKEND_X11 (backend);
   Display *xdisplay = meta_backend_x11_get_xdisplay (backend_x11);
@@ -104,6 +54,7 @@ update_root_window_atom (MetaColorManagerX11 *color_manager_x11,
   Atom icc_profile_atom;
   Atom icc_profile_version_atom;
   MetaMonitor *monitor;
+  MetaColorProfile *color_profile;
   const uint8_t *profile_contents = NULL;
   size_t profile_size;
 
@@ -111,32 +62,11 @@ update_root_window_atom (MetaColorManagerX11 *color_manager_x11,
   if (!meta_monitor_is_primary (monitor))
     return;
 
-  if (meta_monitor_supports_color_transform (monitor))
-    {
-      GBytes *profile_bytes;
-
-      /*
-       * If the output supports color transforms, then
-       * applications should use the standard sRGB color profile and
-       * the window system will take care of converting colors to
-       * match the output device's measured color profile.
-       */
-      profile_bytes = ensure_srgb_profile_bytes (color_manager_x11);
-      if (!profile_bytes)
-        g_warning_once ("Failed to generate sRGB ICC profile");
-      else
-        profile_contents = g_bytes_get_data (profile_bytes, &profile_size);
-    }
-  else
+  color_profile = meta_color_device_get_assigned_profile (color_device);
+  if (color_profile)
     {
-      MetaColorProfile *color_profile;
-
-      color_profile = meta_color_device_get_assigned_profile (color_device);
-      if (color_profile)
-        {
-          profile_contents = meta_color_profile_get_data (color_profile);
-          profile_size = meta_color_profile_get_data_size (color_profile);
-        }
+      profile_contents = meta_color_profile_get_data (color_profile);
+      profile_size = meta_color_profile_get_data_size (color_profile);
     }
 
   icc_profile_atom = XInternAtom (xdisplay, "_ICC_PROFILE", False);
@@ -187,7 +117,7 @@ double_to_ctmval (double value)
 }
 
 static MetaOutputCtm
-mat33_to_ctm (CdMat3x3 matrix)
+mat33_to_ctm (const CdMat3x3 *matrix)
 {
   MetaOutputCtm ctm;
 
@@ -195,29 +125,25 @@ mat33_to_ctm (CdMat3x3 matrix)
    * libcolord generates a matrix containing double values. RandR's CTM
    * property expects values in S31.32 fixed-point sign-magnitude format
    */
-  ctm.matrix[0] = double_to_ctmval (matrix.m00);
-  ctm.matrix[1] = double_to_ctmval (matrix.m01);
-  ctm.matrix[2] = double_to_ctmval (matrix.m02);
-  ctm.matrix[3] = double_to_ctmval (matrix.m10);
-  ctm.matrix[4] = double_to_ctmval (matrix.m11);
-  ctm.matrix[5] = double_to_ctmval (matrix.m12);
-  ctm.matrix[6] = double_to_ctmval (matrix.m20);
-  ctm.matrix[7] = double_to_ctmval (matrix.m21);
-  ctm.matrix[8] = double_to_ctmval (matrix.m22);
+  ctm.matrix[0] = double_to_ctmval (matrix->m00);
+  ctm.matrix[1] = double_to_ctmval (matrix->m01);
+  ctm.matrix[2] = double_to_ctmval (matrix->m02);
+  ctm.matrix[3] = double_to_ctmval (matrix->m10);
+  ctm.matrix[4] = double_to_ctmval (matrix->m11);
+  ctm.matrix[5] = double_to_ctmval (matrix->m12);
+  ctm.matrix[6] = double_to_ctmval (matrix->m20);
+  ctm.matrix[7] = double_to_ctmval (matrix->m21);
+  ctm.matrix[8] = double_to_ctmval (matrix->m22);
 
   return ctm;
 }
 
 static void
-update_device_ctm (MetaColorManagerX11 *color_manager_x11,
-                   MetaColorDevice     *color_device)
+update_device_ctm (MetaColorDevice *color_device)
 {
   MetaMonitor *monitor;
   MetaColorProfile *color_profile;
-  CdIcc *srgb_cd_icc;
-  g_autoptr (GError) error = NULL;
-  CdIcc *cd_icc;
-  CdMat3x3 csc;
+  const MetaColorCalibration *color_calibration;
   MetaOutputCtm ctm;
   MetaOutput *output;
   MetaOutputXrandr *output_xrandr;
@@ -230,19 +156,12 @@ update_device_ctm (MetaColorManagerX11 *color_manager_x11,
   if (!color_profile)
     return;
 
-  srgb_cd_icc = ensure_srgb_profile (color_manager_x11);
-  if (!srgb_cd_icc)
-    return;
+  color_calibration = meta_color_profile_get_calibration (color_profile);
 
-  cd_icc = meta_color_profile_get_cd_icc (color_profile);
-  if (!cd_icc_utils_get_adaptation_matrix (cd_icc, srgb_cd_icc, &csc, &error))
-    {
-      g_warning_once ("Failed to calculate adaption matrix: %s",
-                      error->message);
-      return;
-    }
+  if (!color_calibration->has_adaptation_matrix)
+    return;
 
-  ctm = mat33_to_ctm (csc);
+  ctm = mat33_to_ctm (&color_calibration->adaptation_matrix);
 
   output = meta_monitor_get_main_output (monitor);
   output_xrandr = META_OUTPUT_XRANDR (output);
@@ -253,11 +172,8 @@ static void
 on_color_device_updated (MetaColorManager *color_manager,
                          MetaColorDevice  *color_device)
 {
-  MetaColorManagerX11 *color_manager_x11 =
-    META_COLOR_MANAGER_X11 (color_manager);
-
-  update_root_window_atom (color_manager_x11, color_device);
-  update_device_ctm (color_manager_x11, color_device);
+  update_root_window_atom (color_manager, color_device);
+  update_device_ctm (color_device);
 }
 
 static void
@@ -271,24 +187,12 @@ meta_color_manager_x11_constructed (GObject *object)
   G_OBJECT_CLASS (meta_color_manager_x11_parent_class)->constructed (object);
 }
 
-static void
-meta_color_manager_x11_finalize (GObject *object)
-{
-  MetaColorManagerX11 *color_manager_x11 = META_COLOR_MANAGER_X11 (object);
-
-  g_clear_pointer (&color_manager_x11->srgb_icc_bytes, g_bytes_unref);
-  g_clear_object (&color_manager_x11->srgb_cd_icc);
-
-  G_OBJECT_CLASS (meta_color_manager_x11_parent_class)->finalize (object);
-}
-
 static void
 meta_color_manager_x11_class_init (MetaColorManagerX11Class *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
   object_class->constructed = meta_color_manager_x11_constructed;
-  object_class->finalize = meta_color_manager_x11_finalize;
 }
 
 static void
diff --git a/src/tests/color-management-tests.c b/src/tests/color-management-tests.c
index 9d838630e6..e8c0480949 100644
--- a/src/tests/color-management-tests.c
+++ b/src/tests/color-management-tests.c
@@ -20,6 +20,8 @@
 
 #include "config.h"
 
+#include <fcntl.h>
+
 #include "backends/meta-color-device.h"
 #include "backends/meta-color-manager-private.h"
 #include "backends/meta-color-profile.h"
@@ -105,6 +107,22 @@ static MonitorTestCaseSetup base_monitor_setup = {
     .white_y = 0.329102, \
   })
 
+#define assert_color_xyz_equal(color, expected_color) \
+  g_assert_cmpfloat_with_epsilon (color->X, expected_color->X, \
+                                  PRIMARY_EPSILON); \
+  g_assert_cmpfloat_with_epsilon (color->Y, expected_color->Y, \
+                                  PRIMARY_EPSILON); \
+  g_assert_cmpfloat_with_epsilon (color->Z, expected_color->Z, \
+                                  PRIMARY_EPSILON);
+
+#define assert_color_yxy_equal(color, expected_color) \
+  g_assert_cmpfloat_with_epsilon (color->x, expected_color->x, \
+                                  PRIMARY_EPSILON); \
+  g_assert_cmpfloat_with_epsilon (color->y, expected_color->y, \
+                                  PRIMARY_EPSILON); \
+  g_assert_cmpfloat_with_epsilon (color->Y, expected_color->Y, \
+                                  PRIMARY_EPSILON);
+
 static GDBusProxy *
 get_colord_mock_proxy (void)
 {
@@ -515,6 +533,155 @@ meta_test_color_management_profile_system (void)
                    srgb_profile_id);
 }
 
+static void
+generate_efi_test_profile (const char *path,
+                           double      gamma,
+                           CdColorYxy *red,
+                           CdColorYxy *green,
+                           CdColorYxy *blue,
+                           CdColorYxy *white)
+{
+  g_autoptr (GError) error = NULL;
+  g_autoptr (CdIcc) cd_icc = NULL;
+  g_autoptr (GFile) file = NULL;
+  const CdColorXYZ *red_xyz;
+  const CdColorXYZ *green_xyz;
+  const CdColorXYZ *blue_xyz;
+  const CdColorXYZ *white_xyz;
+
+  cd_icc = cd_icc_new ();
+
+  if (!cd_icc_create_from_edid (cd_icc, 2.2, red, green, blue, white, &error))
+    g_error ("Failed to generate reference profile: %s", error->message);
+
+  file = g_file_new_for_path (path);
+  if (!cd_icc_save_file (cd_icc, file, CD_ICC_SAVE_FLAGS_NONE,
+                         NULL, &error))
+    g_error ("Failed to save reference profile: %s", error->message);
+
+  g_clear_object (&cd_icc);
+
+  cd_icc = cd_icc_new ();
+  if (!cd_icc_load_file (cd_icc, file, CD_ICC_LOAD_FLAGS_PRIMARIES,
+                         NULL, &error))
+    g_error ("Failed to load reference profile: %s", error->message);
+
+  red_xyz = cd_icc_get_red (cd_icc);
+  green_xyz = cd_icc_get_green (cd_icc);
+  blue_xyz = cd_icc_get_blue (cd_icc);
+  white_xyz = cd_icc_get_white (cd_icc);
+  cd_color_xyz_to_yxy (red_xyz, red);
+  cd_color_xyz_to_yxy (green_xyz, green);
+  cd_color_xyz_to_yxy (blue_xyz, blue);
+  cd_color_xyz_to_yxy (white_xyz, white);
+}
+
+static void
+meta_test_color_management_profile_efivar (void)
+{
+  MetaBackend *backend = meta_context_get_backend (test_context);
+  MetaMonitorManager *monitor_manager =
+    meta_backend_get_monitor_manager (backend);
+  MetaMonitorManagerTest *monitor_manager_test =
+    META_MONITOR_MANAGER_TEST (monitor_manager);
+  MetaColorManager *color_manager =
+    meta_backend_get_color_manager (backend);
+  char efivar_path[] = "/tmp/efivar-test-profile-XXXXXX";
+  int fd;
+  CdColorYxy *reference_red_yxy;
+  CdColorYxy *reference_green_yxy;
+  CdColorYxy *reference_blue_yxy;
+  CdColorYxy *reference_white_yxy;
+  MetaEdidInfo edid_info;
+  MonitorTestCaseSetup test_case_setup = base_monitor_setup;
+  MetaMonitorTestSetup *test_setup;
+  MetaMonitor *monitor;
+  MetaColorDevice *color_device;
+  MetaColorProfile *color_profile;
+  CdIcc *cd_icc;
+  g_autoptr (CdIcc) srgb_cd_icc = NULL;
+  const CdColorXYZ *red_xyz;
+  const CdColorXYZ *green_xyz;
+  const CdColorXYZ *blue_xyz;
+  const CdColorXYZ *white_xyz;
+  const CdColorXYZ *srgb_red_xyz;
+  const CdColorXYZ *srgb_green_xyz;
+  const CdColorXYZ *srgb_blue_xyz;
+  const CdColorXYZ *srgb_white_xyz;
+  const MetaColorCalibration *color_calibration;
+
+  fd = mkostemp (efivar_path, O_CLOEXEC);
+  g_assert_cmpint (fd, >=, 0);
+  close (fd);
+
+  reference_red_yxy = cd_color_yxy_new ();
+  reference_green_yxy = cd_color_yxy_new ();
+  reference_blue_yxy = cd_color_yxy_new ();
+  reference_white_yxy = cd_color_yxy_new ();
+
+  cd_color_yxy_set (reference_red_yxy, 0.0, 0.3, 0.6);
+  cd_color_yxy_set (reference_green_yxy, 0.0, 0.7, 0.2);
+  cd_color_yxy_set (reference_blue_yxy, 0.0, 0.1, 0.2);
+  cd_color_yxy_set (reference_white_yxy, 1.0, 0.3, 0.3);
+
+  generate_efi_test_profile (efivar_path,
+                             2.2,
+                             reference_red_yxy,
+                             reference_green_yxy,
+                             reference_blue_yxy,
+                             reference_white_yxy);
+  meta_set_color_efivar_test_path (efivar_path);
+
+  edid_info = ANCOR_VX239_EDID;
+  test_case_setup.outputs[0].serial = __func__;
+  test_case_setup.outputs[0].edid_info = edid_info;
+  test_case_setup.outputs[0].has_edid_info = TRUE;
+  test_case_setup.n_outputs = 1;
+  test_setup = meta_create_monitor_test_setup (backend, &test_case_setup,
+                                               MONITOR_TEST_FLAG_NO_STORED);
+  meta_monitor_manager_test_emulate_hotplug (monitor_manager_test, test_setup);
+
+  monitor = meta_monitor_manager_get_monitors (monitor_manager)->data;
+  color_device = meta_color_manager_get_color_device (color_manager, monitor);
+  g_assert_nonnull (color_device);
+
+  while (!meta_color_device_is_ready (color_device))
+    g_main_context_iteration (NULL, TRUE);
+
+  color_profile = meta_color_device_get_device_profile (color_device);
+  g_assert_nonnull (color_profile);
+
+  cd_icc = meta_color_profile_get_cd_icc (color_profile);
+  g_assert_nonnull (cd_icc);
+
+  red_xyz = cd_icc_get_red (cd_icc);
+  green_xyz = cd_icc_get_green (cd_icc);
+  blue_xyz = cd_icc_get_blue (cd_icc);
+  white_xyz = cd_icc_get_white (cd_icc);
+
+  srgb_cd_icc = cd_icc_new ();
+  g_assert_true (cd_icc_create_default_full (srgb_cd_icc,
+                                             CD_ICC_LOAD_FLAGS_PRIMARIES,
+                                             NULL));
+
+  srgb_red_xyz = cd_icc_get_red (srgb_cd_icc);
+  srgb_green_xyz = cd_icc_get_green (srgb_cd_icc);
+  srgb_blue_xyz = cd_icc_get_blue (srgb_cd_icc);
+  srgb_white_xyz = cd_icc_get_white (srgb_cd_icc);
+
+  /* Make sure we the values from the sRGB profile. */
+  assert_color_xyz_equal (red_xyz, srgb_red_xyz);
+  assert_color_xyz_equal (green_xyz, srgb_green_xyz);
+  assert_color_xyz_equal (blue_xyz, srgb_blue_xyz);
+  assert_color_xyz_equal (white_xyz, srgb_white_xyz);
+
+  color_calibration = meta_color_profile_get_calibration (color_profile);
+  g_assert_true (color_calibration->has_adaptation_matrix);
+
+  meta_set_color_efivar_test_path (NULL);
+  unlink (efivar_path);
+}
+
 static void
 wait_for_profile_assigned (MetaColorDevice *color_device,
                            const char      *profile_id)
@@ -1124,6 +1291,8 @@ init_tests (void)
                   meta_test_color_management_profile_device);
   add_color_test ("/color-management/profile/system",
                   meta_test_color_management_profile_system);
+  add_color_test ("/color-management/profile/efivar",
+                  meta_test_color_management_profile_efivar);
   add_color_test ("/color-management/night-light/calibrated",
                   meta_test_color_management_night_light_calibrated);
   add_color_test ("/color-management/night-light/uncalibrated",


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