diff --git a/src/backends/meta-color-device.c b/src/backends/meta-color-device.c index 4641616a1..f8240606a 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; + g_autoptr (GBytes) calibration_bytes = NULL; + g_autoptr (GBytes) srgb_bytes = NULL; + CdMat3x3 csc; - bytes = g_bytes_new_take (g_steal_pointer (&contents), length); + 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, + + cd_icc_add_metadata (calibration_cd_icc, CD_PROFILE_PROPERTY_FILENAME, + "/dev/null"); + set_icc_checksum (calibration_cd_icc, calibration_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); - 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); + 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->cd_icc = g_steal_pointer (&cd_icc); - data->bytes = bytes; + 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 b844c4577..573acadb8 100644 --- a/src/backends/meta-color-profile.c +++ b/src/backends/meta-color-profile.c @@ -24,7 +24,6 @@ #include #include -#include #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 53f240029..2b240d0b3 100644 --- a/src/backends/meta-color-profile.h +++ b/src/backends/meta-color-profile.h @@ -20,24 +20,38 @@ #include #include +#include #include #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 088049d32..ae0188390 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 fbe7357c1..64ecfc849 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)) + color_profile = meta_color_device_get_assigned_profile (color_device); + if (color_profile) { - 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 - { - 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) + color_calibration = meta_color_profile_get_calibration (color_profile); + + if (!color_calibration->has_adaptation_matrix) return; - 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; - } - - 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 9d838630e..e8c048094 100644 --- a/src/tests/color-management-tests.c +++ b/src/tests/color-management-tests.c @@ -20,6 +20,8 @@ #include "config.h" +#include + #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",