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>
This commit is contained in:
Jonas Ådahl 2022-08-30 23:30:35 +02:00 committed by Marge Bot
parent 5b251bd8a7
commit 9aa9cacb3d
6 changed files with 371 additions and 167 deletions

View File

@ -612,6 +612,8 @@ typedef struct
char *file_path; char *file_path;
GBytes *bytes; GBytes *bytes;
CdIcc *cd_icc; CdIcc *cd_icc;
MetaColorCalibration *color_calibration;
} GenerateProfileData; } GenerateProfileData;
static void static void
@ -620,6 +622,7 @@ generate_profile_data_free (GenerateProfileData *data)
g_free (data->file_path); g_free (data->file_path);
g_clear_object (&data->cd_icc); g_clear_object (&data->cd_icc);
g_clear_pointer (&data->bytes, g_bytes_unref); g_clear_pointer (&data->bytes, g_bytes_unref);
g_clear_pointer (&data->color_calibration, meta_color_calibration_free);
g_free (data); g_free (data);
} }
@ -655,7 +658,8 @@ on_profile_written (GObject *source_object,
color_profile = color_profile =
meta_color_profile_new_from_icc (color_manager, meta_color_profile_new_from_icc (color_manager,
g_steal_pointer (&data->cd_icc), 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); 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, cd_icc_add_metadata (cd_icc, CD_PROFILE_METADATA_FILE_CHECKSUM,
file_md5_checksum); file_md5_checksum);
data->color_calibration =
meta_color_calibration_new (cd_icc, NULL);
data->cd_icc = g_steal_pointer (&cd_icc); data->cd_icc = g_steal_pointer (&cd_icc);
data->bytes = bytes; data->bytes = bytes;
save_icc_profile (file_path, task); 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 static void
on_efi_panel_color_info_loaded (GObject *source_object, on_efi_panel_color_info_loaded (GObject *source_object,
GAsyncResult *res, GAsyncResult *res,
@ -970,37 +986,75 @@ on_efi_panel_color_info_loaded (GObject *source_object,
NULL, NULL,
&error)) &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, meta_topic (META_DEBUG_COLOR,
"Generating ICC profile for '%s' from EFI variable", "Generating ICC profile for '%s' from EFI variable",
meta_color_device_get_id (color_device)); meta_color_device_get_id (color_device));
cd_icc = cd_icc_new (); srgb_cd_icc = cd_icc_new ();
if (cd_icc_load_data (cd_icc, 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, (uint8_t *) contents,
length, length,
CD_ICC_LOAD_FLAGS_METADATA, (CD_ICC_LOAD_FLAGS_METADATA |
CD_ICC_LOAD_FLAGS_PRIMARIES),
&error)) &error))
{ {
GenerateProfileData *data = g_task_get_task_data (task); GenerateProfileData *data = g_task_get_task_data (task);
const char *file_path = data->file_path; const char *file_path = data->file_path;
g_autofree char *file_md5_checksum = NULL; g_autoptr (GBytes) calibration_bytes = NULL;
GBytes *bytes; 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 */ /* 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); 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, if (!cd_icc_utils_get_adaptation_matrix (calibration_cd_icc,
bytes); srgb_cd_icc,
cd_icc_add_metadata (cd_icc, CD_PROFILE_METADATA_FILE_CHECKSUM, &csc,
file_md5_checksum); &error))
{
g_warning ("Failed to calculate adaption matrix: %s",
error->message);
goto out;
}
data->cd_icc = g_steal_pointer (&cd_icc); data->color_calibration =
data->bytes = bytes; 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)); save_icc_profile (file_path, g_steal_pointer (&task));
return; 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); g_warning ("Failed to read EFI panel color info: %s", error->message);
} }
out:
create_device_profile_from_edid (color_device, g_steal_pointer (&task)); create_device_profile_from_edid (color_device, g_steal_pointer (&task));
} }

View File

@ -24,7 +24,6 @@
#include <colord.h> #include <colord.h>
#include <gio/gio.h> #include <gio/gio.h>
#include <lcms2.h>
#include "backends/meta-color-manager-private.h" #include "backends/meta-color-manager-private.h"
@ -45,6 +44,7 @@ struct _MetaColorProfile
CdIcc *cd_icc; CdIcc *cd_icc;
GBytes *bytes; GBytes *bytes;
MetaColorCalibration *calibration;
char *cd_profile_id; char *cd_profile_id;
gboolean is_owner; gboolean is_owner;
@ -146,6 +146,7 @@ meta_color_profile_finalize (GObject *object)
g_clear_object (&color_profile->cd_icc); g_clear_object (&color_profile->cd_icc);
g_clear_pointer (&color_profile->bytes, g_bytes_unref); g_clear_pointer (&color_profile->bytes, g_bytes_unref);
g_clear_object (&color_profile->cd_profile); 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); G_OBJECT_CLASS (meta_color_profile_parent_class)->finalize (object);
} }
@ -265,7 +266,8 @@ create_cd_profile (MetaColorProfile *color_profile,
MetaColorProfile * MetaColorProfile *
meta_color_profile_new_from_icc (MetaColorManager *color_manager, meta_color_profile_new_from_icc (MetaColorManager *color_manager,
CdIcc *cd_icc, CdIcc *cd_icc,
GBytes *raw_bytes) GBytes *raw_bytes,
MetaColorCalibration *color_calibration)
{ {
MetaColorProfile *color_profile; MetaColorProfile *color_profile;
const char *checksum; const char *checksum;
@ -277,6 +279,7 @@ meta_color_profile_new_from_icc (MetaColorManager *color_manager,
color_profile->color_manager = color_manager; color_profile->color_manager = color_manager;
color_profile->cd_icc = cd_icc; color_profile->cd_icc = cd_icc;
color_profile->bytes = raw_bytes; color_profile->bytes = raw_bytes;
color_profile->calibration = color_calibration;
color_profile->cancellable = g_cancellable_new (); color_profile->cancellable = g_cancellable_new ();
color_profile->is_owner = TRUE; color_profile->is_owner = TRUE;
@ -303,7 +306,8 @@ MetaColorProfile *
meta_color_profile_new_from_cd_profile (MetaColorManager *color_manager, meta_color_profile_new_from_cd_profile (MetaColorManager *color_manager,
CdProfile *cd_profile, CdProfile *cd_profile,
CdIcc *cd_icc, CdIcc *cd_icc,
GBytes *raw_bytes) GBytes *raw_bytes,
MetaColorCalibration *color_calibration)
{ {
MetaColorProfile *color_profile; MetaColorProfile *color_profile;
const char *checksum; 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->color_manager = color_manager;
color_profile->cd_icc = cd_icc; color_profile->cd_icc = cd_icc;
color_profile->bytes = raw_bytes; color_profile->bytes = raw_bytes;
color_profile->calibration = color_calibration;
color_profile->cancellable = g_cancellable_new (); color_profile->cancellable = g_cancellable_new ();
color_profile->is_owner = FALSE; color_profile->is_owner = FALSE;
@ -378,8 +383,7 @@ meta_color_profile_get_file_path (MetaColorProfile *color_profile)
const char * const char *
meta_color_profile_get_brightness_profile (MetaColorProfile *color_profile) meta_color_profile_get_brightness_profile (MetaColorProfile *color_profile)
{ {
return cd_profile_get_metadata_item (color_profile->cd_profile, return color_profile->calibration->brightness_profile;
CD_PROFILE_METADATA_SCREEN_BRIGHTNESS);
} }
static void static void
@ -406,7 +410,7 @@ set_blackbody_color_for_temperature (CdColorRGB *blackbody_color,
static MetaGammaLut * static MetaGammaLut *
generate_gamma_lut_from_vcgt (MetaColorProfile *color_profile, generate_gamma_lut_from_vcgt (MetaColorProfile *color_profile,
const cmsToneCurve **vcgt, cmsToneCurve **vcgt,
unsigned int temperature, unsigned int temperature,
size_t lut_size) size_t lut_size)
{ {
@ -484,17 +488,12 @@ meta_color_profile_generate_gamma_lut (MetaColorProfile *color_profile,
unsigned int temperature, unsigned int temperature,
size_t lut_size) size_t lut_size)
{ {
cmsHPROFILE lcms_profile;
const cmsToneCurve **vcgt;
g_return_val_if_fail (lut_size > 0, NULL); g_return_val_if_fail (lut_size > 0, NULL);
lcms_profile = cd_icc_get_handle (color_profile->cd_icc); if (color_profile->calibration->has_vcgt)
vcgt = cmsReadTag (lcms_profile, cmsSigVcgtTag);
if (vcgt && *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); temperature, lut_size);
} }
else else
@ -502,3 +501,52 @@ meta_color_profile_generate_gamma_lut (MetaColorProfile *color_profile,
return generate_gamma_lut (color_profile, temperature, lut_size); 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);
}

View File

@ -20,24 +20,38 @@
#include <colord.h> #include <colord.h>
#include <glib-object.h> #include <glib-object.h>
#include <lcms2.h>
#include <stdint.h> #include <stdint.h>
#include "backends/meta-backend-types.h" #include "backends/meta-backend-types.h"
#include "core/util-private.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 ()) #define META_TYPE_COLOR_PROFILE (meta_color_profile_get_type ())
G_DECLARE_FINAL_TYPE (MetaColorProfile, meta_color_profile, G_DECLARE_FINAL_TYPE (MetaColorProfile, meta_color_profile,
META, COLOR_PROFILE, META, COLOR_PROFILE,
GObject) GObject)
MetaColorProfile * meta_color_profile_new_from_icc (MetaColorManager *color_manager, MetaColorProfile * meta_color_profile_new_from_icc (MetaColorManager *color_manager,
CdIcc *icc, CdIcc *cd_icc,
GBytes *raw_bytes); GBytes *raw_bytes,
MetaColorCalibration *color_calibration);
MetaColorProfile * meta_color_profile_new_from_cd_profile (MetaColorManager *color_manager, MetaColorProfile * meta_color_profile_new_from_cd_profile (MetaColorManager *color_manager,
CdProfile *cd_profile, CdProfile *cd_profile,
CdIcc *cd_icc, CdIcc *cd_icc,
GBytes *raw_bytes); GBytes *raw_bytes,
MetaColorCalibration *color_calibration);
gboolean meta_color_profile_equals_bytes (MetaColorProfile *color_profile, gboolean meta_color_profile_equals_bytes (MetaColorProfile *color_profile,
GBytes *bytes); GBytes *bytes);
@ -64,4 +78,12 @@ MetaGammaLut * meta_color_profile_generate_gamma_lut (MetaColorProfile *color_pr
unsigned int temperature, unsigned int temperature,
size_t lut_size); 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 */ #endif /* META_COLOR_PROFILE_H */

View File

@ -116,6 +116,7 @@ create_profile_from_contents (MetaColorStore *color_store,
g_autoptr (GError) error = NULL; g_autoptr (GError) error = NULL;
g_autoptr (GBytes) bytes = NULL; g_autoptr (GBytes) bytes = NULL;
g_autofree char *file_md5_checksum = NULL; g_autofree char *file_md5_checksum = NULL;
MetaColorCalibration *color_calibration;
MetaColorProfile *color_profile; MetaColorProfile *color_profile;
cd_icc = cd_icc_new (); cd_icc = cd_icc_new ();
@ -139,10 +140,12 @@ create_profile_from_contents (MetaColorStore *color_store,
bytes); bytes);
cd_icc_add_metadata (cd_icc, CD_PROFILE_METADATA_FILE_CHECKSUM, cd_icc_add_metadata (cd_icc, CD_PROFILE_METADATA_FILE_CHECKSUM,
file_md5_checksum); file_md5_checksum);
color_calibration = meta_color_calibration_new (cd_icc, NULL);
color_profile = color_profile =
meta_color_profile_new_from_icc (color_store->color_manager, meta_color_profile_new_from_icc (color_store->color_manager,
g_steal_pointer (&cd_icc), g_steal_pointer (&cd_icc),
g_steal_pointer (&bytes)); g_steal_pointer (&bytes),
color_calibration);
g_signal_connect (color_profile, "ready", g_signal_connect (color_profile, "ready",
G_CALLBACK (on_directory_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_autoptr (CdIcc) cd_icc = NULL;
g_autofree char *file_md5_checksum = NULL; g_autofree char *file_md5_checksum = NULL;
GBytes *bytes; GBytes *bytes;
MetaColorCalibration *color_calibration;
MetaColorProfile *color_profile; MetaColorProfile *color_profile;
if (!g_file_load_contents_finish (file, res, if (!g_file_load_contents_finish (file, res,
@ -631,11 +635,13 @@ on_cd_profile_contents_loaded (GObject *source_object,
file_md5_checksum); file_md5_checksum);
bytes = g_bytes_new_take (g_steal_pointer (&contents), length); bytes = g_bytes_new_take (g_steal_pointer (&contents), length);
color_calibration = meta_color_calibration_new (cd_icc, NULL);
color_profile = color_profile =
meta_color_profile_new_from_cd_profile (color_manager, meta_color_profile_new_from_cd_profile (color_manager,
cd_profile, cd_profile,
g_steal_pointer (&cd_icc), g_steal_pointer (&cd_icc),
bytes); bytes,
color_calibration);
g_hash_table_insert (color_store->profiles, g_hash_table_insert (color_store->profiles,
g_strdup (meta_color_profile_get_id (color_profile)), g_strdup (meta_color_profile_get_id (color_profile)),

View File

@ -34,9 +34,6 @@
struct _MetaColorManagerX11 struct _MetaColorManagerX11
{ {
MetaColorManager parent; MetaColorManager parent;
CdIcc *srgb_cd_icc;
GBytes *srgb_icc_bytes;
}; };
G_DEFINE_TYPE (MetaColorManagerX11, meta_color_manager_x11, 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_MAJOR 0
#define ICC_PROFILE_IN_X_VERSION_MINOR 3 #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 static void
update_root_window_atom (MetaColorManagerX11 *color_manager_x11, update_root_window_atom (MetaColorManager *color_manager,
MetaColorDevice *color_device) MetaColorDevice *color_device)
{ {
MetaColorManager *color_manager = META_COLOR_MANAGER (color_manager_x11);
MetaBackend *backend = meta_color_manager_get_backend (color_manager); MetaBackend *backend = meta_color_manager_get_backend (color_manager);
MetaBackendX11 *backend_x11 = META_BACKEND_X11 (backend); MetaBackendX11 *backend_x11 = META_BACKEND_X11 (backend);
Display *xdisplay = meta_backend_x11_get_xdisplay (backend_x11); 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_atom;
Atom icc_profile_version_atom; Atom icc_profile_version_atom;
MetaMonitor *monitor; MetaMonitor *monitor;
MetaColorProfile *color_profile;
const uint8_t *profile_contents = NULL; const uint8_t *profile_contents = NULL;
size_t profile_size; size_t profile_size;
@ -111,33 +62,12 @@ update_root_window_atom (MetaColorManagerX11 *color_manager_x11,
if (!meta_monitor_is_primary (monitor)) if (!meta_monitor_is_primary (monitor))
return; 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
{
MetaColorProfile *color_profile;
color_profile = meta_color_device_get_assigned_profile (color_device); color_profile = meta_color_device_get_assigned_profile (color_device);
if (color_profile) if (color_profile)
{ {
profile_contents = meta_color_profile_get_data (color_profile); profile_contents = meta_color_profile_get_data (color_profile);
profile_size = meta_color_profile_get_data_size (color_profile); profile_size = meta_color_profile_get_data_size (color_profile);
} }
}
icc_profile_atom = XInternAtom (xdisplay, "_ICC_PROFILE", False); icc_profile_atom = XInternAtom (xdisplay, "_ICC_PROFILE", False);
icc_profile_version_atom = XInternAtom (xdisplay, icc_profile_version_atom = XInternAtom (xdisplay,
@ -187,7 +117,7 @@ double_to_ctmval (double value)
} }
static MetaOutputCtm static MetaOutputCtm
mat33_to_ctm (CdMat3x3 matrix) mat33_to_ctm (const CdMat3x3 *matrix)
{ {
MetaOutputCtm ctm; MetaOutputCtm ctm;
@ -195,29 +125,25 @@ mat33_to_ctm (CdMat3x3 matrix)
* libcolord generates a matrix containing double values. RandR's CTM * libcolord generates a matrix containing double values. RandR's CTM
* property expects values in S31.32 fixed-point sign-magnitude format * property expects values in S31.32 fixed-point sign-magnitude format
*/ */
ctm.matrix[0] = double_to_ctmval (matrix.m00); ctm.matrix[0] = double_to_ctmval (matrix->m00);
ctm.matrix[1] = double_to_ctmval (matrix.m01); ctm.matrix[1] = double_to_ctmval (matrix->m01);
ctm.matrix[2] = double_to_ctmval (matrix.m02); ctm.matrix[2] = double_to_ctmval (matrix->m02);
ctm.matrix[3] = double_to_ctmval (matrix.m10); ctm.matrix[3] = double_to_ctmval (matrix->m10);
ctm.matrix[4] = double_to_ctmval (matrix.m11); ctm.matrix[4] = double_to_ctmval (matrix->m11);
ctm.matrix[5] = double_to_ctmval (matrix.m12); ctm.matrix[5] = double_to_ctmval (matrix->m12);
ctm.matrix[6] = double_to_ctmval (matrix.m20); ctm.matrix[6] = double_to_ctmval (matrix->m20);
ctm.matrix[7] = double_to_ctmval (matrix.m21); ctm.matrix[7] = double_to_ctmval (matrix->m21);
ctm.matrix[8] = double_to_ctmval (matrix.m22); ctm.matrix[8] = double_to_ctmval (matrix->m22);
return ctm; return ctm;
} }
static void static void
update_device_ctm (MetaColorManagerX11 *color_manager_x11, update_device_ctm (MetaColorDevice *color_device)
MetaColorDevice *color_device)
{ {
MetaMonitor *monitor; MetaMonitor *monitor;
MetaColorProfile *color_profile; MetaColorProfile *color_profile;
CdIcc *srgb_cd_icc; const MetaColorCalibration *color_calibration;
g_autoptr (GError) error = NULL;
CdIcc *cd_icc;
CdMat3x3 csc;
MetaOutputCtm ctm; MetaOutputCtm ctm;
MetaOutput *output; MetaOutput *output;
MetaOutputXrandr *output_xrandr; MetaOutputXrandr *output_xrandr;
@ -230,19 +156,12 @@ update_device_ctm (MetaColorManagerX11 *color_manager_x11,
if (!color_profile) if (!color_profile)
return; return;
srgb_cd_icc = ensure_srgb_profile (color_manager_x11); color_calibration = meta_color_profile_get_calibration (color_profile);
if (!srgb_cd_icc)
if (!color_calibration->has_adaptation_matrix)
return; return;
cd_icc = meta_color_profile_get_cd_icc (color_profile); ctm = mat33_to_ctm (&color_calibration->adaptation_matrix);
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);
output = meta_monitor_get_main_output (monitor); output = meta_monitor_get_main_output (monitor);
output_xrandr = META_OUTPUT_XRANDR (output); output_xrandr = META_OUTPUT_XRANDR (output);
@ -253,11 +172,8 @@ static void
on_color_device_updated (MetaColorManager *color_manager, on_color_device_updated (MetaColorManager *color_manager,
MetaColorDevice *color_device) MetaColorDevice *color_device)
{ {
MetaColorManagerX11 *color_manager_x11 = update_root_window_atom (color_manager, color_device);
META_COLOR_MANAGER_X11 (color_manager); update_device_ctm (color_device);
update_root_window_atom (color_manager_x11, color_device);
update_device_ctm (color_manager_x11, color_device);
} }
static void static void
@ -271,24 +187,12 @@ meta_color_manager_x11_constructed (GObject *object)
G_OBJECT_CLASS (meta_color_manager_x11_parent_class)->constructed (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 static void
meta_color_manager_x11_class_init (MetaColorManagerX11Class *klass) meta_color_manager_x11_class_init (MetaColorManagerX11Class *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = meta_color_manager_x11_constructed; object_class->constructed = meta_color_manager_x11_constructed;
object_class->finalize = meta_color_manager_x11_finalize;
} }
static void static void

View File

@ -20,6 +20,8 @@
#include "config.h" #include "config.h"
#include <fcntl.h>
#include "backends/meta-color-device.h" #include "backends/meta-color-device.h"
#include "backends/meta-color-manager-private.h" #include "backends/meta-color-manager-private.h"
#include "backends/meta-color-profile.h" #include "backends/meta-color-profile.h"
@ -105,6 +107,22 @@ static MonitorTestCaseSetup base_monitor_setup = {
.white_y = 0.329102, \ .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 * static GDBusProxy *
get_colord_mock_proxy (void) get_colord_mock_proxy (void)
{ {
@ -515,6 +533,155 @@ meta_test_color_management_profile_system (void)
srgb_profile_id); 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 static void
wait_for_profile_assigned (MetaColorDevice *color_device, wait_for_profile_assigned (MetaColorDevice *color_device,
const char *profile_id) const char *profile_id)
@ -1124,6 +1291,8 @@ init_tests (void)
meta_test_color_management_profile_device); meta_test_color_management_profile_device);
add_color_test ("/color-management/profile/system", add_color_test ("/color-management/profile/system",
meta_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", add_color_test ("/color-management/night-light/calibrated",
meta_test_color_management_night_light_calibrated); meta_test_color_management_night_light_calibrated);
add_color_test ("/color-management/night-light/uncalibrated", add_color_test ("/color-management/night-light/uncalibrated",